<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.stiles.casa/index.php?action=history&amp;feed=atom&amp;title=Module%3ALua_set</id>
	<title>Module:Lua set - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.stiles.casa/index.php?action=history&amp;feed=atom&amp;title=Module%3ALua_set"/>
	<link rel="alternate" type="text/html" href="https://wiki.stiles.casa/index.php?title=Module:Lua_set&amp;action=history"/>
	<updated>2026-05-07T14:30:38Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.39.2</generator>
	<entry>
		<id>https://wiki.stiles.casa/index.php?title=Module:Lua_set&amp;diff=6719&amp;oldid=prev</id>
		<title>imported&gt;Alexiscoutinho: Updated TableTools dependency</title>
		<link rel="alternate" type="text/html" href="https://wiki.stiles.casa/index.php?title=Module:Lua_set&amp;diff=6719&amp;oldid=prev"/>
		<updated>2021-10-04T14:25:35Z</updated>

		<summary type="html">&lt;p&gt;Updated TableTools dependency&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;require(&amp;#039;Module:Lua class&amp;#039;)&lt;br /&gt;
local libraryUtil = require(&amp;#039;libraryUtil&amp;#039;)&lt;br /&gt;
local TableTools = require(&amp;#039;Module:TableTools&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
-- Note: hash collisions are not handled yet&lt;br /&gt;
local frozenset = class(&amp;#039;frozenset&amp;#039;, {&lt;br /&gt;
	__init = function (self, args)&lt;br /&gt;
		local elements = {}&lt;br /&gt;
&lt;br /&gt;
		if #args == 0 then -- for performance&lt;br /&gt;
			self._elements = elements&lt;br /&gt;
			return&lt;br /&gt;
		elseif #args == 1 then&lt;br /&gt;
			local arg = args[1]&lt;br /&gt;
			if type(arg) == &amp;#039;string&amp;#039; then&lt;br /&gt;
				for i = 1, mw.ustring.len(arg) do&lt;br /&gt;
					elements[mw.ustring.sub(arg, i,i)] = true&lt;br /&gt;
				end&lt;br /&gt;
				self._elements = elements&lt;br /&gt;
				return&lt;br /&gt;
			elseif pcall(pairs, arg) or pcall(ipairs, arg) then&lt;br /&gt;
				args = arg&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		if TableTools.isArrayLike(args) then&lt;br /&gt;
			for i, v in ipairs(args) do&lt;br /&gt;
				if (pcall(pairs, v) or pcall(ipairs, v)) and not (isinstance(v) and v.hash) then&lt;br /&gt;
					error((&amp;quot;TypeError: invalid element #%d type (got %s, a mutable collection)&amp;quot;):format(i, type(v)), 3)&lt;br /&gt;
				end&lt;br /&gt;
				self._set(elements, v)&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			for k in pairs(args) do&lt;br /&gt;
				if (pcall(pairs, k) or pcall(ipairs, k)) and not (isinstance(k) and k.hash) then&lt;br /&gt;
					error((&amp;quot;TypeError: invalid element type (got %s, a mutable collection)&amp;quot;):format(type(k)), 3)&lt;br /&gt;
				end&lt;br /&gt;
				self._set(elements, k)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		self._elements = elements&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	__pairs = function (self)&lt;br /&gt;
		local k, v&lt;br /&gt;
		local function iterator(elements)&lt;br /&gt;
			k, v = next(elements, k)&lt;br /&gt;
			if v == true then&lt;br /&gt;
				return k&lt;br /&gt;
			else&lt;br /&gt;
				return v -- nil at the end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return iterator, self._elements&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	__ipairs = function (self)&lt;br /&gt;
		error(&amp;quot;IterationError: a set is unordered, use &amp;#039;pairs&amp;#039; instead&amp;quot;, 2)&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	_get = function (elements, elem)&lt;br /&gt;
		if isinstance(elem) and elem.hash then&lt;br /&gt;
			return elements[elem.hash()]&lt;br /&gt;
		else&lt;br /&gt;
			return elements[elem]&lt;br /&gt;
		end&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	_set = function (elements, elem)&lt;br /&gt;
		if isinstance(elem) and elem.hash then&lt;br /&gt;
			elements[elem.hash()] = elem -- otherwise different objects with the same content would duplicate&lt;br /&gt;
		else&lt;br /&gt;
			elements[elem] = true&lt;br /&gt;
		end&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	_hash = function (self)&lt;br /&gt;
		if self.__hash then&lt;br /&gt;
			return self.__hash&lt;br /&gt;
		end&lt;br /&gt;
		-- frozensets with the same elements/keys (meaning equal) may have a different order, so &amp;#039;order&amp;#039; them before hashing&lt;br /&gt;
		local ordered_keys = TableTools.keysToList(self._elements)&lt;br /&gt;
		-- convert keys to strings for table.concat; note that information will be lost for functions&lt;br /&gt;
		for i, key in ipairs(ordered_keys) do&lt;br /&gt;
			if type(key) == &amp;#039;string&amp;#039; then&lt;br /&gt;
				ordered_keys[i] = &amp;quot;&amp;#039;&amp;quot; .. key .. &amp;quot;&amp;#039;&amp;quot;&lt;br /&gt;
			else&lt;br /&gt;
				ordered_keys[i] = tostring(key)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local str = &amp;#039;{&amp;#039; .. table.concat(ordered_keys, &amp;#039;,&amp;#039;) .. &amp;#039;}&amp;#039; -- wrap in {} to differentiate from tuple&lt;br /&gt;
		self.__hash = tonumber(&amp;#039;0x&amp;#039; .. mw.hash.hashValue(&amp;#039;fnv1a32&amp;#039;, str))&lt;br /&gt;
		return self.__hash&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	__tostring = function (self)&lt;br /&gt;
		local string_elems = {}&lt;br /&gt;
		for elem in pairs(self) do&lt;br /&gt;
			if type(elem) == &amp;#039;string&amp;#039; then&lt;br /&gt;
				string_elems[#string_elems+1] = &amp;quot;&amp;#039;&amp;quot; .. elem .. &amp;quot;&amp;#039;&amp;quot;&lt;br /&gt;
			else&lt;br /&gt;
				string_elems[#string_elems+1] = tostring(elem)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		local str = &amp;#039;{&amp;#039; .. table.concat(string_elems, &amp;#039;, &amp;#039;) .. &amp;#039;}&amp;#039;&lt;br /&gt;
		return str&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	len = function (self)&lt;br /&gt;
		return TableTools.size(self._elements)&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	has = function (self, elem)&lt;br /&gt;
		if isinstance(elem, &amp;#039;set&amp;#039;) then&lt;br /&gt;
			elem = frozenset{elem}&lt;br /&gt;
		elseif (pcall(pairs, elem) or pcall(ipairs, elem)) and not (isinstance(elem) and elem.hash) then&lt;br /&gt;
			error((&amp;quot;TypeError: invalid element type (got %s, a mutable collection)&amp;quot;):format(type(elem)), 2)&lt;br /&gt;
		end&lt;br /&gt;
		return self._get(self._elements, elem) and true or false&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	isdisjoint = function (self, other)&lt;br /&gt;
		libraryUtil.checkTypeMulti(&amp;#039;isdisjoint&amp;#039;, 1, other, {&amp;#039;set&amp;#039;, &amp;#039;frozenset&amp;#039;})&lt;br /&gt;
		for elem in pairs(other) do&lt;br /&gt;
			if self._get(self._elements, elem) then&lt;br /&gt;
				return false&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return true&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	issubset = function (self, other)&lt;br /&gt;
		return self &amp;lt;= frozenset{other}&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	__le = function (a, b)&lt;br /&gt;
		for elem in pairs(a) do&lt;br /&gt;
			if not b._get(b._elements, elem) then&lt;br /&gt;
				return false&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return true&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	__lt = function (a, b)&lt;br /&gt;
		return a &amp;lt;= b and a.len() &amp;lt; b.len() -- is calculating a&amp;#039;s length during its traversal in __le faster?&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	issuperset = function (self, other)&lt;br /&gt;
		return self &amp;gt;= frozenset{other}&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	union = function (self, ...)&lt;br /&gt;
		local sum = set{self}&lt;br /&gt;
		sum.update(...)&lt;br /&gt;
		return sum&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	__add = function (a, b)&lt;br /&gt;
		local elements = {}&lt;br /&gt;
		for elem in pairs(a) do&lt;br /&gt;
			a._set(elements, elem)&lt;br /&gt;
		end&lt;br /&gt;
		for elem in pairs(b) do&lt;br /&gt;
			b._set(elements, elem)&lt;br /&gt;
		end&lt;br /&gt;
		return a.__class{elements}&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	intersection = function (self, ...)&lt;br /&gt;
		local product = set{self}&lt;br /&gt;
		product.intersection_update(...)&lt;br /&gt;
		return product&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	__mul = function (a, b)&lt;br /&gt;
		local elements = {}&lt;br /&gt;
		for elem in pairs(a) do&lt;br /&gt;
			if b._get(b._elements, elem) then&lt;br /&gt;
				b._set(elements, elem)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return a.__class{elements}&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	difference = function (self, ...)&lt;br /&gt;
		local difference = set{self}&lt;br /&gt;
		difference.difference_update(...)&lt;br /&gt;
		return difference&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	__sub = function (a, b)&lt;br /&gt;
		local elements = {}&lt;br /&gt;
		for elem in pairs(a) do&lt;br /&gt;
			if not b._get(b._elements, elem) then&lt;br /&gt;
				b._set(elements, elem)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return a.__class{elements}&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	symmetric_difference = function (self, other)&lt;br /&gt;
		return self ^ frozenset{other}&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	__pow = function (a, b)&lt;br /&gt;
		local elements = {}&lt;br /&gt;
		for elem in pairs(a) do&lt;br /&gt;
			if not b._get(b._elements, elem) then&lt;br /&gt;
				b._set(elements, elem)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		for elem in pairs(b) do&lt;br /&gt;
			if not a._get(a._elements, elem) then&lt;br /&gt;
				a._set(elements, elem)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return a.__class{elements}&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	copy = function (self)&lt;br /&gt;
		return self.__class{self}&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	__eq = function (a, b)&lt;br /&gt;
		return a &amp;lt;= b and a &amp;gt;= b&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	__staticmethods = {&amp;#039;_get&amp;#039;, &amp;#039;_set&amp;#039;},&lt;br /&gt;
	__protected = {&amp;#039;_get&amp;#039;, &amp;#039;_set&amp;#039;}&lt;br /&gt;
})&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local set = class(&amp;#039;set&amp;#039;, frozenset, {&lt;br /&gt;
	_del = function (elements, elem)&lt;br /&gt;
		if isinstance(elem) and elem.hash then&lt;br /&gt;
			elements[elem.hash()] = nil&lt;br /&gt;
		else&lt;br /&gt;
			elements[elem] = nil&lt;br /&gt;
		end&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	update = function (self, ...)&lt;br /&gt;
		local others, other = {...}, nil&lt;br /&gt;
		for i = 1, select(&amp;#039;#&amp;#039;, ...) do&lt;br /&gt;
			other = frozenset{others[i]}&lt;br /&gt;
			for elem in pairs(other) do&lt;br /&gt;
				self._set(self._elements, elem)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	intersection_update = function (self, ...)&lt;br /&gt;
		local others, other = {...}, nil&lt;br /&gt;
		for i = 1, select(&amp;#039;#&amp;#039;, ...) do&lt;br /&gt;
			other = frozenset{others[i]}&lt;br /&gt;
			for elem in pairs(self) do&lt;br /&gt;
				if not other.has(elem) then -- probably faster than iterating through (likely longer) other to access self._get&lt;br /&gt;
					self._del(self._elements, elem)&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	difference_update = function (self, ...)&lt;br /&gt;
		local others, other = {...}, nil&lt;br /&gt;
		for i = 1, select(&amp;#039;#&amp;#039;, ...) do&lt;br /&gt;
			other = frozenset{others[i]}&lt;br /&gt;
			for elem in pairs(self) do&lt;br /&gt;
				if other.has(elem) then&lt;br /&gt;
					self._del(self._elements, elem)&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	symmetric_difference_update = function (self, other)&lt;br /&gt;
		other = frozenset{other}&lt;br /&gt;
		for elem in pairs(self) do&lt;br /&gt;
			if other.has(elem) then&lt;br /&gt;
				self._del(self._elements, elem)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		for elem in pairs(other) do&lt;br /&gt;
			if not self._get(self._elements, elem) then&lt;br /&gt;
				self._set(self._elements, elem)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	add = function (self, elem)&lt;br /&gt;
		if (pcall(pairs, elem) or pcall(ipairs, elem)) and not (isinstance(elem) and elem.hash) then&lt;br /&gt;
			error((&amp;quot;TypeError: invalid element type (got %s, a mutable collection)&amp;quot;):format(type(elem)), 2)&lt;br /&gt;
		end&lt;br /&gt;
		self._set(self._elements, elem)&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	remove = function (self, elem)&lt;br /&gt;
		if isinstance(elem, &amp;#039;set&amp;#039;) then&lt;br /&gt;
			elem = frozenset{elem}&lt;br /&gt;
		elseif (pcall(pairs, elem) or pcall(ipairs, elem)) and not (isinstance(elem) and elem.hash) then&lt;br /&gt;
			error((&amp;quot;TypeError: invalid element type (got %s, a mutable collection)&amp;quot;):format(type(elem)), 2)&lt;br /&gt;
		end&lt;br /&gt;
		if not self._get(self._elements, elem) then -- cannot use self.has since error level would be incorrect&lt;br /&gt;
			error((&amp;quot;KeyError: %s&amp;quot;):format(tostring(elem)), 2)&lt;br /&gt;
		end&lt;br /&gt;
		self._del(self._elements, elem)&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	discard = function (self, elem)&lt;br /&gt;
		if isinstance(elem, &amp;#039;set&amp;#039;) then&lt;br /&gt;
			elem = frozenset{elem}&lt;br /&gt;
		elseif (pcall(pairs, elem) or pcall(ipairs, elem)) and not (isinstance(elem) and elem.hash) then&lt;br /&gt;
			error((&amp;quot;TypeError: invalid element type (got %s, a mutable collection)&amp;quot;):format(type(elem)), 2)&lt;br /&gt;
		end&lt;br /&gt;
		self._del(self._elements, elem)&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	pop = function (self)&lt;br /&gt;
		local k, v = next(self._elements)&lt;br /&gt;
		if k == nil then&lt;br /&gt;
			error(&amp;quot;KeyError: pop from an empty set&amp;quot;, 2)&lt;br /&gt;
		end&lt;br /&gt;
		if v == true then&lt;br /&gt;
			self._del(self._elements, k)&lt;br /&gt;
			return k&lt;br /&gt;
		else&lt;br /&gt;
			self._del(self._elements, v)&lt;br /&gt;
			return v&lt;br /&gt;
		end&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	clear = function (self)&lt;br /&gt;
		self._elements = {}&lt;br /&gt;
	end,&lt;br /&gt;
&lt;br /&gt;
	__staticmethods = {&amp;#039;_del&amp;#039;},&lt;br /&gt;
	__protected = {&amp;#039;_del&amp;#039;}&lt;br /&gt;
})&lt;br /&gt;
&lt;br /&gt;
return {frozenset, set}&lt;/div&gt;</summary>
		<author><name>imported&gt;Alexiscoutinho</name></author>
	</entry>
</feed>