-- 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
return m