type Rc[T] = object
      data: ptr T
      refs: ptr int
    
    
    proc rc[T](value: sink T): Rc[T] =
      result.data = cast[ptr T](alloc(sizeof(T)))
      copyMem(result.data, addr value, sizeof(T))
      result.refs = cast[ptr int](alloc(sizeof(int)))
      result.refs[] = 1
    
    
    proc `=copy`[T](dest: var Rc[T]; source: Rc[T]) =
      `=destroy`(dest)
      wasMoved(dest)
      copyMem(addr dest, addr source, sizeof(Rc[T]))
      inc dest.refs[]
    
    
    proc `=destroy`[T](self: Rc[T]) =
      if self.refs == nil: return
      
      dec self.refs[]
      
      if self.refs[] == 0:
        dealloc(self.data)
        dealloc(self.refs)
    
    
    proc `[]`[T](self: Rc[T]): var T = self.data[]
    
    
    type Person = object
      name: string
    
    var original = Person(name: "Soreto")
    var a = rc(original)
    
    block:
      var b = a
      echo "a: " & a[].name
      echo "b: " & b[].name
      echo "refs: " & $a.refs[]
      
      b[].name = "Paulo"
      echo "a: " & a[].name
      echo "b: " & b[].name
      echo "refs: " & $a.refs[]
    
    echo "a: " & a[].name
    echo "refs: " & $a.refs[]
    
    echo "original: " & original.name
    
    
    
    Run

I'm a little confused about those three lines:
    
    
    proc rc[T](value: sink T): Rc[T] =
      result.data = cast[ptr T](alloc(sizeof(T)))
      copyMem(result.data, addr value, sizeof(T))
    
    
    Run

It feels like I'm making two copies: the first one because of the sink (to 
prevent using the value after creating the Rc[T]), and another one to move it 
to the heap. Is there an alternative way to achieve this? I'm asking for 
educational purposes, as Nim already has this functionality.

Another thing that is bothering me is the fact that I can still use `original` 
after calling `rc(original)`. What am I doing wrong here?

After writing this, I came across another puzzling issue. Inside the `=destroy` 
hook, I need to check if the pointer is nil. The problem is, I can't figure out 
when this would be called with a nil pointer.

Reply via email to