diff options
| -rw-r--r-- | lualibs-table.lua | 280 | ||||
| -rw-r--r-- | lualibs-util-prs.lua | 46 | ||||
| -rw-r--r-- | lualibs-util-str.lua | 2 | ||||
| -rw-r--r-- | lualibs-util-tab.lua | 60 | 
4 files changed, 251 insertions, 137 deletions
diff --git a/lualibs-table.lua b/lualibs-table.lua index 97e0441..b02f210 100644 --- a/lualibs-table.lua +++ b/lualibs-table.lua @@ -39,7 +39,7 @@ end  function table.keys(t)      if t then          local keys, k = { }, 0 -        for key, _ in next, t do +        for key in next, t do              k = k + 1              keys[k] = key          end @@ -50,44 +50,126 @@ function table.keys(t)  end  -- local function compare(a,b) ---     local ta, tb = type(a), type(b) -- needed, else 11 < 2 ---     if ta == tb then +--     local ta = type(a) -- needed, else 11 < 2 +--     local tb = type(b) -- needed, else 11 < 2 +--     if ta == tb and ta == "number" then  --         return a < b  --     else  --         return tostring(a) < tostring(b) -- not that efficient  --     end  -- end +-- local function compare(a,b) +--     local ta = type(a) -- needed, else 11 < 2 +--     local tb = type(b) -- needed, else 11 < 2 +--     if ta == tb and (ta == "number" or ta == "string") then +--         return a < b +--     else +--         return tostring(a) < tostring(b) -- not that efficient +--     end +-- end + +-- local function sortedkeys(tab) +--     if tab then +--         local srt, category, s = { }, 0, 0 -- 0=unknown 1=string, 2=number 3=mixed +--         for key in next, tab do +--             s = s + 1 +--             srt[s] = key +--             if category == 3 then +--                 -- no further check +--             else +--                 local tkey = type(key) +--                 if tkey == "string" then +--                     category = (category == 2 and 3) or 1 +--                 elseif tkey == "number" then +--                     category = (category == 1 and 3) or 2 +--                 else +--                     category = 3 +--                 end +--             end +--         end +--         if category == 0 or category == 3 then +--             sort(srt,compare) +--         else +--             sort(srt) +--         end +--         return srt +--     else +--         return { } +--     end +-- end + +-- local function compare(a,b) +--     local ta = type(a) -- needed, else 11 < 2 +--     local tb = type(b) -- needed, else 11 < 2 +--     if ta == tb and (ta == "number" or ta == "string") then +--         return a < b +--     else +--         return tostring(a) < tostring(b) -- not that efficient +--     end +-- end + +-- local function compare(a,b) +--     local ta = type(a) -- needed, else 11 < 2 +--     if ta == "number" or ta == "string" then +--         local tb = type(b) -- needed, else 11 < 2 +--         if ta == tb then +--             return a < b +--         end +--     end +--     return tostring(a) < tostring(b) -- not that efficient +-- end +  local function compare(a,b)      local ta = type(a) -- needed, else 11 < 2 -    local tb = type(b) -- needed, else 11 < 2 -    if ta == tb and ta == "number" then -        return a < b -    else -        return tostring(a) < tostring(b) -- not that efficient +    if ta == "number" then +        local tb = type(b) -- needed, else 11 < 2 +        if ta == tb then +            return a < b +        elseif tb == "string" then +            return tostring(a) < b +        end +    elseif ta == "string" then +        local tb = type(b) -- needed, else 11 < 2 +        if ta == tb then +            return a < b +        else +            return a < tostring(b) +        end      end +    return tostring(a) < tostring(b) -- not that efficient  end  local function sortedkeys(tab)      if tab then          local srt, category, s = { }, 0, 0 -- 0=unknown 1=string, 2=number 3=mixed -        for key,_ in next, tab do +        for key in next, tab do              s = s + 1              srt[s] = key              if category == 3 then                  -- no further check +            elseif category == 1 then +                if type(key) ~= "string" then +                    category = 3 +                end +            elseif category == 2 then +                if type(key) ~= "number" then +                    category = 3 +                end              else                  local tkey = type(key)                  if tkey == "string" then -                    category = (category == 2 and 3) or 1 +                    category = 1                  elseif tkey == "number" then -                    category = (category == 1 and 3) or 2 +                    category = 2                  else                      category = 3                  end              end          end -        if category == 0 or category == 3 then +        if s < 2 then +            -- nothing to sort +        elseif category == 3 then              sort(srt,compare)          else              sort(srt) @@ -101,13 +183,15 @@ end  local function sortedhashonly(tab)      if tab then          local srt, s = { }, 0 -        for key,_ in next, tab do +        for key in next, tab do              if type(key) == "string" then                  s = s + 1                  srt[s] = key              end          end -        sort(srt) +        if s > 1 then +            sort(srt) +        end          return srt      else          return { } @@ -117,13 +201,15 @@ end  local function sortedindexonly(tab)      if tab then          local srt, s = { }, 0 -        for key,_ in next, tab do +        for key in next, tab do              if type(key) == "number" then                  s = s + 1                  srt[s] = key              end          end -        sort(srt) +        if s > 1 then +            sort(srt) +        end          return srt      else          return { } @@ -133,13 +219,15 @@ end  local function sortedhashkeys(tab,cmp) -- fast one      if tab then          local srt, s = { }, 0 -        for key,_ in next, tab do +        for key in next, tab do              if key then                  s= s + 1                  srt[s] = key              end          end -        sort(srt,cmp) +        if s > 1 then +            sort(srt,cmp) +        end          return srt      else          return { } @@ -149,7 +237,7 @@ end  function table.allkeys(t)      local keys = { }      for k, v in next, t do -        for k, v in next, v do +        for k in next, v do              keys[k] = true          end      end @@ -172,19 +260,21 @@ local function sortedhash(t,cmp)          else              s = sortedkeys(t) -- the robust one          end -        local n = 0          local m = #s -        local function kv() -- (s) -            if n < m then -                n = n + 1 -                local k = s[n] -                return k, t[k] +        if m == 1 then +            return next, t +        elseif m > 0 then +            local n = 0 +            return function() +                if n < m then +                    n = n + 1 +                    local k = s[n] +                    return k, t[k] +                end              end          end -        return kv -- , s -    else -        return nothing      end +    return nothing  end  table.sortedhash  = sortedhash @@ -328,7 +418,7 @@ end  local function copy(t, tables) -- taken from lua wiki, slightly adapted      tables = tables or { } -    local tcopy = {} +    local tcopy = { }      if not tables[t] then          tables[t] = tcopy      end @@ -388,7 +478,7 @@ function table.fromhash(t)      return hsh  end -local noquotes, hexify, handle, reduce, compact, inline, functions +local noquotes, hexify, handle, compact, inline, functions  local reserved = table.tohash { -- intercept a language inconvenience: no reserved words as key      'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for', 'function', 'if', @@ -396,33 +486,67 @@ local reserved = table.tohash { -- intercept a language inconvenience: no reserv      'NaN', 'goto',  } +-- local function simple_table(t) +--     if #t > 0 then +--         local n = 0 +--         for _,v in next, t do +--             n = n + 1 +--         end +--         if n == #t then +--             local tt, nt = { }, 0 +--             for i=1,#t do +--                 local v = t[i] +--                 local tv = type(v) +--                 if tv == "number" then +--                     nt = nt + 1 +--                     if hexify then +--                         tt[nt] = format("0x%X",v) +--                     else +--                         tt[nt] = tostring(v) -- tostring not needed +--                     end +--                 elseif tv == "string" then +--                     nt = nt + 1 +--                     tt[nt] = format("%q",v) +--                 elseif tv == "boolean" then +--                     nt = nt + 1 +--                     tt[nt] = v and "true" or "false" +--                 else +--                     return nil +--                 end +--             end +--             return tt +--         end +--     end +--     return nil +-- end +  local function simple_table(t) -    if #t > 0 then +    local nt = #t +    if nt > 0 then          local n = 0          for _,v in next, t do              n = n + 1 +         -- if type(v) == "table" then +         --     return nil +         -- end          end -        if n == #t then -            local tt, nt = { }, 0 -            for i=1,#t do +        if n == nt then +            local tt = { } +            for i=1,nt do                  local v = t[i]                  local tv = type(v)                  if tv == "number" then -                    nt = nt + 1                      if hexify then -                        tt[nt] = format("0x%X",v) +                        tt[i] = format("0x%X",v)                      else -                        tt[nt] = tostring(v) -- tostring not needed +                        tt[i] = tostring(v) -- tostring not needed                      end                  elseif tv == "string" then -                    nt = nt + 1 -                    tt[nt] = format("%q",v) +                    tt[i] = format("%q",v)                  elseif tv == "boolean" then -                    nt = nt + 1 -                    tt[nt] = v and "true" or "false" +                    tt[i] = v and "true" or "false"                  else -                    tt = nil -                    break +                    return nil                  end              end              return tt @@ -480,14 +604,6 @@ local function do_serialize(root,name,depth,level,indexed)      end      -- we could check for k (index) being number (cardinal)      if root and next(root) ~= nil then -     -- local first, last = nil, 0 -- #root cannot be trusted here (will be ok in 5.2 when ipairs is gone) -     -- if compact then -     --     -- NOT: for k=1,#root do (we need to quit at nil) -     --     for k,v in ipairs(root) do -- can we use next? -     --         if not first then first = k end -     --         last = last + 1 -     --     end -     -- end          local first, last = nil, 0          if compact then              last = #root @@ -503,12 +619,10 @@ local function do_serialize(root,name,depth,level,indexed)          end          local sk = sortedkeys(root)          for i=1,#sk do -            local k = sk[i] -            local v = root[k] -            --~ if v == root then -                -- circular -            --~ else -            local tv, tk = type(v), type(k) +            local k  = sk[i] +            local v  = root[k] +            local tv = type(v) +            local tk = type(k)              if compact and first and tk == "number" and k >= first and k <= last then                  if tv == "number" then                      if hexify then @@ -517,11 +631,7 @@ local function do_serialize(root,name,depth,level,indexed)                          handle(format("%s %s,",depth,v)) -- %.99g                      end                  elseif tv == "string" then -                    if reduce and tonumber(v) then -                        handle(format("%s %s,",depth,v)) -                    else -                        handle(format("%s %q,",depth,v)) -                    end +                    handle(format("%s %q,",depth,v))                  elseif tv == "table" then                      if next(v) == nil then                          handle(format("%s {},",depth)) @@ -577,34 +687,18 @@ local function do_serialize(root,name,depth,level,indexed)                      end                  end              elseif tv == "string" then -                if reduce and tonumber(v) then -                    if tk == "number" then -                        if hexify then -                            handle(format("%s [0x%X]=%s,",depth,k,v)) -                        else -                            handle(format("%s [%s]=%s,",depth,k,v)) -                        end -                    elseif tk == "boolean" then -                        handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) -                    elseif noquotes and not reserved[k] and lpegmatch(propername,k) then -                        handle(format("%s %s=%s,",depth,k,v)) +                if tk == "number" then +                    if hexify then +                        handle(format("%s [0x%X]=%q,",depth,k,v))                      else -                        handle(format("%s [%q]=%s,",depth,k,v)) +                        handle(format("%s [%s]=%q,",depth,k,v))                      end +                elseif tk == "boolean" then +                    handle(format("%s [%s]=%q,",depth,k and "true" or "false",v)) +                elseif noquotes and not reserved[k] and lpegmatch(propername,k) then +                    handle(format("%s %s=%q,",depth,k,v))                  else -                    if tk == "number" then -                        if hexify then -                            handle(format("%s [0x%X]=%q,",depth,k,v)) -                        else -                            handle(format("%s [%s]=%q,",depth,k,v)) -                        end -                    elseif tk == "boolean" then -                        handle(format("%s [%s]=%q,",depth,k and "true" or "false",v)) -                    elseif noquotes and not reserved[k] and lpegmatch(propername,k) then -                        handle(format("%s %s=%q,",depth,k,v)) -                    else -                        handle(format("%s [%q]=%q,",depth,k,v)) -                    end +                    handle(format("%s [%q]=%q,",depth,k,v))                  end              elseif tv == "table" then                  if next(v) == nil then @@ -690,7 +784,6 @@ local function do_serialize(root,name,depth,level,indexed)                      handle(format("%s [%q]=%q,",depth,k,tostring(v)))                  end              end -            --~ end          end      end      if level > 0 then @@ -707,7 +800,6 @@ local function serialize(_handle,root,name,specification) -- handle wins          noquotes  = specification.noquotes          hexify    = specification.hexify          handle    = _handle or specification.handle or print -        reduce    = specification.reduce or false          functions = specification.functions          compact   = specification.compact          inline    = specification.inline and compact @@ -724,7 +816,6 @@ local function serialize(_handle,root,name,specification) -- handle wins          noquotes  = false          hexify    = false          handle    = _handle or print -        reduce    = false          compact   = true          inline    = true          functions = true @@ -798,15 +889,6 @@ end  table.tohandle = serialize --- sometimes tables are real use (zapfino extra pro is some 85M) in which --- case a stepwise serialization is nice; actually, we could consider: --- --- for line in table.serializer(root,name,reduce,noquotes) do ---    ...(line) --- end --- --- so this is on the todo list -  local maxtab = 2*1024  function table.tofile(filename,root,name,specification) diff --git a/lualibs-util-prs.lua b/lualibs-util-prs.lua index ea34c2c..a3c1c6f 100644 --- a/lualibs-util-prs.lua +++ b/lualibs-util-prs.lua @@ -21,6 +21,8 @@ parsers.patterns  = patterns  local setmetatableindex = table.setmetatableindex  local sortedhash        = table.sortedhash +local sortedkeys        = table.sortedkeys +local tohash            = table.tohash  -- we share some patterns @@ -94,9 +96,7 @@ patterns.settings_to_hash_b = pattern_b_s  patterns.settings_to_hash_c = pattern_c_s  function parsers.make_settings_to_hash_pattern(set,how) -    if type(str) == "table" then -        return set -    elseif how == "strict" then +    if how == "strict" then          return (pattern_c/set)^1      elseif how == "tolerant" then          return (pattern_b/set)^1 @@ -106,7 +106,9 @@ function parsers.make_settings_to_hash_pattern(set,how)  end  function parsers.settings_to_hash(str,existing) -    if type(str) == "table" then +    if not str or str == "" then +        return { } +    elseif type(str) == "table" then          if existing then              for k, v in next, str do                  existing[k] = v @@ -115,17 +117,17 @@ function parsers.settings_to_hash(str,existing)          else              return str          end -    elseif str and str ~= "" then +    else          hash = existing or { }          lpegmatch(pattern_a_s,str)          return hash -    else -        return { }      end  end  function parsers.settings_to_hash_tolerant(str,existing) -    if type(str) == "table" then +    if not str or str == "" then +        return { } +    elseif type(str) == "table" then          if existing then              for k, v in next, str do                  existing[k] = v @@ -134,17 +136,17 @@ function parsers.settings_to_hash_tolerant(str,existing)          else              return str          end -    elseif str and str ~= "" then +    else          hash = existing or { }          lpegmatch(pattern_b_s,str)          return hash -    else -        return { }      end  end  function parsers.settings_to_hash_strict(str,existing) -    if type(str) == "table" then +    if not str or str == "" then +        return nil +    elseif type(str) == "table" then          if existing then              for k, v in next, str do                  existing[k] = v @@ -157,8 +159,6 @@ function parsers.settings_to_hash_strict(str,existing)          hash = existing or { }          lpegmatch(pattern_c_s,str)          return next(hash) and hash -    else -        return nil      end  end @@ -174,10 +174,10 @@ patterns.settings_to_array = pattern  -- we could use a weak table as cache  function parsers.settings_to_array(str,strict) -    if type(str) == "table" then -        return str -    elseif not str or str == "" then +    if not str or str == "" then          return { } +    elseif type(str) == "table" then +        return str      elseif strict then          if find(str,"{",1,true) then              return lpegmatch(pattern,str) @@ -262,8 +262,8 @@ end  function parsers.hash_to_string(h,separator,yes,no,strict,omit)      if h then -        local t, tn, s = { }, 0, table.sortedkeys(h) -        omit = omit and table.tohash(omit) +        local t, tn, s = { }, 0, sortedkeys(h) +        omit = omit and tohash(omit)          for i=1,#s do              local key = s[i]              if not omit or not omit[key] then @@ -478,7 +478,7 @@ local defaultspecification = { separator = ",", quote = '"' }  -- database module  function parsers.csvsplitter(specification) -    specification   = specification and table.setmetatableindex(specification,defaultspecification) or defaultspecification +    specification   = specification and setmetatableindex(specification,defaultspecification) or defaultspecification      local separator = specification.separator      local quotechar = specification.quote      local separator = S(separator ~= "" and separator or ",") @@ -517,7 +517,7 @@ end  -- local list, names = mycsvsplitter(crap)        inspect(list) inspect(names)  function parsers.rfc4180splitter(specification) -    specification     = specification and table.setmetatableindex(specification,defaultspecification) or defaultspecification +    specification     = specification and setmetatableindex(specification,defaultspecification) or defaultspecification      local separator   = specification.separator --> rfc: COMMA      local quotechar   = P(specification.quote)  -->      DQUOTE      local dquotechar  = quotechar * quotechar   -->      2DQUOTE @@ -602,10 +602,10 @@ end  -- print(utilities.parsers.unittotex("10^-32 %"),utilities.parsers.unittoxml("10^32 %"))  local cache   = { } -local spaces  = lpeg.patterns.space^0 +local spaces  = lpegpatterns.space^0  local dummy   = function() end -table.setmetatableindex(cache,function(t,k) +setmetatableindex(cache,function(t,k)      local separator = P(k)      local value     = (1-separator)^0      local pattern   = spaces * C(value) * separator^0 * Cp() diff --git a/lualibs-util-str.lua b/lualibs-util-str.lua index de4a87e..c2139b1 100644 --- a/lualibs-util-str.lua +++ b/lualibs-util-str.lua @@ -1118,7 +1118,7 @@ function string.optionalquoted(str)      return lpegmatch(pattern,str) or str  end -local pattern = Cs((newline / os.newline + 1)^0) +local pattern = Cs((newline / (os.newline or "\r") + 1)^0)  function string.replacenewlines(str)      return lpegmatch(pattern,str) diff --git a/lualibs-util-tab.lua b/lualibs-util-tab.lua index 5eae0d5..618f34c 100644 --- a/lualibs-util-tab.lua +++ b/lualibs-util-tab.lua @@ -11,7 +11,7 @@ utilities.tables = utilities.tables or { }  local tables     = utilities.tables  local format, gmatch, gsub, sub = string.format, string.gmatch, string.gsub, string.sub -local concat, insert, remove = table.concat, table.insert, table.remove +local concat, insert, remove, sort = table.concat, table.insert, table.remove, table.sort  local setmetatable, getmetatable, tonumber, tostring = setmetatable, getmetatable, tonumber, tostring  local type, next, rawset, tonumber, tostring, load, select = type, next, rawset, tonumber, tostring, load, select  local lpegmatch, P, Cs, Cc = lpeg.match, lpeg.P, lpeg.Cs, lpeg.Cc @@ -571,8 +571,42 @@ function table.serialize(root,name,specification)      local t -- = { }      local n = 1 +--     local function simple_table(t) +--         local ts = #t +--         if ts > 0 then +--             local n = 0 +--             for _, v in next, t do +--                 n = n + 1 +--                 if type(v) == "table" then +--                     return nil +--                 end +--             end +--             if n == ts then +--                 local tt = { } +--                 local nt = 0 +--                 for i=1,ts do +--                     local v = t[i] +--                     local tv = type(v) +--                     nt = nt + 1 +--                     if tv == "number" then +--                         tt[nt] = v +--                     elseif tv == "string" then +--                         tt[nt] = format("%q",v) -- f_string(v) +--                     elseif tv == "boolean" then +--                         tt[nt] = v and "true" or "false" +--                     else +--                         return nil +--                     end +--                 end +--                 return tt +--             end +--         end +--         return nil +--     end +      local function simple_table(t) -        if #t > 0 then +        local nt = #t +        if nt > 0 then              local n = 0              for _, v in next, t do                  n = n + 1 @@ -580,19 +614,17 @@ function table.serialize(root,name,specification)                      return nil                  end              end -            if n == #t then +            if n == nt then                  local tt = { } -                local nt = 0 -                for i=1,#t do +                for i=1,nt do                      local v = t[i]                      local tv = type(v) -                    nt = nt + 1                      if tv == "number" then -                        tt[nt] = v +                        tt[i] = v -- not needed tostring(v)                      elseif tv == "string" then -                        tt[nt] = format("%q",v) -- f_string(v) +                        tt[i] = format("%q",v) -- f_string(v)                      elseif tv == "boolean" then -                        tt[nt] = v and "true" or "false" +                        tt[i] = v and "true" or "false"                      else                          return nil                      end @@ -636,13 +668,13 @@ function table.serialize(root,name,specification)              if last > 0 then                  first = 1              end -            local sk = sortedkeys(root) -- inline fast version? +            local sk = sortedkeys(root) -- inline fast version?\              for i=1,#sk do                  local k  = sk[i]                  local v  = root[k]                  local tv = type(v)                  local tk = type(k) -                if first and tk == "number" and k >= first and k <= last then +                if first and tk == "number" and k <= last and k >= first then                      if tv == "number" then                          n = n + 1 t[n] = f_val_num(depth,v)                      elseif tv == "string" then @@ -680,11 +712,11 @@ function table.serialize(root,name,specification)                  elseif tv == "table" then                      if next(v) == nil then                          if tk == "number" then -                            n = n + 1 t[n] = f_key_num_value_not(depth,k,v) +                            n = n + 1 t[n] = f_key_num_value_not(depth,k)                          elseif tk == "string" then -                            n = n + 1 t[n] = f_key_str_value_not(depth,k,v) +                            n = n + 1 t[n] = f_key_str_value_not(depth,k)                          elseif tk == "boolean" then -                            n = n + 1 t[n] = f_key_boo_value_not(depth,k,v) +                            n = n + 1 t[n] = f_key_boo_value_not(depth,k)                          end                      else                          local st = simple_table(v)  | 
