Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- Advanced Lua Library v1.1 by ECS
- This library extends a lot of default Lua methods
- and adds some really cool features that haven't been
- implemented yet, such as fastest table serialization,
- table binary searching, string wrapping, numbers rounding, etc.
- ]]
- local filesystem = require("filesystem")
- local unicode = require("unicode")
- local bit32 = require("bit32")
- -------------------------------------------------- System extensions --------------------------------------------------
- function _G.getCurrentScript()
- local info
- for runLevel = 0, math.huge do
- info = debug.getinfo(runLevel)
- if info then
- if info.what == "main" then
- return info.source:sub(2, -1)
- end
- else
- error("Failed to get debug info for runlevel " .. runLevel)
- end
- end
- end
- function enum(...)
- local args, enums = {...}, {}
- for i = 1, #args do
- if type(args[i]) ~= "string" then error("Function argument " .. i .. " have non-string type: " .. type(args[i])) end
- enums[args[i]] = i
- end
- return enums
- end
- function swap(a, b)
- return b, a
- end
- -------------------------------------------------- Bit32 extensions --------------------------------------------------
- -- Merge two numbers into one (0xAABB, 0xCCDD -> 0xAABBCCDD)
- function bit32.merge(number2, number1)
- local cutter = math.ceil(math.log(number1 + 1, 256)) * 8
- while number2 > 0 do
- number1, number2, cutter = bit32.bor(bit32.lshift(bit32.band(number2, 0xFF), cutter), number1), bit32.rshift(number2, 8), cutter + 8
- end
- return number1
- end
- -- Split number to it's own bytes (0xAABBCC -> {0xAA, 0xBB, 0xCC})
- function bit32.numberToByteArray(number)
- local byteArray = {}
- repeat
- table.insert(byteArray, 1, bit32.band(number, 0xFF))
- number = bit32.rshift(number, 8)
- until number <= 0
- return byteArray
- end
- -- Split nubmer to it's own bytes with specified count of bytes (0xAABB, 5 -> {0x00, 0x00, 0x00, 0xAA, 0xBB})
- function bit32.numberToFixedSizeByteArray(number, size)
- local byteArray, counter = {}, 0
- repeat
- table.insert(byteArray, 1, bit32.band(number, 0xFF))
- number = bit32.rshift(number, 8)
- counter = counter + 1
- until number <= 0
- for i = 1, size - counter do
- table.insert(byteArray, 1, 0x0)
- end
- return byteArray
- end
- -- Create number from it's own bytes ({0xAA, 0xBB, 0xCC} -> 0xAABBCC)
- function bit32.byteArrayToNumber(byteArray)
- local result = byteArray[1]
- for i = 2, #byteArray do
- result = bit32.bor(bit32.lshift(result, 8), byteArray[i])
- end
- return result
- end
- -- Create byte from it's bits ({1, 0, 1, 0, 1, 0, 1, 1} -> 0xAB)
- function bit32.bitArrayToByte(bitArray)
- local number = 0
- for i = 1, #bitArray do
- number = bit32.bor(bitArray[i], bit32.lshift(number, 1))
- end
- return number
- end
- -------------------------------------------------- Math extensions --------------------------------------------------
- function math.round(num)
- if num >= 0 then
- return math.floor(num + 0.5)
- else
- return math.ceil(num - 0.5)
- end
- end
- function math.roundToDecimalPlaces(num, decimalPlaces)
- local mult = 10 ^ (decimalPlaces or 0)
- return math.round(num * mult) / mult
- end
- function math.getDigitCount(num)
- return num == 0 and 1 or math.ceil(math.log(num + 1, 10))
- end
- function math.doubleToString(num, digitCount)
- return string.format("%." .. (digitCount or 1) .. "f", num)
- end
- function math.shortenNumber(number, digitCount)
- local shortcuts = {
- "K",
- "M",
- "B",
- "T"
- }
- local index = math.floor(math.log(number, 1000))
- if number < 1000 then
- return number
- elseif index > #shortcuts then
- index = #shortcuts
- end
- return math.roundToDecimalPlaces(number / 1000 ^ index, digitCount) .. shortcuts[index]
- end
- ---------------------------------------------- Filesystem extensions ------------------------------------------------------------------------
- function filesystem.path(path)
- return path:match("^(.+%/).") or ""
- end
- function filesystem.name(path)
- return path:match("%/?([^%/]+)%/?$")
- end
- function filesystem.extension(path, lower)
- local extension = path:match("[^%/]+(%.[^%/]+)%/?$")
- return (lower and extension) and (unicode.lower(extension)) or extension
- end
- function filesystem.hideExtension(path)
- return path:match("(.+)%..+") or path
- end
- function filesystem.isFileHidden(path)
- if path:match("^%..+$") then
- return true
- end
- return false
- end
- function filesystem.sortedList(path, sortingMethod, showHiddenFiles, filenameMatcher, filenameMatcherCaseSensitive)
- if not filesystem.exists(path) then
- error("Failed to get file list: directory \"" .. tostring(path) .. "\" doesn't exists")
- end
- if not filesystem.isDirectory(path) then
- error("Failed to get file list: path \"" .. tostring(path) .. "\" is not a directory")
- end
- local fileList, sortedFileList = {}, {}
- for file in filesystem.list(path) do
- if not filenameMatcher or string.unicodeFind(filenameMatcherCaseSensitive and file or unicode.lower(file), filenameMatcherCaseSensitive and filenameMatcher or unicode.lower(filenameMatcher)) then
- table.insert(fileList, file)
- end
- end
- if #fileList > 0 then
- if sortingMethod == "type" then
- local extension
- for i = 1, #fileList do
- extension = filesystem.extension(fileList[i]) or "Script"
- if filesystem.isDirectory(path .. fileList[i]) and extension ~= ".app" then
- extension = ".01_Folder"
- end
- fileList[i] = {fileList[i], extension}
- end
- table.sort(fileList, function(a, b) return unicode.lower(a[2]) < unicode.lower(b[2]) end)
- local currentExtensionList, currentExtension = {}, fileList[1][2]
- for i = 1, #fileList do
- if currentExtension == fileList[i][2] then
- table.insert(currentExtensionList, fileList[i][1])
- else
- table.sort(currentExtensionList, function(a, b) return unicode.lower(a) < unicode.lower(b) end)
- for j = 1, #currentExtensionList do
- table.insert(sortedFileList, currentExtensionList[j])
- end
- currentExtensionList, currentExtension = {fileList[i][1]}, fileList[i][2]
- end
- end
- table.sort(currentExtensionList, function(a, b) return unicode.lower(a) < unicode.lower(b) end)
- for j = 1, #currentExtensionList do
- table.insert(sortedFileList, currentExtensionList[j])
- end
- elseif sortingMethod == "name" then
- sortedFileList = fileList
- table.sort(sortedFileList, function(a, b) return unicode.lower(a) < unicode.lower(b) end)
- elseif sortingMethod == "date" then
- for i = 1, #fileList do
- fileList[i] = {fileList[i], filesystem.lastModified(path .. fileList[i])}
- end
- table.sort(fileList, function(a, b) return unicode.lower(a[2]) > unicode.lower(b[2]) end)
- for i = 1, #fileList do
- table.insert(sortedFileList, fileList[i][1])
- end
- else
- error("Unknown sorting method: " .. tostring(sortingMethod))
- end
- local i = 1
- while i <= #sortedFileList do
- if not showHiddenFiles and filesystem.isFileHidden(sortedFileList[i]) then
- table.remove(sortedFileList, i)
- else
- i = i + 1
- end
- end
- end
- return sortedFileList
- end
- function filesystem.directorySize(path)
- local size = 0
- for file in filesystem.list(path) do
- if filesystem.isDirectory(path .. file) then
- size = size + filesystem.directorySize(path .. file)
- else
- size = size + filesystem.size(path .. file)
- end
- end
- return size
- end
- -------------------------------------------------- Table extensions --------------------------------------------------
- local function doSerialize(array, prettyLook, indentationSymbol, indentationSymbolAdder, equalsSymbol, currentRecusrionStack, recursionStackLimit)
- local text, indentationSymbolNext, keyType, valueType, stringValue = {"{"}, table.concat({indentationSymbol, indentationSymbolAdder})
- if prettyLook then
- table.insert(text, "\n")
- end
- for key, value in pairs(array) do
- keyType, valueType, stringValue = type(key), type(value), tostring(value)
- if prettyLook then
- table.insert(text, indentationSymbolNext)
- end
- if keyType == "number" then
- table.insert(text, "[")
- table.insert(text, key)
- table.insert(text, "]")
- elseif keyType == "string" then
- if prettyLook and key:match("^%a") and key:match("^%w+$") then
- table.insert(text, key)
- else
- table.insert(text, "[\"")
- table.insert(text, key)
- table.insert(text, "\"]")
- end
- end
- table.insert(text, equalsSymbol)
- if valueType == "number" or valueType == "boolean" or valueType == "nil" then
- table.insert(text, stringValue)
- elseif valueType == "string" or valueType == "function" then
- table.insert(text, "\"")
- table.insert(text, stringValue)
- table.insert(text, "\"")
- elseif valueType == "table" then
- if currentRecusrionStack < recursionStackLimit then
- table.insert(
- text,
- table.concat(
- doSerialize(
- value,
- prettyLook,
- indentationSymbolNext,
- indentationSymbolAdder,
- equalsSymbol,
- currentRecusrionStack + 1,
- recursionStackLimit
- )
- )
- )
- else
- table.insert(text, "\"…\"")
- end
- end
- table.insert(text, ",")
- if prettyLook then
- table.insert(text, "\n")
- end
- end
- -- Удаляем запятую
- if prettyLook then
- if #text > 2 then
- table.remove(text, #text - 1)
- end
- -- Вставляем заодно уж символ индентации, благо чек на притти лук идет
- table.insert(text, indentationSymbol)
- else
- if #text > 1 then
- table.remove(text, #text)
- end
- end
- table.insert(text, "}")
- return text
- end
- function table.serialize(array, prettyLook, indentationWidth, indentUsingTabs, recursionStackLimit)
- checkArg(1, array, "table")
- return table.concat(
- doSerialize(
- array,
- prettyLook,
- "",
- string.rep(indentUsingTabs and " " or " ", indentationWidth or 2),
- prettyLook and " = " or "=",
- 1,
- recursionStackLimit or math.huge
- )
- )
- end
- function table.unserialize(serializedString)
- checkArg(1, serializedString, "string")
- local success, result = pcall(load("return " .. serializedString))
- if success then
- return result
- else
- return nil, result
- end
- end
- table.toString = table.serialize
- table.fromString = table.unserialize
- function table.toFile(path, array, prettyLook, indentationWidth, indentUsingTabs, recursionStackLimit, appendToFile)
- checkArg(1, path, "string")
- checkArg(2, array, "table")
- filesystem.makeDirectory(filesystem.path(path) or "")
- local file, reason = io.open(path, appendToFile and "a" or "w")
- if file then
- file:write(table.serialize(array, prettyLook, indentationWidth, indentUsingTabs, recursionStackLimit))
- file:close()
- else
- error("Failed to open file for writing: " .. tostring(reason))
- end
- end
- function table.fromFile(path)
- checkArg(1, path, "string")
- if filesystem.exists(path) then
- if filesystem.isDirectory(path) then
- error("\"" .. path .. "\" is a directory")
- else
- local file = io.open(path, "r")
- local data = table.unserialize(file:read("*a"))
- file:close()
- return data
- end
- else
- error("\"" .. path .. "\" doesn't exists")
- end
- end
- local function doTableCopy(source, destination)
- for key, value in pairs(source) do
- if type(value) == "table" then
- destination[key] = {}
- doTableCopy(source[key], destination[key])
- else
- destination[key] = value
- end
- end
- end
- function table.copy(tableToCopy)
- local tableThatCopied = {}
- doTableCopy(tableToCopy, tableThatCopied)
- return tableThatCopied
- end
- function table.binarySearch(t, requestedValue)
- local function recursiveSearch(startIndex, endIndex)
- local difference = endIndex - startIndex
- local centerIndex = math.floor(difference / 2 + startIndex)
- if difference > 1 then
- if requestedValue >= t[centerIndex] then
- return recursiveSearch(centerIndex, endIndex)
- else
- return recursiveSearch(startIndex, centerIndex)
- end
- else
- if math.abs(requestedValue - t[startIndex]) > math.abs(t[endIndex] - requestedValue) then
- return t[endIndex]
- else
- return t[startIndex]
- end
- end
- end
- return recursiveSearch(1, #t)
- end
- function table.size(t)
- local size = 0
- for key in pairs(t) do size = size + 1 end
- return size
- end
- function table.contains(t, object)
- for _, value in pairs(t) do
- if value == object then
- return true
- end
- end
- return false
- end
- function table.indexOf(t, object)
- for i = 1, #t do
- if t[i] == object then
- return i
- end
- end
- end
- function table.sortAlphabetically(t)
- table.sort(t, function(a, b) return a < b end)
- end
- -------------------------------------------------- String extensions --------------------------------------------------
- function string.brailleChar(a, b, c, d, e, f, g, h)
- return unicode.char(10240 + 128*h + 64*g + 32*f + 16*d + 8*b + 4*e + 2*c + a)
- end
- function string.readUnicodeChar(file)
- local byteArray = {string.byte(file:read(1))}
- local nullBitPosition = 0
- for i = 1, 7 do
- if bit32.band(bit32.rshift(byteArray[1], 8 - i), 0x1) == 0x0 then
- nullBitPosition = i
- break
- end
- end
- for i = 1, nullBitPosition - 2 do
- table.insert(byteArray, string.byte(file:read(1)))
- end
- return string.char(table.unpack(byteArray))
- end
- function string.canonicalPath(str)
- return string.gsub("/" .. str, "%/+", "/")
- end
- function string.optimize(str, indentationWidth)
- str = string.gsub(str, "\r\n", "\n")
- str = string.gsub(str, " ", string.rep(" ", indentationWidth or 2))
- return str
- end
- function string.optimizeForURLRequests(code)
- if code then
- code = string.gsub(code, "([^%w ])", function (c)
- return string.format("%%%02X", string.byte(c))
- end)
- code = string.gsub(code, " ", "+")
- end
- return code
- end
- function string.unicodeFind(str, pattern, init, plain)
- if init then
- if init < 0 then
- init = -#unicode.sub(str,init)
- elseif init > 0 then
- init = #unicode.sub(str, 1, init - 1) + 1
- end
- end
- a, b = string.find(str, pattern, init, plain)
- if a then
- local ap, bp = str:sub(1, a - 1), str:sub(a,b)
- a = unicode.len(ap) + 1
- b = a + unicode.len(bp) - 1
- return a, b
- else
- return a
- end
- end
- function string.limit(s, limit, mode, noDots)
- local length = unicode.len(s)
- if length <= limit then return s end
- if mode == "left" then
- if noDots then
- return unicode.sub(s, length - limit + 1, -1)
- else
- return "…" .. unicode.sub(s, length - limit + 2, -1)
- end
- elseif mode == "center" then
- local integer, fractional = math.modf(limit / 2)
- if fractional == 0 then
- return unicode.sub(s, 1, integer) .. "…" .. unicode.sub(s, -integer + 1, -1)
- else
- return unicode.sub(s, 1, integer) .. "…" .. unicode.sub(s, -integer, -1)
- end
- else
- if noDots then
- return unicode.sub(s, 1, limit)
- else
- return unicode.sub(s, 1, limit - 1) .. "…"
- end
- end
- end
- function string.wrap(data, limit)
- if type(data) == "string" then data = {data} end
- local wrappedLines, result, preResult, preResultLength = {}
- for i = 1, #data do
- for subLine in data[i]:gmatch("[^\n]+") do
- result = ""
- for word in subLine:gmatch("[^%s]+") do
- preResult = result .. word
- preResultLength = unicode.len(preResult)
- if preResultLength > limit then
- if unicode.len(word) > limit then
- table.insert(wrappedLines, unicode.sub(preResult, 1, limit))
- for i = limit + 1, preResultLength, limit do
- table.insert(wrappedLines, unicode.sub(preResult, i, i + limit - 1))
- end
- result = wrappedLines[#wrappedLines] .. " "
- wrappedLines[#wrappedLines] = nil
- else
- result = result:gsub("%s+$", "")
- table.insert(wrappedLines, result)
- result = word .. " "
- end
- else
- result = preResult .. " "
- end
- end
- result = result:gsub("%s+$", "")
- table.insert(wrappedLines, result)
- end
- end
- return wrappedLines
- end
- -------------------------------------------------- Playground --------------------------------------------------
- -- print(table.toString(require("MineOSCore").OSSettings, true, 2, true, 2))
- -- local t = {
- -- abc = 123,
- -- def = {
- -- cyka = "pidor",
- -- vagina = {
- -- chlen = 555,
- -- devil = 666,
- -- god = 777,
- -- serost = {
- -- tripleTable = "aefaef",
- -- aaa = "bbb",
- -- ccc = 123,
- -- }
- -- }
- -- },
- -- ghi = "HEHE",
- -- emptyTable = {},
- -- }
- -- print(table.toString(t, true))
- ------------------------------------------------------------------------------------------------------------------
- return {loaded = true}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement