1if not modules then modules = { } end modules ['l-table'] = {
2 version = 1.001,
3 comment = "companion to luat-lib.mkiv",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9local type, next, tostring, tonumber, select, rawget = type, next, tostring, tonumber, select, rawget
10local table, string = table, string
11local concat, sort = table.concat, table.sort
12local format, lower, dump = string.format, string.lower, string.dump
13local getmetatable, setmetatable = getmetatable, setmetatable
14local lpegmatch, patterns = lpeg.match, lpeg.patterns
15local floor = math.floor
16
17
18
19
20
21
22local stripper = patterns.stripper
23
24function table.getn(t)
25 return t and #t
26end
27
28function table.strip(tab)
29 local lst = { }
30 local l = 0
31 for i=1,#tab do
32 local s = lpegmatch(stripper,tab[i]) or ""
33 if s == "" then
34
35 else
36 l = l + 1
37 lst[l] = s
38 end
39 end
40 return lst
41end
42
43function table.keys(t)
44 if t then
45 local keys = { }
46 local k = 0
47 for key in next, t do
48 k = k + 1
49 keys[k] = key
50 end
51 return keys
52 else
53 return { }
54 end
55end
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128local function compare(a,b)
129 local ta = type(a)
130 if ta == "number" then
131 local tb = type(b)
132 if ta == tb then
133 return a < b
134 elseif tb == "string" then
135 return tostring(a) < b
136 end
137 elseif ta == "string" then
138 local tb = type(b)
139 if ta == tb then
140 return a < b
141 else
142 return a < tostring(b)
143 end
144 end
145 return tostring(a) < tostring(b)
146end
147
148local function sortedkeys(tab)
149 if tab then
150 local srt = { }
151 local category = 0
152 local s = 0
153 for key in next, tab do
154 s = s + 1
155 srt[s] = key
156 if category ~= 3 then
157 local tkey = type(key)
158 if category == 1 then
159 if tkey ~= "string" then
160 category = 3
161 end
162 elseif category == 2 then
163 if tkey ~= "number" then
164 category = 3
165 end
166 else
167 if tkey == "string" then
168 category = 1
169 elseif tkey == "number" then
170 category = 2
171 else
172 category = 3
173 end
174 end
175 end
176 end
177 if s < 2 then
178
179 elseif category == 3 then
180 sort(srt,compare)
181 else
182 sort(srt)
183 end
184 return srt
185 else
186 return { }
187 end
188end
189
190local function sortedhashonly(tab)
191 if tab then
192 local srt = { }
193 local s = 0
194 for key in next, tab do
195 if type(key) == "string" then
196 s = s + 1
197 srt[s] = key
198 end
199 end
200 if s > 1 then
201 sort(srt)
202 end
203 return srt
204 else
205 return { }
206 end
207end
208
209local function sortedindexonly(tab)
210 if tab then
211 local srt = { }
212 local s = 0
213 for key in next, tab do
214 if type(key) == "number" then
215 s = s + 1
216 srt[s] = key
217 end
218 end
219 if s > 1 then
220 sort(srt)
221 end
222 return srt
223 else
224 return { }
225 end
226end
227
228local function sortedhashkeys(tab,cmp)
229 if tab then
230 local srt = { }
231 local s = 0
232 for key in next, tab do
233 if key then
234 s= s + 1
235 srt[s] = key
236 end
237 end
238 if s > 1 then
239 sort(srt,cmp)
240 end
241 return srt
242 else
243 return { }
244 end
245end
246
247function table.allkeys(t)
248 local keys = { }
249 for k, v in next, t do
250 for k in next, v do
251 keys[k] = true
252 end
253 end
254 return sortedkeys(keys)
255end
256
257table.sortedkeys = sortedkeys
258table.sortedhashonly = sortedhashonly
259table.sortedindexonly = sortedindexonly
260table.sortedhashkeys = sortedhashkeys
261
262local function nothing() end
263
264local function sortedhash(t,cmp)
265 if t then
266 local s
267 if cmp then
268
269 s = sortedhashkeys(t,function(a,b) return cmp(t,a,b) end)
270 else
271 s = sortedkeys(t)
272 end
273 local m = #s
274 if m == 1 then
275 return next, t
276 elseif m > 0 then
277 local n = 0
278 return function()
279 if n < m then
280 n = n + 1
281 local k = s[n]
282 return k, t[k]
283 end
284 end
285 end
286 end
287 return nothing
288end
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321table.sortedhash = sortedhash
322table.sortedpairs = sortedhash
323
324function table.append(t,list)
325 local n = #t
326 for i=1,#list do
327 n = n + 1
328 t[n] = list[i]
329 end
330 return t
331end
332
333function table.prepend(t, list)
334 local nl = #list
335 local nt = nl + #t
336 for i=#t,1,-1 do
337 t[nt] = t[i]
338 nt = nt - 1
339 end
340 for i=1,#list do
341 t[i] = list[i]
342 end
343 return t
344end
345
346
347
348
349
350
351
352
353
354
355
356
357function table.merge(t, ...)
358 if not t then
359 t = { }
360 end
361 for i=1,select("#",...) do
362 for k, v in next, (select(i,...)) do
363 t[k] = v
364 end
365 end
366 return t
367end
368
369
370
371
372
373
374
375
376
377
378
379function table.merged(...)
380 local t = { }
381 for i=1,select("#",...) do
382 for k, v in next, (select(i,...)) do
383 t[k] = v
384 end
385 end
386 return t
387end
388
389
390
391
392
393
394
395
396
397
398
399
400
401function table.imerge(t, ...)
402 local nt = #t
403 for i=1,select("#",...) do
404 local nst = select(i,...)
405 for j=1,#nst do
406 nt = nt + 1
407 t[nt] = nst[j]
408 end
409 end
410 return t
411end
412
413
414
415
416
417
418
419
420
421
422
423
424
425function table.imerged(...)
426 local tmp = { }
427 local ntmp = 0
428 for i=1,select("#",...) do
429 local nst = select(i,...)
430 for j=1,#nst do
431 ntmp = ntmp + 1
432 tmp[ntmp] = nst[j]
433 end
434 end
435 return tmp
436end
437
438local function fastcopy(old,metatabletoo)
439 if old then
440 local new = { }
441 for k, v in next, old do
442 if type(v) == "table" then
443 new[k] = fastcopy(v,metatabletoo)
444 else
445 new[k] = v
446 end
447 end
448 if metatabletoo then
449
450 local mt = getmetatable(old)
451 if mt then
452 setmetatable(new,mt)
453 end
454 end
455 return new
456 else
457 return { }
458 end
459end
460
461
462
463local function copy(t,tables)
464 if not tables then
465 tables = { }
466 end
467 local tcopy = { }
468 if not tables[t] then
469 tables[t] = tcopy
470 end
471 for i,v in next, t do
472 if type(i) == "table" then
473 if tables[i] then
474 i = tables[i]
475 else
476 i = copy(i,tables)
477 end
478 end
479 if type(v) ~= "table" then
480 tcopy[i] = v
481 elseif tables[v] then
482 tcopy[i] = tables[v]
483 else
484 tcopy[i] = copy(v,tables)
485 end
486 end
487 local mt = getmetatable(t)
488 if mt then
489 setmetatable(tcopy,mt)
490 end
491 return tcopy
492end
493
494table.fastcopy = fastcopy
495table.copy = copy
496
497function table.derive(parent)
498 local child = { }
499 if parent then
500 setmetatable(child,{ __index = parent })
501 end
502 return child
503end
504
505function table.tohash(t,value)
506 local h = { }
507 if t then
508 if value == nil then value = true end
509 for _, v in next, t do
510 h[v] = value
511 end
512 end
513 return h
514end
515
516function table.fromhash(t)
517 local hsh = { }
518 local h = 0
519 for k, v in next, t do
520 if v then
521 h = h + 1
522 hsh[h] = k
523 end
524 end
525 return hsh
526end
527
528local noquotes, hexify, handle, compact, inline, functions, metacheck, accurate
529
530local reserved = table.tohash {
531 'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for', 'function', 'if',
532 'in', 'local', 'nil', 'not', 'or', 'repeat', 'return', 'then', 'true', 'until', 'while',
533 'NaN', 'goto', 'const',
534}
535
536local function is_simple_table(t,hexify,accurate)
537 local nt = #t
538 if nt > 0 then
539 local n = 0
540 for _, v in next, t do
541 n = n + 1
542 if type(v) == "table" then
543 return nil
544 end
545 end
546
547 local haszero = rawget(t,0)
548 if n == nt then
549 local tt = { }
550 for i=1,nt do
551 local v = t[i]
552 local tv = type(v)
553 if tv == "number" then
554
555 if hexify then
556 tt[i] = format("0x%X",v)
557 elseif accurate then
558 tt[i] = format("%q",v)
559 else
560 tt[i] = v
561 end
562 elseif tv == "string" then
563 tt[i] = format("%q",v)
564 elseif tv == "boolean" then
565 tt[i] = v and "true" or "false"
566 else
567 return nil
568 end
569 end
570 return tt
571 elseif haszero and (n == nt + 1) then
572 local tt = { }
573 for i=0,nt do
574 local v = t[i]
575 local tv = type(v)
576 if tv == "number" then
577
578 if hexify then
579 tt[i+1] = format("0x%X",v)
580 elseif accurate then
581 tt[i+1] = format("%q",v)
582 else
583 tt[i+1] = v
584 end
585 elseif tv == "string" then
586 tt[i+1] = format("%q",v)
587 elseif tv == "boolean" then
588 tt[i+1] = v and "true" or "false"
589 else
590 return nil
591 end
592 end
593 tt[1] = "[0] = " .. tt[1]
594 return tt
595 end
596 end
597 return nil
598end
599
600table.is_simple_table = is_simple_table
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619local propername = patterns.propername
620
621local function dummy() end
622
623local function do_serialize(root,name,depth,level,indexed)
624 if level > 0 then
625 depth = depth .. " "
626 if indexed then
627 handle(format("%s{",depth))
628 else
629 local tn = type(name)
630 if tn == "number" then
631 if hexify then
632 handle(format("%s[0x%X]={",depth,name))
633 else
634 handle(format("%s[%s]={",depth,name))
635 end
636 elseif tn == "string" then
637 if noquotes and not reserved[name] and lpegmatch(propername,name) then
638 handle(format("%s%s={",depth,name))
639 else
640 handle(format("%s[%q]={",depth,name))
641 end
642 elseif tn == "boolean" then
643 handle(format("%s[%s]={",depth,name and "true" or "false"))
644 else
645 handle(format("%s{",depth))
646 end
647 end
648 end
649
650 if root and next(root) ~= nil then
651 local first = nil
652 local last = 0
653 if compact then
654 last = #root
655 for k=1,last do
656
657 if rawget(root,k) == nil then
658 last = k - 1
659 break
660 end
661 end
662 if last > 0 then
663 first = 1
664 end
665 end
666 local sk = sortedkeys(root)
667 for i=1,#sk do
668 local k = sk[i]
669 local v = root[k]
670 local tv = type(v)
671 local tk = type(k)
672 if compact and first and tk == "number" and k >= first and k <= last then
673 if tv == "number" then
674 if hexify then
675 handle(format("%s 0x%X,",depth,v))
676 elseif accurate then
677 handle(format("%s %q,",depth,v))
678 else
679 handle(format("%s %s,",depth,v))
680 end
681 elseif tv == "string" then
682 handle(format("%s %q,",depth,v))
683 elseif tv == "table" then
684 if next(v) == nil then
685 handle(format("%s {},",depth))
686 elseif inline then
687 local st = is_simple_table(v,hexify,accurate)
688 if st then
689 handle(format("%s { %s },",depth,concat(st,", ")))
690 else
691 do_serialize(v,k,depth,level+1,true)
692 end
693 else
694 do_serialize(v,k,depth,level+1,true)
695 end
696 elseif tv == "boolean" then
697 handle(format("%s %s,",depth,v and "true" or "false"))
698 elseif tv == "function" then
699 if functions then
700 handle(format('%s load(%q),',depth,dump(v)))
701 else
702 handle(format('%s "function",',depth))
703 end
704 else
705 handle(format("%s %q,",depth,tostring(v)))
706 end
707 elseif k == "__p__" then
708 if false then
709 handle(format("%s __p__=nil,",depth))
710 end
711 elseif tv == "number" then
712 if tk == "number" then
713 if hexify then
714 handle(format("%s [0x%X]=0x%X,",depth,k,v))
715 elseif accurate then
716 handle(format("%s [%s]=%q,",depth,k,v))
717 else
718 handle(format("%s [%s]=%s,",depth,k,v))
719 end
720 elseif tk == "boolean" then
721 if hexify then
722 handle(format("%s [%s]=0x%X,",depth,k and "true" or "false",v))
723 elseif accurate then
724 handle(format("%s [%s]=%q,",depth,k and "true" or "false",v))
725 else
726 handle(format("%s [%s]=%s,",depth,k and "true" or "false",v))
727 end
728 elseif tk ~= "string" then
729
730 elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
731 if hexify then
732 handle(format("%s %s=0x%X,",depth,k,v))
733 elseif accurate then
734 handle(format("%s %s=%q,",depth,k,v))
735 else
736 handle(format("%s %s=%s,",depth,k,v))
737 end
738 else
739 if hexify then
740 handle(format("%s [%q]=0x%X,",depth,k,v))
741 elseif accurate then
742 handle(format("%s [%q]=%q,",depth,k,v))
743 else
744 handle(format("%s [%q]=%s,",depth,k,v))
745 end
746 end
747 elseif tv == "string" then
748 if tk == "number" then
749 if hexify then
750 handle(format("%s [0x%X]=%q,",depth,k,v))
751 elseif accurate then
752 handle(format("%s [%q]=%q,",depth,k,v))
753 else
754 handle(format("%s [%s]=%q,",depth,k,v))
755 end
756 elseif tk == "boolean" then
757 handle(format("%s [%s]=%q,",depth,k and "true" or "false",v))
758 elseif tk ~= "string" then
759
760 elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
761 handle(format("%s %s=%q,",depth,k,v))
762 else
763 handle(format("%s [%q]=%q,",depth,k,v))
764 end
765 elseif tv == "table" then
766 if next(v) == nil then
767 if tk == "number" then
768 if hexify then
769 handle(format("%s [0x%X]={},",depth,k))
770 elseif accurate then
771 handle(format("%s [%q]={},",depth,k))
772 else
773 handle(format("%s [%s]={},",depth,k))
774 end
775 elseif tk == "boolean" then
776 handle(format("%s [%s]={},",depth,k and "true" or "false"))
777 elseif tk ~= "string" then
778
779 elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
780 handle(format("%s %s={},",depth,k))
781 else
782 handle(format("%s [%q]={},",depth,k))
783 end
784 elseif inline then
785 local st = is_simple_table(v,hexify,accurate)
786 if st then
787 if tk == "number" then
788 if hexify then
789 handle(format("%s [0x%X]={ %s },",depth,k,concat(st,", ")))
790 elseif accurate then
791 handle(format("%s [%q]={ %s },",depth,k,concat(st,", ")))
792 else
793 handle(format("%s [%s]={ %s },",depth,k,concat(st,", ")))
794 end
795 elseif tk == "boolean" then
796 handle(format("%s [%s]={ %s },",depth,k and "true" or "false",concat(st,", ")))
797 elseif tk ~= "string" then
798
799 elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
800 handle(format("%s %s={ %s },",depth,k,concat(st,", ")))
801 else
802 handle(format("%s [%q]={ %s },",depth,k,concat(st,", ")))
803 end
804 else
805 do_serialize(v,k,depth,level+1)
806 end
807 else
808 do_serialize(v,k,depth,level+1)
809 end
810 elseif tv == "boolean" then
811 if tk == "number" then
812 if hexify then
813 handle(format("%s [0x%X]=%s,",depth,k,v and "true" or "false"))
814 elseif accurate then
815 handle(format("%s [%q]=%s,",depth,k,v and "true" or "false"))
816 else
817 handle(format("%s [%s]=%s,",depth,k,v and "true" or "false"))
818 end
819 elseif tk == "boolean" then
820 handle(format("%s [%s]=%s,",depth,tostring(k),v and "true" or "false"))
821 elseif tk ~= "string" then
822
823 elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
824 handle(format("%s %s=%s,",depth,k,v and "true" or "false"))
825 else
826 handle(format("%s [%q]=%s,",depth,k,v and "true" or "false"))
827 end
828 elseif tv == "function" then
829 if functions then
830 local getinfo = debug and debug.getinfo
831 if getinfo then
832 local f = getinfo(v).what == "C" and dump(dummy) or dump(v)
833
834 if tk == "number" then
835 if hexify then
836 handle(format("%s [0x%X]=load(%q),",depth,k,f))
837 elseif accurate then
838 handle(format("%s [%q]=load(%q),",depth,k,f))
839 else
840 handle(format("%s [%s]=load(%q),",depth,k,f))
841 end
842 elseif tk == "boolean" then
843 handle(format("%s [%s]=load(%q),",depth,k and "true" or "false",f))
844 elseif tk ~= "string" then
845
846 elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
847 handle(format("%s %s=load(%q),",depth,k,f))
848 else
849 handle(format("%s [%q]=load(%q),",depth,k,f))
850 end
851 end
852 end
853 else
854 if tk == "number" then
855 if hexify then
856 handle(format("%s [0x%X]=%q,",depth,k,tostring(v)))
857 elseif accurate then
858 handle(format("%s [%q]=%q,",depth,k,tostring(v)))
859 else
860 handle(format("%s [%s]=%q,",depth,k,tostring(v)))
861 end
862 elseif tk == "boolean" then
863 handle(format("%s [%s]=%q,",depth,k and "true" or "false",tostring(v)))
864 elseif tk ~= "string" then
865
866 elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
867 handle(format("%s %s=%q,",depth,k,tostring(v)))
868 else
869 handle(format("%s [%q]=%q,",depth,k,tostring(v)))
870 end
871 end
872 end
873 end
874 if level > 0 then
875 handle(format("%s},",depth))
876 end
877end
878
879
880
881
882local function serialize(_handle,root,name,specification)
883 local tname = type(name)
884 if type(specification) == "table" then
885 noquotes = specification.noquotes
886 hexify = specification.hexify
887 accurate = specification.accurate
888 handle = _handle or specification.handle or print
889 functions = specification.functions
890 compact = specification.compact
891 inline = specification.inline and compact
892 metacheck = specification.metacheck
893 if functions == nil then
894 functions = true
895 end
896 if compact == nil then
897 compact = true
898 end
899 if inline == nil then
900 inline = compact
901 end
902 if metacheck == nil then
903 metacheck = true
904 end
905 else
906 noquotes = false
907 hexify = false
908 handle = _handle or print
909 compact = true
910 inline = true
911 functions = true
912 metacheck = true
913 end
914 if tname == "string" then
915 if name == "return" then
916 handle("return {")
917 else
918 handle(name .. "={")
919 end
920 elseif tname == "number" then
921 if hexify then
922 handle(format("[0x%X]={",name))
923 else
924 handle("[" .. name .. "]={")
925 end
926 elseif tname == "boolean" then
927 if name then
928 handle("return {")
929 else
930 handle("{")
931 end
932 else
933 handle("t={")
934 end
935 if root then
936
937
938
939 if metacheck and getmetatable(root) then
940 local dummy = root._w_h_a_t_e_v_e_r_
941 root._w_h_a_t_e_v_e_r_ = nil
942 end
943
944 if next(root) ~= nil then
945 do_serialize(root,name,"",0)
946 end
947 end
948 handle("}")
949end
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965function table.serialize(root,name,specification)
966 local t = { }
967 local n = 0
968 local function flush(s)
969 n = n + 1
970 t[n] = s
971 end
972 serialize(flush,root,name,specification)
973 return concat(t,"\n")
974end
975
976
977
978
979
980
981
982
983table.tohandle = serialize
984
985local maxtab = 2*1024
986
987function table.tofile(filename,root,name,specification)
988 local f = io.open(filename,'w')
989 if f then
990 if maxtab > 1 then
991 local t = { }
992 local n = 0
993 local function flush(s)
994 n = n + 1
995 t[n] = s
996 if n > maxtab then
997 f:write(concat(t,"\n"),"\n")
998 t = { }
999 n = 0
1000 end
1001 end
1002 serialize(flush,root,name,specification)
1003 f:write(concat(t,"\n"),"\n")
1004 else
1005 local function flush(s)
1006 f:write(s,"\n")
1007 end
1008 serialize(flush,root,name,specification)
1009 end
1010 f:close()
1011 io.flush()
1012 end
1013end
1014
1015local function flattened(t,f,depth)
1016 if f == nil then
1017 f = { }
1018 depth = 0xFFFF
1019 elseif tonumber(f) then
1020
1021 depth = f
1022 f = { }
1023 elseif not depth then
1024 depth = 0xFFFF
1025 end
1026 for k, v in next, t do
1027 if type(k) ~= "number" then
1028 if depth > 0 and type(v) == "table" then
1029 flattened(v,f,depth-1)
1030 else
1031 f[#f+1] = v
1032 end
1033 end
1034 end
1035 for k=1,#t do
1036 local v = t[k]
1037 if depth > 0 and type(v) == "table" then
1038 flattened(v,f,depth-1)
1039 else
1040 f[#f+1] = v
1041 end
1042 end
1043 return f
1044end
1045
1046table.flattened = flattened
1047
1048local function collapsed(t,f,h)
1049 if f == nil then
1050 f = { }
1051 h = { }
1052 end
1053 for k=1,#t do
1054 local v = t[k]
1055 if type(v) == "table" then
1056 collapsed(v,f,h)
1057 elseif not h[v] then
1058 f[#f+1] = v
1059 h[v] = true
1060 end
1061 end
1062 return f
1063end
1064
1065local function collapsedhash(t,h)
1066 if h == nil then
1067 h = { }
1068 end
1069 for k=1,#t do
1070 local v = t[k]
1071 if type(v) == "table" then
1072 collapsedhash(v,h)
1073 else
1074 h[v] = true
1075 end
1076 end
1077 return h
1078end
1079
1080table.collapsed = collapsed
1081table.collapsedhash = collapsedhash
1082
1083local function unnest(t,f)
1084 if not f then
1085 f = { }
1086 end
1087 for i=1,#t do
1088 local v = t[i]
1089 if type(v) == "table" then
1090 if type(v[1]) == "table" then
1091 unnest(v,f)
1092 else
1093 f[#f+1] = v
1094 end
1095 else
1096 f[#f+1] = v
1097 end
1098 end
1099 return f
1100end
1101
1102function table.unnest(t)
1103 return unnest(t)
1104end
1105
1106local function are_equal(a,b,n,m)
1107 if a == b then
1108 return true
1109 elseif a and b and #a == #b then
1110 if not n then
1111 n = 1
1112 end
1113 if not m then
1114 m = #a
1115 end
1116 for i=n,m do
1117 local ai, bi = a[i], b[i]
1118 if ai==bi then
1119
1120 elseif type(ai) == "table" and type(bi) == "table" then
1121 if not are_equal(ai,bi) then
1122 return false
1123 end
1124 else
1125 return false
1126 end
1127 end
1128 return true
1129 else
1130 return false
1131 end
1132end
1133
1134local function identical(a,b)
1135 if a ~= b then
1136 for ka, va in next, a do
1137 local vb = b[ka]
1138 if va == vb then
1139
1140 elseif type(va) == "table" and type(vb) == "table" then
1141 if not identical(va,vb) then
1142 return false
1143 end
1144 else
1145 return false
1146 end
1147 end
1148 end
1149 return true
1150end
1151
1152table.identical = identical
1153table.are_equal = are_equal
1154
1155local function sparse(old,nest,keeptables)
1156 local new = { }
1157 for k, v in next, old do
1158 if not (v == "" or v == false) then
1159 if nest and type(v) == "table" then
1160 v = sparse(v,nest)
1161 if keeptables or next(v) ~= nil then
1162 new[k] = v
1163 end
1164 else
1165 new[k] = v
1166 end
1167 end
1168 end
1169 return new
1170end
1171
1172table.sparse = sparse
1173
1174function table.compact(t)
1175 return sparse(t,true,true)
1176end
1177
1178function table.contains(t, v)
1179 if t then
1180 for i=1, #t do
1181 if t[i] == v then
1182 return i
1183 end
1184 end
1185 end
1186 return false
1187end
1188
1189function table.count(t)
1190 local n = 0
1191 for k, v in next, t do
1192 n = n + 1
1193 end
1194 return n
1195end
1196
1197function table.swapped(t,s)
1198 local n = { }
1199 if s then
1200 for k, v in next, s do
1201 n[k] = v
1202 end
1203 end
1204 for k, v in next, t do
1205 n[v] = k
1206 end
1207 return n
1208end
1209
1210function table.hashed(t)
1211 for i=1,#t do
1212 t[t[i]] = i
1213 end
1214 return t
1215end
1216
1217function table.mirrored(t)
1218 local n = { }
1219 for k, v in next, t do
1220 n[v] = k
1221 n[k] = v
1222 end
1223 return n
1224end
1225
1226function table.reversed(t)
1227 if t then
1228 local tt = { }
1229 local tn = #t
1230 if tn > 0 then
1231 local ttn = 0
1232 for i=tn,1,-1 do
1233 ttn = ttn + 1
1234 tt[ttn] = t[i]
1235 end
1236 end
1237 return tt
1238 end
1239end
1240
1241function table.reverse(t)
1242 if t then
1243 local n = #t
1244 local m = n + 1
1245 for i=1,floor(n/2) do
1246 local j = m - i
1247 t[i], t[j] = t[j], t[i]
1248 end
1249 return t
1250 end
1251end
1252
1253
1254
1255local function sequenced(t,sep,simple)
1256 if not t then
1257 return ""
1258 elseif type(t) ~= "table" then
1259 return t
1260 end
1261 local n = #t
1262 local s = { }
1263 if n > 0 then
1264
1265 for i=1,n do
1266 local v = t[i]
1267 if type(v) == "table" then
1268 s[i] = "{" .. sequenced(v,sep,simple) .. "}"
1269 else
1270 s[i] = tostring(t[i])
1271 end
1272 end
1273 else
1274
1275 n = 0
1276 for k, v in sortedhash(t) do
1277 if simple then
1278 if v == true then
1279 n = n + 1
1280 s[n] = k
1281 elseif v and v~= "" then
1282 n = n + 1
1283 if type(v) == "table" then
1284 s[n] = k .. "={" .. sequenced(v,sep,simple) .. "}"
1285 else
1286 s[n] = k .. "=" .. tostring(v)
1287 end
1288 end
1289 else
1290 n = n + 1
1291 if type(v) == "table" then
1292 s[n] = k .. "={" .. sequenced(v,sep,simple) .. "}"
1293 else
1294 s[n] = k .. "=" .. tostring(v)
1295 end
1296 end
1297 end
1298 end
1299 if sep == true then
1300 return "{ " .. concat(s,", ") .. " }"
1301 else
1302 return concat(s,sep or " | ")
1303 end
1304end
1305
1306table.sequenced = sequenced
1307
1308function table.print(t,...)
1309 if type(t) ~= "table" then
1310 print(tostring(t))
1311 else
1312 serialize(print,t,...)
1313 end
1314end
1315
1316if setinspector then
1317 setinspector("table",function(v) if type(v) == "table" then serialize(print,v,"table") return true end end)
1318end
1319
1320
1321
1322
1323
1324function table.sub(t,i,j)
1325 return { unpack(t,i,j) }
1326end
1327
1328
1329
1330function table.is_empty(t)
1331 return not t or next(t) == nil
1332end
1333
1334function table.has_one_entry(t)
1335 return t and next(t,next(t)) == nil
1336end
1337
1338
1339
1340function table.loweredkeys(t)
1341 local l = { }
1342 for k, v in next, t do
1343 l[lower(k)] = v
1344 end
1345 return l
1346end
1347
1348
1349
1350function table.unique(old)
1351 local hash = { }
1352 local new = { }
1353 local n = 0
1354 for i=1,#old do
1355 local oi = old[i]
1356 if not hash[oi] then
1357 n = n + 1
1358 new[n] = oi
1359 hash[oi] = true
1360 end
1361 end
1362 return new
1363end
1364
1365function table.sorted(t,...)
1366 sort(t,...)
1367 return t
1368end
1369
1370
1371
1372function table.values(t,s)
1373 if t then
1374 local values = { }
1375 local keys = { }
1376 local v = 0
1377 for key, value in next, t do
1378 if not keys[value] then
1379 v = v + 1
1380 values[v] = value
1381 keys[k] = key
1382 end
1383 end
1384 if s then
1385 sort(values)
1386 end
1387 return values
1388 else
1389 return { }
1390 end
1391end
1392
1393
1394
1395
1396
1397
1398
1399function table.filtered(t,pattern,sort,cmp)
1400 if t and type(pattern) == "string" then
1401 if sort then
1402 local s
1403 if cmp then
1404
1405 s = sortedhashkeys(t,function(a,b) return cmp(t,a,b) end)
1406 else
1407 s = sortedkeys(t)
1408 end
1409 local n = 0
1410 local m = #s
1411 local function kv(s)
1412 while n < m do
1413 n = n + 1
1414 local k = s[n]
1415 if find(k,pattern) then
1416 return k, t[k]
1417 end
1418 end
1419 end
1420 return kv, s
1421 else
1422 local n = next(t)
1423 local function iterator()
1424 while n ~= nil do
1425 local k = n
1426 n = next(t,k)
1427 if find(k,pattern) then
1428 return k, t[k]
1429 end
1430 end
1431 end
1432 return iterator, t
1433 end
1434 else
1435 return nothing
1436 end
1437end
1438
1439
1440
1441if not table.move then
1442
1443 function table.move(a1,f,e,t,a2)
1444 if a2 and a1 ~= a2 then
1445 for i=f,e do
1446 a2[t] = a1[i]
1447 t = t + 1
1448 end
1449 return a2
1450 else
1451 t = t + e - f
1452 for i=e,f,-1 do
1453 a1[t] = a1[i]
1454 t = t - 1
1455 end
1456 return a1
1457 end
1458 end
1459
1460end
1461 |