1 // SemiTwist Library 2 // Written in the D programming language. 3 4 module semitwist.refbox; 5 6 import std.stdio; 7 import std.math; 8 import std..string; 9 import std.algorithm : find; 10 11 import semitwist.util.all; 12 13 //TODO: Does phobos's Variant make this obsolete? 14 //TODO? convert to struct 15 /// A boxable wrapper useful for variables of primitive types. 16 class RefBox(T) 17 { 18 private T* val; 19 private T optionalValSrc; 20 21 this() 22 { 23 this.val = &optionalValSrc; 24 } 25 26 this(T* val) 27 { 28 this.val = val; 29 } 30 31 T opCall() 32 { 33 return *val; 34 } 35 36 void opAssign(T val) 37 { 38 *this.val = val; 39 } 40 41 const bool opEquals(ref const(RefBox!(T)) val) 42 { 43 return *this.val == *val.val; 44 } 45 46 const bool opEquals(ref const(T) val) 47 { 48 return *this.val == val; 49 } 50 51 RefBox!(T) dup() 52 { 53 auto newBox = new RefBox!(T)(); 54 newBox.optionalValSrc = *this.val; 55 return newBox; 56 } 57 } 58 59 string getRefBoxTypeName(Object o) 60 { 61 string head = RefBox.stringof[0..$-3]~"!("; 62 string unknown = "{unknown}"; 63 string typeName = o.classinfo.name; 64 65 //TODO?: Replace this with a regex search (if possible) and handle nested ()'s 66 67 auto start = locatePrior(typeName, head); 68 if(start == typeName.length) 69 return unknown; 70 start += head.length; 71 72 auto end = locate(typeName[start..$], ')')+start; 73 if(end == typeName.length) 74 return unknown; 75 76 // Nested () inside "RefBox!(...)" is not currently supported 77 if(std.algorithm.find(typeName[start..end], '(') != []) 78 return unknown; 79 80 return typeName[start..end]; 81 } 82 83 /// Helpful templates 84 template unbox(alias obj, string name) 85 { 86 enum unbox = 87 unboxToTypeAndArray!(obj, name~"AsInt", int )~ 88 unboxToTypeAndArray!(obj, name~"AsBool", bool )~ 89 unboxToTypeAndArray!(obj, name~"AsStr", string); 90 //pragma(msg, "unbox:\n" ~ unbox); 91 } 92 93 private template unboxToTypeAndArray(alias obj, string name, type) 94 { 95 enum unboxToTypeAndArray = 96 unboxTo!(obj, name, type.stringof )~ 97 unboxTo!(obj, name~"s", type.stringof~"[]"); 98 } 99 100 private template unboxTo(alias obj, string name, string type) 101 { 102 enum unboxTo = "auto "~name~" = cast(RefBox!("~type~"))"~obj.stringof~";\n"; 103 } 104 105 106 template dupRefBox(alias from, string tempName, alias to) 107 { 108 enum dupRefBox = 109 unbox!(from, tempName)~ 110 "if(false) {}\n"~ 111 dupRefBoxTypeAndArray!(from, tempName~"AsInt", int , to)~ 112 dupRefBoxTypeAndArray!(from, tempName~"AsBool", bool , to)~ 113 dupRefBoxTypeAndArray!(from, tempName~"AsStr", string, to)~ 114 "else "~to.stringof~" = null;\n"; 115 //pragma(msg, "dupRefBox:\n" ~ dupRefBox); 116 } 117 118 private template dupRefBoxTypeAndArray(alias from, string tempName, type, alias to) 119 { 120 enum dupRefBoxTypeAndArray = 121 dupRefBoxFrom!(from, tempName, type.stringof , to)~ 122 dupRefBoxFrom!(from, tempName~"s", type.stringof~"[]", to); 123 } 124 125 private template dupRefBoxFrom(alias from, string tempName, string type, alias to) 126 { 127 enum dupRefBoxFrom = "else if("~tempName~") "~to.stringof~" = "~tempName~".dup();\n"; 128 } 129 130 131 template isKnownRefBox(alias obj) 132 { 133 enum isKnownRefBox = 134 isKnownRefBoxTypeAndArray!(obj, int )~ 135 isKnownRefBoxTypeAndArray!(obj, bool )~ 136 isKnownRefBoxTypeAndArray!(obj, string)~ 137 "false "; 138 //pragma(msg, "isKnownRefBox:\n" ~ isKnownRefBox); 139 } 140 141 private template isKnownRefBoxTypeAndArray(alias obj, type) 142 { 143 enum isKnownRefBoxTypeAndArray = 144 isKnownRefBoxOf!(obj, type.stringof )~ 145 isKnownRefBoxOf!(obj, type.stringof~"[]"); 146 } 147 148 private template isKnownRefBoxOf(alias obj, string type) 149 { 150 enum isKnownRefBoxOf = "cast(RefBox!("~type~"))"~obj.stringof~" ||\n"; 151 }