| 1 | -- Prosody IM |
| 2 | -- Copyright (C) 2008-2010 Matthew Wild |
| 3 | -- Copyright (C) 2008-2010 Waqas Hussain |
| 4 | -- |
| 5 | -- This project is MIT/X11 licensed. Please see the |
| 6 | -- COPYING file in the source package for more information. |
| 7 | -- |
| 8 | |
| 9 | local t_insert, t_sort, t_remove, t_concat |
| 10 | = table.insert, table.sort, table.remove, table.concat; |
| 11 | |
| 12 | local array = {}; |
| 13 | local array_base = {}; |
| 14 | local array_methods = {}; |
| 15 | local array_mt = { __index = array_methods, __tostring = function (array) return array:concat(", "); end }; |
| 16 | |
| 17 | local function new_array(_, t) |
| 18 | return setmetatable(t or {}, array_mt); |
| 19 | end |
| 20 | |
| 21 | function array_mt.__add(a1, a2) |
| 22 | local res = new_array(); |
| 23 | return res:append(a1):append(a2); |
| 24 | end |
| 25 | |
| 26 | setmetatable(array, { __call = new_array }); |
| 27 | |
| 28 | function array_base.map(outa, ina, func) |
| 29 | for k,v in ipairs(ina) do |
| 30 | outa[k] = func(v); |
| 31 | end |
| 32 | return outa; |
| 33 | end |
| 34 | |
| 35 | function array_base.filter(outa, ina, func) |
| 36 | local inplace, start_length = ina == outa, #ina; |
| 37 | local write = 1; |
| 38 | for read=1,start_length do |
| 39 | local v = ina[read]; |
| 40 | if func(v) then |
| 41 | outa[write] = v; |
| 42 | write = write + 1; |
| 43 | end |
| 44 | end |
| 45 | |
| 46 | if inplace and write <= start_length then |
| 47 | for i=write,start_length do |
| 48 | outa[i] = nil; |
| 49 | end |
| 50 | end |
| 51 | |
| 52 | return outa; |
| 53 | end |
| 54 | |
| 55 | function array_base.sort(outa, ina, ...) |
| 56 | if ina ~= outa then |
| 57 | outa:append(ina); |
| 58 | end |
| 59 | t_sort(outa, ...); |
| 60 | return outa; |
| 61 | end |
| 62 | |
| 63 | --- These methods only mutate |
| 64 | function array_methods:random() |
| 65 | return self[math.random(1,#self)]; |
| 66 | end |
| 67 | |
| 68 | function array_methods:shuffle(outa, ina) |
| 69 | local len = #self; |
| 70 | for i=1,#self do |
| 71 | local r = math.random(i,len); |
| 72 | self[i], self[r] = self[r], self[i]; |
| 73 | end |
| 74 | return self; |
| 75 | end |
| 76 | |
| 77 | function array_methods:reverse() |
| 78 | local len = #self-1; |
| 79 | for i=len,1,-1 do |
| 80 | self:push(self[i]); |
| 81 | self:pop(i); |
| 82 | end |
| 83 | return self; |
| 84 | end |
| 85 | |
| 86 | function array_methods:append(array) |
| 87 | local len,len2 = #self, #array; |
| 88 | for i=1,len2 do |
| 89 | self[len+i] = array[i]; |
| 90 | end |
| 91 | return self; |
| 92 | end |
| 93 | |
| 94 | array_methods.push = table.insert; |
| 95 | array_methods.pop = table.remove; |
| 96 | array_methods.concat = table.concat; |
| 97 | array_methods.length = function (t) return #t; end |
| 98 | |
| 99 | --- These methods always create a new array |
| 100 | function array.collect(f, s, var) |
| 101 | local t, var = {}; |
| 102 | while true do |
| 103 | var = f(s, var); |
| 104 | if var == nil then break; end |
| 105 | table.insert(t, var); |
| 106 | end |
| 107 | return setmetatable(t, array_mt); |
| 108 | end |
| 109 | |
| 110 | --- |
| 111 | |
| 112 | -- Setup methods from array_base |
| 113 | for method, f in pairs(array_base) do |
| 114 | local base_method = f; |
| 115 | -- Setup global array method which makes new array |
| 116 | array[method] = function (old_a, ...) |
| 117 | local a = new_array(); |
| 118 | return base_method(a, old_a, ...); |
| 119 | end |
| 120 | -- Setup per-array (mutating) method |
| 121 | array_methods[method] = function (self, ...) |
| 122 | return base_method(self, self, ...); |
| 123 | end |
| 124 | end |
| 125 | |
| 126 | _G.array = array; |
| 127 | module("array"); |
| 128 | |
| 129 | return array; |