module cow_bug; import std.string : format; import std.stdio : writefln, writef; struct COWArray(T) { private { T[] arr = null; size_t* ctr = null; } /* * Returns cowarray definition as a string for debugging */ debug private string stat() { return format("COWArray(0x%08x[0..%d]) @ %d", arr.ptr, arr.length, ctr ? *ctr : 0); } /* * Post-blit function; increment reference count since we've just been * copied. */ this(this) in{debug writefln("> this(this); ",stat);} out{debug writefln("< this(this); ",stat);} body { ++ *(this.ctr); } /* * Dtor; decrement ref count, destroy memory if the counter is zero. */ ~this() in{debug writefln("> ~this(); ",stat);} out{debug writefln("< ~this(); ",stat);} body { // Accounts for empty cowarrays. if( this.ctr ) { -- *(this.ctr); if( *(this.ctr) == 0 ) delete this.ctr; } } const size_t length() { return arr.length; } COWArray opAssign(T[] arr) in{debug writefln("> opAssign(T[]); ",stat);} out{debug writefln("< opAssign(T[]); ",stat);} body { // If we already have an array, dec ref, destroy if counter == 0. if( this.ctr !is null ) { -- *(this.ctr); if( *(this.ctr) == 0 ) delete this.ctr; } // Attach to new array, assume no aliasing. this.arr = arr; this.ctr = new size_t; *(this.ctr) = 1; return this; } string toString() { return format("%s", this.arr); } } void main() { // New array, no ctor, so it's not pointing at anything, and has zero // length. COWArray!(int) a; // opAssign array; should have a single reference. a = [1,2,3,4]; // This shouldn't affect ref counts auto a_str = a.toString; writefln("a: %s", a_str); // Should have one reference, zero after the dtor, and the memory should // be deleted. }