forked from enlightenment/efl
elua: use custom string buffer impl for format (avoids multiple table allocs and calls to string.char)
This commit is contained in:
parent
8738ca957d
commit
a6e50fa9c7
|
@ -2,11 +2,10 @@
|
||||||
|
|
||||||
local ffi = require("ffi")
|
local ffi = require("ffi")
|
||||||
local cast = ffi.cast
|
local cast = ffi.cast
|
||||||
|
local new = ffi.new
|
||||||
ffi.cdef [[
|
local copy = ffi.copy
|
||||||
int isalnum(int c);
|
local str = ffi.string
|
||||||
int isdigit(int c);
|
local gc = ffi.gc
|
||||||
]]
|
|
||||||
|
|
||||||
local C = ffi.C
|
local C = ffi.C
|
||||||
|
|
||||||
|
@ -166,16 +165,79 @@ end
|
||||||
|
|
||||||
-- string fmt
|
-- string fmt
|
||||||
|
|
||||||
|
ffi.cdef [[
|
||||||
|
typedef struct _Str_Buf {
|
||||||
|
char *buf;
|
||||||
|
size_t len, cap;
|
||||||
|
} Str_Buf;
|
||||||
|
|
||||||
|
void *malloc(size_t);
|
||||||
|
void free(void*);
|
||||||
|
size_t strlen(const char *str);
|
||||||
|
|
||||||
|
int isalnum(int c);
|
||||||
|
int isdigit(int c);
|
||||||
|
]]
|
||||||
|
|
||||||
local char = string.char
|
local char = string.char
|
||||||
local tconc = table.concat
|
local tconc = table.concat
|
||||||
local fmt = string.format
|
local fmt = string.format
|
||||||
local pcall = pcall
|
local pcall = pcall
|
||||||
local error = error
|
local error = error
|
||||||
local type = type
|
local type = type
|
||||||
|
local tostr = tostring
|
||||||
|
|
||||||
local bytes = { ("cdeEfgGiopuxXsq"):byte() }
|
local bytes = { ("cdeEfgGiopuxXsq"):byte() }
|
||||||
for i, v in ipairs(bytes) do bytes[v] = true end
|
for i, v in ipairs(bytes) do bytes[v] = true end
|
||||||
|
|
||||||
|
local Str_Buf = ffi.metatype("Str_Buf", {
|
||||||
|
__new = function(self)
|
||||||
|
local r = new("Str_Buf")
|
||||||
|
r.buf = C.malloc(8)
|
||||||
|
r.len = 0
|
||||||
|
r.cap = 8
|
||||||
|
gc(r, self.free)
|
||||||
|
return r
|
||||||
|
end,
|
||||||
|
__tostring = function(self)
|
||||||
|
return str(self.buf, self.len)
|
||||||
|
end,
|
||||||
|
__index = {
|
||||||
|
free = function(self)
|
||||||
|
C.free(self.buf)
|
||||||
|
self.buf = nil
|
||||||
|
end,
|
||||||
|
clear = function(self)
|
||||||
|
self.len = 0
|
||||||
|
end,
|
||||||
|
grow = function(self, newcap)
|
||||||
|
local oldcap = self.cap
|
||||||
|
if oldcap >= newcap then return end
|
||||||
|
local buf = C.malloc(newcap)
|
||||||
|
copy(buf, self.buf, self.len)
|
||||||
|
C.free(self.buf)
|
||||||
|
self.buf = buf
|
||||||
|
self.cap = newcap
|
||||||
|
end,
|
||||||
|
append_char = function(self, c)
|
||||||
|
local len = self.len
|
||||||
|
self:grow (len + 1)
|
||||||
|
self.buf [len] = c
|
||||||
|
self.len = len + 1
|
||||||
|
end,
|
||||||
|
append_str = function(self, str, strlen)
|
||||||
|
local strp = cast("const char*", str)
|
||||||
|
strlen = strlen or C.strlen(strp)
|
||||||
|
local len = self.len
|
||||||
|
self:grow(len + strlen)
|
||||||
|
for i = 0, strlen - 1 do
|
||||||
|
self.buf[len + i] = strp[i]
|
||||||
|
end
|
||||||
|
self.len = len + strlen
|
||||||
|
end
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
getmetatable("").__mod = function(fmts, params)
|
getmetatable("").__mod = function(fmts, params)
|
||||||
if not fmts then return nil end
|
if not fmts then return nil end
|
||||||
if type(params) ~= "table" then params = { params } end
|
if type(params) ~= "table" then params = { params } end
|
||||||
|
@ -184,20 +246,20 @@ getmetatable("").__mod = function(fmts, params)
|
||||||
local c
|
local c
|
||||||
c, s = s[0], s + 1
|
c, s = s[0], s + 1
|
||||||
local argn = 1
|
local argn = 1
|
||||||
|
local nbuf = Str_Buf()
|
||||||
while c ~= 0 do
|
while c ~= 0 do
|
||||||
if c == 37 then -- %
|
if c == 37 then -- %
|
||||||
c, s = s[0], s + 1
|
c, s = s[0], s + 1
|
||||||
local nbuf = {}
|
|
||||||
while c ~= 0 and C.isalnum(c) ~= 0 do
|
while c ~= 0 and C.isalnum(c) ~= 0 do
|
||||||
nbuf[#nbuf + 1] = c
|
nbuf:append_char(c)
|
||||||
c, s = s[0], s + 1
|
c, s = s[0], s + 1
|
||||||
end
|
end
|
||||||
if c == 36 then -- $
|
if c == 36 then -- $
|
||||||
c, s = s[0], s + 1
|
c, s = s[0], s + 1
|
||||||
local n = char(unpack(nbuf))
|
local n = tostr(nbuf)
|
||||||
nbuf = {}
|
nbuf:clear()
|
||||||
while C.isdigit(c) ~= 0 or c == 45 or c == 46 do -- -, .
|
while C.isdigit(c) ~= 0 or c == 45 or c == 46 do -- -, .
|
||||||
nbuf[#nbuf + 1] = c
|
nbuf:append_char(c)
|
||||||
c, s = s[0], s + 1
|
c, s = s[0], s + 1
|
||||||
end
|
end
|
||||||
if bytes[c] then
|
if bytes[c] then
|
||||||
|
@ -205,10 +267,11 @@ getmetatable("").__mod = function(fmts, params)
|
||||||
buf[#buf + 1] = "$"
|
buf[#buf + 1] = "$"
|
||||||
buf[#buf + 1] = char(c)
|
buf[#buf + 1] = char(c)
|
||||||
else
|
else
|
||||||
nbuf[#nbuf + 1] = c
|
nbuf:append_char(c)
|
||||||
local idx = tonumber(n) or n
|
local idx = tonumber(n) or n
|
||||||
local stat, val = pcall(fmt, "%" .. char(unpack(nbuf)),
|
local stat, val = pcall(fmt, "%" .. tostr(nbuf),
|
||||||
params[idx])
|
params[idx])
|
||||||
|
nbuf:clear()
|
||||||
if stat then
|
if stat then
|
||||||
buf[#buf + 1] = val
|
buf[#buf + 1] = val
|
||||||
else
|
else
|
||||||
|
@ -222,11 +285,12 @@ getmetatable("").__mod = function(fmts, params)
|
||||||
else
|
else
|
||||||
while c ~= 0 and (bytes[c] or C.isdigit(c) ~= 0
|
while c ~= 0 and (bytes[c] or C.isdigit(c) ~= 0
|
||||||
or c == 45 or c == 46) do
|
or c == 45 or c == 46) do
|
||||||
nbuf[#nbuf + 1] = c
|
nbuf:append_char(c)
|
||||||
c, s = s[0], s + 1
|
c, s = s[0], s + 1
|
||||||
end
|
end
|
||||||
local stat, val = pcall(fmt, "%" .. char(unpack(nbuf)),
|
local stat, val = pcall(fmt, "%" .. tostr(nbuf),
|
||||||
params[argn])
|
params[argn])
|
||||||
|
nbuf:clear()
|
||||||
if stat then
|
if stat then
|
||||||
buf[#buf + 1] = val
|
buf[#buf + 1] = val
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in New Issue