parsav  mem.t at [5b3a03ad34]

File mem.t artifact e41dd1991a part of check-in 5b3a03ad34


-- vim: ft=terra
local m = {
	zero = macro(function(r)
		return quote
			for i = 0, [r.tree.type.N] do r[i] = 0 end
		end
	end);
	heapa_raw = terralib.externfunction('malloc', intptr -> &opaque);
	heapr_raw = terralib.externfunction('realloc', {&opaque, intptr} -> &opaque);
	heapf = terralib.externfunction('free', &opaque -> {});
	cpy = terralib.externfunction('mempcpy',{&opaque, &opaque, intptr} -> &opaque);
}

m.heapa = macro(function(ty, sz)
	local p = m.ptr(ty:astype())
	return `p {
		ptr = [&ty:astype()](m.heapa_raw(sizeof(ty) * sz));
		ct = sz;
	}
end)

local function mkptr(ty, dyn)
	local t = terralib.types.newstruct(string.format('%s<%s>', dyn and 'ptr' or 'ref', ty))
	t.entries = {
		{'ptr', &ty};
		{'ct', intptr};
	}
	t.ptr_basetype = ty
	local recurse = false
	if ty:isstruct() then
		if ty.methods.free then recurse = true end
	end
	t.metamethods.__not = macro(function(self)
		return `self.ptr
	end)
	if dyn then
		t.methods = {
			free = terra(self: &t): bool
				[recurse and quote
					self.ptr:free()
				end or {}]
				if self.ct > 0 then
					m.heapf(self.ptr)
					self.ct = 0
					return true
				end
				return false
			end;
			init = terra(self: &t, newct: intptr): bool
				var nv = [&ty](m.heapa_raw(sizeof(ty) * newct))
				if nv ~= nil then
					self.ptr = nv
					self.ct = newct
					return true
				else return false end
			end;
			resize = terra(self: &t, newct: intptr): bool
				var nv: &ty
				if self.ct > 0
					then nv = [&ty](m.heapr_raw(self.ptr, sizeof(ty) * newct))
					else nv = [&ty](m.heapa_raw(sizeof(ty) * newct))
				end
				if nv ~= nil then
					self.ptr = nv
					self.ct = newct
					return true
				else return false end
			end;
		}
		terra t:ensure(n: intptr)
			if self.ptr == nil then
				if not self:init(n) then return t {ptr=nil,ct=0} end
			end
			if self.ct >= n then return @self end
			self:resize(n)
			return @self
		end
	end
	terra t:advance(n: intptr)
		self.ptr = self.ptr + n
		self.ct = self.ct - n
		return self.ptr
	end
	if not ty:isstruct() then
		terra t:cmp_raw(other: &ty)
			for i=0, self.ct do
				if self.ptr[i] ~= other[i] then return false end
			end
			return true
		end
		terra t:cmp(other: t)
			if other.ct ~= self.ct then return false end
			return self:cmp_raw(other.ptr)
		end
	end
	return t
end

m.ptr = terralib.memoize(function(ty) return mkptr(ty, true) end)
m.ref = terralib.memoize(function(ty) return mkptr(ty, false) end)

m.vec = terralib.memoize(function(ty)
	local v = terralib.types.newstruct(string.format('vec<%s>', ty.name))
	v.entries = {
		{field = 'storage', type = m.ptr(ty)};
		{field = 'sz', type = intptr};
		{field = 'run', type = intptr};
	}
	local terra biggest(a: intptr, b: intptr)
		if a > b then return a else return b end
	end
	terra v:assure(n: intptr)
		if self.storage.ct < n then
			self.storage:resize(biggest(n, self.storage.ct + self.run))
		end
	end
	v.methods = {
		init = terra(self: &v, run: intptr): bool
			if not self.storage:init(run) then return false end
			self.run = run
			self.sz = 0
			return true
		end;
		new = terra(self: &v): &ty
			self:assure(self.sz + 1)
			self.sz = self.sz + 1
			return self.storage.ptr + (self.sz - 1)
		end;
		push = terra(self: &v, val: ty)
			self:assure(self.sz + 1)
			self.storage.ptr[self.sz] = val
			self.sz = self.sz + 1
		end;
		free = terra(self: &v) self.storage:free() end;
		last = terra(self: &v, idx: intptr): &ty
			if self.sz > idx then
				return self.storage.ptr + (self.sz - (idx+1))
			else lib.bail('vector underrun!') end
		end;
		crush = terra(self: &v)
			self.storage:resize(self.sz)
			return self.storage
		end;
	}
	v.metamethods.__apply = terra(self: &v, idx: intptr): &ty -- no index??
		if self.sz > idx then
			return self.storage.ptr + idx
		else lib.bail('vector overrun!') end
	end
	return v 
end)

return m