I'm trying to understand how the [lifetime-tracking 
hooks](https://nim-lang.github.io/Nim/destructors.html) work, but I'm not sure 
if I'm doing it correctly. The code below is an implementation of a slab (an 
array with reusable slots). It is almost an exact copy of the 
[example](https://nim-lang.github.io/Nim/destructors.html#motivating-example).

  1. Inside the `=destroy` hook, I'm using a try/except because the compiler is 
indicating that ``=destroy`(self.data[i])` will raise an exception.
  2. When will `=dup` be called instead of copy?
  3. In the 
[example](https://nim-lang.github.io/Nim/destructors.html#motivating-example), 
the `=dup` hook is annotated with `{.nodestroy.}`. Is there any particular 
reason for this?


    
    
    type
      Key = distinct uint64
      
      Slab*[T] = object
        len, cap: uint64
        data: ptr UncheckedArray[T]
        
        available: seq[Key]
        highestKey: uint64
    
    
    proc `=destroy`[T](self: Slab[T])=
      if self.data != nil:
        for i in 0..<self.len:
          try: `=destroy`(self.data[i])
          except: discard
        dealloc(self.data)
    
    
    proc `=trace`[T](self: var Slab[T], env: pointer) =
      if self.data == nil: return
      for i in 0..<self.len: `=trace`(self.data[i], env)
    
    
    proc `=copy`[T](dest: var Slab[T], src: Slab[T]) =
      if dest.data == src.data: return
      `=destroy`(dest)
      wasMoved(dest)
      
      dest.len = src.len
      dest.cap = src.cap
      
      if src.data == nil: return
      dest.data = cast[typeof(src.data)](alloc(dest.cap * uint64(sizeof(T))))
      for i in 0..<dest.len:
        dest.data[i] = src.data[i]
    
    
    proc `=sink`[T](dest: var Slab[T], src: Slab[T]) =
      `=destroy`(dest)
      wasMoved(dest)
      
      dest.len = src.len
      dest.cap = src.cap
      dest.data = src.data
    
    
    proc `=dup`[T](self: Slab[T]): Slab[T] =
      result.len = self.len
      result.cap = self.cap
      
      if self.data != nil:
        result.data = cast[typeof(result.data)](alloc(result.cap * 
uint64(sizeof(T))))
        for i in 0..<result.len:
          result.data[i] = `=dup`(self.data[i])
    
    
    proc len*[T](self: Slab[T]): uint64 = self.len
    
    
    proc capacity*[T](self: Slab[T]): uint64 = self.cap
    
    
    proc `[]`*[T](self: Slab[T], key: Key): lent T=
      self.data[uint64(key)]
    
    
    proc add*[T](self: var Slab[T], value: sink T): Key =
      if self.available.len > 0:
        return self.available.pop()
      
      result = Key(self.highestKey)
      inc self.highestKey
      
      self.data[uint64(result)] = value
      inc self.len
    
    
    proc remove*[T](self: var Slab[T], key: sink Key): T =
      result = self.data[uint64(key)]
      self.available.add(key)
      dec self.len
    
    
    proc clear*[T](self: var Slab[T]) = discard
    
    
    proc initSlab*[T](capacity: uint64 = 1024): Slab[T] =
      result.cap = capacity
      result.len = 0
      result.data = cast[typeof(result.data)](alloc0(result.cap * 
uint64(sizeof(T))))
      
      result.available = @[]
      result.highestKey = 0
    
    
    iterator items*[T](self: var Slab[T]): lent T =
      for i in 0..<self.highestKey:
        yield self.data[i]
    
    
    
    Run

Reply via email to