--!strict --!optimize 2 local Array = {} Array.__index = Array type constructor = { __inner: {T} } export type Array = setmetatable, typeof(Array)> type FnCall = (T, number, Array) -> R function Array.new(from: {T}?): Array return setmetatable({ __inner = from or {} }, Array) end function Array:into_table(): {T} return self.__inner end function Array:len(): number return #self.__inner end function Array:pop(): T? return table.remove(self.__inner, self:len()) end function Array:concat(sep: string?, i: number?, j: number?): string return table.concat(self.__inner, sep, i, j) end function Array:clone(): Array return Array.new(table.clone(self.__inner)) end function Array:is_empty(): boolean return self:len() == 0 end function Array:type_id(): string return type(self.__inner[1]) end function Array:get(index: I): T? return self.__inner[index] end function Array:get_base0(index: number): T? return self:get(index + 1) end function Array:join(sep: T): Array return self end function Array:append(other: Array): Array return self:append_table(other:into_table()) end function Array:append_table(t: {T}): Array table.move(t, 1, #t, self:len() + 1, self.__inner) return self end function Array:slice(start: number, endj: number?): Array local slice_t: {T} = {} table.move(self.__inner, start, endj or self:len(), 1, slice_t) return Array.new(slice_t) end function Array:push(...: T): () for _, val: T in {...} do table.insert(self.__inner, val) end end function Array:foreach(f: FnCall): Array for ind: number, val: T in self.__inner do f(val, ind, self) end return self end function Array:map(f: FnCall): Array local t_map: {M} = {} for ind: number, val: T in self.__inner do table.insert(t_map, f(val, ind, self)) end return Array.new(t_map) end function Array:filter(f: FnCall): Array local t_filter: {T} = {} for ind: number, val: T in self.__inner do if f(val, ind, self) then table.insert(t_filter, val) end end return Array.new(t_filter) end function Array:reverse(): Array local t_rev: {T} = {} local t_len = self:len() for i = 1, t_len do t_rev[i] = self.__inner[t_len - i + 1] end self.__inner = t_rev return self end function Array:sort(): Array table.sort(self.__inner, function(a: T, z: T) if type(a) == "number" then return a < z end return tostring(a) < tostring(z) end) return self end function Array:reduce(f: (number, number) -> number): number local init_v = self.__inner[1] if type(init_v) == "string" then return tonumber("nan") :: number end for _, val: number in self.__inner do init_v = f(init_v, val) end return init_v end local function binary_search_by(self: Array, x: number, eq: (number, number) -> number): number? local size = self:len() if size == 0 then return nil end local base = 1 while base <= size do local mid = eq(base, size) if self.__inner[mid] == x then return mid elseif self.__inner[mid] < x then base = mid + 1 else size = mid - 1 end end return nil end function Array:binary_search(x: number): number? if self:type_id() ~= "number" then return nil end return binary_search_by(self, x, function(base, size) return bit32.rshift(base + size, 1) end) end function Array:binary_search_64(x: number): number? if self:type_id() ~= "number" then return nil end return binary_search_by(self, x, function(base, size) return math.floor((base + size) / 2) end) end function Array:tostring(): string return self:map(function(val: T, index: number) local formatted_val = if type(val) == "string" then `"{val}"` else tostring(val) local formatted_end = if index ~= self:len() then ", " else "" return index .. ": " .. formatted_val .. formatted_end end):concat() end return Array