1 /*******************************************************************************
2 
3     This modules contains utilities and aliases that are used during D1->D2
4     transition process. Idea is to define single module that contains wrapper
5     aliases / structures and switch all code to use it. Once actual porting
6     time comes it will be enough to simply change version in this module.
7 
8     version(D2) can't be used because D2 code can't be even parsed by D1
9     compiler, resorting to commenting out because of that.
10 
11     Copyright:
12         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
13         All rights reserved.
14 
15     License:
16         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
17         Alternatively, this file may be distributed under the terms of the Tango
18         3-Clause BSD License (see LICENSE_BSD.txt for details).
19 
20 *******************************************************************************/
21 
22 module ocean.transition;
23 
24 import ocean.meta.traits.Basic;
25 import ocean.meta.types.Arrays;
26 
27 public import ocean.core.TypeConvert : assumeUnique;
28 public import ocean.meta.types.Qualifiers;
29 public import ocean.meta.types.Typedef;
30 
31 /*******************************************************************************
32 
33     Checks (non-transitively) if type is mutable
34 
35     Params:
36         T = any plain type
37 
38 *******************************************************************************/
39 
40 template isMutable( T )
41 {
42     enum isMutable = !is(T == const) && !is(T == immutable);
43 }
44 
45 unittest
46 {
47     static assert (!isMutable!(typeof("aaa"[0])));
48 }
49 
50 /*******************************************************************************
51 
52     Helper to smooth transition between D1 and D2 runtime behaviours regarding
53     array stomping. In D2 appending to array slice after length has been changed
54     results in allocating new array to prevent overwriting old data.
55 
56     We use and actually rely on that behaviour for buffer re-usage.
57     `assumeSafeAppend` from object.d enables stomping back but adding using this
58     no-op wrapper in D1 code will save time on trying to find those extremely
59     subtle issues upon actual transition.
60 
61     All places that reset length to 0 will need to call this helper.
62 
63     Params:
64         array = array slice that is going to be overwritten
65 
66 *******************************************************************************/
67 
68 void enableStomping(T)(ref T[] array)
69 {
70     static assert (
71         is(T == Unqual!(T)),
72         "Must not call `enableStomping` on const/immutable array"
73     );
74 
75     assumeSafeAppend(array);
76 }
77 
78 /*******************************************************************************
79 
80     Helper template that can be used instead of octal literals. In some cases
81     preserving octal notation is really important for readability and those
82     can't be simply replace with decimal/hex ones.
83 
84     Params:
85         literal = octal number literal as string
86 
87 *******************************************************************************/
88 
89 static import ocean.text.convert.Integer_tango;
90 
91 template Octal(istring literal)
92 {
93     static immutable Octal = ocean.text.convert.Integer_tango.parse(literal, 8);
94 }
95 
96 unittest
97 {
98     static assert (Octal!("00") == 0);
99     static assert (Octal!("12") == 10);
100     static assert (Octal!("1") == 1);
101     static assert (Octal!("0001") == 1);
102     static assert (Octal!("0010") == 8);
103     static assert (Octal!("666") == (6 + 8*6 + 8*8*6));
104 }
105 
106 /*******************************************************************************
107 
108     In D1 ModuleInfo is a class. In D2 it is a struct. ModuleInfoPtr aliases
109     to matching reference type for each of those.
110 
111 *******************************************************************************/
112 
113 alias ModuleInfo* ModuleInfoPtr;
114 
115 /*******************************************************************************
116 
117     In D2 variables are thread-local by default. In many cases this is exactly
118     what you need but sometimes true globals are necessary - primarily related
119     to thread and related tool implementation.
120 
121     This small mixin helper prepends __gshared to input declaration when
122     compiled in D2 mode.
123 
124 *******************************************************************************/
125 
126 istring global(istring decl)
127 {
128     return "__gshared " ~ decl ~ ";";
129 }
130 
131 unittest
132 {
133     mixin(global("int x = 42"));
134     assert(x == 42);
135 }
136 
137 /*******************************************************************************
138 
139     In D2 .min was renamed to .min_normal for floating point types to
140     make its meaning more obvious. This is a trivial template wrapper that
141     unifies the naming.
142 
143     Params:
144         T = any floating point type
145 
146     Return:
147         minimal normalized value for that type
148 
149 *******************************************************************************/
150 
151 template min_normal(T : real)
152 {
153     static immutable min_normal = T.min_normal;
154 }
155 
156 unittest
157 {
158     static assert (min_normal!(double) == double.min_normal);
159 }
160 
161 /*******************************************************************************
162 
163     Mixin helper to generate proper opCmp declaration. It differs between D1
164     and D2 runtime and not matching exact signature will result in weird
165     segmentation faults from inside the runtime.
166 
167     Params:
168         func_body = code of opCmp as string. Must refer to argument as `rhs`
169 
170     Returns:
171         full declaration/definition of opCmp that matches current compiler
172 
173 *******************************************************************************/
174 
175 istring genOpCmp(istring func_body)
176 {
177     istring result;
178 
179     // We need to know if it's a class or not. If it is, one might want to
180     // compare against literals, so we cannot take it by `const ref`.
181 
182     result ~= "static if (is(typeof(this) == class))\n{\n";
183     result ~= "override int opCmp(Object rhs)\n";
184     result ~= func_body;
185     result ~= "\n}\nelse\n{\n";
186     result ~= "int opCmp(const typeof(this) rhs) const\n";
187     result ~= func_body;
188     result ~= "\n}\n";
189 
190     return result;
191 }
192 
193 unittest
194 {
195     struct S
196     {
197         int x;
198 
199         mixin (genOpCmp("
200         {
201             if (this.x >= rhs.x)
202                 return this.x > rhs.x;
203             return -1;
204         }
205         "));
206 
207         equals_t opEquals (S rhs)
208         {
209             return (&this).opCmp(rhs) == 0;
210         }
211     }
212 
213     class C
214     {
215         private int x;
216 
217         this (int a)
218         {
219             this.x = a;
220         }
221 
222         mixin (genOpCmp(
223         `{
224             auto o = cast(typeof(this)) rhs;
225             if (o is null)
226                 return -1;
227             if (this.x >= o.x)
228                 return this.x > o.x;
229             return -1;
230         }`));
231     }
232 
233     assert (S(1) < S(2));
234     assert (S(2) > S(1));
235     assert (S(2) >= S(2));
236     assert (S(2) <= S(2));
237     assert (new C(1) < new C(2));
238     assert (new C(2) > new C(1));
239     assert (new C(2) >= new C(2));
240     assert (new C(2) <= new C(2));
241 }
242 
243 /*******************************************************************************
244 
245     Mixin helper to generate proper opEquals declaration. It differs between D1
246     and D2 runtime and not matching exact signature will result in the default
247     version, defined by the compiler, to be silently called instead.
248 
249     Params:
250         func_body = code of opEquals as string. Must refer to argument as `rhs`
251 
252     Returns:
253         full declaration/definition of opEquals that matches current compiler
254 
255 *******************************************************************************/
256 
257 public istring genOpEquals(istring func_body)
258 {
259     istring result;
260 
261     // We need to know if it's a class or not. If it is, one might want to
262     // compare against literals, so we cannot take it by `const ref`.
263 
264     result ~= "static if (is(typeof(this) == class))\n{\n";
265     result ~= "override equals_t opEquals(Object rhs)\n";
266     result ~= func_body;
267     result ~= "\n}\nelse\n{\n";
268     result ~= "bool opEquals(const typeof(this) rhs) const\n";
269     result ~= func_body;
270     result ~= "\n}\n";
271 
272     return result;
273 }
274 
275 unittest
276 {
277     struct S
278     {
279         int x;
280         int y;
281 
282         // Use a crazy definition, as the default one would pass those tests :)
283         mixin (genOpEquals("
284         {
285             return this.x == rhs.y && this.y == rhs.x;
286         }
287         "));
288     }
289 
290     class C
291     {
292         private int x;
293 
294         this (int a)
295         {
296             this.x = a;
297         }
298 
299         mixin (genOpEquals(
300         `{
301             auto o = cast(typeof(this)) rhs;
302             if (o is null) return false;
303             return (this.x == o.x);
304         }`));
305     }
306 
307     assert (S(2, 1) == S(1, 2));
308     assert (new C(2) == new C(2));
309 
310     assert (S(1, 2) != S(1, 2));
311     assert (S(2, 1) != S(2, 1));
312     assert (!(S(1, 2) == S(1, 2)));
313     assert (!(S(2, 1) == S(2, 1)));
314 
315     C nil;
316 
317     assert (new C(1) != new C(2));
318     assert (new C(2) != new C(1));
319     assert (!(new C(1) == new C(2)));
320     assert (!(new C(2) == new C(1)));
321     assert (new C(1) != nil);
322     assert (!(new C(1) == nil));
323 
324     // D1 runtime dereference null if it's LHS...
325     //assert (nil != new C(2));
326     //assert (!(nil == new C(2)));
327 }
328 
329 /*******************************************************************************
330 
331     In D1, typeof(this) is always a reference type to the aggregate, while in
332     D2 it's the actual type of the aggregate. It doesn't change anything for
333     classes which are reference types, but for struct and unions, it yields
334     a pointer instead of the actual type.
335     d1tod2fix does the conversion automatically for `structs`, but there are
336     places where manual intervention is needed (e.g. `mixin template`s).
337 
338 *******************************************************************************/
339 
340 public template TypeofThis()
341 {
342     alias typeof(this) This;
343 }
344 
345 version (UnitTest)
346 {
347     private struct FooClass
348     {
349         mixin TypeofThis;
350     }
351     private struct FooStruct
352     {
353         mixin TypeofThis;
354     }
355 
356     private union FooUnion
357     {
358         mixin TypeofThis;
359     }
360 }
361 
362 unittest
363 {
364     static assert (is(FooClass.This == FooClass));
365     static assert (is(FooStruct.This == FooStruct));
366     static assert (is(FooUnion.This == FooUnion));
367 }
368 
369 /*******************************************************************************
370 
371     Helper which provides stub implementation of GC.usage if it is not present
372     upstream in order to keep ocean compiling and passing tests.
373 
374 *******************************************************************************/
375 
376 static import core.memory;
377 
378 static if (is(typeof(core.memory.GC.stats)))
379 {
380     void gc_usage ( out size_t used, out size_t free )
381     {
382         auto stats = core.memory.GC.stats();
383         used = stats.usedSize;
384         free = stats.freeSize;
385     }
386 }
387 else static if (is(typeof(core.memory.GC.usage)))
388 {
389     alias core.memory.GC.usage gc_usage;
390 }
391 else
392 {
393     void gc_usage ( out size_t used, out size_t free )
394     {
395         // no-op
396     }
397 }
398 
399 /*******************************************************************************
400 
401     Utility intended to help with situations when generic function had to return
402     its templated argument which could turn out to be a static array. In D1 that
403     would require slicing such argument as returning static array types is not
404     allowed. In D2, however, static arrays are value types and such slicing is
405     neither necessary nor memory-safe.
406 
407     Examples:
408 
409     ---
410     SliceIfD1StaticArray!(T) foo ( T ) ( T input )
411     {
412         return input;
413     }
414 
415     foo(42);
416     foo("abcd"); // wouldn't work if `foo` tried to return just T
417     ---
418 
419     Params:
420         T = any type
421 
422     Returns:
423         If T is a static array, evaluates to matching dynamic array. Othwerwise
424         evaluates to just T.
425 
426 *******************************************************************************/
427 
428 public template SliceIfD1StaticArray ( T )
429 {
430     alias T SliceIfD1StaticArray;
431 }
432 
433 unittest
434 {
435     static assert (is(SliceIfD1StaticArray!(int[4]) == int[4]));
436     static assert (is(SliceIfD1StaticArray!(int[]) == int[]));
437     static assert (is(SliceIfD1StaticArray!(double) == double));
438 }