std.typecons
This module implements a variety of type constructors, i.e., templates that allow construction of new, useful general-purpose types. Synopsis:// value tuples alias Tuple!(float, "x", float, "y", float, "z") Coord; Coord c; c.field[1] = 1; // access by index c.z = 1; // access by given name alias Tuple!(string, string) DicEntry; // names can be omitted // enumerated values with conversions to and from strings mixin(defineEnum!("Openmode", "READ", "WRITE", "READWRITE", "APPEND")); void foo() { Openmode m = Openmode.READ; string s = enumToString(m); assert(s == "READ"); Openmode m1; assert(enumFromString(s, m1) && m1 == m); } // Rebindable references to const and invariant 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; }Author:
Andrei Alexandrescu, Bartosz Milewski, Don Clugston
- 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.
Example:
- this(RefT p);
- 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;
- this(ref RefT p);
- 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.field[0] for the first field, obj.field[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.
Example:
Tuple!(int, int) point; // assign coordinates point.field[0] = 5; point.field[1] = 6; // read coordinates auto x = point.field[0]; auto y = point.[1];
Tuple members can be named. It is legal to mix named and unnamed members. The method above is still applicable to all fields. Example:
alias Tuple!(int, "index", string, "value") Entry; Entry e; e.index = 4; e.value = "Hello"; assert(e.field[1] == "Hello"); assert(e.field[0] == 4);
Tuples with named fields are distinct types from tuples with unnamed fields, i.e. each naming imparts a separate type for the tuple. Two tuple differing in naming only are still distinct, even though they might have the same structure. Example:
Tuple!(int, "x", int, "y") point1; Tuple!(int, int) point2; assert(!is(typeof(point1) == typeof(point2))); // passes
- The type of the tuple's components.
- Constructor taking one value for each field. Each argument must be implicitly assignable to the respective element of the target.
- 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 equality.
- Assignment from another tuple. Each element of the source must be
implicitly assignable to the respective element of the target.
- 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.
Example:
Tuple!(int, string, float, double) a; a.field[1] = "abc"; a.field[2] = 4.5; auto s = a.slice!(1, 3); static assert(is(typeof(s) == Tuple!(string, float))); assert(s.field[0] == "abc" && s.field[1] == 4.5);
- Converts to string.
- Returns a Tuple object instantiated and initialized according to
the arguments.
Example:
auto value = tuple(5, 6.7, "hello"); assert(value.field[0] == 5); assert(value.field[1] == 6.7); assert(value.field[2] == "hello");
- Defines truly named enumerated values with parsing and stringizing
primitives.
Example:
mixin(defineEnum!("Abc", "A", "B", 5, "C"));
is equivalent to the following code:enum Abc { A, B = 5, C } string enumToString(Abc v) { ... } Abc enumFromString(string s) { ... }
The enumToString function generates the unqualified names of the enumerated values, i.e. "A", "B", and "C". The enumFromString function expects one of "A", "B", and "C", and throws an exception in any other case. A base type can be specified for the enumeration like this:mixin(defineEnum!("Abc", ubyte, "A", "B", "C", 255));
In this case the generated enum will have a ubyte representation. - 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 a; } } 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
However, Rebindable!(Widget) does allow reassignment, while otherwise behaving exactly like a const Widget:auto a = Rebindable!(const Widget)(new Widget); a.y(); // fine a.x = 5; // error! can't modify const a a = new Widget; // fine
You may want to use Rebindable when you want to have mutable storage referring to const objects, for example an array of references that must be sorted in place. Rebindable does not break the soundness of D's type system and does not incur any of the risks usually associated with cast. - Order the provided members to minimize size while preserving alignment.
Returns a declaration to be mixed in.
Example:
struct Banner { mixin(alignForSize!(byte[6], double)(["name", "height"])); }
Alignment is not always optimal for 80-bit reals, nor for structs declared as align(1). BUG:
bugzilla 2029 prevents the signature from being (string[] names...), so we need to use an ugly array literal instead.