Compare commits

...

5 Commits

@ -14,10 +14,16 @@ local algo = {}
--
-- @number x value to clamp.
-- @number a interval lower bound (inclusive).
-- @number b interval upper bound (includive).
-- @number b interval upper bound (inclusive).
-- @treturn number clamped value.
function algo.clamp(x, a, b) return min(max(x, a), b) end
--- Sign function.
--
-- @number x value whose sign should be returned.
-- @treturn number sign of x, -1 if negative, 1 if positive, 0 otherwise.
function algo.sign(x) return x > 0 and 1 or x < 0 and -1 or 0 end
--- Fast remove from array.
--
-- Replace 'array[i]' with last array's element and

@ -8,6 +8,100 @@ local strings = {}
-- Platform preferred path separator
local SEP = package.config:sub(1,1)
local DOT = string.byte('.')
local SLASH = string.byte('/')
local BACKSLASH = string.byte('\\')
local COLON = string.byte(':')
--- Find file extension within path.
--
-- @string path a file path
-- @string[opt] sep path separator pattern, any combination of '/', '\\' or ':' to support various OSes, defaults to all
-- @treturn number extension position within path if an extension is found, nil otherwise
function strings.findpathext(path, sep)
sep = sep or '/\\:'
for i = 1,#sep do
local byt = sep:byte(i)
if byt ~= SLASH and byt ~= BACKSLASH and byt ~= COLON then
error(("Unsupported path separator pattern: %q"):format(sep))
end
end
local function issep(byt)
for i = 1,#sep do
if byt == sep:byte(i) then return true end
end
end
local pos = nil
for i = #path,2,-1 do
local byt = path:byte(i)
if byt == DOT and not issep(path:byte(i-1)) then
-- Update extension position
pos = i
elseif issep(byt) then
break
end
end
return pos
end
--- Set default file extension.
--
-- If path contains an extension, returns the path unaltered,
-- otherwise set extension to the specified one.
--
-- @string path a file path
-- @string ext default extension to be set
-- @string[opt] sep path separator pattern, any combination of '/', '\\' or ':' to support various OSes, defaults to all
-- @treturn string updated path, and separator position
function strings.setdefpathext(path, ext, sep)
if ext:byte(1) ~= DOT then
error(("Bad extension %q: must be a string starting with '.'"):format(ext))
end
local pos = strings.findpathext(path, sep)
if not pos then
-- Append default extension
pos = #path
path = path..ext
end
return path, pos
end
--- Set file extension.
--
-- @string path a file path
-- @string ext extension to be set (including '.')
-- @string[opt] sep path separator pattern, any combination of '/', '\\' or ':' to support various OSes, defaults to all
-- @treturn string updated path and separator position
function strings.setpathext(path, ext, sep)
if ext:byte(1) ~= DOT then
error(("Bad extension %q: must be a string starting with '.'"):format(ext))
end
local pos = strings.findpathext(path, sep)
if pos then
-- Trim existing extension
path = path:sub(1, pos-1)
end
return path..ext, pos
end
--- Get file extension.
--
-- @string path a file path
-- @string[opt] sep path separator pattern, any combination of '/', '\\' or ':' to support various OSes, defaults to all
-- @treturn string file extension and position, if any is found, nil otherwise
function strings.getpathext(path, sep)
local pos = strings.findpathext(path, sep)
if pos then return path:sub(pos), pos end
end
--- Remove redundant slashes and resolve dot and dot-dots in path.
--
@ -61,6 +155,28 @@ function strings.splitpath(path)
return path:match("(.-)([^\\/]-)(%.?[^%.\\/]*)$")
end
--- Test whether the path is absolute.
--
-- @string path a path to be tested
-- @string[opt] sep separator pattern, '/' for Unix, '\\' for Windows, if none is provided, path is tested for both
-- @treturn boolean true if path is absolute, false otherwise
function strings.isabspath(path, sep)
if sep == nil then
-- Conservative test, both Unix-style and Windows-style
return strings.isabspath(path, '/') or strings.isabspath(path, '\\')
elseif sep == '/' then
-- Unix-style
return #path >= 1 and path:byte(1) == SLASH
elseif sep == '\\' then
-- Windows-style
return
(#path >= 1 and path:byte(1) == BACKSLASH) or
(#path >= 3 and path:byte(2) == COLON and path:byte(3) == BACKSLASH)
else
error(("Unsupported separator pattern: %q"):format(sep))
end
end
--- Test whether a string starts with a prefix.
--
-- This is an optimized version of: return s:sub(1, #prefix) == prefix.

@ -88,7 +88,9 @@ function Timer:every(delay, after, count)
end
function Timer:cancel(handle)
self.functions[handle] = nil
if handle then
self.functions[handle] = nil
end
end
function Timer:clear()

Loading…
Cancel
Save