diff options
Diffstat (limited to 'lualibs-table.lua')
| -rw-r--r-- | lualibs-table.lua | 637 | 
1 files changed, 503 insertions, 134 deletions
| diff --git a/lualibs-table.lua b/lualibs-table.lua index 80f28c2..640bbbb 100644 --- a/lualibs-table.lua +++ b/lualibs-table.lua @@ -6,68 +6,23 @@ if not modules then modules = { } end modules ['l-table'] = {      license   = "see context related readme files"  } -local type, next, tostring, tonumber, ipairs = type, next, tostring, tonumber, ipairs +local type, next, tostring, tonumber, ipairs, select = type, next, tostring, tonumber, ipairs, select  local table, string = table, string  local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove -local format, find, gsub, lower, dump, match = string.format, string.find, string.gsub, string.lower, string.dump, string.match +local format, lower, dump = string.format, string.lower, string.dump  local getmetatable, setmetatable = getmetatable, setmetatable  local getinfo = debug.getinfo - --- Starting with version 5.2 Lua no longer provide ipairs, which makes --- sense. As we already used the for loop and # in most places the --- impact on ConTeXt was not that large; the remaining ipairs already --- have been replaced. In a similar fashion we also hardly used pairs. --- --- Hm, actually ipairs was retained, but we no longer use it anyway. --- --- Just in case, we provide the fallbacks as discussed in Programming --- in Lua (http://www.lua.org/pil/7.3.html): - -if not ipairs then - -    -- for k, v in ipairs(t) do                ... end -    -- for k=1,#t            do local v = t[k] ... end - -    local function iterate(a,i) -        i = i + 1 -        local v = a[i] -        if v ~= nil then -            return i, v --, nil -        end -    end - -    function ipairs(a) -        return iterate, a, 0 -    end - -end - -if not pairs then - -    -- for k, v in pairs(t) do ... end -    -- for k, v in next, t  do ... end - -    function pairs(t) -        return next, t -- , nil -    end - -end - --- Also, unpack has been moved to the table table, and for compatiility --- reasons we provide both now. - -if not table.unpack then -    table.unpack = _G.unpack -elseif not unpack then -    _G.unpack = table.unpack -end +local lpegmatch, patterns = lpeg.match, lpeg.patterns +local floor = math.floor  -- extra functions, some might go (when not used) +local stripper = patterns.stripper +  function table.strip(tab)      local lst, l = { }, 0      for i=1,#tab do -        local s = gsub(tab[i],"^%s*(.-)%s*$","%1") +        local s = lpegmatch(stripper,tab[i]) or ""          if s == "" then              -- skip this one          else @@ -130,7 +85,7 @@ local function sortedkeys(tab)      end  end -local function sortedhashkeys(tab) -- fast one +local function sortedhashkeys(tab,cmp) -- fast one      if tab then          local srt, s = { }, 0          for key,_ in next, tab do @@ -139,21 +94,38 @@ local function sortedhashkeys(tab) -- fast one                  srt[s] = key              end          end -        sort(srt) +        sort(srt,cmp)          return srt      else          return { }      end  end +function table.allkeys(t) +    local keys = { } +    for k, v in next, t do +        for k, v in next, v do +            keys[k] = true +        end +    end +    return sortedkeys(keys) +end +  table.sortedkeys     = sortedkeys  table.sortedhashkeys = sortedhashkeys  local function nothing() end -local function sortedhash(t) +local function sortedhash(t,cmp)      if t then -        local n, s = 0, sortedkeys(t) -- the robust one +        local s +        if cmp then +            -- it would be nice if teh sort function would accept a third argument (or nicer, an optional first) +            s = sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) +        else +            s = sortedkeys(t) -- the robust one +        end +        local n = 0          local function kv(s)              n = n + 1              local k = s[n] @@ -166,7 +138,7 @@ local function sortedhash(t)  end  table.sortedhash  = sortedhash -table.sortedpairs = sortedhash +table.sortedpairs = sortedhash -- obsolete  function table.append(t,list)      local n = #t @@ -190,31 +162,63 @@ function table.prepend(t, list)      return t  end +-- function table.merge(t, ...) -- first one is target +--     t = t or { } +--     local lst = { ... } +--     for i=1,#lst do +--         for k, v in next, lst[i] do +--             t[k] = v +--         end +--     end +--     return t +-- end +  function table.merge(t, ...) -- first one is target      t = t or { } -    local lst = { ... } -    for i=1,#lst do -        for k, v in next, lst[i] do +    for i=1,select("#",...) do +        for k, v in next, (select(i,...)) do              t[k] = v          end      end      return t  end +-- function table.merged(...) +--     local tmp, lst = { }, { ... } +--     for i=1,#lst do +--         for k, v in next, lst[i] do +--             tmp[k] = v +--         end +--     end +--     return tmp +-- end +  function table.merged(...) -    local tmp, lst = { }, { ... } -    for i=1,#lst do -        for k, v in next, lst[i] do -            tmp[k] = v +    local t = { } +    for i=1,select("#",...) do +        for k, v in next, (select(i,...)) do +            t[k] = v          end      end -    return tmp +    return t  end +-- function table.imerge(t, ...) +--     local lst, nt = { ... }, #t +--     for i=1,#lst do +--         local nst = lst[i] +--         for j=1,#nst do +--             nt = nt + 1 +--             t[nt] = nst[j] +--         end +--     end +--     return t +-- end +  function table.imerge(t, ...) -    local lst, nt = { ... }, #t -    for i=1,#lst do -        local nst = lst[i] +    local nt = #t +    for i=1,select("#",...) do +        local nst = select(i,...)          for j=1,#nst do              nt = nt + 1              t[nt] = nst[j] @@ -223,10 +227,22 @@ function table.imerge(t, ...)      return t  end +-- function table.imerged(...) +--     local tmp, ntmp, lst = { }, 0, {...} +--     for i=1,#lst do +--         local nst = lst[i] +--         for j=1,#nst do +--             ntmp = ntmp + 1 +--             tmp[ntmp] = nst[j] +--         end +--     end +--     return tmp +-- end +  function table.imerged(...) -    local tmp, ntmp, lst = { }, 0, {...} -    for i=1,#lst do -        local nst = lst[i] +    local tmp, ntmp = { }, 0 +    for i=1,select("#",...) do +        local nst = select(i,...)          for j=1,#nst do              ntmp = ntmp + 1              tmp[ntmp] = nst[j] @@ -238,7 +254,7 @@ end  local function fastcopy(old,metatabletoo) -- fast one      if old then          local new = { } -        for k,v in next, old do +        for k, v in next, old do              if type(v) == "table" then                  new[k] = fastcopy(v,metatabletoo) -- was just table.copy              else @@ -292,7 +308,7 @@ end  table.fastcopy = fastcopy  table.copy     = copy -function table.derive(parent) +function table.derive(parent) -- for the moment not public      local child = { }      if parent then          setmetatable(child,{ __index = parent }) @@ -373,6 +389,15 @@ end  -- problem: there no good number_to_string converter with the best resolution +-- probably using .. is faster than format +-- maybe split in a few cases (yes/no hexify) + +-- todo: %g faster on numbers than %s + +-- we can speed this up with repeaters and formatters (is indeed faster) + +local propername = patterns.propername -- was find(name,"^%a[%w%_]*$") +  local function dummy() end  local function do_serialize(root,name,depth,level,indexed) @@ -382,14 +407,14 @@ local function do_serialize(root,name,depth,level,indexed)              handle(format("%s{",depth))          else              local tn = type(name) -            if tn == "number" then -- or find(k,"^%d+$") then +            if tn == "number" then                  if hexify then                      handle(format("%s[0x%04X]={",depth,name))                  else                      handle(format("%s[%s]={",depth,name))                  end              elseif tn == "string" then -                if noquotes and not reserved[name] and find(name,"^%a[%w%_]*$") then +                if noquotes and not reserved[name] and lpegmatch(propername,name) then                      handle(format("%s%s={",depth,name))                  else                      handle(format("%s[%q]={",depth,name)) @@ -415,7 +440,6 @@ local function do_serialize(root,name,depth,level,indexed)          if compact then              last = #root              for k=1,last do ---                 if not root[k] then                  if root[k] == nil then                      last = k - 1                      break @@ -463,7 +487,7 @@ local function do_serialize(root,name,depth,level,indexed)                      handle(format("%s %s,",depth,tostring(v)))                  elseif t == "function" then                      if functions then -                        handle(format('%s loadstring(%q),',depth,dump(v))) +                        handle(format('%s load(%q),',depth,dump(v)))                      else                          handle(format('%s "function",',depth))                      end @@ -475,7 +499,7 @@ local function do_serialize(root,name,depth,level,indexed)                      handle(format("%s __p__=nil,",depth))                  end              elseif t == "number" then -                if tk == "number" then -- or find(k,"^%d+$") then +                if tk == "number" then                      if hexify then                          handle(format("%s [0x%04X]=0x%04X,",depth,k,v))                      else @@ -487,7 +511,7 @@ local function do_serialize(root,name,depth,level,indexed)                      else                          handle(format("%s [%s]=%s,",depth,tostring(k),v)) -- %.99g                      end -                elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then +                elseif noquotes and not reserved[k] and lpegmatch(propername,k) then                      if hexify then                          handle(format("%s %s=0x%04X,",depth,k,v))                      else @@ -502,7 +526,7 @@ local function do_serialize(root,name,depth,level,indexed)                  end              elseif t == "string" then                  if reduce and tonumber(v) then -                    if tk == "number" then -- or find(k,"^%d+$") then +                    if tk == "number" then                          if hexify then                              handle(format("%s [0x%04X]=%s,",depth,k,v))                          else @@ -510,13 +534,13 @@ local function do_serialize(root,name,depth,level,indexed)                          end                      elseif tk == "boolean" then                          handle(format("%s [%s]=%s,",depth,tostring(k),v)) -                    elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then +                    elseif noquotes and not reserved[k] and lpegmatch(propername,k) then                          handle(format("%s %s=%s,",depth,k,v))                      else                          handle(format("%s [%q]=%s,",depth,k,v))                      end                  else -                    if tk == "number" then -- or find(k,"^%d+$") then +                    if tk == "number" then                          if hexify then                              handle(format("%s [0x%04X]=%q,",depth,k,v))                          else @@ -524,7 +548,7 @@ local function do_serialize(root,name,depth,level,indexed)                          end                      elseif tk == "boolean" then                          handle(format("%s [%s]=%q,",depth,tostring(k),v)) -                    elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then +                    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)) @@ -532,7 +556,7 @@ local function do_serialize(root,name,depth,level,indexed)                  end              elseif t == "table" then                  if not next(v) then -                    if tk == "number" then -- or find(k,"^%d+$") then +                    if tk == "number" then                          if hexify then                              handle(format("%s [0x%04X]={},",depth,k))                          else @@ -540,7 +564,7 @@ local function do_serialize(root,name,depth,level,indexed)                          end                      elseif tk == "boolean" then                          handle(format("%s [%s]={},",depth,tostring(k))) -                    elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then +                    elseif noquotes and not reserved[k] and lpegmatch(propername,k) then                          handle(format("%s %s={},",depth,k))                      else                          handle(format("%s [%q]={},",depth,k)) @@ -548,15 +572,15 @@ local function do_serialize(root,name,depth,level,indexed)                  elseif inline then                      local st = simple_table(v)                      if st then -                        if tk == "number" then -- or find(k,"^%d+$") then +                        if tk == "number" then                              if hexify then                                  handle(format("%s [0x%04X]={ %s },",depth,k,concat(st,", ")))                              else                                  handle(format("%s [%s]={ %s },",depth,k,concat(st,", ")))                              end -                        elseif tk == "boolean" then -- or find(k,"^%d+$") then +                        elseif tk == "boolean" then                              handle(format("%s [%s]={ %s },",depth,tostring(k),concat(st,", "))) -                        elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then +                        elseif noquotes and not reserved[k] and lpegmatch(propername,k) then                              handle(format("%s %s={ %s },",depth,k,concat(st,", ")))                          else                              handle(format("%s [%q]={ %s },",depth,k,concat(st,", "))) @@ -568,15 +592,15 @@ local function do_serialize(root,name,depth,level,indexed)                      do_serialize(v,k,depth,level+1)                  end              elseif t == "boolean" then -                if tk == "number" then -- or find(k,"^%d+$") then +                if tk == "number" then                      if hexify then                          handle(format("%s [0x%04X]=%s,",depth,k,tostring(v)))                      else                          handle(format("%s [%s]=%s,",depth,k,tostring(v)))                      end -                elseif tk == "boolean" then -- or find(k,"^%d+$") then +                elseif tk == "boolean" then                      handle(format("%s [%s]=%s,",depth,tostring(k),tostring(v))) -                elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then +                elseif noquotes and not reserved[k] and lpegmatch(propername,k) then                      handle(format("%s %s=%s,",depth,k,tostring(v)))                  else                      handle(format("%s [%q]=%s,",depth,k,tostring(v))) @@ -585,30 +609,30 @@ local function do_serialize(root,name,depth,level,indexed)                  if functions then                      local f = getinfo(v).what == "C" and dump(dummy) or dump(v)                   -- local f = getinfo(v).what == "C" and dump(function(...) return v(...) end) or dump(v) -                    if tk == "number" then -- or find(k,"^%d+$") then +                    if tk == "number" then                          if hexify then -                            handle(format("%s [0x%04X]=loadstring(%q),",depth,k,f)) +                            handle(format("%s [0x%04X]=load(%q),",depth,k,f))                          else -                            handle(format("%s [%s]=loadstring(%q),",depth,k,f)) +                            handle(format("%s [%s]=load(%q),",depth,k,f))                          end                      elseif tk == "boolean" then -                        handle(format("%s [%s]=loadstring(%q),",depth,tostring(k),f)) -                    elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then -                        handle(format("%s %s=loadstring(%q),",depth,k,f)) +                        handle(format("%s [%s]=load(%q),",depth,tostring(k),f)) +                    elseif noquotes and not reserved[k] and lpegmatch(propername,k) then +                        handle(format("%s %s=load(%q),",depth,k,f))                      else -                        handle(format("%s [%q]=loadstring(%q),",depth,k,f)) +                        handle(format("%s [%q]=load(%q),",depth,k,f))                      end                  end              else -                if tk == "number" then -- or find(k,"^%d+$") then +                if tk == "number" then                      if hexify then                          handle(format("%s [0x%04X]=%q,",depth,k,tostring(v)))                      else                          handle(format("%s [%s]=%q,",depth,k,tostring(v)))                      end -                elseif tk == "boolean" then -- or find(k,"^%d+$") then +                elseif tk == "boolean" then                      handle(format("%s [%s]=%q,",depth,tostring(k),tostring(v))) -                elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then +                elseif noquotes and not reserved[k] and lpegmatch(propername,k) then                      handle(format("%s %s=%q,",depth,k,tostring(v)))                  else                      handle(format("%s [%q]=%q,",depth,k,tostring(v))) @@ -689,14 +713,330 @@ local function serialize(_handle,root,name,specification) -- handle wins      handle("}")  end ---~ name: ---~ ---~ true     : return     { } ---~ false    :            { } ---~ nil      : t        = { } ---~ string   : string   = { } ---~ 'return' : return     { } ---~ number   : [number] = { } +--    -- This is some 20% faster than using format (because formatters are much faster) but +--    -- of course, inlining the format using .. is then again faster .. anyway, as we do +--    -- some pretty printing as well there is not that much to gain unless we make a 'fast' +--    -- ugly variant as well. But, we would have to move the formatter to l-string then. + +--    local formatters = string.formatters + +--    local function do_serialize(root,name,level,indexed) +--        if level > 0 then +--            if indexed then +--                handle(formatters["%w{"](level)) +--            else +--                local tn = type(name) +--                if tn == "number" then +--                    if hexify then +--                        handle(formatters["%w[%04H]={"](level,name)) +--                    else +--                        handle(formatters["%w[%s]={"](level,name)) +--                    end +--                elseif tn == "string" then +--                    if noquotes and not reserved[name] and lpegmatch(propername,name) then +--                        handle(formatters["%w%s={"](level,name)) +--                    else +--                        handle(formatters["%w[%q]={"](level,name)) +--                    end +--                elseif tn == "boolean" then +--                    handle(formatters["%w[%S]={"](level,name)) +--                else +--                    handle(formatters["%w{"](level)) +--                end +--            end +--        end +--        -- we could check for k (index) being number (cardinal) +--        if root and next(root) 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 +--                for k=1,last do +--                    if root[k] == nil then +--                        last = k - 1 +--                        break +--                    end +--                end +--                if last > 0 then +--                    first = 1 +--                end +--            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 t, tk = type(v), type(k) +--                if compact and first and tk == "number" and k >= first and k <= last then +--                    if t == "number" then +--                        if hexify then +--                            handle(formatters["%w %04H,"](level,v)) +--                        else +--                            handle(formatters["%w %s,"](level,v)) -- %.99g +--                        end +--                    elseif t == "string" then +--                        if reduce and tonumber(v) then +--                            handle(formatters["%w %s,"](level,v)) +--                        else +--                            handle(formatters["%w %q,"](level,v)) +--                        end +--                    elseif t == "table" then +--                        if not next(v) then +--                            handle(formatters["%w {},"](level)) +--                        elseif inline then -- and #t > 0 +--                            local st = simple_table(v) +--                            if st then +--                                handle(formatters["%w { %, t },"](level,st)) +--                            else +--                                do_serialize(v,k,level+1,true) +--                            end +--                        else +--                            do_serialize(v,k,level+1,true) +--                        end +--                    elseif t == "boolean" then +--                        handle(formatters["%w %S,"](level,v)) +--                    elseif t == "function" then +--                        if functions then +--                            handle(formatters['%w load(%q),'](level,dump(v))) +--                        else +--                            handle(formatters['%w "function",'](level)) +--                        end +--                    else +--                        handle(formatters["%w %Q,"](level,v)) +--                    end +--                elseif k == "__p__" then -- parent +--                    if false then +--                        handle(formatters["%w __p__=nil,"](level)) +--                    end +--                elseif t == "number" then +--                    if tk == "number" then +--                        if hexify then +--                            handle(formatters["%w [%04H]=%04H,"](level,k,v)) +--                        else +--                            handle(formatters["%w [%s]=%s,"](level,k,v)) -- %.99g +--                        end +--                    elseif tk == "boolean" then +--                        if hexify then +--                            handle(formatters["%w [%S]=%04H,"](level,k,v)) +--                        else +--                            handle(formatters["%w [%S]=%s,"](level,k,v)) -- %.99g +--                        end +--                    elseif noquotes and not reserved[k] and lpegmatch(propername,k) then +--                        if hexify then +--                            handle(formatters["%w %s=%04H,"](level,k,v)) +--                        else +--                            handle(formatters["%w %s=%s,"](level,k,v)) -- %.99g +--                        end +--                    else +--                        if hexify then +--                            handle(formatters["%w [%q]=%04H,"](level,k,v)) +--                        else +--                            handle(formatters["%w [%q]=%s,"](level,k,v)) -- %.99g +--                        end +--                    end +--                elseif t == "string" then +--                    if reduce and tonumber(v) then +--                        if tk == "number" then +--                            if hexify then +--                                handle(formatters["%w [%04H]=%s,"](level,k,v)) +--                            else +--                                handle(formatters["%w [%s]=%s,"](level,k,v)) +--                            end +--                        elseif tk == "boolean" then +--                            handle(formatters["%w [%S]=%s,"](level,k,v)) +--                        elseif noquotes and not reserved[k] and lpegmatch(propername,k) then +--                            handle(formatters["%w %s=%s,"](level,k,v)) +--                        else +--                            handle(formatters["%w [%q]=%s,"](level,k,v)) +--                        end +--                    else +--                        if tk == "number" then +--                            if hexify then +--                                handle(formatters["%w [%04H]=%q,"](level,k,v)) +--                            else +--                                handle(formatters["%w [%s]=%q,"](level,k,v)) +--                            end +--                        elseif tk == "boolean" then +--                            handle(formatters["%w [%S]=%q,"](level,k,v)) +--                        elseif noquotes and not reserved[k] and lpegmatch(propername,k) then +--                            handle(formatters["%w %s=%q,"](level,k,v)) +--                        else +--                            handle(formatters["%w [%q]=%q,"](level,k,v)) +--                        end +--                    end +--                elseif t == "table" then +--                    if not next(v) then +--                        if tk == "number" then +--                            if hexify then +--                                handle(formatters["%w [%04H]={},"](level,k)) +--                            else +--                                handle(formatters["%w [%s]={},"](level,k)) +--                            end +--                        elseif tk == "boolean" then +--                            handle(formatters["%w [%S]={},"](level,k)) +--                        elseif noquotes and not reserved[k] and lpegmatch(propername,k) then +--                            handle(formatters["%w %s={},"](level,k)) +--                        else +--                            handle(formatters["%w [%q]={},"](level,k)) +--                        end +--                    elseif inline then +--                        local st = simple_table(v) +--                        if st then +--                            if tk == "number" then +--                                if hexify then +--                                    handle(formatters["%w [%04H]={ %, t },"](level,k,st)) +--                                else +--                                    handle(formatters["%w [%s]={ %, t },"](level,k,st)) +--                                end +--                            elseif tk == "boolean" then +--                                handle(formatters["%w [%S]={ %, t },"](level,k,st)) +--                            elseif noquotes and not reserved[k] and lpegmatch(propername,k) then +--                                handle(formatters["%w %s={ %, t },"](level,k,st)) +--                            else +--                                handle(formatters["%w [%q]={ %, t },"](level,k,st)) +--                            end +--                        else +--                            do_serialize(v,k,level+1) +--                        end +--                    else +--                        do_serialize(v,k,level+1) +--                    end +--                elseif t == "boolean" then +--                    if tk == "number" then +--                        if hexify then +--                            handle(formatters["%w [%04H]=%S,"](level,k,v)) +--                        else +--                            handle(formatters["%w [%s]=%S,"](level,k,v)) +--                        end +--                    elseif tk == "boolean" then +--                        handle(formatters["%w [%S]=%S,"](level,k,v)) +--                    elseif noquotes and not reserved[k] and lpegmatch(propername,k) then +--                        handle(formatters["%w %s=%S,"](level,k,v)) +--                    else +--                        handle(formatters["%w [%q]=%S,"](level,k,v)) +--                    end +--                elseif t == "function" then +--                    if functions then +--                        local f = getinfo(v).what == "C" and dump(dummy) or dump(v) +--                     -- local f = getinfo(v).what == "C" and dump(function(...) return v(...) end) or dump(v) +--                        if tk == "number" then +--                            if hexify then +--                                handle(formatters["%w [%04H]=load(%q),"](level,k,f)) +--                            else +--                                handle(formatters["%w [%s]=load(%q),"](level,k,f)) +--                            end +--                        elseif tk == "boolean" then +--                            handle(formatters["%w [%S]=load(%q),"](level,k,f)) +--                        elseif noquotes and not reserved[k] and lpegmatch(propername,k) then +--                            handle(formatters["%w %s=load(%q),"](level,k,f)) +--                        else +--                            handle(formatters["%w [%q]=load(%q),"](level,k,f)) +--                        end +--                    end +--                else +--                    if tk == "number" then +--                        if hexify then +--                            handle(formatters["%w [%04H]=%Q,"](level,k,v)) +--                        else +--                            handle(formatters["%w [%s]=%Q,"](level,k,v)) +--                        end +--                    elseif tk == "boolean" then +--                        handle(formatters["%w [%S]=%Q,"](level,k,v)) +--                    elseif noquotes and not reserved[k] and lpegmatch(propername,k) then +--                        handle(formatters["%w %s=%Q,"](level,k,v)) +--                    else +--                        handle(formatters["%w [%q]=%Q,"](level,k,v)) +--                    end +--                end +--                --~ end +--            end +--        end +--        if level > 0 then +--            handle(formatters["%w}"](level)) +--        end +--    end + +--    local function serialize(_handle,root,name,specification) -- handle wins +--        local tname = type(name) +--        if type(specification) == "table" then +--            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 +--            if functions == nil then +--                functions = true +--            end +--            if compact == nil then +--                compact = true +--            end +--            if inline == nil then +--                inline = compact +--            end +--        else +--            noquotes  = false +--            hexify    = false +--            handle    = _handle or print +--            reduce    = false +--            compact   = true +--            inline    = true +--            functions = true +--        end +--        if tname == "string" then +--            if name == "return" then +--                handle("return {") +--            else +--                handle(name .. "={") +--            end +--        elseif tname == "number" then +--            if hexify then +--                handle(format("[0x%04X]={",name)) +--            else +--                handle("[" .. name .. "]={") +--            end +--        elseif tname == "boolean" then +--            if name then +--                handle("return {") +--            else +--                handle("{") +--            end +--        else +--            handle("t={") +--        end +--        if root then +--            -- The dummy access will initialize a table that has a delayed initialization +--            -- using a metatable. (maybe explicitly test for metatable) +--            if getmetatable(root) then -- todo: make this an option, maybe even per subtable +--                local dummy = root._w_h_a_t_e_v_e_r_ +--                root._w_h_a_t_e_v_e_r_ = nil +--            end +--            -- Let's forget about empty tables. +--            if next(root) then +--                do_serialize(root,name,0) +--            end +--        end +--        handle("}") +--    end + +-- name: +-- +-- true     : return     { } +-- false    :            { } +-- nil      : t        = { } +-- string   : string   = { } +-- "return" : return     { } +-- number   : [number] = { }  function table.serialize(root,name,specification)      local t, n = { }, 0 @@ -708,6 +1048,13 @@ function table.serialize(root,name,specification)      return concat(t,"\n")  end +--   local a = { e = { 1,2,3,4,5,6}, a = 1, b = 2, c = "ccc", d = { a = 1, b = 2, c = "ccc", d = { a = 1, b = 2, c = "ccc" } } } +--   local t = os.clock() +--   for i=1,10000 do +--       table.serialize(a) +--   end +--   print(os.clock()-t,table.serialize(a)) +  table.tohandle = serialize  -- sometimes tables are real use (zapfino extra pro is some 85M) in which @@ -752,7 +1099,7 @@ local function flattened(t,f,depth)          f = { }          depth = 0xFFFF      elseif tonumber(f) then -        -- assume then only two arguments are given +        -- assume that only two arguments are given          depth = f          f = { }      elseif not depth then @@ -785,7 +1132,7 @@ table.flattened = flattened  local function unnest(t,f) -- only used in mk, for old times sake      if not f then          -- and only relevant for token lists -        f = { } +        f = { }            -- this one can become obsolete      end      for i=1,#t do          local v = t[i] @@ -814,7 +1161,7 @@ local function are_equal(a,b,n,m) -- indexed              local ai, bi = a[i], b[i]              if ai==bi then                  -- same -            elseif type(ai)=="table" and type(bi)=="table" then +            elseif type(ai) == "table" and type(bi) == "table" then                  if not are_equal(ai,bi) then                      return false                  end @@ -849,10 +1196,10 @@ table.are_equal = are_equal  -- maybe also make a combined one -function table.compact(t) +function table.compact(t) -- remove empty tables, assumes subtables      if t then -        for k,v in next, t do -            if not next(v) then +        for k, v in next, t do +            if not next(v) then -- no type checking                  t[k] = nil              end          end @@ -881,25 +1228,25 @@ end  function table.swapped(t,s) -- hash      local n = { }      if s then ---~         for i=1,#s do ---~             n[i] = s[i] ---~         end          for k, v in next, s do              n[k] = v          end      end ---~     for i=1,#t do ---~         local ti = t[i] -- don't ask but t[i] can be nil ---~         if ti then ---~             n[ti] = i ---~         end ---~     end      for k, v in next, t do          n[v] = k      end      return n  end +function table.mirrored(t) -- hash +    local n = { } +    for k, v in next, t do +        n[v] = k +        n[k] = v +    end +    return n +end +  function table.reversed(t)      if t then          local tt, tn = { }, #t @@ -914,9 +1261,31 @@ function table.reversed(t)      end  end -function table.sequenced(t,sep) -- hash only +function table.reverse(t)      if t then -        local s, n = { }, 0 +        local n = #t +        for i=1,floor(n/2) do +            local j = n - i + 1 +            t[i], t[j] = t[j], t[i] +        end +        return t +    end +end + +function table.sequenced(t,sep,simple) -- hash only +    if not t then +        return "" +    end +    local n = #t +    local s = { } +    if n > 0 then +        -- indexed +        for i=1,n do +            s[i] = tostring(t[i]) +        end +    else +        -- hashed +        n = 0          for k, v in sortedhash(t) do              if simple then                  if v == true then @@ -931,20 +1300,20 @@ function table.sequenced(t,sep) -- hash only                  s[n] = k .. "=" .. tostring(v)              end          end -        return concat(s, sep or " | ") -    else -        return ""      end +    return concat(s,sep or " | ")  end  function table.print(t,...)      if type(t) ~= "table" then          print(tostring(t))      else -        table.tohandle(print,t,...) +        serialize(print,t,...)      end  end +setinspector(function(v) if type(v) == "table" then serialize(print,v,"table") return true end end) +  -- -- -- obsolete but we keep them for a while and might comment them later -- -- --  -- roughly: copy-loop : unpack : sub == 0.9 : 0.4 : 0.45 (so in critical apps, use unpack) @@ -990,7 +1359,7 @@ function table.unique(old)      return new  end --- function table.sorted(t,...) ---     table.sort(t,...) ---     return t -- still sorts in-place --- end +function table.sorted(t,...) +    sort(t,...) +    return t -- still sorts in-place +end | 
