/
Table.lua
355 lines (303 loc) · 7.45 KB
/
Table.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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
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
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
--[=[
Provide a variety of utility table operations
@class Table
]=]
local Table = {}
--[=[
Concats `target` with `source`.
@param target table -- Table to append to
@param source table -- Table read from
@return table -- parameter table
]=]
function Table.append(target, source)
for _, value in pairs(source) do
target[#target+1] = value
end
return target
end
--[=[
Shallow merges two tables without modifying either.
@param orig table -- Original table
@param new table -- Result
@return table
]=]
function Table.merge(orig, new)
local result = table.clone(orig)
for key, val in pairs(new) do
result[key] = val
end
return result
end
--[=[
Reverses the list and returns the reversed copy
@param orig table -- Original table
@return table
]=]
function Table.reverse(orig)
local new = {}
for i=#orig, 1, -1 do
table.insert(new, orig[i])
end
return new
end
--[=[
Returns a list of all of the values that a table has.
@param source table -- Table source to extract values from
@return table -- A list with all the values the table has
]=]
function Table.values(source)
local new = {}
for _, val in pairs(source) do
table.insert(new, val)
end
return new
end
--[=[
Returns a list of all of the keys that a table has. (In order of pairs)
@param source table -- Table source to extract keys from
@return table -- A list with all the keys the table has
]=]
function Table.keys(source)
local new = {}
for key, _ in pairs(source) do
table.insert(new, key)
end
return new
end
--[=[
Shallow merges two lists without modifying either.
@param orig table -- Original table
@param new table -- Result
@return table
]=]
function Table.mergeLists(orig, new)
local _table = {}
for _, val in pairs(orig) do
table.insert(_table, val)
end
for _, val in pairs(new) do
table.insert(_table, val)
end
return _table
end
--[=[
Swaps keys with values, overwriting additional values if duplicated.
@param orig table -- Original table
@return table
]=]
function Table.swapKeyValue(orig)
local tab = {}
for key, val in pairs(orig) do
tab[val] = key
end
return tab
end
--[=[
Converts a table to a list.
@param _table table -- Table to convert to a list
@return table
]=]
function Table.toList(_table)
local list = {}
for _, item in pairs(_table) do
table.insert(list, item)
end
return list
end
--[=[
Counts the number of items in `_table`.
Useful since `__len` on table in Lua 5.2 returns just the array length.
@param _table table -- Table to count
@return number -- count
]=]
function Table.count(_table)
local count = 0
for _, _ in pairs(_table) do
count = count + 1
end
return count
end
--[=[
Shallow copies a table from target into a new table
@function Table.copy
@param target table -- Table to copy
@return table -- Result
@within Table
]=]
Table.copy = table.clone
--[=[
Deep copies a table including metatables
@param target table -- Table to deep copy
@param _context table? -- Context to deepCopy the value in
@return table -- Result
]=]
function Table.deepCopy(target, _context)
_context = _context or {}
if _context[target] then
return _context[target]
end
if type(target) == "table" then
local new = {}
_context[target] = new
for index, value in pairs(target) do
new[Table.deepCopy(index, _context)] = Table.deepCopy(value, _context)
end
return setmetatable(new, Table.deepCopy(getmetatable(target), _context))
else
return target
end
end
--[=[
Overwrites a table's value
@param target table -- Target table
@param source table -- Table to read from
@return table -- target
]=]
function Table.deepOverwrite(target, source)
for index, value in pairs(source) do
if type(target[index]) == "table" and type(value) == "table" then
target[index] = Table.deepOverwrite(target[index], value)
else
target[index] = value
end
end
return target
end
--[=[
Gets an index by value, returning `nil` if no index is found.
@param haystack table -- To search in
@param needle Value to search for
@return The index of the value, if found
@return nil -- if not found
]=]
function Table.getIndex(haystack, needle)
assert(needle ~= nil, "Needle cannot be nil")
for index, item in pairs(haystack) do
if needle == item then
return index
end
end
return nil
end
--[=[
Recursively prints the table. Does not handle recursive tables.
@param _table table -- Table to stringify
@param indent number? -- Indent level
@param output string? -- Output string, used recursively
@return string -- The table in string form
]=]
function Table.stringify(_table, indent, output)
output = output or tostring(_table)
indent = indent or 0
for key, value in pairs(_table) do
local formattedText = "\n" .. string.rep(" ", indent) .. tostring(key) .. ": "
if type(value) == "table" then
output = output .. formattedText
output = Table.stringify(value, indent + 1, output)
else
output = output .. formattedText .. tostring(value)
end
end
return output
end
--[=[
Returns whether `value` is within `table`
@param _table table -- To search in for value
@param value any -- Value to search for
@return boolean -- `true` if within, `false` otherwise
]=]
function Table.contains(_table, value)
for _, item in pairs(_table) do
if item == value then
return true
end
end
return false
end
--[=[
Overwrites an existing table with the source values.
@param target table -- Table to overwite
@param source table -- Source table to read from
@return table -- target
]=]
function Table.overwrite(target, source)
for index, item in pairs(source) do
target[index] = item
end
return target
end
--[=[
Deep equivalent comparison of a table assuming keys are indexable in the same way.
@param target table -- Table to check
@param source table -- Other table to check
@return boolean
]=]
function Table.deepEquivalent(target, source)
if target == source then
return true
end
if type(target) ~= type(source) then
return false
end
if type(target) == "table" then
for key, value in pairs(target) do
if not Table.deepEquivalent(value, source[key]) then
return false
end
end
for key, value in pairs(source) do
if not Table.deepEquivalent(value, target[key]) then
return false
end
end
return true
else
-- target == source should do it.
return false
end
end
--[=[
Takes `count` entries from the table. If the table does not have
that many entries, will return up to the number the table has to
provide.
@param source table -- Source table to retrieve values from
@param count number -- Number of entries to take
@return table -- List with the entries retrieved
]=]
function Table.take(source, count)
local newTable = {}
for i=1, math.min(#source, count) do
newTable[i] = source[i]
end
return newTable
end
local function errorOnIndex(_, index)
error(string.format("Bad index %q", tostring(index)), 2)
end
local READ_ONLY_METATABLE = {
__index = errorOnIndex;
__newindex = errorOnIndex;
}
--[=[
Sets a metatable on a table such that it errors when
indexing a nil value
@param target table -- Table to error on indexing
@return table -- The same table, with the metatable set to readonly
]=]
function Table.readonly(target)
return setmetatable(target, READ_ONLY_METATABLE)
end
--[=[
Recursively sets the table as ReadOnly
@param target table -- Table to error on indexing
@return table -- The same table
]=]
function Table.deepReadonly(target)
for _, item in pairs(target) do
if type(item) == "table" then
Table.deepReadonly(item)
end
end
return Table.readonly(target)
end
return Table