Differences From
Artifact [d98a573fe7]:
107 107 end
108 108
109 109 struct m.acc {
110 110 buf: rawstring
111 111 sz: intptr
112 112 run: intptr
113 113 space: intptr
114 + pool: &lib.mem.pool
114 115 }
115 116
116 117 terra m.cdowncase(c: int8)
117 118 if c >= @'A' and c <= @'Z' then
118 119 return c + (@'a' - @'A')
119 120 else return c end
120 121 end
................................................................................
127 128
128 129 local terra biggest(a: intptr, b: intptr)
129 130 if a > b then return a else return b end
130 131 end
131 132
132 133 terra m.acc:init(run: intptr)
133 134 --lib.dbg('initializing string accumulator')
135 + self.pool = nil
134 136 if run == 0 then
135 137 lib.warn('attempted to allocate zero-length string accumulator')
136 138 self.buf = nil
137 139 else
138 140 self.buf = [rawstring](lib.mem.heapa_raw(run))
139 141 if self.buf == nil then
140 142 lib.warn('string buffer allocation failed, very little memory availble')
................................................................................
141 143 end
142 144 end
143 145 self.run = lib.trn(self.buf == nil, 0, run)
144 146 self.space = self.run
145 147 self.sz = 0
146 148 return self
147 149 end;
150 +
151 +terra m.acc:pool(pool: &lib.mem.pool, run: intptr)
152 + self.buf = [&int8](pool:alloc_bytes(run))
153 + self.pool = pool
154 + self.run = run
155 + self.space = self.run
156 + self.sz = 0
157 + return self
158 +end
148 159
149 160 terra m.acc:free()
150 161 --lib.dbg('freeing string accumulator')
162 + if self.pool ~= nil then
163 + lib.dbg('attempted to free pooled string accumulator; use frame-reset instead')
164 + return
165 + end
151 166 if self.buf ~= nil and self.space > 0 then
152 167 lib.mem.heapf(self.buf)
153 168 end
154 169 end;
155 170
156 171 terra m.acc:crush()
157 172 --lib.dbg('crushing string accumulator')
173 + if self.pool ~= nil then return self end -- no point unless at end of buffer
158 174 self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.sz))
159 175 self.space = self.sz
160 176 return self
161 177 end;
162 178
163 179 terra m.acc:finalize()
164 180 --lib.dbg('finalizing string accumulator')
................................................................................
169 185 self.buf = nil
170 186 self.sz = 0
171 187 return pt
172 188 end;
173 189
174 190 terra m.acc:cue(sz: intptr)
175 191 if sz <= self.run then return end
192 + var curspace = self.space
176 193 self.run = sz
177 194 if self.space - self.sz < self.run then
178 195 self.space = self.sz + self.run
179 - self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.space))
196 + if self.pool ~= nil then
197 + self.buf = [&int8](self.pool:realloc_bytes(self.buf, curspace, self.space))
198 + else
199 + self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.space))
200 + end
180 201 end
181 202 end
182 203
183 204 terra m.acc:reset() -- semantic convenience function
184 205 self.sz = 0
185 206 end
186 207
................................................................................
189 210 if str == nil then return self end
190 211 --if str[len - 1] == 0xA then llen = llen - 1 end -- don't display newlines in debug output
191 212 -- lib.dbg('pushing "',{str,llen},'" onto accumulator')
192 213 if self.buf == nil then self:init(self.run) end
193 214 if self.buf == nil then lib.warn('attempted to push string onto unallocated accumulator') return self end
194 215 if len == 0 then len = m.sz(str) end
195 216 if len >= self.space - self.sz then
196 - self.space = self.space + biggest(self.run,len + 1)
197 - self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.space))
217 + self:cue(self.space + biggest(self.run,len + 1))
218 + --self.space = self.space + biggest(self.run,len + 1)
219 + --self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.space))
198 220 end
199 221 lib.mem.cpy(self.buf + self.sz, str, len)
200 222 self.sz = self.sz + len
201 223 self.buf[self.sz] = 0
202 224 return self
203 225 end;
204 226
................................................................................
242 264 return `self:push([str:asvalue()], [#(str:asvalue())]) end)
243 265 m.acc.methods.ppush = terra(self: &m.acc, str: lib.mem.ptr(int8))
244 266 self:push(str.ptr, str.ct) return self end;
245 267 m.acc.methods.rpush = terra(self: &m.acc, str: lib.mem.ref(int8))
246 268 self:push(str.ptr, str.ct) return self end;
247 269 m.acc.methods.merge = terra(self: &m.acc, str: lib.mem.ptr(int8))
248 270 self:push(str.ptr, str.ct) str:free() return self end;
249 -m.acc.methods.compose = macro(function(self, ...)
271 +local composefn = function(call, ...)
250 272 local minlen = 0
251 273 local pstrs = {}
252 274 for i,v in ipairs{...} do
253 275 if type(v) == 'table' then
254 276 local gl = 16 -- guess wildly
255 277 if v.tree and v.tree.type.convertible == 'tuple' then
256 278 pstrs[#pstrs+1] = {str = `v._0, len = `v._1}
................................................................................
263 285 else pstrs[#pstrs+1] = {str = v, len = 0} end
264 286 minlen = minlen + gl
265 287 elseif type(v) == 'string' then
266 288 pstrs[#pstrs+1] = {str = v, len = #v}
267 289 minlen = minlen + #v + 1
268 290 else error('invalid type in compose expression') end
269 291 end
270 - local call = `self:init(minlen)
292 + call = call(minlen) --`self:init(minlen)
271 293 for i,v in ipairs(pstrs) do
272 294 call = `[call]:push([v.str],[v.len])
273 295 end
274 296 return call
297 +end
298 +m.acc.methods.compose = macro(function(self, ...)
299 + return composefn(function(minlen) return `self:init(minlen) end, ...)
300 +end)
301 +m.acc.methods.pcompose = macro(function(self, pool, ...)
302 + return composefn(function(minlen) return `self:pool(pool,minlen) end, ...)
275 303 end)
304 +
276 305 m.acc.metamethods.__lshift = terralib.overloadedfunction('(<<)', {
277 306 terra(self: &m.acc, str: rawstring) return self: push(str,0) end;
278 307 terra(self: &m.acc, str: lib.mem.ptr(int8)) return self:ppush(str ) end;
279 308 })
280 309
281 310 m.box = terralib.memoize(function(ty)
282 311 local b = struct {