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 }