lume.lua 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  1. --
  2. -- lume
  3. --
  4. -- Copyright (c) 2015 rxi
  5. --
  6. -- This library is free software; you can redistribute it and/or modify it
  7. -- under the terms of the MIT license. See LICENSE for details.
  8. --
  9. local lume = { _version = "2.2.3" }
  10. local pairs, ipairs = pairs, ipairs
  11. local type, assert, unpack = type, assert, unpack or table.unpack
  12. local tostring, tonumber = tostring, tonumber
  13. local math_floor = math.floor
  14. local math_ceil = math.ceil
  15. local math_random = math.random
  16. local math_atan2 = math.atan2 or math.atan
  17. local math_sqrt = math.sqrt
  18. local math_abs = math.abs
  19. local noop = function()
  20. end
  21. local identity = function(x)
  22. return x
  23. end
  24. local patternescape = function(str)
  25. return str:gsub("[%(%)%.%%%+%-%*%?%[%]%^%$]", "%%%1")
  26. end
  27. local absindex = function(len, i)
  28. return i < 0 and (len + i + 1) or i
  29. end
  30. local iscallable = function(x)
  31. if type(x) == "function" then return true end
  32. local mt = getmetatable(x)
  33. return mt and mt.__call ~= nil
  34. end
  35. local getiter = function(x)
  36. if lume.isarray(x) then
  37. return ipairs
  38. elseif type(x) == "table" then
  39. return pairs
  40. end
  41. error("expected table", 3)
  42. end
  43. local iteratee = function(x)
  44. if x == nil then return identity end
  45. if iscallable(x) then return x end
  46. if type(x) == "table" then
  47. return function(z)
  48. for k, v in pairs(x) do
  49. if z[k] ~= v then return false end
  50. end
  51. return true
  52. end
  53. end
  54. return function(z) return z[x] end
  55. end
  56. function lume.clamp(x, min, max)
  57. return x < min and min or (x > max and max or x)
  58. end
  59. function lume.round(x, increment)
  60. if increment then return lume.round(x / increment) * increment end
  61. return x >= 0 and math_floor(x + .5) or math_ceil(x - .5)
  62. end
  63. function lume.sign(x)
  64. return x < 0 and -1 or 1
  65. end
  66. function lume.lerp(a, b, amount)
  67. return a + (b - a) * lume.clamp(amount, 0, 1)
  68. end
  69. function lume.smooth(a, b, amount)
  70. local t = lume.clamp(amount, 0, 1)
  71. local m = t * t * (3 - 2 * t)
  72. return a + (b - a) * m
  73. end
  74. function lume.pingpong(x)
  75. return 1 - math_abs(1 - x % 2)
  76. end
  77. function lume.distance(x1, y1, x2, y2, squared)
  78. local dx = x1 - x2
  79. local dy = y1 - y2
  80. local s = dx * dx + dy * dy
  81. return squared and s or math_sqrt(s)
  82. end
  83. function lume.angle(x1, y1, x2, y2)
  84. return math_atan2(y2 - y1, x2 - x1)
  85. end
  86. function lume.random(a, b)
  87. if not a then a, b = 0, 1 end
  88. if not b then b = 0 end
  89. return a + math_random() * (b - a)
  90. end
  91. function lume.randomchoice(t)
  92. return t[math_random(#t)]
  93. end
  94. function lume.weightedchoice(t)
  95. local sum = 0
  96. for _, v in pairs(t) do
  97. assert(v >= 0, "weight value less than zero")
  98. sum = sum + v
  99. end
  100. assert(sum ~= 0, "all weights are zero")
  101. local rnd = lume.random(sum)
  102. for k, v in pairs(t) do
  103. if rnd < v then return k end
  104. rnd = rnd - v
  105. end
  106. end
  107. function lume.isarray(x)
  108. return (type(x) == "table" and x[1] ~= nil) and true or false
  109. end
  110. function lume.push(t, ...)
  111. local n = select("#", ...)
  112. for i = 1, n do
  113. t[#t + 1] = select(i, ...)
  114. end
  115. return ...
  116. end
  117. function lume.remove(t, x)
  118. local iter = getiter(t)
  119. for i, v in iter(t) do
  120. if v == x then
  121. if lume.isarray(t) then
  122. table.remove(t, i)
  123. break
  124. else
  125. t[i] = nil
  126. break
  127. end
  128. end
  129. end
  130. return x
  131. end
  132. function lume.clear(t)
  133. local iter = getiter(t)
  134. for k in iter(t) do
  135. t[k] = nil
  136. end
  137. return t
  138. end
  139. function lume.extend(t, ...)
  140. for i = 1, select("#", ...) do
  141. local x = select(i, ...)
  142. if x then
  143. for k, v in pairs(x) do
  144. t[k] = v
  145. end
  146. end
  147. end
  148. return t
  149. end
  150. function lume.shuffle(t)
  151. local rtn = {}
  152. for i = 1, #t do
  153. local r = math_random(i)
  154. if r ~= i then
  155. rtn[i] = rtn[r]
  156. end
  157. rtn[r] = t[i]
  158. end
  159. return rtn
  160. end
  161. function lume.sort(t, comp)
  162. local rtn = lume.clone(t)
  163. if comp then
  164. if type(comp) == "string" then
  165. table.sort(rtn, function(a, b) return a[comp] < b[comp] end)
  166. else
  167. table.sort(rtn, comp)
  168. end
  169. else
  170. table.sort(rtn)
  171. end
  172. return rtn
  173. end
  174. function lume.array(...)
  175. local t = {}
  176. for x in ... do t[#t + 1] = x end
  177. return t
  178. end
  179. function lume.each(t, fn, ...)
  180. local iter = getiter(t)
  181. if type(fn) == "string" then
  182. for _, v in iter(t) do v[fn](v, ...) end
  183. else
  184. for _, v in iter(t) do fn(v, ...) end
  185. end
  186. return t
  187. end
  188. function lume.map(t, fn)
  189. fn = iteratee(fn)
  190. local iter = getiter(t)
  191. local rtn = {}
  192. for k, v in iter(t) do rtn[k] = fn(v) end
  193. return rtn
  194. end
  195. function lume.all(t, fn)
  196. fn = iteratee(fn)
  197. local iter = getiter(t)
  198. for _, v in iter(t) do
  199. if not fn(v) then return false end
  200. end
  201. return true
  202. end
  203. function lume.any(t, fn)
  204. fn = iteratee(fn)
  205. local iter = getiter(t)
  206. for _, v in iter(t) do
  207. if fn(v) then return true end
  208. end
  209. return false
  210. end
  211. function lume.reduce(t, fn, first)
  212. local acc = first
  213. local started = first and true or false
  214. local iter = getiter(t)
  215. for _, v in iter(t) do
  216. if started then
  217. acc = fn(acc, v)
  218. else
  219. acc = v
  220. started = true
  221. end
  222. end
  223. assert(started, "reduce of an empty table with no first value")
  224. return acc
  225. end
  226. function lume.set(t)
  227. local rtn = {}
  228. for k in pairs(lume.invert(t)) do
  229. rtn[#rtn + 1] = k
  230. end
  231. return rtn
  232. end
  233. function lume.filter(t, fn, retainkeys)
  234. fn = iteratee(fn)
  235. local iter = getiter(t)
  236. local rtn = {}
  237. if retainkeys then
  238. for k, v in iter(t) do
  239. if fn(v) then rtn[k] = v end
  240. end
  241. else
  242. for _, v in iter(t) do
  243. if fn(v) then rtn[#rtn + 1] = v end
  244. end
  245. end
  246. return rtn
  247. end
  248. function lume.reject(t, fn, retainkeys)
  249. fn = iteratee(fn)
  250. local iter = getiter(t)
  251. local rtn = {}
  252. if retainkeys then
  253. for k, v in iter(t) do
  254. if not fn(v) then rtn[k] = v end
  255. end
  256. else
  257. for _, v in iter(t) do
  258. if not fn(v) then rtn[#rtn + 1] = v end
  259. end
  260. end
  261. return rtn
  262. end
  263. function lume.merge(...)
  264. local rtn = {}
  265. for i = 1, select("#", ...) do
  266. local t = select(i, ...)
  267. local iter = getiter(t)
  268. for k, v in iter(t) do
  269. rtn[k] = v
  270. end
  271. end
  272. return rtn
  273. end
  274. function lume.concat(...)
  275. local rtn = {}
  276. for i = 1, select("#", ...) do
  277. local t = select(i, ...)
  278. if t ~= nil then
  279. local iter = getiter(t)
  280. for _, v in iter(t) do
  281. rtn[#rtn + 1] = v
  282. end
  283. end
  284. end
  285. return rtn
  286. end
  287. function lume.find(t, value)
  288. local iter = getiter(t)
  289. for k, v in iter(t) do
  290. if v == value then return k end
  291. end
  292. return nil
  293. end
  294. function lume.match(t, fn)
  295. fn = iteratee(fn)
  296. local iter = getiter(t)
  297. for k, v in iter(t) do
  298. if fn(v) then return v, k end
  299. end
  300. return nil
  301. end
  302. function lume.count(t, fn)
  303. local count = 0
  304. local iter = getiter(t)
  305. if fn then
  306. fn = iteratee(fn)
  307. for _, v in iter(t) do
  308. if fn(v) then count = count + 1 end
  309. end
  310. else
  311. if lume.isarray(t) then
  312. return #t
  313. end
  314. for _ in iter(t) do count = count + 1 end
  315. end
  316. return count
  317. end
  318. function lume.slice(t, i, j)
  319. i = i and absindex(#t, i) or 1
  320. j = j and absindex(#t, j) or #t
  321. local rtn = {}
  322. for x = i < 1 and 1 or i, j > #t and #t or j do
  323. rtn[#rtn + 1] = t[x]
  324. end
  325. return rtn
  326. end
  327. function lume.first(t, n)
  328. if not n then return t[1] end
  329. return lume.slice(t, 1, n)
  330. end
  331. function lume.last(t, n)
  332. if not n then return t[#t] end
  333. return lume.slice(t, -n, -1)
  334. end
  335. function lume.invert(t)
  336. local rtn = {}
  337. for k, v in pairs(t) do rtn[v] = k end
  338. return rtn
  339. end
  340. function lume.pick(t, ...)
  341. local rtn = {}
  342. for i = 1, select("#", ...) do
  343. local k = select(i, ...)
  344. rtn[k] = t[k]
  345. end
  346. return rtn
  347. end
  348. function lume.keys(t)
  349. local rtn = {}
  350. local iter = getiter(t)
  351. for k in iter(t) do rtn[#rtn + 1] = k end
  352. return rtn
  353. end
  354. function lume.clone(t)
  355. local rtn = {}
  356. for k, v in pairs(t) do rtn[k] = v end
  357. return rtn
  358. end
  359. function lume.fn(fn, ...)
  360. assert(iscallable(fn), "expected a function as the first argument")
  361. local args = { ... }
  362. return function(...)
  363. local a = lume.concat(args, { ... })
  364. return fn(unpack(a))
  365. end
  366. end
  367. function lume.once(fn, ...)
  368. local f = lume.fn(fn, ...)
  369. local done = false
  370. return function(...)
  371. if done then return end
  372. done = true
  373. return f(...)
  374. end
  375. end
  376. local memoize_fnkey = {}
  377. local memoize_nil = {}
  378. function lume.memoize(fn)
  379. local cache = {}
  380. return function(...)
  381. local c = cache
  382. for i = 1, select("#", ...) do
  383. local a = select(i, ...) or memoize_nil
  384. c[a] = c[a] or {}
  385. c = c[a]
  386. end
  387. c[memoize_fnkey] = c[memoize_fnkey] or {fn(...)}
  388. return unpack(c[memoize_fnkey])
  389. end
  390. end
  391. function lume.combine(...)
  392. local n = select('#', ...)
  393. if n == 0 then return noop end
  394. if n == 1 then
  395. local fn = select(1, ...)
  396. if not fn then return noop end
  397. assert(iscallable(fn), "expected a function or nil")
  398. return fn
  399. end
  400. local funcs = {}
  401. for i = 1, n do
  402. local fn = select(i, ...)
  403. if fn ~= nil then
  404. assert(iscallable(fn), "expected a function or nil")
  405. funcs[#funcs + 1] = fn
  406. end
  407. end
  408. return function(...)
  409. for _, f in ipairs(funcs) do f(...) end
  410. end
  411. end
  412. function lume.call(fn, ...)
  413. if fn then
  414. return fn(...)
  415. end
  416. end
  417. function lume.time(fn, ...)
  418. local start = os.clock()
  419. local rtn = {fn(...)}
  420. return (os.clock() - start), unpack(rtn)
  421. end
  422. local lambda_cache = {}
  423. function lume.lambda(str)
  424. if not lambda_cache[str] then
  425. local args, body = str:match([[^([%w,_ ]-)%->(.-)$]])
  426. assert(args and body, "bad string lambda")
  427. local s = "return function(" .. args .. ")\nreturn " .. body .. "\nend"
  428. lambda_cache[str] = lume.dostring(s)
  429. end
  430. return lambda_cache[str]
  431. end
  432. local serialize
  433. local serialize_map = {
  434. [ "boolean" ] = tostring,
  435. [ "nil" ] = tostring,
  436. [ "string" ] = function(v) return string.format("%q", v) end,
  437. [ "number" ] = function(v)
  438. if v ~= v then return "0/0" -- nan
  439. elseif v == 1 / 0 then return "1/0" -- inf
  440. elseif v == -1 / 0 then return "-1/0" end -- -inf
  441. return tostring(v)
  442. end,
  443. [ "table" ] = function(t, stk)
  444. stk = stk or {}
  445. if stk[t] then error("circular reference") end
  446. local rtn = {}
  447. stk[t] = true
  448. for k, v in pairs(t) do
  449. rtn[#rtn + 1] = "[" .. serialize(k, stk) .. "]=" .. serialize(v, stk)
  450. end
  451. stk[t] = nil
  452. return "{" .. table.concat(rtn, ",") .. "}"
  453. end
  454. }
  455. setmetatable(serialize_map, {
  456. __index = function(_, k) error("unsupported serialize type: " .. k) end
  457. })
  458. serialize = function(x, stk)
  459. return serialize_map[type(x)](x, stk)
  460. end
  461. function lume.serialize(x)
  462. return serialize(x)
  463. end
  464. function lume.deserialize(str)
  465. return lume.dostring("return " .. str)
  466. end
  467. function lume.split(str, sep)
  468. if not sep then
  469. return lume.array(str:gmatch("([%S]+)"))
  470. else
  471. assert(sep ~= "", "empty separator")
  472. local psep = patternescape(sep)
  473. return lume.array((str..sep):gmatch("(.-)("..psep..")"))
  474. end
  475. end
  476. function lume.trim(str, chars)
  477. if not chars then return str:match("^[%s]*(.-)[%s]*$") end
  478. chars = patternescape(chars)
  479. return str:match("^[" .. chars .. "]*(.-)[" .. chars .. "]*$")
  480. end
  481. function lume.wordwrap(str, limit)
  482. limit = limit or 72
  483. local check
  484. if type(limit) == "number" then
  485. check = function(s) return #s >= limit end
  486. else
  487. check = limit
  488. end
  489. local rtn = {}
  490. local line = ""
  491. for word, spaces in str:gmatch("(%S+)(%s*)") do
  492. local s = line .. word
  493. if check(s) then
  494. table.insert(rtn, line .. "\n")
  495. line = word
  496. else
  497. line = s
  498. end
  499. for c in spaces:gmatch(".") do
  500. if c == "\n" then
  501. table.insert(rtn, line .. "\n")
  502. line = ""
  503. else
  504. line = line .. c
  505. end
  506. end
  507. end
  508. table.insert(rtn, line)
  509. return table.concat(rtn)
  510. end
  511. function lume.format(str, vars)
  512. if not vars then return str end
  513. local f = function(x)
  514. return tostring(vars[x] or vars[tonumber(x)] or "{" .. x .. "}")
  515. end
  516. return (str:gsub("{(.-)}", f))
  517. end
  518. function lume.trace(...)
  519. local info = debug.getinfo(2, "Sl")
  520. local t = { info.short_src .. ":" .. info.currentline .. ":" }
  521. for i = 1, select("#", ...) do
  522. local x = select(i, ...)
  523. if type(x) == "number" then
  524. x = string.format("%g", lume.round(x, .01))
  525. end
  526. t[#t + 1] = tostring(x)
  527. end
  528. api.print(table.concat(t, " "))
  529. end
  530. function lume.dostring(str)
  531. return assert((loadstring or load)(str))()
  532. end
  533. function lume.uuid()
  534. local fn = function(x)
  535. local r = math_random(16) - 1
  536. r = (x == "x") and (r + 1) or (r % 4) + 9
  537. return ("0123456789abcdef"):sub(r, r)
  538. end
  539. return (("xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"):gsub("[xy]", fn))
  540. end
  541. function lume.hotswap(modname)
  542. local oldglobal = lume.clone(_G)
  543. local updated = {}
  544. local function update(old, new)
  545. if updated[old] then return end
  546. updated[old] = true
  547. local oldmt, newmt = getmetatable(old), getmetatable(new)
  548. if oldmt and newmt then update(oldmt, newmt) end
  549. for k, v in pairs(new) do
  550. if type(v) == "table" then update(old[k], v) else old[k] = v end
  551. end
  552. end
  553. local err = nil
  554. local function onerror(e)
  555. for k in pairs(_G) do _G[k] = oldglobal[k] end
  556. err = lume.trim(e)
  557. end
  558. local ok, oldmod = pcall(require, modname)
  559. oldmod = ok and oldmod or nil
  560. xpcall(function()
  561. package.loaded[modname] = nil
  562. local newmod = require(modname)
  563. if type(oldmod) == "table" then update(oldmod, newmod) end
  564. for k, v in pairs(oldglobal) do
  565. if v ~= _G[k] and type(v) == "table" then
  566. update(v, _G[k])
  567. _G[k] = v
  568. end
  569. end
  570. end, onerror)
  571. package.loaded[modname] = oldmod
  572. if err then return nil, err end
  573. return oldmod
  574. end
  575. local ripairs_iter = function(t, i)
  576. i = i - 1
  577. local v = t[i]
  578. if v then return i, v end
  579. end
  580. function lume.ripairs(t)
  581. return ripairs_iter, t, (#t + 1)
  582. end
  583. function lume.color(str, mul)
  584. mul = mul or 1
  585. local r, g, b, a
  586. r, g, b = str:match("#(%x%x)(%x%x)(%x%x)")
  587. if r then
  588. r = tonumber(r, 16) / 0xff
  589. g = tonumber(g, 16) / 0xff
  590. b = tonumber(b, 16) / 0xff
  591. a = 1
  592. elseif str:match("rgba?%s*%([%d%s%.,]+%)") then
  593. local f = str:gmatch("[%d.]+")
  594. r = (f() or 0) / 0xff
  595. g = (f() or 0) / 0xff
  596. b = (f() or 0) / 0xff
  597. a = f() or 1
  598. else
  599. error(("bad color string '%s'"):format(str))
  600. end
  601. return r * mul, g * mul, b * mul, a * mul
  602. end
  603. function lume.rgba(color)
  604. local a = math_floor((color / 16777216) % 256)
  605. local r = math_floor((color / 65536) % 256)
  606. local g = math_floor((color / 256) % 256)
  607. local b = math_floor((color) % 256)
  608. return r, g, b, a
  609. end
  610. local chain_mt = {}
  611. chain_mt.__index = lume.map(lume.filter(lume, iscallable, true),
  612. function(fn)
  613. return function(self, ...)
  614. self._value = fn(self._value, ...)
  615. return self
  616. end
  617. end)
  618. chain_mt.__index.result = function(x) return x._value end
  619. function lume.chain(value)
  620. return setmetatable({ _value = value }, chain_mt)
  621. end
  622. setmetatable(lume, {
  623. __call = function(_, ...)
  624. return lume.chain(...)
  625. end
  626. })
  627. return lume