-
Notifications
You must be signed in to change notification settings - Fork 10
/
util.lua
185 lines (168 loc) · 3.47 KB
/
util.lua
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
local sort, pairs, select, unpack, error =
table.sort, pairs, select, unpack, error
local type, setmetatable, getmetatable =
type, setmetatable, getmetatable
local random = math.random
-- bounds b so a<=b<=c
function bound(a, b, c)
if b<a then return a
elseif b>c then return c
else return b end
end
-- mods b so a<=b<=c
function wrap(a, b, c)
return (b-a)%(c-a+1)+a
end
-- map for numeric tables
function map(func, tab)
local ret = {}
for i=1, #tab do
ret[i]=func(tab[i])
end
return ret
end
-- map for dicts
function map_dict(func, tab)
local ret = {}
for key,val in pairs(tab) do
ret[key]=func(val)
end
return ret
end
function map_inplace(func, tab)
for i=1, #tab do
tab[i]=func(tab[i])
end
return tab
end
function map_dict_inplace(func, tab)
for key,val in pairs(tab) do
tab[key]=func(val)
end
return tab
end
-- reduce for numeric tables
function reduce(func, tab, ...)
local idx, value = 2, nil
if select("#", ...) ~= 0 then
value = select(1, ...)
idx = 1
elseif #tab == 0 then
error("Tried to reduce empty table with no initial value")
else
value = tab[1]
end
for i=idx,#tab do
value = func(value, tab[i])
end
return value
end
function car(tab)
return tab[1]
end
-- This sucks lol
function cdr(tab)
return {select(2, unpack(tab))}
end
-- a useful right inverse of table.concat
function procat(str)
local ret = {}
for i=1,#str do
ret[i]=str:sub(i,i)
end
return ret
end
-- iterate over frozen pairs in sorted order
function spairs(tab)
local keys,vals,idx = {},{},0
for k in pairs(tab) do
keys[#keys+1] = k
end
sort(keys)
for i=1,#keys do
vals[i]=tab[keys[i]]
end
return function()
idx = idx + 1
return keys[idx], vals[idx]
end
end
function uniformly(t)
return t[random(#t)]
end
function content_equal(a,b)
if type(a) ~= "table" or type(b) ~= "table" then
return a == b
end
for i=1,2 do
for k,v in pairs(a) do
if b[k] ~= v then
return false
end
end
a,b=b,a
end
return true
end
-- does not perform deep comparisons of keys which are tables.
function deep_content_equal(a,b)
if type(a) ~= "table" or type(b) ~= "table" then
return a == b
end
for i=1,2 do
for k,v in pairs(a) do
if not deep_content_equal(v,b[k]) then
return false
end
end
a,b=b,a
end
return true
end
function shallowcpy(tab)
local ret = {}
for k,v in pairs(tab) do
ret[k]=v
end
return ret
end
local deepcpy_mapping = {}
local real_deepcpy
function real_deepcpy(tab)
if deepcpy_mapping[tab] ~= nil then
return deepcpy_mapping[tab]
end
local ret = {}
deepcpy_mapping[tab] = ret
deepcpy_mapping[ret] = ret
for k,v in pairs(tab) do
if type(k) == "table" then
k=real_deepcpy(k)
end
if type(v) == "table" then
v=real_deepcpy(v)
end
ret[k]=v
end
return setmetatable(ret, getmetatable(tab))
end
function deepcpy(tab)
if type(tab) ~= "table" then return tab end
local ret = real_deepcpy(tab)
deepcpy_mapping = {}
return ret
end
-- Not actually for encoding/decoding byte streams as base64.
-- Rather, it's for encoding streams of 6-bit symbols in printable characters.
base64encode = procat("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890+/")
base64decode = {}
for i=1,64 do
local val = i-1
base64decode[base64encode[i]]={}
local bit = 32
for j=1,6 do
base64decode[base64encode[i]][j]=(val>=bit)
val=val%bit
bit=bit/2
end
end