mirror of
https://github.com/1bardesign/batteries.git
synced 2024-11-25 23:24:35 +00:00
66a6c5a50e
As a new user, there were things I was skeptical about and after digging in, these were my conclusions. Compared to the simple and obvious lua wiki solutions, batteries' string functions are slightly faster. GC is the same. Test local str = "hello world" local fn = function() local x = 0 if stringx.ends_with(str, "h") then x = x + 1 end if stringx.ends_with(str, "helll") then x = x + 1 end if stringx.ends_with(str, "helicopter") then x = x + 1 end end local pretty = require "inspect" print("stringx =", pretty({ time_taken = {measure.time_taken(fn, 10000)}, memory_taken = {measure.memory_taken(fn, 10000)} })) local function starts_with(str, prefix) return str:find(prefix, 1, true) == 1 end local function ends_with(str, ending) return ending == "" or str:sub(-#ending) == ending end local fn = function() local x = 0 if ends_with(str, "h") then x = x + 1 end if ends_with(str, "helll") then x = x + 1 end if ends_with(str, "helicopter") then x = x + 1 end end print("find =", pretty({ time_taken = {measure.time_taken(fn, 10000)}, memory_taken = {measure.memory_taken(fn, 10000)} })) starts_with =========== stringx = { memory_taken = { 0, 0, 0 }, time_taken = { 1.5098012518138e-007, 9.988434612751e-008, 2.1699932403862e-005 } } find = { memory_taken = { 0, 0, 0 }, time_taken = { 2.7349997544661e-007, 1.9988510757685e-007, 9.1999536380172e-006 } } ends_with ========= stringx = { memory_taken = { 0, 0, 0 }, time_taken = { 9.0479978825897e-008, 0, 2.5199959054589e-005 } } find = { memory_taken = { 0, 0, 0 }, time_taken = { 2.1833006758243e-007, 1.9988510757685e-007, 6.1000464484096e-006 } }
181 lines
4.1 KiB
Lua
181 lines
4.1 KiB
Lua
--[[
|
|
set type with appropriate operations
|
|
|
|
NOTE: This is actually a unique list (ordered set). So it's more than just
|
|
a table with keys for values.
|
|
]]
|
|
|
|
local path = (...):gsub("set", "")
|
|
local class = require(path .. "class")
|
|
local table = require(path .. "tablex") --shadow global table module
|
|
|
|
local set = class({
|
|
name = "set",
|
|
})
|
|
|
|
--construct a new set
|
|
--elements is an optional ordered table of elements to be added to the set
|
|
function set:new(elements)
|
|
self._keyed = {}
|
|
self._ordered = {}
|
|
if elements then
|
|
for _, v in ipairs(elements) do
|
|
self:add(v)
|
|
end
|
|
end
|
|
end
|
|
|
|
--check if an element is present in the set
|
|
function set:has(v)
|
|
return self._keyed[v] or false
|
|
end
|
|
|
|
--add a value to the set, if it's not already present
|
|
function set:add(v)
|
|
if not self:has(v) then
|
|
self._keyed[v] = true
|
|
table.insert(self._ordered, v)
|
|
end
|
|
return self
|
|
end
|
|
|
|
--remove a value from the set, if it's present
|
|
function set:remove(v)
|
|
if self:has(v) then
|
|
self._keyed[v] = nil
|
|
table.remove_value(self._ordered, v)
|
|
end
|
|
return self
|
|
end
|
|
|
|
--remove all elements from the set
|
|
function set:clear()
|
|
if table.clear then
|
|
table.clear(self._keyed)
|
|
table.clear(self._ordered)
|
|
else
|
|
self._keyed = {}
|
|
self._ordered = {}
|
|
end
|
|
end
|
|
|
|
--get the number of distinct values in the set
|
|
function set:size()
|
|
return #self._ordered
|
|
end
|
|
|
|
--return a value from the set
|
|
--index must be between 1 and size() inclusive
|
|
--adding/removing invalidates indices
|
|
function set:get(index)
|
|
return self._ordered[index]
|
|
end
|
|
|
|
--iterate the values in the set, along with their index
|
|
--the index is useless but harmless, and adding a custom iterator seems
|
|
--like a really easy way to encourage people to use slower-than-optimal code
|
|
function set:ipairs()
|
|
return ipairs(self._ordered)
|
|
end
|
|
|
|
--get a copy of the values in the set, as a simple table
|
|
function set:values()
|
|
return table.copy(self._ordered)
|
|
end
|
|
|
|
--get a direct reference to the internal list of values in the set
|
|
--do NOT modify the result, or you'll break the set!
|
|
--for read-only access it avoids a needless table copy
|
|
--(eg this is sensible to pass to functional apis)
|
|
function set:values_readonly()
|
|
return self._ordered
|
|
end
|
|
|
|
--convert to an ordered table, destroying set-like properties
|
|
--and deliberately disabling the initial set object
|
|
function set:to_table()
|
|
local r = self._ordered
|
|
self._ordered = nil
|
|
self._keyed = nil
|
|
return r
|
|
end
|
|
|
|
--modifying operations
|
|
|
|
--add all the elements present in the other set
|
|
function set:add_set(other)
|
|
for i, v in other:ipairs() do
|
|
self:add(v)
|
|
end
|
|
return self
|
|
end
|
|
|
|
--remove all the elements present in the other set
|
|
function set:subtract_set(other)
|
|
for i, v in other:ipairs() do
|
|
self:remove(v)
|
|
end
|
|
return self
|
|
end
|
|
|
|
--new collection operations
|
|
|
|
--copy a set
|
|
function set:copy()
|
|
return set():add_set(self)
|
|
end
|
|
|
|
--create a new set containing the complement of the other set contained in this one
|
|
--the elements present in this set but not present in the other set will remain in the result
|
|
function set:complement(other)
|
|
return self:copy():subtract_set(other)
|
|
end
|
|
|
|
--alias
|
|
set.difference = set.complement
|
|
|
|
--create a new set containing the union of this set with another
|
|
--an element present in either set will be present in the result
|
|
function set:union(other)
|
|
return self:copy():add_set(other)
|
|
end
|
|
|
|
--create a new set containing the intersection of this set with another
|
|
--only the elements present in both sets will remain in the result
|
|
function set:intersection(other)
|
|
local r = set()
|
|
for i, v in self:ipairs() do
|
|
if other:has(v) then
|
|
r:add(v)
|
|
end
|
|
end
|
|
return r
|
|
end
|
|
|
|
--create a new set containing the symmetric difference of this set with another
|
|
--only the elements not present in both sets will remain in the result
|
|
--similiar to a logical XOR operation
|
|
--
|
|
--equal to self:union(other):subtract_set(self:intersection(other))
|
|
-- but with much less wasted effort
|
|
function set:symmetric_difference(other)
|
|
local r = set()
|
|
for i, v in self:ipairs() do
|
|
if not other:has(v) then
|
|
r:add(v)
|
|
end
|
|
end
|
|
for i, v in other:ipairs() do
|
|
if not self:has(v) then
|
|
r:add(v)
|
|
end
|
|
end
|
|
return r
|
|
end
|
|
|
|
--alias
|
|
set.xor = set.symmetric_difference
|
|
|
|
--
|
|
return set
|