Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env rdmd -unittest
- import std.stdio, std.typecons;
- version = DebugRefCounted;
- /**
- Offers reference counting on top of any type. Currently not
- implemented for classes.
- */
- struct RefCounted(T) {
- // We allocate payload and counter together.
- private Tuple!(uint, "refs", T, "payload") * data;
- // "empty" object intended for static and immutable methods when
- // the data pointer is null. It won't be modified. We assume the
- // empty object is equivalent to a null stored pointer.
- private static immutable T _empty;
- private ref immutable(T) asImmutable() immutable
- {
- return data ? data.payload : _empty;
- }
- private ref const(T) asConst() const
- {
- return data ? data.payload : _empty;
- }
- // Makes sure that the payload exists and is not shared.
- void ensureUnique()
- {
- if (!data)
- {
- data = new typeof(*data)(1, T.init);
- }
- else if (data.refs > 1)
- {
- data = new typeof(*data)(1, data.payload.dup);
- }
- }
- // Copying adds to the reference count
- this(this)
- {
- if (!data) return;
- ++data.refs;
- version(DebugRefCounted) writeln("Increasing refcount to ", data.refs);
- }
- void opAssign(ref RefCounted rhs)
- {
- if (data == rhs.data) return;
- version(DebugRefCounted) writeln("Assigning to ", data ? "existing object." : "empty object.");
- this.__dtor();
- data = rhs.data;
- if (data) ++data.refs;
- }
- // Destruction deletes the target if no more references
- ~this()
- {
- if (!data || --data.refs) return;
- version(DebugRefCounted) writeln("Gone with the wind.");
- data.payload.dispose();
- }
- // Const methods against the data
- auto ref opDispatch(string fun, A...)(auto ref A args) const
- {
- version(DebugRefCounted) writeln("Calling ", fun, "(", args, ") const.");
- return mixin("asConst()." ~ fun ~ "(args)");
- }
- // Immutable methods against the data
- auto ref opDispatch(string fun, A...)(auto ref A args) immutable
- {
- version(DebugRefCounted) writeln("Calling ", fun, "(", args, ") immutable.");
- return mixin("asImmutable()." ~ fun ~ "(args)");
- }
- // Non-const methods always ensure that the payload is unique
- // prior to the call.
- auto ref opDispatch(string fun, A...)(auto ref A args)
- {
- alias typeof(mixin("data.payload." ~ fun ~ "(args)")) Result;
- static if (is(typeof(mixin("asConst()." ~ fun ~ "(args)")) ConstResult))
- {
- // Invoking the method as const would work! Let's see
- // whether the programmer intended it to work the same as
- // for non-const objects.
- static if (is(Result == ConstResult))
- {
- // Same thing, let's save some sweat and call the const method
- version(DebugRefCounted) writeln("Calling ", T.stringof, ".", fun, "(", args, ") const.");
- return mixin("asConst()." ~ fun ~ "(args)");
- }
- else
- {
- // Ehm, must call the non-const version
- ensureUnique();
- assert(data);
- version(DebugRefCounted) writeln("Calling ", T.stringof, ".", fun, "(", args, ").");
- return mixin("data.payload." ~ fun ~ "(args)");
- }
- }
- else
- {
- // Only mutable version is callable.
- version(DebugRefCounted) writeln("Calling ", T.stringof, ".", fun, "(", args, ").");
- ensureUnique();
- assert(data);
- return mixin("data.payload." ~ fun ~ "(args)");
- }
- }
- }
- /**
- Doubly-linked list prototype.
- */
- struct DListImpl(T)
- {
- struct Node
- {
- Node * prev, next;
- T payload;
- this(T payload)
- {
- this.payload = payload;
- }
- }
- Node * root;
- static void connect(Node* first, Node* second)
- {
- assert(first && second);
- first.next = second;
- second.prev = first;
- }
- void insertFront(T value)
- {
- auto n = new Node(value);
- if (root)
- {
- connect(n, root);
- }
- root = n;
- }
- @property ref T front()
- {
- assert(root);
- return root.payload;
- }
- @property bool empty() const
- {
- return !root;
- }
- void dispose()
- {
- for (auto n = root; n; )
- {
- auto goner = n;
- n = n.next;
- delete goner;
- }
- root = null;
- }
- DListImpl dup()
- {
- DListImpl result;
- if (!root) return result;
- result.root = new Node(root.payload);
- auto target = root;
- for (auto n = root.next; n; n = n.next)
- {
- auto dupe = new Node(n.payload);
- connect(target, dupe);
- target = dupe;
- }
- return result;
- }
- }
- template DList(T)
- {
- alias RefCounted!(DListImpl!T) DList;
- }
- unittest
- {
- DList!int lst;
- assert(lst.empty);
- lst.insertFront(42);
- assert(lst.front == 42);
- auto p = &lst.front;
- assert(*p == 42);
- // Assignment
- lst = lst;
- DList!int lst2;
- lst2 = lst;
- lst2.insertFront(43);
- assert(lst.front == 42);
- assert(lst2.front == 43);
- lst = lst2;
- }
- void main(){}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement