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 }