Advertisement
Guest User

Untitled

a guest
Nov 14th, 2017
83
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.51 KB | None | 0 0
  1.  
  2. --[[
  3.  
  4. Advanced Lua Library v1.1 by ECS
  5.  
  6. This library extends a lot of default Lua methods
  7. and adds some really cool features that haven't been
  8. implemented yet, such as fastest table serialization,
  9. table binary searching, string wrapping, numbers rounding, etc.
  10.  
  11. ]]
  12.  
  13. local filesystem = require("filesystem")
  14. local unicode = require("unicode")
  15. local bit32 = require("bit32")
  16.  
  17. -------------------------------------------------- System extensions --------------------------------------------------
  18.  
  19. function _G.getCurrentScript()
  20. local info
  21. for runLevel = 0, math.huge do
  22. info = debug.getinfo(runLevel)
  23. if info then
  24. if info.what == "main" then
  25. return info.source:sub(2, -1)
  26. end
  27. else
  28. error("Failed to get debug info for runlevel " .. runLevel)
  29. end
  30. end
  31. end
  32.  
  33. function enum(...)
  34. local args, enums = {...}, {}
  35. for i = 1, #args do
  36. if type(args[i]) ~= "string" then error("Function argument " .. i .. " have non-string type: " .. type(args[i])) end
  37. enums[args[i]] = i
  38. end
  39. return enums
  40. end
  41.  
  42. function swap(a, b)
  43. return b, a
  44. end
  45.  
  46. -------------------------------------------------- Bit32 extensions --------------------------------------------------
  47.  
  48. -- Merge two numbers into one (0xAABB, 0xCCDD -> 0xAABBCCDD)
  49. function bit32.merge(number2, number1)
  50. local cutter = math.ceil(math.log(number1 + 1, 256)) * 8
  51. while number2 > 0 do
  52. number1, number2, cutter = bit32.bor(bit32.lshift(bit32.band(number2, 0xFF), cutter), number1), bit32.rshift(number2, 8), cutter + 8
  53. end
  54.  
  55. return number1
  56. end
  57.  
  58. -- Split number to it's own bytes (0xAABBCC -> {0xAA, 0xBB, 0xCC})
  59. function bit32.numberToByteArray(number)
  60. local byteArray = {}
  61.  
  62. repeat
  63. table.insert(byteArray, 1, bit32.band(number, 0xFF))
  64. number = bit32.rshift(number, 8)
  65. until number <= 0
  66.  
  67. return byteArray
  68. end
  69.  
  70. -- Split nubmer to it's own bytes with specified count of bytes (0xAABB, 5 -> {0x00, 0x00, 0x00, 0xAA, 0xBB})
  71. function bit32.numberToFixedSizeByteArray(number, size)
  72. local byteArray, counter = {}, 0
  73.  
  74. repeat
  75. table.insert(byteArray, 1, bit32.band(number, 0xFF))
  76. number = bit32.rshift(number, 8)
  77. counter = counter + 1
  78. until number <= 0
  79.  
  80. for i = 1, size - counter do
  81. table.insert(byteArray, 1, 0x0)
  82. end
  83.  
  84. return byteArray
  85. end
  86.  
  87. -- Create number from it's own bytes ({0xAA, 0xBB, 0xCC} -> 0xAABBCC)
  88. function bit32.byteArrayToNumber(byteArray)
  89. local result = byteArray[1]
  90. for i = 2, #byteArray do
  91. result = bit32.bor(bit32.lshift(result, 8), byteArray[i])
  92. end
  93.  
  94. return result
  95. end
  96.  
  97. -- Create byte from it's bits ({1, 0, 1, 0, 1, 0, 1, 1} -> 0xAB)
  98. function bit32.bitArrayToByte(bitArray)
  99. local number = 0
  100. for i = 1, #bitArray do
  101. number = bit32.bor(bitArray[i], bit32.lshift(number, 1))
  102. end
  103. return number
  104. end
  105.  
  106. -------------------------------------------------- Math extensions --------------------------------------------------
  107.  
  108. function math.round(num)
  109. if num >= 0 then
  110. return math.floor(num + 0.5)
  111. else
  112. return math.ceil(num - 0.5)
  113. end
  114. end
  115.  
  116. function math.roundToDecimalPlaces(num, decimalPlaces)
  117. local mult = 10 ^ (decimalPlaces or 0)
  118. return math.round(num * mult) / mult
  119. end
  120.  
  121. function math.getDigitCount(num)
  122. return num == 0 and 1 or math.ceil(math.log(num + 1, 10))
  123. end
  124.  
  125. function math.doubleToString(num, digitCount)
  126. return string.format("%." .. (digitCount or 1) .. "f", num)
  127. end
  128.  
  129. function math.shortenNumber(number, digitCount)
  130. local shortcuts = {
  131. "K",
  132. "M",
  133. "B",
  134. "T"
  135. }
  136.  
  137. local index = math.floor(math.log(number, 1000))
  138. if number < 1000 then
  139. return number
  140. elseif index > #shortcuts then
  141. index = #shortcuts
  142. end
  143.  
  144. return math.roundToDecimalPlaces(number / 1000 ^ index, digitCount) .. shortcuts[index]
  145. end
  146.  
  147. ---------------------------------------------- Filesystem extensions ------------------------------------------------------------------------
  148.  
  149. function filesystem.path(path)
  150. return path:match("^(.+%/).") or ""
  151. end
  152.  
  153. function filesystem.name(path)
  154. return path:match("%/?([^%/]+)%/?$")
  155. end
  156.  
  157. function filesystem.extension(path, lower)
  158. local extension = path:match("[^%/]+(%.[^%/]+)%/?$")
  159. return (lower and extension) and (unicode.lower(extension)) or extension
  160. end
  161.  
  162. function filesystem.hideExtension(path)
  163. return path:match("(.+)%..+") or path
  164. end
  165.  
  166. function filesystem.isFileHidden(path)
  167. if path:match("^%..+$") then
  168. return true
  169. end
  170. return false
  171. end
  172.  
  173. function filesystem.sortedList(path, sortingMethod, showHiddenFiles, filenameMatcher, filenameMatcherCaseSensitive)
  174. if not filesystem.exists(path) then
  175. error("Failed to get file list: directory \"" .. tostring(path) .. "\" doesn't exists")
  176. end
  177. if not filesystem.isDirectory(path) then
  178. error("Failed to get file list: path \"" .. tostring(path) .. "\" is not a directory")
  179. end
  180.  
  181. local fileList, sortedFileList = {}, {}
  182. for file in filesystem.list(path) do
  183. if not filenameMatcher or string.unicodeFind(filenameMatcherCaseSensitive and file or unicode.lower(file), filenameMatcherCaseSensitive and filenameMatcher or unicode.lower(filenameMatcher)) then
  184. table.insert(fileList, file)
  185. end
  186. end
  187.  
  188. if #fileList > 0 then
  189. if sortingMethod == "type" then
  190. local extension
  191. for i = 1, #fileList do
  192. extension = filesystem.extension(fileList[i]) or "Script"
  193. if filesystem.isDirectory(path .. fileList[i]) and extension ~= ".app" then
  194. extension = ".01_Folder"
  195. end
  196. fileList[i] = {fileList[i], extension}
  197. end
  198.  
  199. table.sort(fileList, function(a, b) return unicode.lower(a[2]) < unicode.lower(b[2]) end)
  200.  
  201. local currentExtensionList, currentExtension = {}, fileList[1][2]
  202. for i = 1, #fileList do
  203. if currentExtension == fileList[i][2] then
  204. table.insert(currentExtensionList, fileList[i][1])
  205. else
  206. table.sort(currentExtensionList, function(a, b) return unicode.lower(a) < unicode.lower(b) end)
  207. for j = 1, #currentExtensionList do
  208. table.insert(sortedFileList, currentExtensionList[j])
  209. end
  210. currentExtensionList, currentExtension = {fileList[i][1]}, fileList[i][2]
  211. end
  212. end
  213.  
  214. table.sort(currentExtensionList, function(a, b) return unicode.lower(a) < unicode.lower(b) end)
  215. for j = 1, #currentExtensionList do
  216. table.insert(sortedFileList, currentExtensionList[j])
  217. end
  218. elseif sortingMethod == "name" then
  219. sortedFileList = fileList
  220. table.sort(sortedFileList, function(a, b) return unicode.lower(a) < unicode.lower(b) end)
  221. elseif sortingMethod == "date" then
  222. for i = 1, #fileList do
  223. fileList[i] = {fileList[i], filesystem.lastModified(path .. fileList[i])}
  224. end
  225.  
  226. table.sort(fileList, function(a, b) return unicode.lower(a[2]) > unicode.lower(b[2]) end)
  227.  
  228. for i = 1, #fileList do
  229. table.insert(sortedFileList, fileList[i][1])
  230. end
  231. else
  232. error("Unknown sorting method: " .. tostring(sortingMethod))
  233. end
  234.  
  235. local i = 1
  236. while i <= #sortedFileList do
  237. if not showHiddenFiles and filesystem.isFileHidden(sortedFileList[i]) then
  238. table.remove(sortedFileList, i)
  239. else
  240. i = i + 1
  241. end
  242. end
  243. end
  244.  
  245. return sortedFileList
  246. end
  247.  
  248. function filesystem.directorySize(path)
  249. local size = 0
  250. for file in filesystem.list(path) do
  251. if filesystem.isDirectory(path .. file) then
  252. size = size + filesystem.directorySize(path .. file)
  253. else
  254. size = size + filesystem.size(path .. file)
  255. end
  256. end
  257.  
  258. return size
  259. end
  260.  
  261. -------------------------------------------------- Table extensions --------------------------------------------------
  262.  
  263. local function doSerialize(array, prettyLook, indentationSymbol, indentationSymbolAdder, equalsSymbol, currentRecusrionStack, recursionStackLimit)
  264. local text, indentationSymbolNext, keyType, valueType, stringValue = {"{"}, table.concat({indentationSymbol, indentationSymbolAdder})
  265. if prettyLook then
  266. table.insert(text, "\n")
  267. end
  268.  
  269. for key, value in pairs(array) do
  270. keyType, valueType, stringValue = type(key), type(value), tostring(value)
  271.  
  272. if prettyLook then
  273. table.insert(text, indentationSymbolNext)
  274. end
  275.  
  276. if keyType == "number" then
  277. table.insert(text, "[")
  278. table.insert(text, key)
  279. table.insert(text, "]")
  280. elseif keyType == "string" then
  281. if prettyLook and key:match("^%a") and key:match("^%w+$") then
  282. table.insert(text, key)
  283. else
  284. table.insert(text, "[\"")
  285. table.insert(text, key)
  286. table.insert(text, "\"]")
  287. end
  288. end
  289.  
  290. table.insert(text, equalsSymbol)
  291.  
  292. if valueType == "number" or valueType == "boolean" or valueType == "nil" then
  293. table.insert(text, stringValue)
  294. elseif valueType == "string" or valueType == "function" then
  295. table.insert(text, "\"")
  296. table.insert(text, stringValue)
  297. table.insert(text, "\"")
  298. elseif valueType == "table" then
  299. if currentRecusrionStack < recursionStackLimit then
  300. table.insert(
  301. text,
  302. table.concat(
  303. doSerialize(
  304. value,
  305. prettyLook,
  306. indentationSymbolNext,
  307. indentationSymbolAdder,
  308. equalsSymbol,
  309. currentRecusrionStack + 1,
  310. recursionStackLimit
  311. )
  312. )
  313. )
  314. else
  315. table.insert(text, "\"…\"")
  316. end
  317. end
  318.  
  319. table.insert(text, ",")
  320. if prettyLook then
  321. table.insert(text, "\n")
  322. end
  323. end
  324.  
  325. -- Удаляем запятую
  326. if prettyLook then
  327. if #text > 2 then
  328. table.remove(text, #text - 1)
  329. end
  330. -- Вставляем заодно уж символ индентации, благо чек на притти лук идет
  331. table.insert(text, indentationSymbol)
  332. else
  333. if #text > 1 then
  334. table.remove(text, #text)
  335. end
  336. end
  337.  
  338. table.insert(text, "}")
  339.  
  340. return text
  341. end
  342.  
  343. function table.serialize(array, prettyLook, indentationWidth, indentUsingTabs, recursionStackLimit)
  344. checkArg(1, array, "table")
  345.  
  346. return table.concat(
  347. doSerialize(
  348. array,
  349. prettyLook,
  350. "",
  351. string.rep(indentUsingTabs and " " or " ", indentationWidth or 2),
  352. prettyLook and " = " or "=",
  353. 1,
  354. recursionStackLimit or math.huge
  355. )
  356. )
  357. end
  358.  
  359. function table.unserialize(serializedString)
  360. checkArg(1, serializedString, "string")
  361.  
  362. local success, result = pcall(load("return " .. serializedString))
  363. if success then
  364. return result
  365. else
  366. return nil, result
  367. end
  368. end
  369.  
  370. table.toString = table.serialize
  371. table.fromString = table.unserialize
  372.  
  373. function table.toFile(path, array, prettyLook, indentationWidth, indentUsingTabs, recursionStackLimit, appendToFile)
  374. checkArg(1, path, "string")
  375. checkArg(2, array, "table")
  376.  
  377. filesystem.makeDirectory(filesystem.path(path) or "")
  378.  
  379. local file, reason = io.open(path, appendToFile and "a" or "w")
  380. if file then
  381. file:write(table.serialize(array, prettyLook, indentationWidth, indentUsingTabs, recursionStackLimit))
  382. file:close()
  383. else
  384. error("Failed to open file for writing: " .. tostring(reason))
  385. end
  386. end
  387.  
  388. function table.fromFile(path)
  389. checkArg(1, path, "string")
  390.  
  391. if filesystem.exists(path) then
  392. if filesystem.isDirectory(path) then
  393. error("\"" .. path .. "\" is a directory")
  394. else
  395. local file = io.open(path, "r")
  396. local data = table.unserialize(file:read("*a"))
  397. file:close()
  398. return data
  399. end
  400. else
  401. error("\"" .. path .. "\" doesn't exists")
  402. end
  403. end
  404.  
  405. local function doTableCopy(source, destination)
  406. for key, value in pairs(source) do
  407. if type(value) == "table" then
  408. destination[key] = {}
  409. doTableCopy(source[key], destination[key])
  410. else
  411. destination[key] = value
  412. end
  413. end
  414. end
  415.  
  416. function table.copy(tableToCopy)
  417. local tableThatCopied = {}
  418. doTableCopy(tableToCopy, tableThatCopied)
  419.  
  420. return tableThatCopied
  421. end
  422.  
  423. function table.binarySearch(t, requestedValue)
  424. local function recursiveSearch(startIndex, endIndex)
  425. local difference = endIndex - startIndex
  426. local centerIndex = math.floor(difference / 2 + startIndex)
  427.  
  428. if difference > 1 then
  429. if requestedValue >= t[centerIndex] then
  430. return recursiveSearch(centerIndex, endIndex)
  431. else
  432. return recursiveSearch(startIndex, centerIndex)
  433. end
  434. else
  435. if math.abs(requestedValue - t[startIndex]) > math.abs(t[endIndex] - requestedValue) then
  436. return t[endIndex]
  437. else
  438. return t[startIndex]
  439. end
  440. end
  441. end
  442.  
  443. return recursiveSearch(1, #t)
  444. end
  445.  
  446. function table.size(t)
  447. local size = 0
  448. for key in pairs(t) do size = size + 1 end
  449. return size
  450. end
  451.  
  452. function table.contains(t, object)
  453. for _, value in pairs(t) do
  454. if value == object then
  455. return true
  456. end
  457. end
  458. return false
  459. end
  460.  
  461. function table.indexOf(t, object)
  462. for i = 1, #t do
  463. if t[i] == object then
  464. return i
  465. end
  466. end
  467. end
  468.  
  469. function table.sortAlphabetically(t)
  470. table.sort(t, function(a, b) return a < b end)
  471. end
  472.  
  473. -------------------------------------------------- String extensions --------------------------------------------------
  474.  
  475. function string.brailleChar(a, b, c, d, e, f, g, h)
  476. return unicode.char(10240 + 128*h + 64*g + 32*f + 16*d + 8*b + 4*e + 2*c + a)
  477. end
  478.  
  479. function string.readUnicodeChar(file)
  480. local byteArray = {string.byte(file:read(1))}
  481.  
  482. local nullBitPosition = 0
  483. for i = 1, 7 do
  484. if bit32.band(bit32.rshift(byteArray[1], 8 - i), 0x1) == 0x0 then
  485. nullBitPosition = i
  486. break
  487. end
  488. end
  489.  
  490. for i = 1, nullBitPosition - 2 do
  491. table.insert(byteArray, string.byte(file:read(1)))
  492. end
  493.  
  494. return string.char(table.unpack(byteArray))
  495. end
  496.  
  497. function string.canonicalPath(str)
  498. return string.gsub("/" .. str, "%/+", "/")
  499. end
  500.  
  501. function string.optimize(str, indentationWidth)
  502. str = string.gsub(str, "\r\n", "\n")
  503. str = string.gsub(str, " ", string.rep(" ", indentationWidth or 2))
  504. return str
  505. end
  506.  
  507. function string.optimizeForURLRequests(code)
  508. if code then
  509. code = string.gsub(code, "([^%w ])", function (c)
  510. return string.format("%%%02X", string.byte(c))
  511. end)
  512. code = string.gsub(code, " ", "+")
  513. end
  514. return code
  515. end
  516.  
  517. function string.unicodeFind(str, pattern, init, plain)
  518. if init then
  519. if init < 0 then
  520. init = -#unicode.sub(str,init)
  521. elseif init > 0 then
  522. init = #unicode.sub(str, 1, init - 1) + 1
  523. end
  524. end
  525.  
  526. a, b = string.find(str, pattern, init, plain)
  527.  
  528. if a then
  529. local ap, bp = str:sub(1, a - 1), str:sub(a,b)
  530. a = unicode.len(ap) + 1
  531. b = a + unicode.len(bp) - 1
  532. return a, b
  533. else
  534. return a
  535. end
  536. end
  537.  
  538. function string.limit(s, limit, mode, noDots)
  539. local length = unicode.len(s)
  540. if length <= limit then return s end
  541.  
  542. if mode == "left" then
  543. if noDots then
  544. return unicode.sub(s, length - limit + 1, -1)
  545. else
  546. return "…" .. unicode.sub(s, length - limit + 2, -1)
  547. end
  548. elseif mode == "center" then
  549. local integer, fractional = math.modf(limit / 2)
  550. if fractional == 0 then
  551. return unicode.sub(s, 1, integer) .. "…" .. unicode.sub(s, -integer + 1, -1)
  552. else
  553. return unicode.sub(s, 1, integer) .. "…" .. unicode.sub(s, -integer, -1)
  554. end
  555. else
  556. if noDots then
  557. return unicode.sub(s, 1, limit)
  558. else
  559. return unicode.sub(s, 1, limit - 1) .. "…"
  560. end
  561. end
  562. end
  563.  
  564. function string.wrap(data, limit)
  565. if type(data) == "string" then data = {data} end
  566.  
  567. local wrappedLines, result, preResult, preResultLength = {}
  568. for i = 1, #data do
  569. for subLine in data[i]:gmatch("[^\n]+") do
  570. result = ""
  571.  
  572. for word in subLine:gmatch("[^%s]+") do
  573. preResult = result .. word
  574. preResultLength = unicode.len(preResult)
  575.  
  576. if preResultLength > limit then
  577. if unicode.len(word) > limit then
  578. table.insert(wrappedLines, unicode.sub(preResult, 1, limit))
  579. for i = limit + 1, preResultLength, limit do
  580. table.insert(wrappedLines, unicode.sub(preResult, i, i + limit - 1))
  581. end
  582.  
  583. result = wrappedLines[#wrappedLines] .. " "
  584. wrappedLines[#wrappedLines] = nil
  585. else
  586. result = result:gsub("%s+$", "")
  587. table.insert(wrappedLines, result)
  588.  
  589. result = word .. " "
  590. end
  591. else
  592. result = preResult .. " "
  593. end
  594. end
  595.  
  596. result = result:gsub("%s+$", "")
  597. table.insert(wrappedLines, result)
  598. end
  599. end
  600.  
  601. return wrappedLines
  602. end
  603.  
  604. -------------------------------------------------- Playground --------------------------------------------------
  605.  
  606. -- print(table.toString(require("MineOSCore").OSSettings, true, 2, true, 2))
  607.  
  608. -- local t = {
  609. -- abc = 123,
  610. -- def = {
  611. -- cyka = "pidor",
  612. -- vagina = {
  613. -- chlen = 555,
  614. -- devil = 666,
  615. -- god = 777,
  616. -- serost = {
  617. -- tripleTable = "aefaef",
  618. -- aaa = "bbb",
  619. -- ccc = 123,
  620. -- }
  621. -- }
  622. -- },
  623. -- ghi = "HEHE",
  624. -- emptyTable = {},
  625. -- }
  626.  
  627. -- print(table.toString(t, true))
  628.  
  629. ------------------------------------------------------------------------------------------------------------------
  630.  
  631. return {loaded = true}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement