diff options
author | chai <chaifix@163.com> | 2021-11-15 13:53:59 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2021-11-15 13:53:59 +0800 |
commit | 942a030afd348ab2e02eac8054b43e3c3a72ea48 (patch) | |
tree | a13459f39a3d2f1b533fbd1b5ab523d7a621f673 /Data/BuiltIn/Libraries/lua-addons/addons/libs/lists.lua | |
parent | e307051a56a54c27f10438fd2025edf61d0dfeed (diff) |
*rename
Diffstat (limited to 'Data/BuiltIn/Libraries/lua-addons/addons/libs/lists.lua')
-rw-r--r-- | Data/BuiltIn/Libraries/lua-addons/addons/libs/lists.lua | 455 |
1 files changed, 455 insertions, 0 deletions
diff --git a/Data/BuiltIn/Libraries/lua-addons/addons/libs/lists.lua b/Data/BuiltIn/Libraries/lua-addons/addons/libs/lists.lua new file mode 100644 index 0000000..2ea86e1 --- /dev/null +++ b/Data/BuiltIn/Libraries/lua-addons/addons/libs/lists.lua @@ -0,0 +1,455 @@ +--[[ + A library providing advanced list support and better optimizations for list-based operations. +]] + +_libs = _libs or {} + +require('tables') + +local table = _libs.tables + +list = {} + +local list = list + +_libs.lists = list + +_raw = _raw or {} +_raw.table = _raw.table or {} + +_meta = _meta or {} +_meta.L = {} + +_meta.L.__index = function(l, k) + if type(k) == 'number' then + k = k < 0 and l.n + k + 1 or k + + return rawget(l, k) + end + + return list[k] or table[k] +end + +_meta.L.__newindex = function(l, k, v) + if type(k) == 'number' then + k = k < 0 and l.n + k + 1 or k + + if k >= 1 and k <= l.n then + rawset(l, k, v) + else + (warning or print)('Trying to assign outside of list range (%u/%u): %s':format(k, l.n, tostring(v))) + end + + else + (warning or print)('Trying to assign to non-numerical list index:', k) + + end +end +_meta.L.__class = 'List' + +function L(t) + local l + if class(t) == 'Set' then + l = L{} + + for el in pairs(t) do + l:append(el) + end + else + l = t or {} + end + + l.n = #l + return setmetatable(l, _meta.L) +end + +function list.empty(l) + return l.n == 0 +end + +function list.length(l) + return l.n +end + +function list.flat(l) + for key = 1, l.n do + if type(rawget(l, key)) == 'table' then + return false + end + end + + return true +end + +function list.equals(l1, l2) + if l1.n ~= l2.n then + return false + end + + for key = 1, l.n do + if rawget(l1, key) ~= rawget(l2, key) then + return false + end + end + + return true +end + +function list.append(l, el) + l.n = l.n + 1 + return rawset(l, l.n, el) +end + +function list.last(l, i) + return rawget(l, l.n - ((i or 1) - 1)) +end + +function list.insert(l, i, el) + l.n = l.n + 1 + table.insert(l, i, el) +end + +function list.remove(l, i) + i = i or l.n + local res = rawget(l, i) + + for key = i, l.n do + rawset(l, key, rawget(l, key + 1)) + end + + l.n = l.n - 1 + return res +end + +function list.extend(l1, l2) + local n1 = l1.n + local n2 = l2.n + for k = 1, n2 do + rawset(l1, n1 + k, rawget(l2, k)) + end + + l1.n = n1 + n2 + return l1 +end + +_meta.L.__add = function(l1, l2) + return L{}:extend(l1):extend(l2) +end + +function list.contains(l, el) + for key = 1, l.n do + if rawget(l, key) == el then + return true + end + end + + return false +end + +function list.count(l, fn) + local count = 0 + if type(fn) ~= 'function' then + for i = 1, l.n do + if rawget(l, i) == fn then + count = count + 1 + end + end + else + for i = 1, l.n do + if fn(rawget(l, i)) then + count = count + 1 + end + end + end + + return count +end + +function list.concat(l, str, from, to) + str = str or '' + from = from or 1 + to = to or l.n + local res = '' + + for key = from, to do + local val = rawget(l, key) + if val then + res = res..tostring(val) + if key < l.n then + res = res..str + end + end + end + + return res +end + +function list.with(l, attr, val) + for i = 1, l.n do + local el = rawget(l, i) + if type(el) == 'table' and rawget(el, attr) == val then + return el + end + end +end + +function list.map(l, fn) + local res = {} + + for key = 1, l.n do + res[key] = fn(rawget(l, key)) + end + + res.n = l.n + return setmetatable(res, _meta.L) +end + +function list.filter(l, fn) + local res = {} + + local key = 0 + local val + for okey = 1, l.n do + val = rawget(l, okey) + if fn(val) == true then + key = key + 1 + rawset(res, key, val) + end + end + + res.n = key + return setmetatable(res, _meta.L) +end + +function list.flatten(l, rec) + rec = true and (rec ~= false) + + local res = {} + local key = 0 + local val + local flat + local n2 + for k1 = 1, l.n do + val = rawget(l, k1) + if type(val) == 'table' then + if rec then + flat = list.flatten(val, rec) + n2 = flat.n + for k2 = 1, n2 do + rawset(res, key + k2, rawget(flat, k2)) + end + else + if class(val) == 'List' then + n2 = val.n + else + n2 = #val + end + for k2 = 1, n2 do + rawset(res, key + k2, rawget(val, k2)) + end + end + key = key + n2 + else + key = key + 1 + rawset(res, key, val) + end + end + + res.n = key + return setmetatable(res, _meta.L) +end + +function list.it(l) + local key = 0 + return function() + key = key + 1 + return rawget(l, key), key + end +end + +function list.equals(l1, l2) + if l1.n ~= l2.n then + return false + end + + for key = 1, l1.n do + if rawget(l1, key) ~= rawget(l2, key) then + return false + end + end + + return true +end + +function list.slice(l, from, to) + local n = l.n + + from = from or 1 + if from < 0 then + from = (from % n) + 1 + end + + to = to or n + if to < 0 then + to = (to % n) + 1 + end + + local res = {} + local key = 0 + for i = from, to do + key = key + 1 + rawset(res, key, rawget(l, i)) + end + + res.n = key + return setmetatable(res, _meta.L) +end + +function list.splice(l1, from, to, l2) + -- TODO + (_raw.error or error)('list.splice is not yet implemented.') +end + +function list.clear(l) + for key = 1, l.n do + rawset(l, key, nil) + end + + l.n = 0 + return l +end + +function list.copy(l, deep) + deep = deep ~= false and true + local res = {} + + for key = 1, l.n do + local value = rawget(l, key) + if deep and type(value) == 'table' then + res[key] = (not rawget(value, copy) and value.copy or table.copy)(value) + else + res[key] = value + end + end + + res.n = l.n + return setmetatable(res, _meta.L) +end + +function list.reassign(l, ln) + l:clear() + + for key = 1, ln.n do + rawset(l, key, rawget(ln, key)) + end + + l.n = ln.n + return l +end + +_raw.table.sort = _raw.table.sort or table.sort + +function list.sort(l, ...) + _raw.table.sort(l, ...) + return l +end + +function list.reverse(l) + local res = {} + + local n = l.n + local rkey = n + for key = 1, n do + rawset(res, key, rawget(l, rkey)) + rkey = rkey - 1 + end + + res.n = n + return setmetatable(res, _meta.L) +end + +function list.range(n, init) + local res = {} + + for key = 1, n do + rawset(res, key, init or key) + end + + res.n = n + return setmetatable(res, _meta.L) +end + +function list.tostring(l) + local str = '[' + + for key = 1, l.n do + if key > 1 then + str = str..', ' + end + str = str..tostring(rawget(l, key)) + end + + return str..']' +end + +_meta.L.__tostring = list.tostring + +function list.format(l, trail, subs) + if l.n == 0 then + return subs or '' + end + + trail = trail or 'and' + + local last + if trail == 'and' then + last = ' and ' + elseif trail == 'or' then + last = ' or ' + elseif trail == 'list' then + last = ', ' + elseif trail == 'csv' then + last = ',' + elseif trail == 'oxford' then + last = ', and ' + elseif trail == 'oxford or' then + last = ', or ' + else + warning('Invalid format for table.format: \''..trail..'\'.') + end + + local res = '' + for i = 1, l.n do + local add = tostring(l[i]) + if trail == 'csv' and add:match('[,"]') then + res = res .. add:gsub('"', '""'):enclose('"') + else + res = res .. add + end + + if i < l.n - 1 then + if trail == 'csv' then + res = res .. ',' + else + res = res .. ', ' + end + elseif i == l.n - 1 then + res = res .. last + end + end + + return res +end + +--[[ +Copyright © 2013-2015, Windower +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * 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. + * Neither the name of Windower nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Windower 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. +]] |