Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[=[
- Version 1.0.0
- This is intended for Roblox ModuleScripts
- BSD 2-Clause Licence
- Copyright ©, 2020 - Blockzez (devforum.roblox.com/u/Blockzez and github.com/Blockzez)
- All rights reserved.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- 1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WlistANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WlistANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- ]=]--
- local tup = { };
- local list = { };
- local module = setmetatable({ }, { __index = { tuple = tup, list = list }, __newindex = function() error("Attempt to modify a readonly table", 2) end, __metatable = "The metatable is locked" });
- -- A pointer so it won't throw an error for index being nil
- local nullpointer = newproxy();
- -- A placeholder pointer for getting the data
- local getdata = newproxy();
- local proxy = { };
- local addr = { };
- local hashes = { };
- --[=[ Tuple ]=]--
- local function nullifnil(value)
- if value == nil then
- return nullpointer;
- end;
- return value;
- end;
- local function compare_list(left, right)
- for i = 0, math.min(#left, #right) - 1 do
- if left[i] ~= right[i] then
- return (left[i] > right[i]) and 1 or -1;
- end;
- end;
- return (#left > #right) and 1 or ((#left < #right) and -1 or 0);
- end;
- -- Operators
- -- <= and =>
- local function le(left, right)
- return compare_list(left, right) <= 0;
- end;
- -- < and >
- local function lt(left, right)
- return compare_list(left, right) < 0;
- end;
- -- == (This is NOT rawequal)
- local function eq(left, right)
- if #left ~= #right then
- return false;
- end;
- for i = 0, #left - 1 do
- if left[i] ~= right[i] then
- return false;
- end;
- end;
- return true;
- end;
- -- + and ..
- local function concat_tup(left, right)
- if not (proxy[left] and proxy[right]) then
- error("attempt to concatenate " .. typeof(right) .. " with " .. typeof(right), 2);
- end;
- local ret = { };
- for _, v in ipairs(proxy[left].data) do
- table.insert(ret, v);
- end;
- for _, v in ipairs(proxy[right].data) do
- table.insert(ret, v);
- end;
- return tup.fromList(ret);
- end;
- -- *
- local function mul_tup(left, right)
- if proxy[left] and proxy[right] then
- error("attempt to perform arithmetic (mul) on userdata", 2);
- elseif type(left) ~= "number" and type(right) ~= "number" then
- error("attempt to perform arithmetic (mul) on " .. typeof(left) .. " and " .. typeof(right), 2);
- end;
- local rep, tuple;
- if type(right) == "number" then
- rep = right;
- tuple = proxy[left].data;
- else
- rep = left;
- tuple = proxy[right].data;
- end;
- local ret = { };
- for _ = 1, rep do
- for _, v in ipairs(tuple) do
- table.insert(ret, v);
- end;
- end;
- return tup.fromList(ret);
- end;
- -- Other
- local function len(self)
- return #proxy[self].data;
- end;
- local function tostr_tup(self)
- return table.concat(proxy[self].data, ', ');
- end;
- -- Index
- local function getattr_tup(self, ind)
- if type(ind) == "number" then
- if ind >= #self or ind < -#self then
- error("tuple index out of range", 2);
- end;
- if ind < 0 then
- return proxy[self].data[(#self + ind) + 1];
- end;
- return proxy[self].data[ind + 1];
- elseif type(ind) ~= "string" then
- return;
- end;
- if ind:match('Item[1-9]%d*') then
- return proxy[self].data[tonumber(ind:sub(5))];
- end;
- return (ind ~= "new" and ind ~= "fromList") and tup[ind];
- end;
- -- Constuctors
- function tup.new(...)
- return tup.fromList { ... };
- end;
- function tup.fromList(list)
- if type(list) ~= "table" and not proxy[list] then
- error("bad argument #1 (table expected, got" .. typeof(list) .. ")", 2);
- end;
- local position = hashes;
- local list_copy = { };
- if type(list) == "table" then
- local i = 1;
- for ind, val in next, list do
- -- Check
- if ind ~= i then
- error("bad argument #1 (array expected, got dictionary)", 2);
- end;
- if not position[nullifnil(val)] then
- position[nullifnil(val)] = { };
- end;
- position = position[nullifnil(val)];
- list_copy[ind] = val;
- i = i + 1;
- end;
- elseif proxy[list].list then
- for _, val in list do
- if not position[nullifnil(val)] then
- position[nullifnil(val)] = { };
- end;
- position = position[nullifnil(val)];
- table.insert(list_copy, val);
- end;
- else
- return list;
- end;
- if position[getdata] then
- return position[getdata];
- end;
- local pointer = newproxy(true);
- position[getdata] = pointer;
- proxy[pointer] = { list = false, data = list_copy };
- addr[pointer] = tostring(pointer):sub(11);
- local pointer_metatable = getmetatable(pointer);
- pointer_metatable.__metatable = "The metatable is locked";
- pointer_metatable.__index = getattr_tup;
- -- Operators
- pointer_metatable.__le = le;
- pointer_metatable.__lt = lt;
- pointer_metatable.__eq = eq;
- pointer_metatable.__add = concat_tup;
- pointer_metatable.__concat = concat_tup;
- pointer_metatable.__mul = mul_tup;
- -- Iterator
- local ind = 0;
- pointer_metatable.__call = function()
- ind = ind + 1;
- if ind > #proxy[pointer].data then
- ind = 0;
- return;
- end;
- return ind - 1, proxy[pointer].data[ind];
- end;
- -- Others
- pointer_metatable.__len = len;
- pointer_metatable.__tostring = tostr_tup;
- return pointer;
- end;
- -- Methods
- setmetatable(tup, { __newindex = function(self, ind, func) rawset(self, ind,
- function(self1, ...) if (not proxy[self1]) then error(self == module and ("bad argument #1 (tuple expected, got " .. typeof(self) .. ')')
- or ("Expected ':' not '.' calling member function " .. ind), 2); end; return func(self1, ...) end); end; });
- function tup:unpack()
- return unpack(proxy[self].data);
- end;
- function tup:filter(func, self_arg)
- if type(func) ~= "function" then
- error("bad argument #2 (function expected, got " .. typeof(func) .. ')', 2);
- end;
- local ret = { };
- for _, val in ipairs(proxy[self].data) do
- if self_arg and func(self, val) or func(val) then
- table.insert(ret, val);
- end;
- end;
- return tup.fromList(ret);
- end;
- function tup:index(val)
- return table.find(proxy[self].data, val);
- end;
- function tup:count(val, self_arg)
- if self_arg ~= nil then
- if type(val) ~= "function" then
- error("bad argument #2 (function expected, got " .. typeof(val) .. ')', 2);
- end;
- end;
- local ret = 0;
- for _, val1 in ipairs(proxy[self].data) do
- if self_arg ~= nil then
- if self_arg and val(self, val1) or val(val1) then
- ret = ret + 1;
- end;
- elseif val == val1 then
- ret = ret + 1;
- end;
- end;
- return ret;
- end;
- function tup:pop(ind)
- if type(ind) ~= "number" then
- error("bad argument #2 (integer expected, got " .. typeof(ind) .. ')', 2);
- elseif ind % 1 ~= 0 then
- error("bad argument #2 (integer expected, got float)", 2);
- end;
- local ret = { };
- ind = ind or -1;
- if ind < 0 then
- ind = #self + ind;
- end;
- for k, v in ipairs(proxy[self].data) do
- if k - 1 ~= ind then
- table.insert(ret, v);
- end;
- end;
- return tup.fromList(ret);
- end;
- --[=[ Lists ]=]--
- -- + and ..
- local function concat_list(left, right)
- if not (proxy[left] and proxy[right]) then
- error("attempt to concatenate " .. typeof(right) .. " with " .. typeof(right), 2);
- end;
- local ret = { };
- for _, v in ipairs(proxy[left].data) do
- table.insert(ret, v);
- end;
- for _, v in ipairs(proxy[right].data) do
- table.insert(ret, v);
- end;
- return list.new(ret);
- end;
- -- *
- local function mul_list(left, right)
- if proxy[left] and proxy[right] then
- error("attempt to perform arithmetic (mul) on userdata", 2);
- elseif type(left) ~= "number" and type(right) ~= "number" then
- error("attempt to perform arithmetic (mul) on " .. typeof(left) .. " and " .. typeof(right), 2);
- end;
- local _list = list;
- local rep, list;
- if type(right) == "number" then
- rep = right;
- list = proxy[left].data;
- else
- rep = left;
- list = proxy[right].data;
- end;
- local ret = { };
- for _ = 1, rep do
- for _, v in ipairs(list) do
- table.insert(ret, v);
- end;
- end;
- return _list.new(ret);
- end;
- -- Other
- function tostr_list(self)
- return "list: " .. addr[self];
- end;
- -- Index
- local function getattr_list(self, ind)
- if type(ind) == "number" then
- if ind >= #self or ind < -#self then
- error("list index out of range", 2);
- end;
- if ind < 0 then
- return proxy[self].data[(#self + ind) + 1];
- end;
- return proxy[self].data[ind + 1];
- elseif type(ind) ~= "string" then
- return;
- end;
- return (ind ~= "new" and ind ~= "pack") and list[ind];
- end;
- local function setattr_list(self, ind, val)
- if type(ind) ~= "number" then
- if type(ind) ~= "string" then
- error("attempt to index userdata with '" .. typeof(ind) .. "'", 2);
- end;
- error("attempt to index userdata with '" .. ind .. "'", 2);
- end;
- if ind >= #self or ind < -#self then
- error("list index out of range", 2);
- end;
- if ind < 0 then
- proxy[self].data[(#self + ind) + 1] = val;
- end;
- proxy[self].data[ind + 1] = val;
- end;
- -- Constructor
- function list.new(arr)
- if type(arr) ~= "table" and not proxy[arr] then
- error("bad argument #1 (table expected, got" .. typeof(list) .. ")", 2);
- end;
- local arr_copy = { };
- if type(list) == "table" then
- local i = 1;
- for ind, val in next, arr do
- -- Check
- if ind ~= i then
- error("bad argument #1 (array expected, got dictionary)", 2);
- end;
- arr_copy[ind] = val;
- i = i + 1;
- end;
- elseif proxy[arr].list then
- return arr;
- else
- for _, val in arr do
- table.insert(arr_copy, val);
- end;
- end;
- local pointer = newproxy(true);
- proxy[pointer] = { list = true, data = arr_copy };
- addr[pointer] = tostring(pointer):sub(11);
- local pointer_metatable = getmetatable(pointer);
- pointer_metatable.__metatable = "The metatable is locked";
- pointer_metatable.__index = getattr_list;
- pointer_metatable.__newindex = setattr_list;
- -- Operators
- pointer_metatable.__le = le;
- pointer_metatable.__lt = lt;
- pointer_metatable.__eq = eq;
- pointer_metatable.__add = concat_list;
- pointer_metatable.__concat = concat_list;
- pointer_metatable.__mul = mul_list;
- -- Iterator
- local ind = 0;
- pointer_metatable.__call = function()
- ind = ind + 1;
- if ind > #proxy[pointer].data then
- ind = 0;
- return;
- end;
- return ind - 1, proxy[pointer].data[ind];
- end;
- -- Other
- pointer_metatable.__len = len;
- pointer_metatable.__tostring = tostr_list;
- return pointer;
- end;
- function list.pack(...)
- return list.new { ... };
- end;
- -- Methods
- setmetatable(list, { __newindex = function(self, ind, func) rawset(self, ind,
- function(self1, ...) if (not proxy[self1]) then error(self == module and ("bad argument #1 (list expected, got " .. typeof(self) .. ')')
- or ("Expected ':' not '.' calling member function " .. ind), 2); end; return func(self1, ...) end); end; });
- function list:append(value)
- table.insert(proxy[self].data, value);
- return self;
- end;
- function list:insert(ind, value)
- if type(ind) ~= "number" then
- error("bad argument #1 (integer expected, got" .. typeof(ind) .. ")", 2);
- elseif ind % 1 ~= 0 then
- error("bad argument #1 (integer expected, got float)", 2);
- end;
- if ind < 0 then
- table.insert(proxy[self].data, math.max((#self + ind) + 1, 1), value);
- else
- table.insert(proxy[self].data, math.min(ind + 1, #self), value);
- end;
- end;
- function list:pop(ind)
- if type(ind) ~= "number" then
- error("bad argument #1 (integer expected, got" .. typeof(ind) .. ")", 2);
- elseif ind % 1 ~= 0 then
- error("bad argument #1 (integer expected, got float)", 2);
- end;
- if ind < 0 then
- return table.remove(proxy[self].data, math.min((#self + ind) + 1, 1));
- end;
- return table.remove(proxy[self].data, math.max(ind + 1, #self));
- end;
- function list:unpack()
- return unpack(proxy[self].data);
- end;
- function list:filter(func, self_arg)
- if type(func) ~= "function" then
- error("bad argument #2 (function expected, got " .. typeof(func) .. ')', 2);
- end;
- local ret = { };
- for _, val in ipairs(proxy[self].data) do
- if self_arg and func(self, val) or func(val) then
- table.insert(ret, val);
- end;
- end;
- return list.new(ret);
- end;
- function list:index(val)
- return table.find(proxy[self].data, val);
- end;
- function list:count(val, self_arg)
- if self_arg ~= nil then
- if type(val) ~= "function" then
- error("bad argument #2 (function expected, got " .. typeof(val) .. ')', 2);
- end;
- end;
- local ret = 0;
- for _, val1 in ipairs(proxy[self].data) do
- if self_arg ~= nil then
- if self_arg and val(self, val1) or val(val1) then
- ret = ret + 1;
- end;
- elseif val == val1 then
- ret = ret + 1;
- end;
- end;
- return ret;
- end;
- function list:sort(comp)
- return list.new(table.sort(proxy[self].data, comp));
- end;
- function list:copy()
- return list.new(table.move(proxy[self].data, 1, #self, 1, table.create(#self)));
- end;
- function list:reverse()
- if #self > 1 then
- for i = 0, math.floor(#self / 2) - 1 do
- self[i], self[-(i + 1)] = self[-(i + 1)], self[i];
- end;
- end;
- return self;
- end;
- function list:clear()
- for _ = 1, #self do
- table.remove(proxy[self].data);
- end;
- return self;
- end;
- function list:join(sep)
- return table.concat(proxy[self].data, sep or ',');
- end;
- function list:splice(i, c, ...)
- if type(i) ~= "number" then
- error("bad argument #1 (integer expected, got" .. typeof(i) .. ")", 2);
- elseif i % 1 ~= 0 then
- error("bad argument #1 (integer expected, got float)", 2);
- end;
- if type(c) ~= "number" then
- error("bad argument #2 (integer expected, got" .. typeof(c) .. ")", 2);
- elseif c % 1 ~= 0 then
- error("bad argument #2 (integer expected, got float)", 2);
- end;
- local args = { ... };
- if i < 0 then
- i = math.max((#self + i) + 1, 1);
- else
- i = math.min(i + 1, #self);
- end;
- for _ = 1, c do
- table.remove(proxy[self].data, c);
- end;
- for ind = #args, 1, -1 do
- table.insert(proxy[self].data, i, args[ind]);
- end;
- return self;
- end;
- function list:formatenglish()
- if #self == 1 then
- return self[0];
- end;
- return table.concat(proxy[self].data, ', ', 1, -2) .. ' and ' .. self[-1];
- end;
- return module;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement