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 (non-null class, or non-class)
67 /// object by reference, without redundant indirection.
68 T* reference(T)(ref T v)
69 	if (!isReference!T)
70 {
71 	return &v;
72 }
73 
74 /// ditto
75 T reference(T)(T v)
76 	if (isReference!T)
77 {
78 	return v;
79 }
80 
81 /// Reverse of "reference".
82 ref typeof(*T.init) dereference(T)(T v)
83 	if (!isReference!T)
84 {
85 	return *v;
86 }
87 
88 /// ditto
89 T dereference(T)(T v)
90 	if (isReference!T)
91 {
92 	return v;
93 }
94 
95 unittest
96 {
97 	Object o = new Object;
98 	assert(o.reference is o);
99 	assert(o.dereference is o);
100 
101 	static struct S {}
102 	S s;
103 	auto p = s.reference;
104 	assert(p is &s);
105 	assert(p.reference is p);
106 }