--!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author OpportunityLiu, ruki -- @file hashset.lua -- -- load modules local object = require("base/object") local table = require("base/table") local todisplay = require("base/todisplay") -- define module local hashset = hashset or object { _init = {"_DATA", "_SIZE"} } -- representaion for nil key hashset._NIL = setmetatable({}, { __todisplay = function() return "${reset}${color.dump.keyword}nil${reset}" end, __tostring = function() return "symbol(nil)" end }) function hashset._to_key(key) if key == nil then key = hashset._NIL end return key end -- h1 == h1? function hashset:__eq(h) if self._DATA == h._DATA then return true end if self:size() ~= h:size() then return false end for item in h:items() do if not self:has(item) then return false end end return true end -- to display function hashset:__todisplay() return string.format("hashset${reset}(%s) {%s}", todisplay(self._SIZE), table.concat(table.imap(table.keys(self._DATA), function (i, k) if i > 10 then return nil elseif i == 10 and self._SIZE ~= 10 then return "..." else return todisplay(k) end end), ", ")) end -- check value is in hashset function hashset:has(value) value = hashset._to_key(value) return self._DATA[value] or false end -- insert value to hashset, returns false if value has already in the hashset function hashset:insert(value) value = hashset._to_key(value) local result = not (self._DATA[value] or false) if result then self._DATA[value] = true self._SIZE = self._SIZE + 1 end return result end -- remove value from hashset, returns false if value is not in the hashset function hashset:remove(value) value = hashset._to_key(value) local result = self._DATA[value] or false if result then self._DATA[value] = nil self._SIZE = self._SIZE - 1 end return result end -- convert hashset to an array, nil in the set will be ignored function hashset:to_array() local result = {} for item in self:items() do if item ~= nil then table.insert(result, item) end end return result end -- iterate items -- -- @code -- for item in instance:items() do -- ... -- end -- @endcode -- function hashset:items() return function (t, item) local k, _ = next(t._DATA, item) if k == hashset._NIL then return nil else return k end end, self, nil end -- iterate order items -- -- @code -- for item in instance:orderitems() do -- ... -- end -- @endcode -- function hashset:orderitems() local orderkeys = table.orderkeys(self._DATA, function (a, b) if a == hashset._NIL then a = math.inf end if b == hashset._NIL then b = math.inf end if type(a) == "table" then a = tostring(a) end if type(b) == "table" then b = tostring(b) end return a < b end) local i = 1 return function (t, k) k = orderkeys[i] i = i + 1 if k == hashset._NIL then return nil else return k end end, self, nil end -- iterate keys (deprecated, please use items()) -- -- @code -- for _, key in instance:keys() do -- ... -- end -- @endcode -- function hashset:keys() return function (t, key) local k, _ = next(t._DATA, key) if k == hashset._NIL then return k, nil else return k, k end end, self, nil end -- iterate order keys (deprecated, please use orderitems()) -- -- @code -- for _, key in instance:orderkeys() do -- ... -- end -- @endcode -- function hashset:orderkeys() local orderkeys = table.keys(self._DATA) table.sort(orderkeys, function (a, b) if a == hashset._NIL then a = math.inf end if b == hashset._NIL then b = math.inf end if type(a) == "table" then a = tostring(a) end if type(b) == "table" then b = tostring(b) end return a < b end) local i = 1 return function (t, k) k = orderkeys[i] i = i + 1 if k == hashset._NIL then return k, nil else return k, k end end, self, nil end -- get size of hashset function hashset:size() return self._SIZE end -- is empty? function hashset:empty() return self:size() == 0 end -- get data of hashset function hashset:data() return self._DATA end -- clear hashset function hashset:clear() self._DATA = {} self._SIZE = 0 end -- clone hashset function hashset:clone() local h = hashset.new() h._SIZE = self._SIZE h._DATA = table.clone(self._DATA) return h end -- construct from list of items -- -- @param ... the items to insert -- @return the new hashset -- function hashset.of(...) local result = hashset.new() local data = table.pack(...) for i = 1, data.n do result:insert(data[i]) end return result end -- construct from an array -- -- @param array the array of items to insert -- @return the new hashset -- function hashset.from(array) local result = hashset.new() for i = 1, #array do result:insert(array[i]) end return result end -- create a new empty hashset -- -- @return the new hashset -- function hashset.new() return hashset {{}, 0} end -- return module: hashset return hashset