-- 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)
function m.cache(ty,sz)
sz = sz or 32
local struct c {
store: ty[sz]
top: intptr
cur: intptr
}
c.name = string.format('cache<%s,%u>', tostring(ty), sz)
terra c:insert(v: ty)
if [ty.ptr_basetype ~= nil] then
if self.cur < self.top then self.store[self.cur]:free() end
end
self.store[self.cur] = v
self.top = lib.math.biggest(self.top, self.cur + 1)
self.cur = (self.cur + 1) % sz
return v
end
c.metamethods.__apply = terra(self: &c, idx: intptr) return &self.store[idx] end
if ty.ptr_basetype then
terra c:free()
for i=0,self.top do self.store[i]:free() end
end
end
return c
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
if newct == 0 then self.ct = 0 self.ptr = nil return false end
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:init(run: intptr): bool
if not self.storage:init(run) then return false end
self.run = run
self.sz = 0
return true
end;
terra v:assure(n: intptr)
if self.storage.ct < n then
self.storage:resize(biggest(n, self.storage.ct + self.run))
end
end
terra v:new(): &ty
self:assure(self.sz + 1)
self.sz = self.sz + 1
return self.storage.ptr + (self.sz - 1)
end;
terra v:push(val: ty)
self:assure(self.sz + 1)
self.storage.ptr[self.sz] = val
self.sz = self.sz + 1
end;
terra v:free() self.storage:free() end;
terra v:last(idx: intptr): &ty
if self.sz > idx then
return self.storage.ptr + (self.sz - (idx+1))
else lib.bail('vector underrun!') end
end;
terra v:crush()
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