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 }