-- vim: ft=terra
local m = {
shorthand = {maxlen = 14}
}
-- swap in place -- faster on little endian
m.netswap_ip = macro(function(ty, src, dest)
if ty:astype().type ~= 'integer' then error('bad type') end
local bytes = ty:astype().bytes
src = `[&uint8](src)
dest = `[&uint8](dest)
if config.endian == 'little' then
return quote for i = 0, bytes do dest[i] = src[bytes - (i+1)] end end
elseif config.endian == 'big' then
return quote for i = 0, bytes do dest[i] = src[i] end end
else error('unknown endianness '..config.endian) end
end)
-- swap out of place -- safer, more flexible, and optimized to an intrinsic call; trivial on big endian
m.netswap = macro(function(tyq, src)
if config.endian == 'little' then
local ty = tyq:astype()
local a,b = symbol(ty), symbol(ty)
local bytes = ty.bytes
local steps = {}
for i=0,bytes-1 do
steps[#steps + 1] = quote
b = b << 8
b = b or (a and 0xff)
a = a >> 8
end
end
return quote
var [a] = src
var [b] = 0
[steps]
in b end
elseif config.endian == 'big' then return `src
else error('unknown endianness '..config.endian) end
end)
terra m.shorthand.cval(character: int8): {uint8, bool}
var ch = [uint8](character)
if ch >= 0x30 and ch <= 0x39 then
ch = 00 + (ch - 0x30)
elseif ch == 0x2d then ch = 10
elseif ch >= 0x41 and ch <= 0x5a then
ch = 11 + (ch - 0x41)
elseif ch == 0x3a then ch = 37
elseif ch >= 0x61 and ch <= 0x7a then
ch = 38 + (ch - 0x61)
else return 0, false end
return ch, true
end
terra m.shorthand.gen(val: uint64, dest: rawstring): ptrdiff
var lst = "0123456789-ABCDEFGHIJKLMNOPQRSTUVWXYZ:abcdefghijklmnopqrstuvwxyz"
var buf: int8[m.shorthand.maxlen]
var ptr = [&int8](buf)
while val ~= 0 do
var v = val % 64
@ptr = lst[v]
ptr = ptr + 1
val = val / 64
end
var len = ptr - buf
for i = 0, len do
dest[i] = buf[len - (i+1)]
end
dest[len] = 0
return len
end
terra m.shorthand.parse(s: rawstring, len: intptr): {uint64, bool}
var val: uint64 = 0
for i = 0, len do
var v, ok = m.shorthand.cval(s[i])
if ok == false then return 0, false end
val = (val * 64) + v
end
return val, true
end
terra m.truncate64(val: &uint8, len: intptr): uint64
var r: uint64 = 0
for i=0, len do
r = r << 3
r = r + @val
val = val + 1
end
return r
end
m.biggest = macro(function(a,b)
local ty = a.tree.type
if b.tree.type.bytes > ty.bytes then ty = b.tree.type end
return quote
var _a = [a]
var _b = [b]
var r: ty if _a > _b then r = _a else r = _b end
in r end
end)
m.smallest = macro(function(a,b)
local ty = a.tree.type
if b.tree.type.bytes < ty.bytes then ty = b.tree.type end
return quote
var _a = [a]
var _b = [b]
var r: ty if _a < _b then r = _a else r = _b end
in r end
end)
terra m.hexdigit(hb: uint8): int8
var a = hb and 0x0F
if a < 10 then return 0x30 + a
else return 0x61 + (a-10) end
end
terra m.hexbyte(b: uint8): int8[2]
return array(m.hexdigit((b and 0xF0) >> 4), m.hexdigit(b and 0x0F))
end
terra m.hexstr(src: &uint8, str: rawstring, sz: intptr)
for i = 0, sz do
var d = m.hexbyte(src[i])
str[i*2] = d[0]
str[i*2 + 1] = d[1]
end
end
terra m.b32char(v: uint8): int8
if v <= 25 then return 0x61 + v
elseif v < 31 then return 0x32 + (v-26)
else return 0 end
end
terra m.b32(v: uint64, buf: rawstring) -- 5 bytes -> 8 chars
while v > 0 do
var val = v % 32
v = v / 32
@buf = m.b32char(val)
buf = buf + 1
end
end
terra m.b32str(a: lib.mem.ptr(uint64))
end
terra m.decstr(val: intptr, buf: &int8): rawstring
-- works backwards to avoid copies. log10(2^64) ≈ 19.2 and we
-- need a byte for NUL so buf MUST point to THE END OF a buffer
-- at least 21 bytes long
@buf = 0
if val > 0 then while val > 0 do
buf = buf - 1
var dgt = val % 10
val = val / 10
@buf = 0x30 + dgt
end else
buf = buf - 1
@buf = 0x30
end
return buf
end
terra m.decstr_friendly(val: intptr, buf: &int8): rawstring
-- as above except needs size-28 buffers, on account of all the commas
@buf = 0
var dgtct: uint8 = 0
if val > 0 then while val > 0 do
buf = buf - 1
var dgt = val % 10
val = val / 10
@buf = 0x30 + dgt
if dgtct == 2 and val > 0 then
buf = buf - 1 @buf = @','
dgtct = 0
else dgtct = dgtct + 1 end
end else
buf = buf - 1
@buf = 0x30
end
return buf
end
return m