Reference counting example

cc cc at nevernet.com
Tue Apr 26 22:16:01 UTC 2022


On Tuesday, 26 April 2022 at 06:55:34 UTC, Alain De Vos wrote:
> Can someone provide a simple/very simple reference counting or 
> refcounted example i can understand. Thanks.

I've been playing around with the automem[1] library's RefCounted 
feature as we speak, it seems to fit my needs more than 
std.typecons which doesn't quite do what I want.  I did have to 
make some changes to the library though to allow for inheritance 
and manually releasing (below).  It's pretty fun so far so I'm 
looking forward to trying it in some other projects like a non-GC 
XML library.
[1] https://github.com/atilaneves/automem

Test application:
```d
import std.stdio;
import core.memory;
import util.array; // ARRAY Custom wrapper for std.container.array
// The vector/array library provided with automem does NOT 
properly destroy array elements
// so we'll use std.container.array instead

import std.experimental.allocator.mallocator;
import automem;

alias RC(T) = RefCounted!(T, Mallocator);
// Optional default constructor workaround
auto RCREATE(T, Args...)(auto ref Args args) {
	return RC!T.create(args);
}

class Farm {
	ARRAY!(RC!Cow) animals;
	//this() {}
	this(int) { writeln("[Farm]"); }
	~this() {
		writeln("[~Farm]");
		animals.clear();
		writeln("[/Farm]");
	}

	void pet(RC!Animal animal) {
		writefln("Farm: The %s says...", animal);
		animal.speak;
	}

}
class Animal {
	void speak() {
		writeln("Animal: ???");
	}
}
class Cow : Animal {
	ARRAY!(RC!Animal) friends; // Amazingly, this works, as long as 
the array elem type is NOT the same as RC!(this class)
								// otherwise we get a forwarding error
	int x;
	this() { writefln("[Cow]"); }
	this(int x) { this.x = x; writefln("[Cow %s]", x); }
	~this() { writefln("[/Cow %s]", x); }
	override void speak() {
		writefln("Cow#%s: Moo.", x);
	}
}


void main() {
	auto used = GC.stats.usedSize;
	scope(exit) assert(GC.stats.usedSize == used); // GC is not 
touched!
	{
		assert(RCREATE!Cow.x == 0);
		assert(RCREATE!Cow(99).x == 99);
	}

	RC!Animal other;

	auto farm = RC!Farm(1);
	{
		auto cow = RC!Cow(1);
		farm.animals ~= cow;
		farm.animals ~= RC!Cow(2);
		other = farm.animals[1];
		auto cowGoesOutOfScope = RC!Cow(70);
	}
	writeln("out, should have seen Cow#70's dtor");

	farm.animals[0] = farm.animals[1];
	writeln("animals[0] (Cow#1) just got overwritten so we should 
have seen its dtor");

	farm.animals ~= RC!Cow(3);

	farm.pet(other);
	other = null;

	farm = null;

	writeln("done");
}
```

Output:
```
[Cow]
[/Cow 0]
[Cow 99]
[/Cow 99]
[Farm]
[Cow 1]
[Cow 2]
[Cow 70]
[/Cow 70]
out, should have seen Cow#70's dtor
[/Cow 1]
animals[0] (Cow#1) just got overwritten so we should have seen 
its dtor
[Cow 3]
Farm: The memtest.Cow says...
Cow#2: Moo.
[~Farm]
[/Cow 2]
[/Cow 3]
[/Farm]
done
```


I added the following functions to automem `ref_counted.d`:
```d
     // static .create method to allow use of class's default 
constructor if desired
     static if (isGlobal && is(Type == class) && 
__traits(compiles, new Type())) {
         static auto create(Args...)(auto ref Args args) {
             typeof(this) obj;
             obj.makeObject!args();
             return obj;
         }
     }

     // allow instantiation or assignment from derived classes if 
the Allocator is the same
     this(U)(ref RefCounted!(U,Allocator) rhs) if (is(U == class) 
&& !is(U == Type)) {
         _impl = cast(typeof(_impl)) rhs._impl;
         if(_impl !is null) inc;
     }
     void opAssign(U : Type)(ref RefCounted!(U,Allocator) other) 
if (is(U == class) && !is(U == Type)) {
//        if (_impl == other._impl) return;
         if (_impl._rawMemory.ptr == other._impl._rawMemory.ptr) 
return;
         if(_impl !is null) release;
         static if(!isGlobal)
             _allocator = other._allocator;
         _impl = cast(typeof(_impl)) other._impl;
         if(_impl !is null) inc;
     }

     // Allow assigning null to manually release payload
     void opAssign(typeof(null)) {
         if(_impl !is null) release;
         _impl = null;
     }
```



More information about the Digitalmars-d-learn mailing list