Advertisement
Guest User

Tuple & Lists

a guest
Jun 8th, 2020
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 14.98 KB | None | 0 0
  1. --[=[
  2.     Version 1.0.0
  3.     This is intended for Roblox ModuleScripts
  4.     BSD 2-Clause Licence
  5.     Copyright ©, 2020 - Blockzez (devforum.roblox.com/u/Blockzez and github.com/Blockzez)
  6.     All rights reserved.
  7.    
  8.     Redistribution and use in source and binary forms, with or without
  9.     modification, are permitted provided that the following conditions are met:
  10.    
  11.     1. Redistributions of source code must retain the above copyright notice, this
  12.        list of conditions and the following disclaimer.
  13.    
  14.     2. Redistributions in binary form must reproduce the above copyright notice,
  15.        this list of conditions and the following disclaimer in the documentation
  16.        and/or other materials provided with the distribution.
  17.    
  18.     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  19.     AND ANY EXPRESS OR IMPLIED WlistANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  20.     IMPLIED WlistANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21.     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  22.     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  23.     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  24.     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  25.     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  26.     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  27.     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. ]=]--
  29. local tup = { };
  30. local list = { };
  31. local module = setmetatable({ }, { __index = { tuple = tup, list = list }, __newindex = function() error("Attempt to modify a readonly table", 2) end, __metatable = "The metatable is locked" });
  32.  
  33. -- A pointer so it won't throw an error for index being nil
  34. local nullpointer = newproxy();
  35.  
  36. -- A placeholder pointer for getting the data
  37. local getdata = newproxy();
  38.  
  39. local proxy = { };
  40. local addr = { };
  41. local hashes = { };
  42.  
  43. --[=[ Tuple ]=]--
  44. local function nullifnil(value)
  45.     if value == nil then
  46.         return nullpointer;
  47.     end;
  48.     return value;
  49. end;
  50.  
  51. local function compare_list(left, right)
  52.     for i = 0, math.min(#left, #right) - 1 do
  53.         if left[i] ~= right[i] then
  54.             return (left[i] > right[i]) and 1 or -1;
  55.         end;
  56.     end;
  57.     return (#left > #right) and 1 or ((#left < #right) and -1 or 0);
  58. end;
  59.  
  60. -- Operators
  61. -- <= and =>
  62. local function le(left, right)
  63.     return compare_list(left, right) <= 0;
  64. end;
  65.  
  66. -- < and >
  67. local function lt(left, right)
  68.     return compare_list(left, right) < 0;
  69. end;
  70.  
  71. -- == (This is NOT rawequal)
  72. local function eq(left, right)
  73.     if #left ~= #right then
  74.         return false;
  75.     end;
  76.     for i = 0, #left - 1 do
  77.         if left[i] ~= right[i] then
  78.             return false;
  79.         end;
  80.     end;
  81.     return true;
  82. end;
  83.  
  84. -- + and ..
  85. local function concat_tup(left, right)
  86.     if not (proxy[left] and proxy[right]) then
  87.         error("attempt to concatenate " .. typeof(right) .. " with " .. typeof(right), 2);
  88.     end;
  89.     local ret = { };
  90.     for _, v in ipairs(proxy[left].data) do
  91.         table.insert(ret, v);
  92.     end;
  93.     for _, v in ipairs(proxy[right].data) do
  94.         table.insert(ret, v);
  95.     end;
  96.     return tup.fromList(ret);
  97. end;
  98.  
  99. -- *
  100. local function mul_tup(left, right)
  101.     if proxy[left] and proxy[right] then
  102.         error("attempt to perform arithmetic (mul) on userdata", 2);
  103.     elseif type(left) ~= "number" and type(right) ~= "number" then
  104.         error("attempt to perform arithmetic (mul) on " .. typeof(left) .. " and " .. typeof(right), 2);
  105.     end;
  106.     local rep, tuple;
  107.     if type(right) == "number" then
  108.         rep = right;
  109.         tuple = proxy[left].data;
  110.     else
  111.         rep = left;
  112.         tuple = proxy[right].data;
  113.     end;
  114.     local ret = { };
  115.     for _ = 1, rep do
  116.         for _, v in ipairs(tuple) do
  117.             table.insert(ret, v);
  118.         end;
  119.     end;
  120.     return tup.fromList(ret);
  121. end;
  122.  
  123. -- Other
  124. local function len(self)
  125.     return #proxy[self].data;
  126. end;
  127.  
  128. local function tostr_tup(self)
  129.     return table.concat(proxy[self].data, ', ');
  130. end;
  131.  
  132. -- Index
  133. local function getattr_tup(self, ind)
  134.     if type(ind) == "number" then
  135.         if ind >= #self or ind < -#self then
  136.             error("tuple index out of range", 2);
  137.         end;
  138.         if ind < 0 then
  139.             return proxy[self].data[(#self + ind) + 1];
  140.         end;
  141.         return proxy[self].data[ind + 1];
  142.     elseif type(ind) ~= "string" then
  143.         return;
  144.     end;
  145.     if ind:match('Item[1-9]%d*') then
  146.         return proxy[self].data[tonumber(ind:sub(5))];
  147.     end;
  148.     return (ind ~= "new" and ind ~= "fromList") and tup[ind];
  149. end;
  150.  
  151. -- Constuctors
  152. function tup.new(...)
  153.     return tup.fromList { ... };
  154. end;
  155.  
  156. function tup.fromList(list)
  157.     if type(list) ~= "table" and not proxy[list] then
  158.         error("bad argument #1 (table expected, got" .. typeof(list) .. ")", 2);
  159.     end;
  160.     local position = hashes;
  161.     local list_copy = { };
  162.     if type(list) == "table" then
  163.         local i = 1;
  164.         for ind, val in next, list do
  165.             -- Check
  166.             if ind ~= i then
  167.                 error("bad argument #1 (array expected, got dictionary)", 2);
  168.             end;
  169.            
  170.             if not position[nullifnil(val)] then
  171.                 position[nullifnil(val)] = { };
  172.             end;
  173.             position = position[nullifnil(val)];
  174.            
  175.             list_copy[ind] = val;
  176.             i = i + 1;
  177.         end;
  178.     elseif proxy[list].list then
  179.         for _, val in list do
  180.             if not position[nullifnil(val)] then
  181.                 position[nullifnil(val)] = { };
  182.             end;
  183.             position = position[nullifnil(val)];
  184.            
  185.             table.insert(list_copy, val);
  186.         end;
  187.     else
  188.         return list;
  189.     end;
  190.    
  191.     if position[getdata] then
  192.         return position[getdata];
  193.     end;
  194.    
  195.     local pointer = newproxy(true);
  196.     position[getdata] = pointer;
  197.     proxy[pointer] = { list = false, data = list_copy };
  198.     addr[pointer] = tostring(pointer):sub(11);
  199.    
  200.     local pointer_metatable = getmetatable(pointer);
  201.     pointer_metatable.__metatable = "The metatable is locked";
  202.     pointer_metatable.__index = getattr_tup;
  203.    
  204.     -- Operators
  205.     pointer_metatable.__le = le;
  206.     pointer_metatable.__lt = lt;
  207.     pointer_metatable.__eq = eq;
  208.     pointer_metatable.__add = concat_tup;
  209.     pointer_metatable.__concat = concat_tup;
  210.     pointer_metatable.__mul = mul_tup;
  211.    
  212.     -- Iterator
  213.     local ind = 0;
  214.     pointer_metatable.__call = function()
  215.         ind = ind + 1;
  216.         if ind > #proxy[pointer].data then
  217.             ind = 0;
  218.             return;
  219.         end;
  220.         return ind - 1, proxy[pointer].data[ind];
  221.     end;
  222.    
  223.     -- Others
  224.     pointer_metatable.__len = len;
  225.     pointer_metatable.__tostring = tostr_tup;
  226.    
  227.     return pointer;
  228. end;
  229.  
  230. -- Methods
  231. setmetatable(tup, { __newindex = function(self, ind, func) rawset(self, ind,
  232.     function(self1, ...) if (not proxy[self1]) then error(self == module and ("bad argument #1 (tuple expected, got " .. typeof(self) .. ')')
  233.     or ("Expected ':' not '.' calling member function " .. ind), 2); end; return func(self1, ...) end); end; });
  234.  
  235. function tup:unpack()
  236.     return unpack(proxy[self].data);
  237. end;
  238.  
  239. function tup:filter(func, self_arg)
  240.     if type(func) ~= "function" then
  241.         error("bad argument #2 (function expected, got " .. typeof(func) .. ')', 2);
  242.     end;
  243.     local ret = { };
  244.    
  245.     for _, val in ipairs(proxy[self].data) do
  246.         if self_arg and func(self, val) or func(val) then
  247.             table.insert(ret, val);
  248.         end;
  249.     end;
  250.    
  251.     return tup.fromList(ret);
  252. end;
  253.  
  254. function tup:index(val)
  255.     return table.find(proxy[self].data, val);
  256. end;
  257.  
  258. function tup:count(val, self_arg)
  259.     if self_arg ~= nil then
  260.         if type(val) ~= "function" then
  261.             error("bad argument #2 (function expected, got " .. typeof(val) .. ')', 2);
  262.         end;
  263.     end;
  264.     local ret = 0;
  265.    
  266.     for _, val1 in ipairs(proxy[self].data) do
  267.         if self_arg ~= nil then
  268.             if self_arg and val(self, val1) or val(val1) then
  269.                 ret = ret + 1; 
  270.             end;
  271.         elseif val == val1 then
  272.             ret = ret + 1;
  273.         end;
  274.     end;
  275.    
  276.     return ret;
  277. end;
  278.  
  279. function tup:pop(ind)
  280.     if type(ind) ~= "number" then
  281.         error("bad argument #2 (integer expected, got " .. typeof(ind) .. ')', 2);
  282.     elseif ind % 1 ~= 0 then
  283.         error("bad argument #2 (integer expected, got float)", 2);
  284.     end;
  285.     local ret = { };
  286.    
  287.     ind = ind or -1;
  288.     if ind < 0 then
  289.         ind = #self + ind;
  290.     end;
  291.     for k, v in ipairs(proxy[self].data) do
  292.         if k - 1 ~= ind then
  293.             table.insert(ret, v);
  294.         end;
  295.     end;
  296.    
  297.     return tup.fromList(ret);
  298. end;
  299.  
  300. --[=[ Lists ]=]--
  301.  
  302. -- + and ..
  303. local function concat_list(left, right)
  304.     if not (proxy[left] and proxy[right]) then
  305.         error("attempt to concatenate " .. typeof(right) .. " with " .. typeof(right), 2);
  306.     end;
  307.     local ret = { };
  308.     for _, v in ipairs(proxy[left].data) do
  309.         table.insert(ret, v);
  310.     end;
  311.     for _, v in ipairs(proxy[right].data) do
  312.         table.insert(ret, v);
  313.     end;
  314.     return list.new(ret);
  315. end;
  316.  
  317. -- *
  318. local function mul_list(left, right)
  319.     if proxy[left] and proxy[right] then
  320.         error("attempt to perform arithmetic (mul) on userdata", 2);
  321.     elseif type(left) ~= "number" and type(right) ~= "number" then
  322.         error("attempt to perform arithmetic (mul) on " .. typeof(left) .. " and " .. typeof(right), 2);
  323.     end;
  324.     local _list = list;
  325.     local rep, list;
  326.     if type(right) == "number" then
  327.         rep = right;
  328.         list = proxy[left].data;
  329.     else
  330.         rep = left;
  331.         list = proxy[right].data;
  332.     end;
  333.     local ret = { };
  334.     for _ = 1, rep do
  335.         for _, v in ipairs(list) do
  336.             table.insert(ret, v);
  337.         end;
  338.     end;
  339.     return _list.new(ret);
  340. end;
  341.  
  342. -- Other
  343. function tostr_list(self)
  344.     return "list: " .. addr[self];
  345. end;
  346.  
  347. -- Index
  348. local function getattr_list(self, ind)
  349.     if type(ind) == "number" then
  350.         if ind >= #self or ind < -#self then
  351.             error("list index out of range", 2);
  352.         end;
  353.         if ind < 0 then
  354.             return proxy[self].data[(#self + ind) + 1];
  355.         end;
  356.         return proxy[self].data[ind + 1];
  357.     elseif type(ind) ~= "string" then
  358.         return;
  359.     end;
  360.     return (ind ~= "new" and ind ~= "pack") and list[ind];
  361.    
  362. end;
  363.  
  364. local function setattr_list(self, ind, val)
  365.     if type(ind) ~= "number" then
  366.         if type(ind) ~= "string" then
  367.             error("attempt to index userdata with '" .. typeof(ind) .. "'", 2);
  368.         end;
  369.         error("attempt to index userdata with '" .. ind .. "'", 2);
  370.     end;
  371.     if ind >= #self or ind < -#self then
  372.         error("list index out of range", 2);
  373.     end;
  374.     if ind < 0 then
  375.         proxy[self].data[(#self + ind) + 1] = val;
  376.     end;
  377.     proxy[self].data[ind + 1] = val;
  378. end;
  379.  
  380. -- Constructor
  381. function list.new(arr)
  382.     if type(arr) ~= "table" and not proxy[arr] then
  383.         error("bad argument #1 (table expected, got" .. typeof(list) .. ")", 2);
  384.     end;
  385.     local arr_copy = { };
  386.     if type(list) == "table" then
  387.         local i = 1;
  388.         for ind, val in next, arr do
  389.             -- Check
  390.             if ind ~= i then
  391.                 error("bad argument #1 (array expected, got dictionary)", 2);
  392.             end;
  393.            
  394.             arr_copy[ind] = val;
  395.             i = i + 1;
  396.         end;
  397.     elseif proxy[arr].list then
  398.         return arr;
  399.     else
  400.         for _, val in arr do
  401.             table.insert(arr_copy, val);
  402.         end;
  403.     end;
  404.    
  405.     local pointer = newproxy(true);
  406.     proxy[pointer] = { list = true, data = arr_copy };
  407.     addr[pointer] = tostring(pointer):sub(11);
  408.    
  409.     local pointer_metatable = getmetatable(pointer);
  410.     pointer_metatable.__metatable = "The metatable is locked";
  411.     pointer_metatable.__index = getattr_list;
  412.     pointer_metatable.__newindex = setattr_list;
  413.    
  414.     -- Operators
  415.     pointer_metatable.__le = le;
  416.     pointer_metatable.__lt = lt;
  417.     pointer_metatable.__eq = eq;
  418.     pointer_metatable.__add = concat_list;
  419.     pointer_metatable.__concat = concat_list;
  420.     pointer_metatable.__mul = mul_list;
  421.    
  422.     -- Iterator
  423.     local ind = 0;
  424.     pointer_metatable.__call = function()
  425.         ind = ind + 1;
  426.         if ind > #proxy[pointer].data then
  427.             ind = 0;
  428.             return;
  429.         end;
  430.         return ind - 1, proxy[pointer].data[ind];
  431.     end;
  432.    
  433.     -- Other
  434.     pointer_metatable.__len = len;
  435.     pointer_metatable.__tostring = tostr_list;
  436.    
  437.     return pointer;
  438. end;
  439.  
  440. function list.pack(...)
  441.     return list.new { ... };
  442. end;
  443.  
  444. -- Methods
  445. setmetatable(list, { __newindex = function(self, ind, func) rawset(self, ind,
  446.     function(self1, ...) if (not proxy[self1]) then error(self == module and ("bad argument #1 (list expected, got " .. typeof(self) .. ')')
  447.     or ("Expected ':' not '.' calling member function " .. ind), 2); end; return func(self1, ...) end); end; });
  448.  
  449. function list:append(value)
  450.     table.insert(proxy[self].data, value);
  451.     return self;
  452. end;
  453.  
  454. function list:insert(ind, value)
  455.     if type(ind) ~= "number" then
  456.         error("bad argument #1 (integer expected, got" .. typeof(ind) .. ")", 2);
  457.     elseif ind % 1 ~= 0 then
  458.         error("bad argument #1 (integer expected, got float)", 2);
  459.     end;
  460.     if ind < 0 then
  461.         table.insert(proxy[self].data, math.max((#self + ind) + 1, 1), value);
  462.     else
  463.         table.insert(proxy[self].data, math.min(ind + 1, #self), value);
  464.     end;
  465. end;
  466.  
  467. function list:pop(ind)
  468.     if type(ind) ~= "number" then
  469.         error("bad argument #1 (integer expected, got" .. typeof(ind) .. ")", 2);
  470.     elseif ind % 1 ~= 0 then
  471.         error("bad argument #1 (integer expected, got float)", 2);
  472.     end;
  473.     if ind < 0 then
  474.         return table.remove(proxy[self].data, math.min((#self + ind) + 1, 1));
  475.     end;
  476.     return table.remove(proxy[self].data, math.max(ind + 1, #self));
  477. end;
  478.  
  479. function list:unpack()
  480.     return unpack(proxy[self].data);
  481. end;
  482.  
  483. function list:filter(func, self_arg)
  484.     if type(func) ~= "function" then
  485.         error("bad argument #2 (function expected, got " .. typeof(func) .. ')', 2);
  486.     end;
  487.     local ret = { };
  488.    
  489.     for _, val in ipairs(proxy[self].data) do
  490.         if self_arg and func(self, val) or func(val) then
  491.             table.insert(ret, val);
  492.         end;
  493.     end;
  494.    
  495.     return list.new(ret);
  496. end;
  497.  
  498. function list:index(val)
  499.     return table.find(proxy[self].data, val);
  500. end;
  501.  
  502. function list:count(val, self_arg)
  503.     if self_arg ~= nil then
  504.         if type(val) ~= "function" then
  505.             error("bad argument #2 (function expected, got " .. typeof(val) .. ')', 2);
  506.         end;
  507.     end;
  508.     local ret = 0;
  509.    
  510.     for _, val1 in ipairs(proxy[self].data) do
  511.         if self_arg ~= nil then
  512.             if self_arg and val(self, val1) or val(val1) then
  513.                 ret = ret + 1; 
  514.             end;
  515.         elseif val == val1 then
  516.             ret = ret + 1;
  517.         end;
  518.     end;
  519.    
  520.     return ret;
  521. end;
  522.  
  523. function list:sort(comp)
  524.     return list.new(table.sort(proxy[self].data, comp));
  525. end;
  526.  
  527. function list:copy()
  528.     return list.new(table.move(proxy[self].data, 1, #self, 1, table.create(#self)));
  529. end;
  530.  
  531. function list:reverse()
  532.     if #self > 1 then
  533.         for i = 0, math.floor(#self / 2) - 1 do
  534.             self[i], self[-(i + 1)] = self[-(i + 1)], self[i];
  535.         end;
  536.     end;
  537.     return self;
  538. end;
  539.  
  540. function list:clear()
  541.     for _ = 1, #self do
  542.         table.remove(proxy[self].data);
  543.     end;
  544.     return self;
  545. end;
  546.  
  547. function list:join(sep)
  548.     return table.concat(proxy[self].data, sep or ',');
  549. end;
  550.  
  551. function list:splice(i, c, ...)
  552.     if type(i) ~= "number" then
  553.         error("bad argument #1 (integer expected, got" .. typeof(i) .. ")", 2);
  554.     elseif i % 1 ~= 0 then
  555.         error("bad argument #1 (integer expected, got float)", 2);
  556.     end;
  557.     if type(c) ~= "number" then
  558.         error("bad argument #2 (integer expected, got" .. typeof(c) .. ")", 2);
  559.     elseif c % 1 ~= 0 then
  560.         error("bad argument #2 (integer expected, got float)", 2);
  561.     end;
  562.     local args = { ... };
  563.     if i < 0 then
  564.         i = math.max((#self + i) + 1, 1);
  565.     else
  566.         i = math.min(i + 1, #self);
  567.     end;
  568.     for _ = 1, c do
  569.         table.remove(proxy[self].data, c);
  570.     end;
  571.     for ind = #args, 1, -1 do
  572.         table.insert(proxy[self].data, i, args[ind]);
  573.     end;
  574.     return self;
  575. end;
  576.  
  577. function list:formatenglish()
  578.     if #self == 1 then
  579.         return self[0];
  580.     end;
  581.     return table.concat(proxy[self].data, ', ', 1, -2) .. ' and ' .. self[-1];
  582. end;
  583.  
  584. return module;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement