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 <ae@cy.md>
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 	///
22 	static if (is(T == class))
23 		alias T RefType;
24 	else
25 		alias T* RefType;
26 }
27 
28 /// Reverse of `RefType`
29 template FromRefType(R)
30 {
31 	///
32 	static if (is(T == class))
33 		alias T FromRefType;
34 	else
35 	{
36 		static assert(is(typeof(*(R.init))), R.stringof ~ " is not dereferenceable");
37 		alias typeof(*(R.init)) FromRefType;
38 	}
39 }
40 
41 /// A type that can be used to store instances of T.
42 /// A struct with T's instance size if T is a class, T itself otherwise.
43 template StorageType(T)
44 {
45 	///
46 	static if (is(T == class))
47 	{
48 		//alias void*[(__traits(classInstanceSize, T) + size_t.sizeof-1) / size_t.sizeof] StorageType;
49 		//static assert(__traits(classInstanceSize, T) % size_t.sizeof == 0, "TODO"); // union with a pointer
50 
51 		// Use a struct to allow new-ing the type (you can't new a static array directly)
52 		struct StorageType
53 		{
54 			void*[(__traits(classInstanceSize, T) + size_t.sizeof-1) / size_t.sizeof] data; /// Class data store.
55 		}
56 	}
57 	else
58 		alias T StorageType;
59 }
60 
61 // ************************************************************************
62 
63 /// Is T a reference type (a pointer or a class)?
64 template isReference(T)
65 {
66 	enum isReference = isPointer!T || is(T==class);
67 }
68 
69 /// Allow passing a constructed object by reference, without redundant indirection.
70 /// The intended use is with types which support the dot operator
71 /// (a non-null class, a struct, or a non-null struct pointer).
72 T* reference(T)(ref T v)
73 	if (!isReference!T)
74 {
75 	return &v;
76 }
77 
78 /// ditto
79 T reference(T)(T v)
80 	if (isReference!T)
81 {
82 	return v;
83 }
84 
85 /// Reverse of "reference".
86 ref typeof(*T.init) dereference(T)(T v)
87 	if (!isReference!T)
88 {
89 	return *v;
90 }
91 
92 /// ditto
93 T dereference(T)(T v)
94 	if (isReference!T)
95 {
96 	return v;
97 }
98 
99 unittest
100 {
101 	Object o = new Object;
102 	assert(o.reference is o);
103 	assert(o.dereference is o);
104 
105 	static struct S {}
106 	S s;
107 	auto p = s.reference;
108 	assert(p is &s);
109 	assert(p.reference is p);
110 }