forked from lua-stdlib/lua-stdlib
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathset.lua
More file actions
353 lines (281 loc) · 8.8 KB
/
set.lua
File metadata and controls
353 lines (281 loc) · 8.8 KB
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
--[[--
Set container prototype.
This module returns a table of set operators, as well as the prototype
for a Set container object.
Every possible object or primitive value is always present in any Set
container exactly zero or one times.
In addition to the functionality described here, Set containers also
have all the methods and metamethods of the @{std.container.prototype}
(except where overridden here).
Prototype Chain
---------------
table
`-> Container
`-> Set
@prototype std.set
]]
local std = require "std.base"
local Container = require "std.container".prototype
local ielems, pairs, type = std.ielems, std.pairs, std.type
local prototype -- forward declaration
--[[ ==================== ]]--
--[[ Primitive Functions. ]]--
--[[ ==================== ]]--
-- These functions know about internal implementatation.
-- The representation is a table whose tags are the elements, and
-- whose values are true.
local elems = std.pairs
local function insert (set, e)
return rawset (set, e, true)
end
local function member (set, e)
return rawget (set, e) == true
end
--[[ ===================== ]]--
--[[ High Level Functions. ]]--
--[[ ===================== ]]--
-- These functions are independent of the internal implementation.
local difference, symmetric_difference, intersection, union, subset,
proper_subset, equal
function difference (set1, set2)
local r = prototype {}
for e in elems (set1) do
if not member (set2, e) then
insert (r, e)
end
end
return r
end
function symmetric_difference (set1, set2)
return difference (union (set1, set2), intersection (set2, set1))
end
function intersection (set1, set2)
local r = prototype {}
for e in elems (set1) do
if member (set2, e) then
insert (r, e)
end
end
return r
end
function union (set1, set2)
local r = set1 {}
for e in elems (set2) do
insert (r, e)
end
return r
end
function subset (set1, set2)
for e in elems (set1) do
if not member (set2, e) then
return false
end
end
return true
end
function proper_subset (set1, set2)
return subset (set1, set2) and not subset (set2, set1)
end
function equal (set1, set2)
return subset (set1, set2) and subset (set2, set1)
end
--[[ =========== ]]--
--[[ Set Object. ]]--
--[[ =========== ]]--
local function X (decl, fn)
return require "std.debug".argscheck ("std.set." .. decl, fn)
end
--- Set prototype object.
-- @object prototype
-- @string[opt="Set"] _type object name
-- @see std.container.prototype
-- @usage
-- local Set = require "std.set".prototype
-- assert (std.type (Set) == "Set")
prototype = Container {
_type = "Set",
--- Set object initialisation.
--
-- Returns table partially initialised Set container with contents
-- from *t*.
-- @init prototype._init
-- @tparam table new uninitialised Set container object
-- @tparam table t initialisation table from `__call`
_init = function (new, t)
for e in ielems (t) do
insert (new, e)
end
return new
end,
--- Metamethods
-- @section metamethods
--- Union operation.
-- @function prototype:__add
-- @tparam prototype s another set
-- @treturn prototype everything from *this* set plus everything from *s*
-- @see union
-- @usage
-- union = this + s
__add = union,
--- Difference operation.
-- @function prototype:__sub
-- @tparam prototype s another set
-- @treturn prototype everything from *this* set that is not also in *s*
-- @see difference
-- @usage
-- difference = this - s
__sub = difference,
--- Intersection operation.
-- @function prototype:__mul
-- @tparam prototype s another set
-- @treturn prototype anything in both *this* set and in *s*
-- @see intersection
-- @usage
-- intersection = this * s
__mul = intersection,
--- Symmetric difference operation.
-- @function prototype:__div
-- @tparam prototype s another set
-- @treturn prototype everything in *this* set or in *s* but not in both
-- @see symmetric_difference
-- @usage
-- symmetric_difference = this / s
__div = symmetric_difference,
--- Subset operation.
-- @static
-- @function prototype:__le
-- @tparam prototype s another set
-- @treturn boolean `true` if everything in *this* set is also in *s*
-- @see subset
-- @usage
-- issubset = this <= s
__le = subset,
--- Proper subset operation.
-- @function prototype:__lt
-- @tparam prototype s another set
-- @treturn boolean `true` if *s* is not equal to *this* set, but does
-- contain everything from *this* set
-- @see proper_subset
-- @usage
-- ispropersubset = this < s
__lt = proper_subset,
-- Return a string representation of this set.
-- @function prototype:__tostring
-- @treturn string string representation of a set.
-- @see std.tostring
__tostring = function (self)
local keys = {}
for k in pairs (self) do
keys[#keys + 1] = tostring (k)
end
table.sort (keys)
return type (self) .. " {" .. table.concat (keys, ", ") .. "}"
end,
}
return std.object.Module {
prototype = prototype,
--- Functions
-- @section functions
--- Delete an element from a set.
-- @function delete
-- @tparam prototype set a set
-- @param e element
-- @treturn prototype the modified *set*
-- @usage
-- set.delete (available, found)
delete = X ("delete (Set, any)",
function (set, e) return rawset (set, e, nil) end),
--- Find the difference of two sets.
-- @function difference
-- @tparam prototype set1 a set
-- @tparam prototype set2 another set
-- @treturn prototype a copy of *set1* with elements of *set2* removed
-- @usage
-- all = set.difference (all, Set {32, 49, 56})
difference = X ("difference (Set, Set)", difference),
--- Iterator for sets.
-- @function elems
-- @tparam prototype set a set
-- @return *set* iterator
-- @todo Make the iterator return only the key
-- @usage
-- for code in set.elems (isprintable) do print (code) end
elems = X ("elems (Set)", elems),
--- Find whether two sets are equal.
-- @function equal
-- @tparam prototype set1 a set
-- @tparam prototype set2 another set
-- @treturn boolean `true` if *set1* and *set2* each contain identical
-- elements, `false` otherwise
-- @usage
-- if set.equal (keys, Set {META, CTRL, "x"}) then process (keys) end
equal = X ( "equal (Set, Set)", equal),
--- Insert an element into a set.
-- @function insert
-- @tparam prototype set a set
-- @param e element
-- @treturn prototype the modified *set*
-- @usage
-- for byte = 32,126 do
-- set.insert (isprintable, string.char (byte))
-- end
insert = X ("insert (Set, any)", insert),
--- Find the intersection of two sets.
-- @function intersection
-- @tparam prototype set1 a set
-- @tparam prototype set2 another set
-- @treturn prototype a new set with elements in both *set1* and *set2*
-- @usage
-- common = set.intersection (a, b)
intersection = X ("intersection (Set, Set)", intersection),
--- Say whether an element is in a set.
-- @function difference
-- @tparam prototype set a set
-- @param e element
-- @return `true` if *e* is in *set*, otherwise `false`
-- otherwise
-- @usage
-- if not set.member (keyset, pressed) then return nil end
member = X ("member (Set, any)", member),
--- Find whether one set is a proper subset of another.
-- @function proper_subset
-- @tparam prototype set1 a set
-- @tparam prototype set2 another set
-- @treturn boolean `true` if *set2* contains all elements in *set1*
-- but not only those elements, `false` otherwise
-- @usage
-- if set.proper_subset (a, b) then
-- for e in set.elems (set.difference (b, a)) do
-- set.delete (b, e)
-- end
-- end
-- assert (set.equal (a, b))
proper_subset = X ("proper_subset (Set, Set)", proper_subset),
--- Find whether one set is a subset of another.
-- @function subset
-- @tparam prototype set1 a set
-- @tparam prototype set2 another set
-- @treturn boolean `true` if all elements in *set1* are also in *set2*,
-- `false` otherwise
-- @usage
-- if set.subset (a, b) then a = b end
subset = X ("subset (Set, Set)", subset),
--- Find the symmetric difference of two sets.
-- @function symmetric_difference
-- @tparam prototype set1 a set
-- @tparam prototype set2 another set
-- @treturn prototype a new set with elements that are in *set1* or *set2*
-- but not both
-- @usage
-- unique = set.symmetric_difference (a, b)
symmetric_difference = X ("symmetric_difference (Set, Set)",
symmetric_difference),
--- Find the union of two sets.
-- @function union
-- @tparam prototype set1 a set
-- @tparam prototype set2 another set
-- @treturn prototype a copy of *set1* with elements in *set2* merged in
-- @usage
-- all = set.union (a, b)
union = X ("union (Set, Set)", union),
}