@@ -238,28 +238,6 @@ proc setLengthStr(s: NimString, newLen: int): NimString {.compilerRtl.} =
238238
239239# ----------------- sequences ----------------------------------------------
240240
241- proc incrSeq (seq: PGenericSeq , elemSize, elemAlign: int ): PGenericSeq {.compilerproc .} =
242- # increments the length by one:
243- # this is needed for supporting ``add``;
244- #
245- # add(seq, x) generates:
246- # seq = incrSeq(seq, sizeof(x));
247- # seq[seq->len-1] = x;
248- result = seq
249- if result .len >= result .space:
250- let r = resize (result .space)
251- result = cast [PGenericSeq ](growObj (result , align (GenericSeqSize , elemAlign) + elemSize * r))
252- result .reserved = r
253- inc (result .len)
254-
255- proc incrSeqV2 (seq: PGenericSeq , elemSize, elemAlign: int ): PGenericSeq {.compilerproc .} =
256- # incrSeq version 2
257- result = seq
258- if result .len >= result .space:
259- let r = resize (result .space)
260- result = cast [PGenericSeq ](growObj (result , align (GenericSeqSize , elemAlign) + elemSize * r))
261- result .reserved = r
262-
263241proc incrSeqV3 (s: PGenericSeq , typ: PNimType ): PGenericSeq {.compilerproc .} =
264242 if s == nil :
265243 result = cast [PGenericSeq ](newSeq (typ, 1 ))
@@ -274,112 +252,68 @@ proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerproc.} =
274252 # since we steal the content from 's', it's crucial to set s's len to 0.
275253 s.len = 0
276254
277- proc setLengthSeq (seq: PGenericSeq , elemSize, elemAlign, newLen: int ): PGenericSeq {.
278- compilerRtl , inl .} =
279- result = seq
280- if result .space < newLen:
281- let r = max (resize (result .space), newLen)
282- result = cast [PGenericSeq ](growObj (result , align (GenericSeqSize , elemAlign) + elemSize * r))
283- result .reserved = r
284- elif newLen < result .len:
285- # we need to decref here, otherwise the GC leaks!
286- when not defined (boehmGC) and not defined (nogc) and
287- not defined (gcMarkAndSweep) and not defined (gogc) and
288- not defined (gcRegions):
289- if ntfNoRefs notin extGetCellType (result ).base.flags:
290- for i in newLen.. result .len- 1 :
291- forAllChildrenAux (dataPointer (result , elemAlign, elemSize, i),
292- extGetCellType (result ).base, waZctDecRef)
293-
294- # XXX: zeroing out the memory can still result in crashes if a wiped-out
295- # cell is aliased by another pointer (ie proc parameter or a let variable).
296- # This is a tough problem, because even if we don't zeroMem here, in the
297- # presence of user defined destructors, the user will expect the cell to be
298- # "destroyed" thus creating the same problem. We can destroy the cell in the
299- # finalizer of the sequence, but this makes destruction non-deterministic.
300- zeroMem (dataPointer (result , elemAlign, elemSize, newLen), (result .len-% newLen) *% elemSize)
301- result .len = newLen
302-
303- proc setLengthSeqUninit (s: PGenericSeq , typ: PNimType , newLen: int , isTrivial: bool ): PGenericSeq {.
304- compilerRtl .} =
305- sysAssert typ.kind == tySequence, " setLengthSeqUninit: type is not a seq"
255+ proc extendCapacityRaw (src: PGenericSeq ; typ: PNimType ;
256+ elemSize, elemAlign, newLen: int ): PGenericSeq {.inline .} =
257+ # # Reallocs `src` to fit `newLen` elements without any checks.
258+ # # Capacity always increases to at least next `resize` step.
259+ let newCap = max (resize (src.space), newLen)
260+ result = cast [PGenericSeq ](newSeq (typ, newCap))
261+ copyMem (dataPointer (result , elemAlign), dataPointer (src, elemAlign), src.len * elemSize)
262+ # since we steal the content from 's', it's crucial to set s's len to 0.
263+ src.len = 0
264+
265+ proc truncateRaw (src: PGenericSeq ; baseFlags: set [TNimTypeFlag ]; isTrivial: bool ;
266+ elemSize, elemAlign, newLen: int ): PGenericSeq {.inline .} =
267+ # # Truncates `src` to `newLen` without any checks.
268+ # # Does not set `src.len`
269+ # sysAssert src.space > newlen
270+ # sysAssert newLen < src.len
271+ result = src
272+ # we need to decref here, otherwise the GC leaks!
273+ when not defined (boehmGC) and not defined (nogc) and
274+ not defined (gcMarkAndSweep) and not defined (gogc) and
275+ not defined (gcRegions):
276+ if ntfNoRefs notin baseFlags:
277+ for i in newLen..< result .len:
278+ forAllChildrenAux (dataPointer (result , elemAlign, elemSize, i),
279+ extGetCellType (result ).base, waZctDecRef)
280+ # XXX: zeroing out the memory can still result in crashes if a wiped-out
281+ # cell is aliased by another pointer (ie proc parameter or a let variable).
282+ # This is a tough problem, because even if we don't zeroMem here, in the
283+ # presence of user defined destructors, the user will expect the cell to be
284+ # "destroyed" thus creating the same problem. We can destroy the cell in the
285+ # finalizer of the sequence, but this makes destruction non-deterministic.
286+ if not isTrivial: # optimization for trivial types
287+ zeroMem (dataPointer (result , elemAlign, elemSize, newLen),
288+ ((result .len-% newLen) *% elemSize))
289+
290+ template setLengthSeqImpl (s: PGenericSeq , typ: PNimType , newLen: int ; isTrivial: bool ;
291+ doInit: static bool ) =
306292 if s == nil :
307- if newLen == 0 :
308- result = s
309- else :
310- result = cast [PGenericSeq ](newSeq (typ, newLen))
293+ if newLen == 0 : return s
294+ else : return cast [PGenericSeq ](newSeq (typ, newLen)) # newSeq zeroes!
311295 else :
312296 let elemSize = typ.base.size
313297 let elemAlign = typ.base.align
314- if s.space < newLen:
315- let r = max (resize (s.space), newLen)
316- result = cast [PGenericSeq ](newSeq (typ, r))
317- copyMem (dataPointer (result , elemAlign), dataPointer (s, elemAlign), s.len * elemSize)
318- # since we steal the content from 's', it's crucial to set s's len to 0.
319- s.len = 0
320- elif newLen < s.len:
321- result = s
322- # we need to decref here, otherwise the GC leaks!
323- when not defined (boehmGC) and not defined (nogc) and
324- not defined (gcMarkAndSweep) and not defined (gogc) and
325- not defined (gcRegions):
326- if ntfNoRefs notin typ.base.flags:
327- for i in newLen.. result .len- 1 :
328- forAllChildrenAux (dataPointer (result , elemAlign, elemSize, i),
329- extGetCellType (result ).base, waZctDecRef)
330-
331- # XXX: zeroing out the memory can still result in crashes if a wiped-out
332- # cell is aliased by another pointer (ie proc parameter or a let variable).
333- # This is a tough problem, because even if we don't zeroMem here, in the
334- # presence of user defined destructors, the user will expect the cell to be
335- # "destroyed" thus creating the same problem. We can destroy the cell in the
336- # finalizer of the sequence, but this makes destruction non-deterministic.
337- if not isTrivial: # optimization for trivial types
338- zeroMem (dataPointer (result , elemAlign, elemSize, newLen), (result .len-% newLen) *% elemSize)
339- else :
340- result = s
298+ result = if newLen > s.space:
299+ s.extendCapacityRaw (typ, elemSize, elemAlign, newLen)
300+ elif newLen < s.len:
301+ s.truncateRaw (typ.base.flags, isTrivial, elemSize, elemAlign, newLen)
302+ else :
303+ when doInit:
304+ zeroMem (dataPointer (s, elemAlign, elemSize, s.len), (newLen-% s.len) *% elemSize)
305+ s
341306 result .len = newLen
342307
308+ proc setLengthSeqUninit (s: PGenericSeq ; typ: PNimType ; newLen: int ; isTrivial: bool ): PGenericSeq {.
309+ compilerRtl .} =
310+ sysAssert typ.kind == tySequence, " setLengthSeqUninit: type is not a seq"
311+ setLengthSeqImpl (s, typ, newLen, isTrivial, doInit = false )
312+
343313proc setLengthSeqV2 (s: PGenericSeq , typ: PNimType , newLen: int , isTrivial: bool ): PGenericSeq {.
344314 compilerRtl .} =
345315 sysAssert typ.kind == tySequence, " setLengthSeqV2: type is not a seq"
346- if s == nil :
347- if newLen == 0 :
348- result = s
349- else :
350- result = cast [PGenericSeq ](newSeq (typ, newLen))
351- else :
352- let elemSize = typ.base.size
353- let elemAlign = typ.base.align
354- if s.space < newLen:
355- let r = max (resize (s.space), newLen)
356- result = cast [PGenericSeq ](newSeq (typ, r))
357- copyMem (dataPointer (result , elemAlign), dataPointer (s, elemAlign), s.len * elemSize)
358- # since we steal the content from 's', it's crucial to set s's len to 0.
359- s.len = 0
360- elif newLen < s.len:
361- result = s
362- # we need to decref here, otherwise the GC leaks!
363- when not defined (boehmGC) and not defined (nogc) and
364- not defined (gcMarkAndSweep) and not defined (gogc) and
365- not defined (gcRegions):
366- if ntfNoRefs notin typ.base.flags:
367- for i in newLen.. result .len- 1 :
368- forAllChildrenAux (dataPointer (result , elemAlign, elemSize, i),
369- extGetCellType (result ).base, waZctDecRef)
370-
371- # XXX: zeroing out the memory can still result in crashes if a wiped-out
372- # cell is aliased by another pointer (ie proc parameter or a let variable).
373- # This is a tough problem, because even if we don't zeroMem here, in the
374- # presence of user defined destructors, the user will expect the cell to be
375- # "destroyed" thus creating the same problem. We can destroy the cell in the
376- # finalizer of the sequence, but this makes destruction non-deterministic.
377- if not isTrivial: # optimization for trivial types
378- zeroMem (dataPointer (result , elemAlign, elemSize, newLen), (result .len-% newLen) *% elemSize)
379- else :
380- result = s
381- zeroMem (dataPointer (result , elemAlign, elemSize, result .len), (newLen-% result .len) *% elemSize)
382- result .len = newLen
316+ setLengthSeqImpl (s, typ, newLen, isTrivial, doInit = true )
383317
384318func capacity * (self: string ): int {.inline .} =
385319 # # Returns the current capacity of the string.
@@ -402,3 +336,4 @@ func capacity*[T](self: seq[T]): int {.inline.} =
402336
403337 let sek = cast [PGenericSeq ](self)
404338 result = if sek != nil : sek.space else : 0
339+
0 commit comments