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.