summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lualibs-table.lua280
-rw-r--r--lualibs-util-prs.lua46
-rw-r--r--lualibs-util-str.lua2
-rw-r--r--lualibs-util-tab.lua60
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)