This module implements a variety of type constructors, i.e., templates that allow construction of new, useful general-purpose types.
// value tuples alias Tuple!(float, "x", float, "y", float, "z") Coord; Coord c; c[1] = 1; // access by index c.z = 1; // access by given name alias Tuple!(string, string) DicEntry; // names can be omitted // Rebindable references to const and immutable objects void bar() { const w1 = new Widget, w2 = new Widget; w1.foo(); // w1 = w2 would not work; can't rebind const object auto r = Rebindable!(const Widget)(w1); // invoke method as if r were a Widget object r.foo(); // rebind r to refer to another object r = w2; }
Encapsulates unique ownership of a resource. Resource of type T is deleted at the end of the scope, unless it is transferred. The transfer can be explicit, by calling release, or implicit, when returning Unique from a function. The resource can be a polymorphic class object, in which case Unique behaves polymorphically too.
Constructor that takes an rvalue. It will ensure uniqueness, as long as the rvalue isn't just a view on an lvalue (e.g., a cast) Typical usage:
Unique!(Foo) f = new Foo;
Constructor that takes an lvalue. It nulls its source. The nulling will ensure uniqueness as long as there are no previous aliases to the source.
Returns a unique rvalue. Nullifies the current contents
Forwards member access to contents
Tuple of values, for example Tuple!(int, string) is a record that stores an int and a string. Tuple can be used to bundle values together, notably when returning multiple values from a function. If obj is a tuple, the individual members are accessible with the syntax obj[0] for the first field, obj[1] for the second, and so on.
The choice of zero-based indexing instead of one-base indexing was motivated by the ability to use value tuples with various compile-time loop constructs (e.g. type tuple iteration), all of which use zero-based indexing.
Tuple!(int, int) point; // assign coordinates point[0] = 5; point[1] = 6; // read coordinates auto x = point[0]; auto y = point[1];
alias Tuple!(int, "index", string, "value") Entry; Entry e; e.index = 4; e.value = "Hello"; assert(e[1] == "Hello"); assert(e[0] == 4);
Tuple!(int, "x", int, "y") point1; Tuple!(int, int) point2; assert(!is(typeof(point1) == typeof(point2))); // passes
The type of the tuple's components.
Use t. expand for a tuple t to expand it into its components. The result of expand acts as if the tuple components were listed as a list of values. (Ordinarily, a Tuple acts as a single value.)
auto t = tuple(1, " hello ", 2.3); writeln(t); // Tuple!(int, string, double)(1, " hello ", 2.3) writeln(t.expand); // 1 hello 2.3
Constructor taking one value for each field. Each argument must be implicitly assignable to the respective element of the target.
Constructor taking a compatible array. The array element type must be implicitly assignable to each element of the target.
int[2] ints; Tuple!(int, int) t = ints;
Constructor taking a compatible tuple. Each element of the source must be implicitly assignable to the respective element of the target.
Comparison for equality.
Comparison for ordering.
Assignment from another tuple. Each element of the source must be implicitly assignable to the respective element of the target.
Takes a slice of the tuple.
Tuple!(int, string, float, double) a; a[1] = "abc"; a[2] = 4.5; auto s = a.slice!(1, 3); static assert(is(typeof(s) == Tuple!(string, float))); assert(s[0] == "abc" && s[1] == 4.5);
Converts to string.
Returns a Tuple object instantiated and initialized according to the arguments.
auto value = tuple(5, 6.7, "hello"); assert(value[0] == 5); assert(value[1] == 6.7); assert(value[2] == "hello");
Returns true if and only if T is an instance of the Tuple struct template.
Rebindable!(T) is a simple, efficient wrapper that behaves just like an object of type T, except that you can reassign it to refer to another object. For completeness, Rebindable!(T) aliases itself away to T if T is a non-const object type. However, Rebindable!(T) does not compile if T is a non-class type.
Regular const object references cannot be reassigned:
class Widget { int x; int y() const { return x; } } const a = new Widget; a.y(); // fine a.x = 5; // error! can't modify const a a = new Widget; // error! can't modify const a
auto a = Rebindable!(const Widget)(new Widget); a.y(); // fine a.x = 5; // error! can't modify const a a = new Widget; // fine
Convenience function for creating a Rebindable using automatic type inference.
This function simply returns the Rebindable object passed in. It's useful in generic programming cases when a given object may be either a regular class or a Rebindable.
Order the provided members to minimize size while preserving alignment. Returns a declaration to be mixed in.
struct Banner { mixin(alignForSize!(byte[6], double)(["name", "height"])); }
Defines a value paired with a distinctive "null" state that denotes the absence of a value. If default constructed, a Nullable!T object starts in the null state. Assigning it renders it non-null. Calling nullify can nullify it again.
Nullable!int a; assert(a.isNull); a = 5; assert(!a.isNull); assert(a == 5);
Constructor initializing this with value.
Returns true if and only if this is in the null state.
Forces this to the null state.
Assigns value to the internally-held state. If the assignment succeeds, this becomes non-null.
Gets the value. this must not be in the null state. This function is also called for the implicit conversion to T.
Just like Nullable!T, except that the null state is defined as a particular value. For example, Nullable!(uint, uint.max) is an uint that sets aside the value uint.max to denote a null state. Nullable!(T, nullValue) is more storage-efficient than Nullable!T because it does not need to store an extra bool.
Constructor initializing this with value.
Returns true if and only if this is in the null state.
Forces this to the null state.
Assigns value to the internally-held state. No null checks are made. Note that the assignment may leave this in the null state.
Gets the value. this must not be in the null state. This function is also called for the implicit conversion to T.
Just like Nullable!T, except that the object refers to a value sitting elsewhere in memory. This makes assignments overwrite the initially assigned value. Internally NullableRef!T only stores a pointer to T (i.e., Nullable!T.sizeof == (T*).sizeof).
Constructor binding this with value.
Binds the internal state to value.
Returns true if and only if this is in the null state.
Forces this to the null state.
Assigns value to the internally-held state.
Gets the value. this must not be in the null state. This function is also called for the implicit conversion to T.
BlackHole!Base is a subclass of Base which automatically implements all abstract member functions in Base as do-nothing functions. Each auto-implemented function just returns the default value of the return type without doing anything.
The name came from Class::BlackHole Perl module by Sean M. Burke.
abstract class C { int m_value; this(int v) { m_value = v; } int value() @property { return m_value; } abstract real realValue() @property; abstract void doSomething(); } void main() { auto c = new BlackHole!C(42); writeln(c.value); // prints "42" // Abstract functions are implemented as do-nothing: writeln(c.realValue); // prints "NaN" c.doSomething(); // does nothing }
WhiteHole!Base is a subclass of Base which automatically implements all abstract member functions as throw-always functions. Each auto-implemented function fails with throwing an Error and does never return. Useful for trapping use of not-yet-implemented functions.
The name came from Class::WhiteHole Perl module by Michael G Schwern.
class C { abstract void notYetImplemented(); } void main() { auto c = new WhiteHole!C; c.notYetImplemented(); // throws an Error }
AutoImplement automatically implements (by default) all abstract member functions in the class or interface Base in specified way.
how | template which specifies how functions will be implemented/overridden.
Two arguments are passed to how: the type Base and an alias to an implemented function. Then how must return an implemented function body as a string. The generated function body can use these keywords:
You may want to use templated property functions (instead of Implicit Template Properties) to generate complex functions: // Prints log messages for each call to overridden functions. string generateLogger(C, alias fun)() @property { import std.traits; enum qname = C.stringof ~ "." ~ __traits(identifier, fun); string stmt; stmt ~= q{ struct Importer { import std.stdio; } }; stmt ~= `Importer.writeln$(LPAREN)"Log: ` ~ qname ~ `(", args, ")"$(RPAREN);`; static if (!__traits(isAbstractFunction, fun)) { static if (is(ReturnType!fun == void)) stmt ~= q{ parent(args); }; else stmt ~= q{ auto r = parent(args); Importer.writeln("--> ", r); return r; }; } return stmt; } |
what | template which determines what functions should be
implemented/overridden.
An argument is passed to what: an alias to a non-final member function in Base. Then what must return a boolean value. Return true to indicate that the passed function should be implemented/overridden. // Sees if fun returns something. template hasValue(alias fun) { enum bool hasValue = !is(ReturnType!(fun) == void); } |
Predefined how-policies for AutoImplement. These templates are used by BlackHole and WhiteHole, respectively.
Extract object which wrapped by wrap.
interface Quack { int quack(); @property int height(); } interface Flyer { @property int height(); } class Duck : Quack { int quack() { return 1; } @property int height() { return 10; } } class Human { int quack() { return 2; } @property int height() { return 20; } } Duck d1 = new Duck(); Human h1 = new Human(); interface Refleshable { int reflesh(); } // does not have structural conformance static assert(!__traits(compiles, d1.wrap!Refleshable)); static assert(!__traits(compiles, h1.wrap!Refleshable)); // strict upcast Quack qd = d1.wrap!Quack; assert(qd is d1); assert(qd.quack() == 1); // calls Duck.quack // strict downcast Duck d2 = qd.unwrap!Duck; assert(d2 is d1); // structural upcast Quack qh = h1.wrap!Quack; assert(qh.quack() == 2); // calls Human.quack // structural downcast Human h2 = qh.unwrap!Human; assert(h2 is h1); // structural upcast (two steps) Quack qx = h1.wrap!Quack; // Human -> Quack Flyer fx = qx.wrap!Flyer; // Quack -> Flyer assert(fx.height == 20); // calls Human.height // strucural downcast (two steps) Quack qy = fx.unwrap!Quack; // Flyer -> Quack Human hy = qy.unwrap!Human; // Quack -> Human assert(hy is h1); // strucural downcast (one step) Human hz = fx.unwrap!Human; // Flyer -> Human assert(hz is h1);
interface A { int run(); } interface B { int stop(); @property int status(); } class X { int run() { return 1; } int stop() { return 2; } @property int status() { return 3; } } auto x = new X(); auto ab = x.wrap!(A, B); A a = ab; B b = ab; assert(a.run() == 1); assert(b.stop() == 2); assert(b.status == 3); static assert(functionAttributes!(typeof(ab).status) & FunctionAttribute.property);
Options regarding auto-initialization of a RefCounted object (see the definition of RefCounted below).
Defines a reference-counted object containing a T value as payload. RefCounted keeps track of all references of an object, and when the reference count goes down to zero, frees the underlying store. RefCounted uses malloc and free for operation.
RefCounted is unsafe and should be used with care. No references
to the payload should be escaped outside the RefCounted object.
The autoInit option makes the object ensure the store is
automatically initialized. Leaving autoInit ==
RefCountedAutoInitialize.yes (the default option) is convenient but
has the cost of a test whenever the payload is accessed. If autoInit == RefCountedAutoInitialize.no, user code must call either
refCountedStore.isInitialized or refCountedStore.ensureInitialized
before attempting to access the payload. Not doing so results in null
pointer dereference.
// A pair of an $(D int) and a $(D size_t) - the latter being the // reference count - will be dynamically allocated auto rc1 = RefCounted!int(5); assert(rc1 == 5); // No more allocation, add just one extra reference count auto rc2 = rc1; // Reference semantics rc2 = 42; assert(rc1 == 42); // the pair will be freed when rc1 and rc2 go out of scope
RefCounted storage implementation.
Returns true if and only if the underlying store has been allocated and initialized.
Returns underlying reference count if it is allocated and initialized (a positive integer), and 0 otherwise.
Makes sure the payload was properly initialized. Such a call is typically inserted before using the payload.
Returns storage implementation struct.
Constructor that initializes the payload.
Assignment operators
Returns a reference to the payload. If (autoInit == RefCountedAutoInitialize.yes), calls refCountedStore.ensureInitialized. Otherwise, just issues assert(refCountedStore.isInitialized). Used with alias refCountedPayload this;, so callers can just use the RefCounted object as a T.
The first overload exists only if autoInit == RefCountedAutoInitialize.yes. So if autoInit == RefCountedAutoInitialize.no or called for a constant or immutable object, then refCountedPayload will also be qualified as safe and nothrow (but will still assert if not initialized).
Make proxy for a.
struct MyInt { private int value; mixin Proxy!value; this(int n){ value = n; } } MyInt n = 10; // Enable operations that original type has. ++n; assert(n == 11); assert(n * 2 == 22); void func(int n) { } // Disable implicit conversions to original type. //int x = n; //func(n);
Library typedef.
Allocates a class object right inside the current scope, therefore avoiding the overhead of new. This facility is unsafe; it is the responsibility of the user to not escape a reference to the object outside the scope.
class A { int x; this() {x = 0;} this(int i){x = i;} } // Standard usage auto a1 = scoped!A(); auto a2 = scoped!A(1); a1.x = 42; assert(a1.x == 42); assert(a2.x == 1); // Restrictions static assert(!is(typeof({ auto e1 = a1; // illegal, scoped objects can't be copied assert([a2][0].x == 42); // ditto alias ScopedObject = typeof(a1); auto e2 = ScopedObject(); //Illegal, must be built via scoped!A auto e3 = ScopedObject(1); //Illegal, must be built via scoped!A }))); // Use with alias alias makeScopedA = scoped!A; auto a6 = makeScopedA(); auto a7 = makeScopedA();
Defines a simple, self-documenting yes/no flag. This makes it easy for APIs to define functions accepting flags without resorting to bool, which is opaque in calls, and without needing to define an enumerated type separately. Using Flag!"Name" instead of bool makes the flag's meaning visible in calls. Each yes/no flag has its own type, which makes confusions and mix-ups impossible.
// Before string getLine(bool keepTerminator) { ... if (keepTerminator) ... ... } ... // Code calling getLine (usually far away from its definition) can't // be understood without looking at the documentation, even by users // familiar with the API. Assuming the reverse meaning // (i.e. "ignoreTerminator") and inserting the wrong code compiles and // runs with erroneous results. auto line = getLine(false); // After string getLine(Flag!"KeepTerminator" keepTerminator) { ... if (keepTerminator) ... ... } ... // Code calling getLine can be easily read and understood even by // people not fluent with the API. auto line = getLine(Flag!"KeepTerminator".yes);
Convenience names that allow using e.g. Yes.encryption instead of Flag!"encryption".yes and No.encryption instead of Flag!"encryption".no.