1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
if not modules then modules = { } end modules ['util-pck'] = {
version = 1.001,
comment = "companion to luat-lib.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
-- moved from core-uti
local next, tostring, type = next, tostring, type
local sort, concat = table.sort, table.concat
local sortedhashkeys, sortedkeys, tohash = table.sortedhashkeys, table.sortedkeys, table.tohash
utilities = utilities or { }
utilities.packers = utilities.packers or { }
local packers = utilities.packers
packers.version = 1.01
local function hashed(t)
local s, ns = { }, 0
for k, v in next, t do
ns = ns + 1
if type(v) == "table" then
s[ns] = k .. "={" .. hashed(v) .. "}"
else
s[ns] = k .. "=" .. tostring(v)
end
end
sort(s)
return concat(s,",")
end
local function simplehashed(t)
local s, ns = { }, 0
for k, v in next, t do
ns = ns + 1
s[ns] = k .. "=" .. v
end
sort(s)
return concat(s,",")
end
packers.hashed = hashed
packers.simplehashed = simplehashed
-- In luatex < 0.74 (lua 5.1) a next chain was the same for each run so no sort was needed,
-- but in the latest greatest versions (lua 5.2) we really need to sort the keys in order
-- not to get endless runs due to a difference in tuc files.
local function pack(t,keys,skip,hash,index)
if t then
local sk = #t > 0 and sortedkeys(t) or sortedhashkeys(t)
for i=1,#sk do
local k = sk[i]
if not skip or not skip[k] then
local v = t[k]
--
if type(v) == "table" then
pack(v,keys,skip,hash,index)
if keys[k] then
local h = hashed(v)
local i = hash[h]
if not i then
i = #index + 1
index[i] = v
hash[h] = i
end
t[k] = i
end
end
end
end
end
end
local function unpack(t,keys,skip,index)
if t then
for k, v in next, t do
if keys[k] and type(v) == "number" then
local iv = index[v]
if iv then
v = iv
t[k] = v
end
end
if type(v) == "table" and (not skip or not skip[k]) then
unpack(v,keys,skip,index)
end
end
end
end
function packers.new(keys,version,skip)
return {
version = version or packers.version,
keys = tohash(keys),
skip = tohash(skip),
hash = { },
index = { },
}
end
function packers.pack(t,p,shared)
if shared then
pack(t,p.keys,p.skip,p.hash,p.index)
elseif not t.packer then
pack(t,p.keys,p.skip,p.hash,p.index)
if #p.index > 0 then
t.packer = {
version = p.version or packers.version,
keys = p.keys,
skip = p.skip,
index = p.index,
}
end
p.hash = { }
p.index = { }
end
end
function packers.unpack(t,p,shared)
if shared then
if p then
unpack(t,p.keys,p.skip,p.index)
end
else
local tp = t.packer
if tp then
if tp.version == (p and p.version or packers.version) then
unpack(t,tp.keys,tp.skip,tp.index)
else
return false
end
t.packer = nil
end
end
return true
end
function packers.strip(p)
p.hash = nil
end
-- We could have a packer.serialize where we first flush the shared table
-- and then use inline a reference . This saves an unpack.
|