[ create a new paste ] login | about

Link: http://codepad.org/S4TfIdxc    [ raw code | fork ]

D, pasted on Jan 17:
// TODO: Arrays, Initialization from immutable data, (opDot replacement?)
//

/**
Encapsulates unique ownership of a resource (object or struct).
Unique controls the lifetime of owned resource; it also
provides interface for transferring ownership to/from other
Uniques in a way that at any given time only one Unique has ownership.

Default-constructed Uniques do not own any resources.
Associating a resource with a Unique is performed either with
createUnique() function, or by transferring ownership from another Unique.

Unique is non-copyable.
*/
struct Unique(T) if(is(T==class) || is(T==struct)) {

	static if (is(T==class)) {
		alias T RefT;
	} else {
		alias T* RefT;
	}

	private RefT _p = null;

	/**
	Constructs a Unique from an rvalue Unique of the same (or convertible) type.
	Ownership is transferred from other to this.

	Example:
	---
	class Widget { ... };
	class Button : public Widget { ... };

	Unique!Widget widget = createUnique!Button(); // Button ingerits Widget, downcast ok
	---
	*/
	public this(D : T)(Unique!D other) /*@safe*/
	in  { assert(!_p); }
	out { assert(!other && _p); }
	body {
		_p = other._Transfer();
	}

	/**
	Destroys owned object.
	*/
	/*@safe*/ ~this() {
		_Clear();
	}

	/**
	Assignment of an rvalue Unique of the same (or convertible) type.
	Currently owned object is destroyed and ownership is transferred from other to this.

	Example:
	---
	class Widget { ... };
	class Button : public Widget { ... };

	auto widget = createUnique!Widget();
	assert(widget);
	...
	widget = createUnique!Button();
	assert(widget);
	---

	*/
	ref Unique opAssign(D : T)(Unique!D other) /*@safe*/
	out { assert(!other && _p !is null); }
	body {
		_Clear();
		_p = other._Transfer();
		return this;
	}

	/**
	Boolean conversion for checking if a Unique currently owns an object.
	*/
	B opCast(B : bool)() inout pure nothrow /*@safe*/ {
		return _p !is null;
	}

	/**
	Transfers ownership from this Unique into returned Unique.
	Call this when another Unique expects to take ownership, i.e. when passing
	as a parameter into a function.

	Example:
	---

	Unique!Widget upgradeWidget(Unique!Widget w) { ... }
	
	...

	auto widget = createUnique!Widget();
	// Pass ownership into function, 
	// and then get (possibly different) widget back
	widget = upgradeWidget(widget.release());

	---

	Optional template parameter lets you specify a type for the returned Unique.
	T must be convertible to this type. This helps in cases when explicit conversion
	is needed.

	Example:
	---

	class Widget { ... }
	class Button : Widget { ... }

	void consumeWidget(Unique!Widget w) { ... }

	...

	auto button = createUnique!Button();
	consumeWidget(button.release());				// ERROR, even though there is an appropriate constructor
	consumeWidget(Unique!Widget(button.release()));	// ok, Unique!Widget is constructible from Unique!Button
	consumeWidget(button.release!Widget());			// ok, downcast

	---
	*/
	Unique!B release(B = T)() nothrow /*@safe*/ if (is(T:B))
	out { assert(!_p); }
	body {
		scope(exit) { assert(!_p); }
		return Unique!B(_Transfer());
	}

	// Horrid names for private methods to minimize opDot() collisions
	// x.opDot().transfer() would be even more horrid.
	// TODO: consider migrating all interface into non-member functions?

	static if (is(T==struct)) {
		private ref inout(T) _Get() inout /*@safe*/ { if (!_p) throw new Exception("Dereferencing a null Unique"); return *_p; }
		ref inout(T) opDot() inout /*@safe*/ { return _Get(); }
	} else {
		private inout(T) _Get() inout /*@safe*/ { if (!_p) throw new Exception("Dereferencing a null Unique"); return _p; }
		inout(T) opDot() inout /*@safe*/ { return _Get(); }
	}

	// Rvalue constructor, called by makeUnique()
	// Strangely, it compiles even though template overloads are present?..
	private this(RefT p) nothrow /*@safe*/
	in  { assert(p);  }
	out { assert(_p is p);     }
	body {
		_p = p;
	}

	// Destroys owned object
	private void _Clear() /*@safe*/
	out { assert(_p is null); }
	body {
		if (_p) {
			auto x = _Transfer();
			destroy(x);
		}
	}

	// Releases ownership and returns the object
	private RefT _Transfer() nothrow /*@safe*/
	in  { assert(_p !is null); }
	out { assert(_p is null);  }
	body {
		scope(exit) _p = null;
		return _p;
	}

	// Forbidden operations
	@disable this(this);
	@disable void opAssign(ref Unique);
	@disable this(ref RefT);
	// TODO: disable new?
	//@disable new(size_t);
}

/**
Creates a new Unique owning a resource of type T.

Params:
	T =		type (class or struct) to instantiate
	args =	arguments to pass to T's constructor
*/
Unique!T createUnique(T,Args...)(Args args) /*@safe*/ {
	static if(is(T == class)||is(T == struct)) {
		return Unique!T(new T(args));
	} else {
		static assert(false, "createUnique is only defined for classes and structs");
	}
}


Create a new paste based on this one


Comments: