1 /**
2  * Reference type abstraction
3  *
4  * License:
5  *   This Source Code Form is subject to the terms of
6  *   the Mozilla Public License, v. 2.0. If a copy of
7  *   the MPL was not distributed with this file, You
8  *   can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * Authors:
11  *   Vladimir Panteleev <vladimir@thecybershadow.net>
12  */
13 
14 module ae.utils.meta.reference;
15 
16 import std.traits;
17 
18 /// typeof(new T) - what we use to refer to an allocated instance
19 template RefType(T)
20 {
21 	static if (is(T == class))
22 		alias T RefType;
23 	else
24 		alias T* RefType;
25 }
26 
27 /// Reverse of RefType
28 template FromRefType(R)
29 {
30 	static if (is(T == class))
31 		alias T FromRefType;
32 	else
33 	{
34 		static assert(is(typeof(*(R.init))), R.stringof ~ " is not dereferenceable");
35 		alias typeof(*(R.init)) FromRefType;
36 	}
37 }
38 
39 /// A type that can be used to store instances of T.
40 /// A struct with T's instance size if T is a class, T itself otherwise.
41 template StorageType(T)
42 {
43 	static if (is(T == class))
44 	{
45 		//alias void*[(__traits(classInstanceSize, T) + size_t.sizeof-1) / size_t.sizeof] StorageType;
46 		//static assert(__traits(classInstanceSize, T) % size_t.sizeof == 0, "TODO"); // union with a pointer
47 
48 		// Use a struct to allow new-ing the type (you can't new a static array directly)
49 		struct StorageType
50 		{
51 			void*[(__traits(classInstanceSize, T) + size_t.sizeof-1) / size_t.sizeof] data;
52 		}
53 	}
54 	else
55 		alias T StorageType;
56 }
57 
58 // ************************************************************************
59 
60 /// Is T a reference type (a pointer or a class)?
61 template isReference(T)
62 {
63 	enum isReference = isPointer!T || is(T==class);
64 }
65 
66 /// Allow passing a constructed object by reference, without redundant indirection.
67 /// The intended use is with types which support the dot operator
68 /// (a non-null class, a struct, or a non-null struct pointer).
69 T* reference(T)(ref T v)
70 	if (!isReference!T)
71 {
72 	return &v;
73 }
74 
75 /// ditto
76 T reference(T)(T v)
77 	if (isReference!T)
78 {
79 	return v;
80 }
81 
82 /// Reverse of "reference".
83 ref typeof(*T.init) dereference(T)(T v)
84 	if (!isReference!T)
85 {
86 	return *v;
87 }
88 
89 /// ditto
90 T dereference(T)(T v)
91 	if (isReference!T)
92 {
93 	return v;
94 }
95 
96 unittest
97 {
98 	Object o = new Object;
99 	assert(o.reference is o);
100 	assert(o.dereference is o);
101 
102 	static struct S {}
103 	S s;
104 	auto p = s.reference;
105 	assert(p is &s);
106 	assert(p.reference is p);
107 }