On Wednesday, 4 March 2015 at 18:05:52 UTC, Zach the Mystic wrote:
On Wednesday, 4 March 2015 at 17:22:15 UTC, Steven Schveighoffer wrote:
Again, I think this is an issue with the expectation of RCArray. You cannot *save* a ref to an array element, only a ref to the array itself, because you lose control over the reference count.

What you need is a special RCSlave type, which is reference counted not to the type of its *own* data, but to its parent's. In this case, a RCArraySlave!(T) holds data of type T, but a pointer to an RCArray, which it decrements when it gets destroyed. This could get expensive, with an extra pointer per instance than a regular T, but it would probably be safe.

A way to do this is to have a core RCData type which has the count itself and the chunk of memory the count refers to in type ambiguous form:

struct RCData {
  int count;
  // the point is that RCData can be type ambiguous
  void[] chunk;

  this(size_t size)
  {
    chunk = new void[size];
    count = 0;
  }
  void addRef() {
    ++count;
  }
  void decRef() {
    if (count && --count == 0)
      delete chunk;
  }
}

Over top of that you create a basic element type which refcounts an RCData rather than itself:

struct RCType(E) {
  E element;
  RCType* data;

  this(this)
  {
    data.addRef();
  }

  ~this()
  {
    data.decRef();
  }
  [...etc...]
}

Then you have an RCArray which returns RCType elements when indexed rather than naked types:

struct RCArray(E) {

  E[] array;
  private RCData* data;

  RCElement!E opIndex(size_t i) return
  {
    return RCElement!E(array[start + i], data);
  }

  this(E[] a)
  {
    data = new RCData(a * sizeof(a));
    array = cast(E[]) data.chunk;

  }

  this(this)
  {
    data.addRef();
  }

  ~this()
  {
    data.decRef();
  }

  //...
}

This might work. The idea is to only leak references to types which also have pointers to the original data.

Reply via email to