1 module memutils.helpers;
2 public:
3 	import std.traits : isSomeFunction;
4 	import std.range : ElementType;
5 nothrow:
6 @trusted:
7 template UnConst(T) {
8 	static if (is(T U == const(U))) {
9 		alias UnConst = U;
10 	} else static if (is(T V == immutable(V))) {
11 		alias UnConst = V;
12 	} else alias UnConst = T;
13 }
14 
15 
16 // compiler frontend lowers dynamic array deconstruction to this
17 void __ArrayDtor(T)(scope T[] a)
18 {
19     foreach_reverse (ref T e; a)
20         e.__xdtor();
21 }
22 
23 void destructRecurse(E, size_t n)(ref E[n] arr)
24 {
25     static if (hasElaborateDestructor!E)
26     {
27         foreach_reverse (ref elem; arr)
28             destructRecurse(elem);
29     }
30 }
31 
32 void destructRecurse(S)(ref S s)
33     if (is(S == struct))
34 {
35     static if (__traits(hasMember, S, "__dtor") &&
36             // Bugzilla 14746: Check that it's the exact member of S.
37             __traits(isSame, S, __traits(parent, s.__dtor)))
38         s.__dtor();
39 }
40 
41 /// TODO: Imitate Unique! for all objects (assume dtor) with release()
42 /// TODO: implement @override on underlying type T, and check for shadowed members.
43 mixin template Embed(alias OBJ, alias OWNED)
44 {
45 	nothrow:
46 	alias TR = typeof(OBJ);
47 	static if (is(typeof(*OBJ) == struct))
48 			alias T = typeof(*OBJ);
49 	else
50 		alias T = TR;
51 
52 	static if (!isSomeFunction!OBJ)
53 	@property ref const(T) fallthrough() const
54 	{
55 		/*static if (__traits(hasMember, typeof(this), "defaultInit")) {
56 			(cast(typeof(this)*)&this).defaultInit();
57 			checkInvariants();
58 		}*/
59 		static if (is(TR == T*)) return *OBJ;
60 		else return OBJ;
61 	}
62 
63 	@property ref T fallthrough()
64 	{
65 		static if (__traits(hasMember, typeof(this), "defaultInit")) {
66 			defaultInit();
67 			//checkInvariants();
68 		}
69 		static if (is(TR == T*)) return *OBJ;
70 		else return OBJ;
71 	}
72 	
73 	@property ref const(T) opUnary(string op)() const if (op == "*")
74 	{
75 		return this.fallthrough;
76 	}
77 	
78 	
79 	alias fallthrough this;
80 	
81 	static if (!isSomeFunction!OBJ)
82 	@property TR release() {
83 		static if (__traits(hasMember, typeof(this), "defaultInit")) {
84 			defaultInit();
85 			//checkInvariants();
86 		}
87 		TR ret = OBJ;
88 		OBJ = null;
89 		return ret;
90 	}
91 
92 	auto opBinaryRight(string op, Key)(Key key)
93 	inout if (op == "in" && __traits(hasMember, typeof(OBJ), "opBinaryRight")) {
94 		defaultInit();
95 		return fallthrough().opBinaryRight!("in")(key);
96 	}
97 
98 	bool opEquals(U)(auto ref U other) const
99 	{
100 		defaultInit();
101 		return fallthrough().opEquals(other);
102 	}
103 	
104 	int opCmp(U)(auto ref U other) const
105 	{
106 		defaultInit();
107 		return fallthrough().opCmp(other);
108 	}
109 	
110 	int opApply(U...)(U args)
111 		if (__traits(hasMember, typeof(OBJ), "opApply"))
112 	{
113 		defaultInit();
114 		return fallthrough().opApply(args);
115 	}
116 	
117 	int opApply(U...)(U args) const
118 		if (__traits(hasMember, typeof(OBJ), "opApply"))
119 	{
120 		defaultInit();
121 		return fallthrough().opApply(args);
122 	}
123 	
124 	void opSliceAssign(U...)(U args)
125 		if (__traits(hasMember, typeof(OBJ), "opSliceAssign"))
126 	{
127 		defaultInit();
128 		fallthrough().opSliceAssign(args);
129 	}
130 
131 	
132 	auto opSlice(U...)(U args) const
133 		if (__traits(hasMember, typeof(OBJ), "opSlice"))
134 	{
135 		defaultInit();
136 		return (cast()fallthrough()).opSlice(args);
137 		
138 	}
139 
140 	static if (__traits(hasMember, typeof(OBJ), "opDollar"))
141 	size_t opDollar() const
142 	{
143 		return fallthrough().opDollar();
144 	}
145 	
146 	void opOpAssign(string op, U...)(auto ref U args)
147 		if (__traits(compiles, fallthrough().opOpAssign!op(args)))
148 	{
149 		defaultInit();
150 		fallthrough().opOpAssign!op(args);
151 	}
152 	
153 	auto opBinary(string op, U...)(auto ref U args)
154 		if (__traits(compiles, fallthrough().opBinary!op(args)))
155 	{
156 		defaultInit();
157 		return fallthrough().opBinary!op(args);
158 	}
159 	
160 	void opIndexAssign(U, V)(auto const ref U arg1, auto const ref V arg2)
161 		if (__traits(hasMember, typeof(fallthrough()), "opIndexAssign"))
162 	{		
163 		defaultInit();
164 		fallthrough().opIndexAssign(arg1, arg2);
165 	}
166 	
167 	auto ref opIndex(U...)(U args) inout
168 		if (__traits(hasMember, typeof(fallthrough()), "opIndex"))
169 	{
170 		return fallthrough().opIndex(args);
171 	}
172 	
173 	static if (__traits(compiles, fallthrough().opBinaryRight!("in")(ReturnType!(fallthrough().front).init)))
174 		bool opBinaryRight(string op, U)(auto ref U e) const if (op == "in") 
175 	{
176 		defaultInit();
177 		return fallthrough().opBinaryRight!("in")(e);
178 	}
179 }
180 
181 /// ditto
182 T min(T, U)(T a, U b)
183 if (is(typeof(a < b)))
184 {
185    /* Handle the common case without all the template expansions
186     * of the general case
187     */
188     return cast(T) (b < a ? b : a);
189 }
190 
191 /// ditto
192 T max(T, U)(T a, U b)
193 if (is(typeof(a < b)))
194 {
195    /* Handle the common case without all the template expansions
196     * of the general case
197     */
198     return cast(T) (a < b ? b : a);
199 }
200 
201 T* addressOf(T)(ref T val) { return &val; }
202 
203 void fill(Range, Value)(auto ref Range range, auto ref Value value)
204 {
205     alias T = ElementType!Range;
206 
207     static if (is(typeof(range[] = value)))
208     {
209         range[] = value;
210     }
211     else static if (is(typeof(range[] = T(value))))
212     {
213         range[] = T(value);
214     }
215     else
216     {
217         for (int i = 0 ; i < range.length ; i++ )
218         {
219             range[i] = value;
220         }
221     }
222 }
223 
224 void initializeAll(Range)(Range range)
225 if (!is(Range == char[]) && !is(Range == wchar[]))
226 {
227     import std.traits : hasElaborateAssign, isDynamicArray;
228 
229     alias T = ElementType!Range;
230     static if (hasElaborateAssign!T)
231     {
232         //Elaborate opAssign. Must go the memcpy road.
233         //We avoid calling emplace here, because our goal is to initialize to
234         //the static state of T.init,
235         //So we want to avoid any un-necassarilly CC'ing of T.init
236         static if (!__traits(isZeroInit, T))
237         {
238             auto p = T();
239             for (int i = 0 ; i < range.length ; i++ )
240             {
241                 static if (__traits(isStaticArray, T))
242                 {
243                     // static array initializer only contains initialization
244                     // for one element of the static array.
245                     auto elemp = cast(void *) addressOf(range[i]);
246                     auto endp = elemp + T.sizeof;
247                     while (elemp < endp)
248                     {
249                         memcpy(elemp, &p, T.sizeof);
250                         elemp += T.sizeof;
251                     }
252                 }
253                 else
254                 {
255                     memcpy(addressOf(range[i]), &p, T.sizeof);
256                 }
257             }
258         }
259         else
260             static if (isDynamicArray!Range)
261                 memset(range.ptr, 0, range.length * T.sizeof);
262             else
263                 for (int i = 0 ; i < range.length ; i++ )
264                     memset(addressOf(range[i]), 0, T.sizeof);
265     }
266     else
267         fill(range, T.init);
268 }
269 /// ditto
270 void initializeAll(Range)(Range range)
271 if (is(Range == char[]) || is(Range == wchar[]))
272 {
273 	import std.range : ElementEncodingType;
274     alias T = ElementEncodingType!Range;
275     range[] = T.init;
276 }
277 extern(C):
278 void*   wasm_malloc(size_t size);
279 ///
280 void*   wasm_realloc(void* ptr, size_t oldsize, size_t size);
281 ///
282 void    wasm_free(void* ptr, size_t size);
283 
284 ///
285 int   memcmp(scope const void* s1, scope const void* s2, size_t n) pure;
286 
287 void* memcpy(return void* s1, scope const void* s2, size_t n) pure;
288 ///
289 void* memmove(return void* s1, scope const void* s2, size_t n) pure;
290 ///
291 void* memset(return void* s, int c, size_t n) pure;