parsav  math.t at [f8816b0ab5]

File math.t artifact 573a13128c part of check-in f8816b0ab5


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