1 /**
2  * Several trivial functions and structures
3  */
4 module iz.sugar;
5 
6 import
7     std.traits, std.meta, std.typecons, std.functional;
8 import
9     std.range.primitives: isInputRange, ElementType, ElementEncodingType,
10         isBidirectionalRange;
11 
12 version(unittest) import std.stdio;
13 
14 /**
15  * Void version of the init() type function.
16  *
17  * Params:
18  *      T = the argument type, likely to be infered.
19  *      t = a reference to a T.
20  */
21 void reset(T)(ref T t)
22 {
23     t = T.init;
24 }
25 ///
26 @safe @nogc nothrow unittest
27 {
28     uint a = 159;
29     string b = "bla";
30     a.reset;
31     assert(a == 0);
32     b.reset;
33     assert(b == "");
34 }
35 
36 /**
37  * Allows forbidden casts.
38  *
39  * Params:
40  *      OT = The output type.
41  *      IT = The input type, optional, likely to be infered.
42  *      it = A reference to an IT.
43  *
44  * Returns:
45  *      the same as $(D cast(OT) it), except that it never fails to compile.
46  */
47 auto bruteCast(OT, IT)(auto ref IT it)
48 {
49     return *cast(OT*) ⁢
50 }
51 ///
52 nothrow pure @nogc unittest
53 {
54     static immutable array = [0u,1u,2u];
55     size_t len;
56     //len = cast(uint) array; // not allowed.
57     len = bruteCast!uint(array);
58     assert(len == array.length);
59 }
60 
61 
62 /// Enumerates the possible units of a mask.
63 enum MaskKind {Byte, Nibble, Bit}
64 
65 
66 /**
67  * Masks, at compile-time, a byte, a nibble or a bit in the argument.
68  *
69  * Params:
70  *      index = the position, 0-based, of the element to mask.
71  *      kind = the kind of the element to mask.
72  *      value = the value mask.
73  *
74  * Returns:
75  *      The input argument with the element masked.
76  */
77 auto mask(size_t index, MaskKind kind = MaskKind.Byte, T)(const T value)
78 nothrow @safe pure
79 if (    (kind == MaskKind.Byte && index <= T.sizeof)
80     ||  (kind == MaskKind.Nibble && index <= T.sizeof * 2)
81     ||  (kind == MaskKind.Bit && index <= T.sizeof * 8))
82 {
83     T _mask;
84     static if (kind == MaskKind.Byte)
85     {
86         _mask = T.min - 1 - (0xFF << index * 8);
87     }
88     else static if (kind == MaskKind.Nibble)
89     {
90         _mask = T.min - 1 - (0xF << index * 4);
91     }
92     else static if (kind == MaskKind.Bit)
93     {
94         _mask = T.min - 1 - (0x1 << index);
95     }
96     return value & _mask;
97 }
98 ///
99 nothrow @safe @nogc pure unittest
100 {
101     // MaskKind.Byte by default.
102     static assert(mask!1(0x12345678) == 0x12340078);
103     static assert(mask!(1,MaskKind.Nibble)(0x12345678) == 0x12345608);
104 }
105 
106 
107 /// Compile-time $(D mask()) partially specialized for nibble-masking.
108 auto maskNibble(size_t index, T)(const T value) nothrow @safe pure
109 {
110     // note: aliasing prevents template parameter type deduction,
111     // e.g alias maskNibble(size_t index, T) = mask!(index, MaskKind.Nibble, T);
112     return mask!(index, MaskKind.Nibble)(value);
113 }
114 ///
115 nothrow @safe @nogc pure unittest
116 {
117     static assert(maskNibble!1(0x12345678) == 0x12345608);
118 }
119 
120 
121 /// Compile-time $(D mask()) partially specialized for bit-masking.
122 auto maskBit(size_t index, T)(const T value) nothrow @safe pure
123 {
124     return mask!(index, MaskKind.Bit)(value);
125 }
126 ///
127 nothrow @safe @nogc pure unittest
128 {
129     static assert(maskBit!1(0b1111) == 0b1101);
130 }
131 
132 
133 /**
134  * Masks, at run-time, a byte, a nibble or a bit in the argument.
135  *
136  * Params:
137  *      index = the position, 0-based, of the element to mask.
138  *      kind = the kind of the element to mask.
139  *      value = the value mask.
140  *
141  * Returns:
142  *      The input argument with the element masked.
143  */
144 auto mask(MaskKind kind = MaskKind.Byte, T)(const T value, size_t index)
145 nothrow @safe pure
146 {
147     static immutable byteMasker =
148     [
149         0xFFFFFFFFFFFFFF00,
150         0xFFFFFFFFFFFF00FF,
151         0xFFFFFFFFFF00FFFF,
152         0xFFFFFFFF00FFFFFF,
153         0xFFFFFF00FFFFFFFF,
154         0xFFFF00FFFFFFFFFF,
155         0xFF00FFFFFFFFFFFF,
156         0x00FFFFFFFFFFFFFF
157     ];
158 
159     static immutable nibbleMasker =
160     [
161         0xFFFFFFFFFFFFFFF0,
162         0xFFFFFFFFFFFFFF0F,
163         0xFFFFFFFFFFFFF0FF,
164         0xFFFFFFFFFFFF0FFF,
165         0xFFFFFFFFFFF0FFFF,
166         0xFFFFFFFFFF0FFFFF,
167         0xFFFFFFFFF0FFFFFF,
168         0xFFFFFFFF0FFFFFFF,
169         0xFFFFFFF0FFFFFFFF,
170         0xFFFFFF0FFFFFFFFF,
171         0xFFFFF0FFFFFFFFFF,
172         0xFFFF0FFFFFFFFFFF,
173         0xFFF0FFFFFFFFFFFF,
174         0xFF0FFFFFFFFFFFFF,
175         0xF0FFFFFFFFFFFFFF,
176         0x0FFFFFFFFFFFFFFF
177     ];
178     static if (kind == MaskKind.Byte)
179         return value & byteMasker[index];
180     else static if (kind == MaskKind.Nibble)
181         return value & nibbleMasker[index];
182     else
183         return value & (0xFFFFFFFFFFFFFFFF - (1UL << index));
184 }
185 ///
186 nothrow @safe @nogc pure unittest
187 {
188     // MaskKind.Byte by default.
189     assert(mask(0x12345678,1) == 0x12340078);
190     assert(mask!(MaskKind.Nibble)(0x12345678,1) == 0x12345608);
191 }
192 
193 /*
194 First version: less byte code but more latency do to memory access
195 This version: no memory access but similar latency due to more byte code.
196 auto mask(MaskKind kind = MaskKind.Byte, T)(const T value, size_t index) nothrow
197 {
198     static immutable T _max = - 1;
199     static if (kind == MaskKind.Byte)
200         return value & (_max - (0xFF << index * 8));
201     else static if (kind == MaskKind.Nibble)
202         return value & (_max - (0xF << index * 4));
203     else
204         return value & (_max - (0x1 << index));
205 }
206 */
207 
208 
209 /// Run-time $(D mask()) partially specialized for nibble-masking.
210 auto maskNibble(T)(const T value, size_t index)
211 {
212     return mask!(MaskKind.Nibble)(value, index);
213 }
214 ///
215 nothrow @safe @nogc pure unittest
216 {
217     assert(maskNibble(0x12345678,1) == 0x12345608);
218 }
219 
220 
221 /// Run-time $(D mask()) partially specialized for bit-masking.
222 auto maskBit(T)(const T value, size_t index) nothrow @safe pure
223 {
224     return mask!(MaskKind.Bit)(value, index);
225 }
226 ///
227 nothrow @safe pure unittest
228 {
229     assert(maskBit(0b1111,1) == 0b1101);
230 }
231 
232 nothrow @safe pure unittest
233 {
234     enum v0 = 0x44332211;
235     static assert( mask!0(v0) == 0x44332200);
236     static assert( mask!1(v0) == 0x44330011);
237     static assert( mask!2(v0) == 0x44002211);
238     static assert( mask!3(v0) == 0x00332211);
239 
240     assert( mask(v0,0) == 0x44332200);
241     assert( mask(v0,1) == 0x44330011);
242     assert( mask(v0,2) == 0x44002211);
243     assert( mask(v0,3) == 0x00332211);
244 
245     enum v1 = 0x87654321;
246     static assert( mask!(0, MaskKind.Nibble)(v1) == 0x87654320);
247     static assert( mask!(1, MaskKind.Nibble)(v1) == 0x87654301);
248     static assert( mask!(2, MaskKind.Nibble)(v1) == 0x87654021);
249     static assert( mask!(3, MaskKind.Nibble)(v1) == 0x87650321);
250     static assert( mask!(7, MaskKind.Nibble)(v1) == 0x07654321);
251 
252     assert( mask!(MaskKind.Nibble)(v1,0) == 0x87654320);
253     assert( mask!(MaskKind.Nibble)(v1,1) == 0x87654301);
254     assert( mask!(MaskKind.Nibble)(v1,2) == 0x87654021);
255     assert( mask!(MaskKind.Nibble)(v1,3) == 0x87650321);
256     assert( mask!(MaskKind.Nibble)(v1,7) == 0x07654321);
257 
258     enum v2 = 0b11111111;
259     static assert( mask!(0, MaskKind.Bit)(v2) == 0b11111110);
260     static assert( mask!(1, MaskKind.Bit)(v2) == 0b11111101);
261     static assert( mask!(7, MaskKind.Bit)(v2) == 0b01111111);
262 
263     assert( maskBit(v2,0) == 0b11111110);
264     assert( maskBit(v2,1) == 0b11111101);
265     assert( mask!(MaskKind.Bit)(v2,7) == 0b01111111);
266 }
267 
268 
269 /**
270  * Alternative to std.range primitives for arrays.
271  *
272  * The source is never consumed.
273  * The range always verifies isInputRange and isForwardRange. When the source
274  * array element type if not a character type or if the template parameter
275  * assumeDecoded is set to true then the range also verifies
276  * isForwardRange.
277  *
278  * When the source is an array of character and if assumeDecoded is set to false
279  * (the default) then the ArrayRange front type is always dchar because of the
280  * UTF decoding. The parameter can be set to true if the source is known to
281  * contains only SBCs.
282  *
283  * The template parameter infinite allows to turn the range in an infinite range
284  * that loops over the elements.
285  */
286 struct ArrayRange(T, bool assumeDecoded = false, bool infinite = false)
287 {
288     static if (!isSomeChar!T || assumeDecoded || is(T==dchar))
289     {
290         private T* _front, _back;
291         private static if(infinite) T* _first;
292         ///
293         this(ref T[] stuff)
294         {
295             _front = stuff.ptr;
296             _back = _front + stuff.length - 1;
297             static if(infinite) _first = _front;
298         }
299         ///
300         @property bool empty()
301         {
302             static if (infinite)
303                 return false;
304             else
305                 return _front > _back;
306         }
307         ///
308         T front()
309         {
310             return *_front;
311         }
312         ///
313         T back()
314         {
315             return *_back;
316         }
317         ///
318         void popFront()
319         {
320             ++_front;
321             static if (infinite)
322             {
323                 if (_front > _back)
324                     _front = _first;
325             }
326         }
327         ///
328         void popBack()
329         {
330             --_back;
331         }
332         /// returns a slice of the source, according to front and back.
333         T[] array()
334         {
335             return _front[0 .. _back - _front + 1];
336         }
337         ///
338         typeof(this) save()
339         {
340             typeof(this) result;
341             result._front = _front;
342             result._back = _back;
343             return result;
344         }
345     }
346     else
347     {
348 
349     private:
350 
351         import std.utf: decode;
352         size_t _position, _previous, _len;
353         dchar _decoded;
354         T* _front;
355         bool _decode;
356 
357         void readNext()
358         {
359             _previous = _position;
360             auto str = _front[0 .. _len];
361             _decoded = decode(str, _position);
362         }
363 
364     public:
365 
366         ///
367         this(ref T[] stuff)
368         {
369             _front = stuff.ptr;
370             _len = stuff.length;
371             _decode = true;
372         }
373         ///
374         @property bool empty()
375         {
376             return _position >= _len;
377         }
378         ///
379         dchar front()
380         {
381             if (_decode)
382             {
383                 _decode = false;
384                 readNext;
385             }
386             return _decoded;
387         }
388         ///
389         void popFront()
390         {
391             if (_decode) readNext;
392             _decode = true;
393         }
394         /// returns a slice of the source, according to front and back.
395         T[] array()
396         {
397             return _front[_previous .. _len];
398         }
399         ///
400         typeof(this) save()
401         {
402             typeof(this) result;
403             result._position   = _position;
404             result._previous   = _previous;
405             result._len        = _len;
406             result._decoded    = _decoded;
407             result._front      = _front;
408             result._decode     = _decode;
409             return result;
410         }
411     }
412 }
413 
414 unittest
415 {
416     auto arr = "bla";
417     auto rng = ArrayRange!(immutable(char))(arr);
418     assert(rng.array == "bla", rng.array);
419     assert(rng.front == 'b');
420     rng.popFront;
421     assert(rng.front == 'l');
422     rng.popFront;
423     assert(rng.front == 'a');
424     rng.popFront;
425     assert(rng.empty);
426     assert(arr == "bla");
427     //
428     auto t1 = "é_é";
429     auto r1 = ArrayRange!(immutable(char))(t1);
430     auto r2 = r1.save;
431     foreach(i; 0 .. 3) r1.popFront;
432     assert(r1.empty);
433     r1 = r2;
434     assert(r1.front == 'é');
435     //
436     auto r3 = ArrayRange!(immutable(char),true)(t1);
437     foreach(i; 0 .. 5) r3.popFront;
438     assert(r3.empty);
439 }
440 
441 unittest
442 {
443     ubyte[] src = [1,2,3,4,5];
444     ubyte[] arr = src.dup;
445     auto rng = ArrayRange!ubyte(arr);
446     ubyte cnt = 1;
447     while (!rng.empty)
448     {
449         assert(rng.front == cnt++);
450         rng.popFront;
451     }
452     assert(arr == src);
453     auto bck = ArrayRange!ubyte(arr);
454     assert(bck.back == 5);
455     bck.popBack;
456     assert(bck.back == 4);
457     assert(bck.array == [1,2,3,4]);
458     auto sbk = bck.save;
459     bck.popBack;
460     sbk.popBack;
461     assert(bck.back == sbk.back);
462 }
463 
464 
465 /**
466  * Calls a function according to a probability
467  *
468  * Params:
469  *      t = The chance to call, in percentage.
470  *      fun = The function to call. It must be a void function.
471  *      a = The variadic argument passed to fun.
472  *
473  * Returns:
474  *      false if no luck.
475  */
476 bool pickAndCall(T, Fun, A...)(T t, Fun fun, auto ref A a)
477 if (isNumeric!T && isCallable!Fun && is(ReturnType!Fun == void))
478 in
479 {
480     static immutable string err = "chance to pick must be in the 0..100 range";
481     assert(t <= 100, err);
482     assert(t >= 0, err);
483 }
484 body
485 {
486     import std.random: uniform;
487     static immutable T min = 0;
488     static immutable T max = 100;
489     const bool result = uniform!"[]"(min, max) > max - t;
490     if (result) fun(a);
491     return result;
492 }
493 ///
494 @safe unittest
495 {
496     uint cnt;
497     bool test;
498     void foo(uint param0, out bool param1) @safe
499     {
500         cnt += param0;
501         param1 = true;
502     }
503     foreach(immutable i; 0 .. 100)
504         pickAndCall!(double)(75.0, &foo, 1, test);
505     assert(cnt > 25);
506     assert(test);
507     cnt = 0;
508     test = false;
509     foreach(immutable i; 0 .. 100)
510         pickAndCall!(byte)(0, &foo, 1, test);
511     assert(cnt == 0);
512     assert(!test);
513 }
514 
515 /**
516  * Pops an input range while a predicate is true.
517  * Consumes the input argument.
518  *
519  * Params:
520  *      pred = the predicate.
521  *      range = an input range, must be a lvalue.
522  */
523 void popWhile(alias pred, Range)(ref Range range)
524 if (isInputRange!Range && is(typeof(unaryFun!pred)) && isImplicitlyConvertible!
525     (typeof(unaryFun!pred((ElementType!Range).init)), bool))
526 {
527     import std.range.primitives: front, empty, popFront;
528     alias f = unaryFun!pred;
529     while (!range.empty)
530     {
531         if (!f(range.front))
532             break;
533         else
534             range.popFront;
535     }
536 }
537 ///
538 pure @safe unittest
539 {
540     string r0 = "aaaaabcd";
541     r0.popWhile!"a == 'a'";
542     assert(r0 == "bcd");
543 
544     static bool lessTwo(T)(T t)
545     {
546         return t < 2;
547     }
548     int[] r1 = [0,1,2,0,1,2];
549     r1.popWhile!lessTwo;
550     assert(r1 == [2,0,1,2]);
551 
552     static bool posLessFive(T)(T t)
553     {
554         return t < 5 && t > 0;
555     }
556     int[] r3 = [2,3,4,-1];
557     r3.popWhile!posLessFive;
558     assert(r3 == [-1]);
559     int[] r4 = [2,3,4,5];
560     r4.popWhile!posLessFive;
561     assert(r4 == [5]);
562 }
563 
564 /**
565  * Convenience function that calls popWhile() on the input argument 
566  * and returns the consumed range to allow function pipelining.
567  * In addition this wrapper accepts rvalues.
568  */
569 auto dropWhile(alias pred, Range)(auto ref Range range)
570 if (isInputRange!Range && is(typeof(unaryFun!pred)) && isImplicitlyConvertible!
571     (typeof(unaryFun!pred((ElementType!Range).init)), bool))
572 {
573     popWhile!(pred, Range)(range);
574     return range;
575 }
576 ///
577 pure @safe unittest
578 {
579     assert("aaaaabcd".dropWhile!"a == 'a'" == "bcd");
580 }
581 
582 /**
583  * Pops back an input range while a predicate is true.
584  * Consumes the input argument.
585  *
586  * Params:
587  *      pred = the predicate.
588  *      range = an input range, must be a lvalue.
589  */
590 void popBackWhile(alias pred, Range)(ref Range range)
591 if (isBidirectionalRange!Range && is(typeof(unaryFun!pred)) && isImplicitlyConvertible!
592     (typeof(unaryFun!pred((ElementType!Range).init)), bool))
593 {
594     import std.range.primitives: back, empty, popBack;
595     alias f = unaryFun!pred;
596     while (!range.empty)
597     {
598         if (!f(range.back))
599             break;
600         else
601             range.popBack;
602     }
603 }
604 ///
605 pure @safe unittest
606 {
607     string r0 = "bcdaaaa";
608     r0.popBackWhile!"a == 'a'";
609     assert(r0 == "bcd");
610 
611     static bool lessTwo(T)(T t)
612     {
613         return t < 2;
614     }
615     int[] r1 = [0,1,2,2,1,0];
616     r1.popBackWhile!lessTwo;
617     assert(r1 == [0,1,2,2]);
618 
619     static bool posLessFive(T)(T t)
620     {
621         return t < 5 && t > 0;
622     }
623     int[] r3 = [-1,2,3,4];
624     r3.popBackWhile!posLessFive;
625     assert(r3 == [-1]);
626     int[] r4 = [5,2,3,4];
627     r4.popBackWhile!posLessFive;
628     assert(r4 == [5]);
629 }
630 
631 /**
632  * Convenience function that calls popBackWhile() on the input argument
633  * and returns the consumed range to allow function pipelining.
634  * In addition this wrapper accepts rvalues.
635  */
636 auto dropBackWhile(alias pred, Range)(auto ref Range range)
637 if (isBidirectionalRange!Range && is(typeof(unaryFun!pred)) && isImplicitlyConvertible!
638     (typeof(unaryFun!pred((ElementType!Range).init)), bool))
639 {
640     popBackWhile!(pred, Range)(range);
641     return range;
642 }
643 ///
644 pure @safe unittest
645 {
646     assert("abcdefgh".dropBackWhile!"a > 'e'" == "abcde");
647 }
648 
649 /**
650  * Returns a lazy input range that alterntively returns the state of one of two
651  * sub-ranges.
652  *
653  * Similar to std.range roundRobin() or chain() except that the resulting range
654  * is considered as empty when one of the sub range is consumed.
655  *
656  * Params:
657  *      flip = the first input range.
658  *      flop = the second input range.
659  */
660 auto flipFlop(R1, R2)(auto ref R1 flip, auto ref R2 flop)
661 if (isInputRange!R1 && isInputRange!R2 && is(ElementType!R1 == ElementType!R2))
662 {
663     import std.range.primitives: front, empty, popFront;
664     struct FlipFlop
665     {
666         private bool _takeFlop;
667 
668         ///
669         bool empty()
670         {
671             return (flip.empty && !_takeFlop) | (_takeFlop && flop.empty);
672         }
673         ///
674         auto front()
675         {
676             final switch (_takeFlop)
677             {
678                 case false: return flip.front;
679                 case true:  return flop.front;
680             }
681         }
682         ///
683         void popFront()
684         {
685             _takeFlop = !_takeFlop;
686             final switch (_takeFlop)
687             {
688                 case false: return flop.popFront;
689                 case true:  return flip.popFront;
690             }
691         }
692     }
693     FlipFlop ff;
694     return ff;
695 }
696 ///
697 pure @safe unittest
698 {
699     import std.array: array;
700     assert(flipFlop([0,2,4],[1,3,5]).array == [0,1,2,3,4,5]);
701     assert(flipFlop([0,2],[1,3,5]).array == [0,1,2,3]);
702     assert(flipFlop([0,2,4],[1,3]).array == [0,1,2,3,4]);
703     int[] re = [];
704     assert(flipFlop([0], re).array == [0]);
705     assert(flipFlop(re, re).array == []);
706     assert(flipFlop(re, [0]).array == []);
707 }
708 
709 /**
710  * Returns a lazy input range that takes from the input while a predicate is
711  * verified and the input is not empty.
712  *
713  * Params:
714  *      pred = the predicate.
715  *      range = an input range, only consumed when passed by reference.
716  */
717 auto takeWhile(alias pred, Range)(auto ref Range range)
718 if (isInputRange!Range && is(typeof(unaryFun!pred)) && isImplicitlyConvertible!
719     (typeof(unaryFun!pred((ElementType!Range).init)), bool))
720 {
721     alias f = unaryFun!pred;
722     import std.range.primitives: front, empty, popFront;
723     struct Taker
724     {
725         ///
726         bool empty()
727         {
728             return range.empty || !f(range.front);
729         }
730         ///
731         void popFront()
732         {
733             range.popFront;
734         }
735         ///
736         auto front()
737         {
738             return range.front;
739         }
740     }
741     Taker result;
742     return result;
743 }
744 ///
745 pure @safe unittest
746 {
747     import std.range: array;
748     import std.ascii: isDigit;
749     auto r = "012A";
750     assert(takeWhile!((a) => isDigit(a))(r).array == "012");
751     assert(r == "A");
752     assert(takeWhile!((a) => isDigit(a))(r).array == "");
753     assert(takeWhile!((a) => isDigit(a))("").array == "");
754 }
755 
756 /**
757  * Returns a lazy input range that takes from the input tail while a
758  * predicate is verified and the input is not empty.
759  *
760  * Params:
761  *      pred = the predicate.
762  *      range = an bidirectional range, only consumed when passed by reference.
763  */
764 auto takeBackWhile(alias pred, Range)(auto ref Range range)
765 if (isBidirectionalRange!Range && is(typeof(unaryFun!pred)) && isImplicitlyConvertible!
766     (typeof(unaryFun!pred((ElementType!Range).init)), bool))
767 {
768     alias f = unaryFun!pred;
769     import std.range.primitives: back, empty, popBack;
770     struct Taker
771     {
772         ///
773         bool empty()
774         {
775             return range.empty || !f(range.back);
776         }
777         ///
778         void popFront()
779         {
780             range.popBack;
781         }
782         ///
783         auto front()
784         {
785             return range.back;
786         }
787     }
788     Taker result;
789     return result;
790 }
791 ///
792 pure @safe unittest
793 {
794     import std.range: array;
795     import std.ascii: isDigit;
796     auto r = "A123";
797     assert(takeBackWhile!((a) => isDigit(a))(r).array == "321");
798     assert(r == "A");
799     assert(takeBackWhile!((a) => isDigit(a))(r).array == "");
800     assert(takeBackWhile!((a) => isDigit(a))("").array == "");
801 }
802 
803 /**
804  * Indicates how many elements of a range are mutated.
805  *
806  * Params:
807  *      range = An input range. The elements must be mutable and initializable.
808  *      Narrow srings are not considered as validate input parameter.
809  *
810  * Returns:
811  *      A number equal to the count of elements that are different from their
812  *      initializer.
813  */
814 size_t mutatedCount(Range)(Range range)
815 if (isInputRange!Range && is(typeof((ElementType!Range).init))
816     && isMutable!(ElementType!Range) && !isNarrowString!Range)
817 {
818     import std.range.primitives: front, empty, popFront;
819 
820     size_t result;
821     const(ElementType!Range) noone = (ElementType!Range).init;
822     while (!range.empty)
823     {
824         result += ubyte(range.front != noone);
825         range.popFront;
826     }
827     return result;
828 }
829 ///
830 unittest
831 {
832     int[] i = [0,0,1];
833     assert(i.mutatedCount == 1);
834     assert(i[0..$-1].mutatedCount == 0);
835 
836     string[] s = ["","a"];
837     assert(s.mutatedCount == 1);
838 
839     dchar[] dc = [dchar.init, 'g'];
840     assert(dc.mutatedCount == 1);
841 
842     class Foo {}
843     Foo[] f = new Foo[](8);
844     assert(f.mutatedCount == 0);
845     f[0] = new Foo;
846     f[1] = new Foo;
847     assert(f.mutatedCount == 2);
848 
849     // w/char.init leads to decoding invalid UTF8 sequence
850     static assert(!is(typeof(mutatedCount!(char[]))));
851     static assert(!is(typeof(mutatedCount!(wchar[]))));
852 
853     static assert(is(typeof(mutatedCount!(dchar[]))));
854 }
855 
856 /**
857  * Allows to pass always a parameter as value even if it would be accepted
858  * as reference.
859  */
860 auto rValue(T)(auto ref T t)
861 {
862     return t;
863 }
864 ///
865 unittest
866 {
867     void foo(T)(ref T t){}
868     uint a;
869     static assert(is(typeof(foo(a))));
870     static assert(!is(typeof(foo(a.rValue))));
871 }
872 
873 /**
874  * Compares two integral values with additional static checkings.
875  *
876  * If the comparison mixes signed and unsigned operands then the function tries
877  * to widen the unsigned operand to perform a valid comparison, otherwise
878  * a DMD-style warning is emitted.
879  *
880  * Params:
881  *      op = The comparison operator, must be either >, < , <= or >=. Equality
882  *          is also allowed even if this is always a transparent operation.
883  *      lhs = The left operand, an integer.
884  *      rhs = The right operand, an integer.
885  *
886  *  Returns:
887  *      A bool, the comparison result.
888  */
889 bool compare(string op, L, R, string fname = __FILE__, int line = __LINE__)
890     (auto ref L lhs, auto ref R rhs)
891 if ((isIntegral!R &&  isIntegral!L) && op == "<" || op == ">" || op == "<=" ||
892     op == ">=" || op == "==" || op == "!=")
893 {
894     alias LT = Unqual!L;
895     alias RT = Unqual!R;
896 
897     // transparent
898     static if (is(LT == RT) || op == "==" || op == "!=")
899     {
900         mixin("return lhs" ~ op ~ "rhs;");
901     }
902     else
903     {
904         enum err = fname ~ "(" ~ line.stringof ~ "): ";
905         enum wer = "warning, signed and unsigned comparison, the unsigned operand has been widened";
906 
907         template Widened(T)
908         {
909             static if (is(T==ubyte))
910                 alias Widened = short;
911             else static if (is(T==ushort))
912                 alias Widened = int;
913             else static if (is(T==uint))
914                 alias Widened = long;
915         }
916 
917         // widen unsigned to bigger signed
918         static if (isSigned!LT && !isSigned!RT  && RT.sizeof < 8)
919         {
920             version(D_Warnings) pragma(msg, err ~ wer);
921             Widened!RT widenedRhs = rhs;
922             mixin("return lhs" ~ op ~ "widenedRhs;");
923         }
924         else static if (isSigned!RT && !isSigned!LT  && LT.sizeof < 8)
925         {
926             version(D_Warnings) pragma(msg, err ~ wer);
927             Widened!LT widenedLhs = lhs;
928             mixin("return widenedLhs" ~ op ~ "rhs;");
929         }
930         // not fixable by widening
931         else
932         {
933             pragma(msg, err ~ "warning, comparing a " ~ L.stringof ~ " with a "
934                 ~ R.stringof ~ " may result into wrong results");
935             mixin("return lhs" ~ op ~ "rhs;");
936         }
937     }
938 }
939 ///
940 pure @safe @nogc nothrow unittest
941 {
942     int a = -1; uint b;
943     assert(a > b); // wrong result
944     assert(compare!">"(a,b) == false); // fixed by operand widening
945     assert(b < a); // wrong result
946     assert(compare!"<"(b,a) == false); // fixed by operand widening
947 
948     long aa = -1; ulong bb;
949     assert(aa > bb); // wrong result
950     assert(compare!">"(aa,bb) == true); // not statically fixable
951     assert(bb < aa); // wrong result
952     assert(compare!"<"(bb,aa) == true); // not statically fixable
953 
954     assert(compare!"!="(bb,aa) == true); // test for equality is always transparent OP
955 
956     immutable long aaa = -1; const ulong bbb;
957     assert(compare!">"(aaa,bbb) == true);
958 }
959 
960 /**
961  * Throws a static exception, suitable for @nogc functions.
962  */
963 @nogc @safe
964 void throwStaticEx(T, string file = __FILE__, size_t line = __LINE__)()
965 {
966     static const e = new T(file, line);
967     throw e;
968 }
969 
970 /// ditto
971 @nogc @safe
972 void throwStaticEx(string message, string file = __FILE__, size_t line = __LINE__)()
973 {
974     static const e = new Exception(message, file, line);
975     throw e;
976 }
977 
978 /**
979  * Sets the context and the function of a delegate.
980  *
981  * Params:
982  *      T = The type of the delegate.
983  *      t = The delegate to set.
984  *      context = The context pointer, e.g a pointer to a struct or a class instance.
985  *      code = The pointer to the static function.
986  */
987 void setDelegate(T, FT)(ref T t, void* context, FT code)
988 if (is(T == delegate) && is(FT == typeof(T.funcptr)))
989 {
990     t.ptr = context;
991     t.funcptr = code;
992 }
993 ///
994 unittest
995 {
996     struct Foo
997     {
998         bool fun(){return true;}
999     }
1000     Foo foo;
1001     bool delegate() atFun;
1002     atFun.setDelegate(&foo, &Foo.fun);
1003     assert(atFun());
1004 }
1005 
1006 /**
1007  * Sets the context and the function of a new delegate.
1008  *
1009  * Params:
1010  *      T = The type of the delegate.
1011  *      t = The delegate to set.
1012  *      context = The context pointer, e.g a pointer to a struct or a class instance.
1013  *      code = The pointer to the static function.
1014  *
1015  * Returns:
1016  *      A new delegate of type T.
1017  */
1018 auto getDelegate(FT)(void* context, FT code)
1019 if (is(PointerTarget!FT == function))
1020 {
1021     import std.array: replace;
1022     enum type = "alias T = " ~ FT.stringof.replace("function", "delegate") ~ ";";
1023     mixin(type);
1024     T t;
1025     t.ptr = context;
1026     t.funcptr = code;
1027     return t;
1028 }
1029 ///
1030 unittest
1031 {
1032     struct Foo
1033     {
1034         bool fun(){return true;}
1035     }
1036     Foo foo;
1037     bool delegate() atFun = getDelegate(&foo, &Foo.fun);
1038     assert(atFun());
1039 }
1040 
1041 /**
1042  * The delegate union is a conveniant way to setup non gc delegates that
1043  * are compatible with D delegates.
1044  */
1045 union Delegate(FT)
1046 if (is(PointerTarget!FT == function))
1047 {
1048     /// Defines the delegate layout as defined in the D ABI
1049     struct DgMembers
1050     {
1051         /// The $(D this).
1052         void* ptr;
1053         /// The pointer to the function.
1054         FT funcptr;
1055     }
1056 
1057     //// The delegates members;
1058     DgMembers members;
1059     alias members this;
1060 
1061     import std.array: replace;
1062     private enum type = "alias T = " ~ FT.stringof.replace("function", "delegate") ~ ";";
1063     mixin(type);
1064 
1065     /// Allows to use this union as a true D delegate.
1066     T dg;
1067 
1068     /// Helper to call the delegate without accessing $(D dg).
1069     auto opCall(A...)(A a)
1070     {
1071         return dg(a);
1072     }
1073 }
1074 ///
1075 unittest
1076 {
1077     struct Foo
1078     {
1079         bool fun(){return true;}
1080     }
1081     Foo foo;
1082     Delegate!(typeof(&Foo.fun)) atFun;
1083     atFun.ptr = &foo,
1084     atFun.funcptr = &Foo.fun,
1085     assert(atFun());
1086 }
1087 
1088 /**
1089  * Safely cast a value of a type to another, if both have the same size.
1090  *
1091  * Unlike $(D bruteCast), the same location si not shared between the
1092  * source and the target and no pointer is used.
1093  * This function is inspired by http://www.forwardscattering.org/post/27
1094  */
1095 template bitCast(T, S)
1096 if (T.sizeof == S.sizeof
1097     && !is(S == T)
1098     && !(is(S== float) & (size_t.sizeof == 4))
1099     && !is(S == class)     && !is(T == class)
1100     && !is(S == interface) && !is(T == interface))
1101 {
1102     private union BitCaster
1103     {
1104         S ss;
1105         T tt;
1106     }
1107 
1108     static assert(BitCaster.sizeof == S.sizeof);
1109 
1110     pragma(inline, true)
1111     T bitCast(auto ref S s)
1112     {
1113         BitCaster bt;
1114         bt.ss = s;
1115         return bt.tt;
1116     }
1117 }
1118 ///
1119 @safe pure nothrow unittest
1120 {
1121     assert(bitCast!int(1.0f) == 0x3f800000);
1122     version(LittleEndian)
1123         assert(bitCast!(ubyte[2])(ushort(0x1234)) == [0x34, 0x12]);
1124     else
1125         assert(bitCast!(ubyte[2])(ushort(0x1234)) == [0x12, 0x34]);
1126 }
1127 
1128 /// ditto
1129 template bitCast(T, S)
1130 if (T.sizeof == S.sizeof && is(S == float)
1131     && !is(T == class) && !is(T == interface))
1132 {
1133     T bitCast(S[1] source...) pure
1134     {
1135         // S[1]: prevent the source to be loaded in ST(0)
1136         // and any normalization to happen.
1137         asm @trusted @nogc pure nothrow
1138         {
1139             naked;
1140             ret;
1141         }
1142     }
1143 }
1144 
1145 /// Deep iteration mode
1146 enum IdMode
1147 {
1148     depth,
1149     breadth
1150 }
1151 
1152 /**
1153  * Iterates a tree-like structure that exposes an input range interface and calls
1154  * each element with a function.
1155  *
1156  * Params:
1157  *      Fun = The function called for each element. When its return type is bool,
1158  *          and if it returns true, the iterations are stopped.
1159  *      member = The name of the member that gives the real Range.
1160  *      mode = The iteration mode (breadth-first or depth-first).
1161  *      range = The root element.
1162  *      a = The variadic parameters passed to Fun (after the element).
1163  * Returns:
1164  *      True if the iterations have stopped, false otherwise.
1165  */
1166 bool deepIterate(alias Fun, string member = "", IdMode mode = IdMode.breadth,
1167     Range, A...)(Range range, auto ref A a)
1168 {
1169     static if (!member.length)
1170     {
1171         alias Rng = Range;
1172         alias M = void;
1173     }
1174     else
1175     {
1176         mixin("alias M = typeof(Range." ~ member ~ ");");
1177         static assert(__traits(hasMember, Range, member),
1178             "invalid Range member, Range has no member named '" ~ member ~ "'");
1179     }
1180     enum callable = isCallable!M;
1181     static if (callable)
1182         alias Rng = ReturnType!M;
1183     static assert(isInputRange!Rng && is(ElementType!Rng == Range),
1184         "invalid deepIterate Range");
1185 
1186     static if (is(ReturnType!Fun))
1187     {
1188         alias R = ReturnType!Fun;
1189         enum funIsPred = is(R == bool);
1190     }
1191     else enum funIsPred = false;
1192 
1193     bool result;
1194 
1195     enum callWithFront =
1196     q{
1197         static if (funIsPred)
1198             result = Fun(range, a);
1199         else
1200             Fun(range, a);
1201         if (result)
1202             return true;
1203     };
1204 
1205     static if (!__traits(hasMember, range, "front"))
1206     {
1207         import std.range.primitives: front, empty, popFront;
1208     }
1209 
1210     static if (mode == IdMode.breadth)
1211         mixin(callWithFront);
1212 
1213     static if (!member.length)
1214         alias items = range;
1215     else static if (callable)
1216         mixin("auto items = range." ~ member ~ ";");
1217     else
1218         mixin("alias items = range." ~ member ~ ";");
1219 
1220     while (!items.empty)
1221     {
1222         result = deepIterate!(Fun, member, mode, Range, A)(items.front, a);
1223         if (result)
1224             break;
1225         items.popFront;
1226     }
1227 
1228     static if (mode == IdMode.depth)
1229         mixin(callWithFront);
1230 
1231     return result;
1232 }
1233 ///
1234 unittest
1235 {
1236     // creates a tree
1237     Item root = new Item;
1238     root.populate;
1239     root[0].populate;
1240     root[1].populate;
1241 
1242     int cnt, a;
1243 
1244     // count the population
1245     deepIterate!((e) => ++cnt)(root);
1246     assert(cnt == 7);
1247 
1248     // previous content is consumed
1249     root.populate;
1250     root[0].populate;
1251     root[1].populate;
1252 
1253     // the delegate result is used to stop the iteration
1254     deepIterate!((Item e, ref int p){++p; --cnt; return cnt == 4;})(root, a);
1255     assert(cnt == 4);
1256     assert(a == 3);
1257 }
1258 
1259 version(unittest) private class Item
1260 {
1261     alias children this;
1262     Item[] children;
1263     void populate()
1264     {
1265         children.length = 2;
1266         children[0] = new Item;
1267         children[1] = new Item;
1268         assert(children.length == 2);
1269     }
1270 }
1271 
1272 unittest
1273 {
1274     import iz.containers: ObjectTreeItem;
1275     import iz.memory: construct, destruct;
1276     ObjectTreeItem root = construct!ObjectTreeItem;
1277     ObjectTreeItem c1 = root.addNewChild!ObjectTreeItem;
1278     ObjectTreeItem c2 = root.addNewChild!ObjectTreeItem;
1279     ObjectTreeItem c1c1 = c1.addNewChild!ObjectTreeItem;
1280     ObjectTreeItem c1c2 = c1.addNewChild!ObjectTreeItem;
1281     ObjectTreeItem c2c1 = c2.addNewChild!ObjectTreeItem;
1282     ObjectTreeItem c2c2 = c2.addNewChild!ObjectTreeItem;
1283 
1284     int cnt, a;
1285     deepIterate!((e) => ++cnt, "children")(root);
1286     assert(cnt == 7);
1287 
1288     root.deleteChildren;
1289     destruct(root);
1290 }
1291 
1292 /**
1293  * Allows to call recursively the function being executed.
1294  *
1295  * Params:
1296  *      a = the parameters expected by the function.
1297  * Examples:
1298  *
1299  * ---
1300  * long factorial(long a)
1301  * {
1302  *     if (a <= 1)
1303  *         return a;
1304  *      else
1305  *          return a * recursion(a-1);
1306  * }
1307  * ---
1308  *
1309  * Returns:
1310  *      The same as the function being executed.
1311  */
1312 auto recursion(string Fun = __FUNCTION__ , A...)(auto ref A a)
1313 {
1314     import std.typecons: tuple;
1315     mixin("return " ~ Fun ~ "(" ~ a.stringof ~ "[0..$]);");
1316 }
1317 
1318 /**
1319  * Used the annotate the member functions that wrap other member functions.
1320  * Each instance must specify aither the type, the instance and the name of the
1321  * function that's wrapped or the name of a context-free function.
1322  * Each string must be colon-separated.
1323  */
1324 struct Wrap{string[] targets;}
1325 ///
1326 unittest
1327 {
1328     struct Foo
1329     {
1330         @Wrap(["Type:instance:name", "freeFunction"])
1331         void foo(){}
1332     }
1333 }
1334 
1335 /**
1336  * Scans the method wrapped by the caller.
1337  *
1338  * Params:
1339  *      f = The caller' s name. Autodetected.
1340  *      returns = The variables that get the result of each wrapped function.
1341  *      They must be references.
1342  *
1343  * Returns:
1344  *      A string that has to be mixed in the caller's body.
1345  */
1346 string applyWrap(string f = __FUNCTION__, R...)(ref R returns)
1347 {
1348     static assert(R.length == 0, "returns are not implemented yet");
1349 
1350     import std.array: array;
1351     import std.algorithm.iteration: splitter;
1352     import std.meta: aliasSeqOf;
1353     import std.range: iota;
1354     import std..string: join;
1355     import std.traits: getUDAs, Parameters, ParameterIdentifierTuple,  ReturnType;
1356 
1357     alias attrbs = getUDAs!(mixin(f), Wrap);
1358     alias params = Parameters!(mixin(f));
1359 
1360     string result;
1361 
1362     foreach(i; aliasSeqOf!(iota(0, attrbs.length)))
1363     {
1364         foreach(j; aliasSeqOf!(iota(0, attrbs[i].targets.length)))
1365         {
1366             enum s = splitter(attrbs[i].targets[j], ":").array;
1367 
1368             if (s.length != 3 && s.length != 1)
1369             {
1370                 assert(0, "Invalid Type:instance:method specifier: \n"
1371                     ~ attrbs[i].targets[j]);
1372             }
1373             static if (s.length == 3)
1374             {
1375                 static assert (__traits(hasMember, mixin(s[0]), s[2]), s[0]  ~
1376                     " has no member named " ~ s[2]);
1377                 enum typeDotMethod = s[0] ~ "." ~ s[2];
1378                 enum instanceDotMethod = s[1] ~ "." ~ s[2];
1379                 alias p = Parameters!(mixin(typeDotMethod));
1380                 alias r = ReturnType!(mixin(typeDotMethod));
1381             }
1382             else
1383             {
1384                 alias p = Parameters!(mixin(s[0]));
1385                 alias r = ReturnType!(mixin(s[0]));
1386             }
1387 
1388             static if (!p.length)
1389             {
1390                 static if (s.length == 3)
1391                     result ~= instanceDotMethod ~ ";";
1392                 else
1393                     result ~= s[0] ~ ";";
1394             }
1395             else static if (is(p == params))
1396             {
1397                 static if (s.length == 3)
1398                 {
1399                     alias n = ParameterIdentifierTuple!(mixin(typeDotMethod));
1400                     result ~= instanceDotMethod ~ "(" ~ [n[0..$]].join(", ") ~ ");";
1401                 }
1402                 else
1403                 {
1404                     alias n = ParameterIdentifierTuple!(mixin(s[0]));
1405                     result ~= s[0] ~ "(" ~ [n[0..$]].join(", ") ~ ");";
1406                 }
1407             }
1408             else static assert(0, "incompatible parameters: \n"
1409                 ~ "got     :" ~ p.stringof ~ "\n"
1410                 ~ "expected:" ~ params.stringof);
1411         }
1412     }
1413     return result;
1414 }
1415 ///
1416 version (none) unittest
1417 {
1418     static bool int42, int8, ffree1, ffree2;
1419 
1420     static struct Inner
1421     {
1422         void foo(int p0, int p1){int42 = true; int8 = true;}
1423         void bar() {ffree1 = true;}
1424     }
1425 
1426     static void freeFunc()
1427     {
1428         ffree2 = true;
1429     }
1430 
1431     static struct Composed
1432     {
1433         Inner inner;
1434 
1435         @Wrap(["Inner:inner:foo", "Inner:inner:bar", "freeFunc"])
1436         void foo(int p0, int p1)
1437         {
1438             mixin(applyWrap());
1439         }
1440     }
1441 
1442     static  Composed c;
1443     c.foo(42,8);
1444     assert(int42 & int8 & ffree1 & ffree2);
1445 }
1446 
1447 /**
1448  * Wraps a floating point type that doesn't follow D permissive float conversion
1449  * rules.
1450  *
1451  * In D, as in C++, implicit conversion from $(D double) to $(D float) is allowed,
1452  * leading to a possible precision loss. This can't happen when using this wrapper.
1453  */
1454 struct CoercionSafeFloat(T)
1455 if (isFloatingPoint!T)
1456 {
1457     private T _value;
1458     alias _value this;
1459 
1460     private enum antiCoercion =
1461     q{
1462         static assert(V.sizeof <= T.sizeof, "coercion from " ~ V.stringof ~
1463         " to " ~ T.stringof ~ " is not allowed");
1464     };
1465 
1466     /// Prevent Coercion from construction.
1467     this(V)(V v) {mixin(antiCoercion); _value = v;}
1468 
1469     /// Prevent Coercion from assignation.
1470     void opAssign(V)(V v) {mixin(antiCoercion); _value = v;}
1471     /// Prevent Coercion from operator assignation.
1472     void opOpAssign(string op, V)(V v)
1473     {
1474         mixin(antiCoercion);
1475         mixin("_value " ~ op ~ "= v;");
1476     }
1477 }
1478 ///
1479 unittest
1480 {
1481     alias Float = CoercionSafeFloat!float;
1482     alias Double = CoercionSafeFloat!double;
1483     alias Real = CoercionSafeFloat!real;
1484 
1485     Float f; Double d; Real r;
1486 
1487     import std.math;
1488     static assert(!__traits(compiles, f = (atan(1.0) * 4) / 2));
1489     static assert( __traits(compiles, f = (atan(1.0f) * 4f) / 2f));
1490     static assert(!__traits(compiles, d = (atan(1.0L) * 4L) / 2L));
1491     static assert(__traits(compiles, d = f));
1492     static assert(!__traits(compiles, f = d));
1493     static assert(!__traits(compiles, d = r));
1494     static assert(!__traits(compiles, d += r));
1495     static assert(__traits(compiles, r *= d));
1496 }
1497 
1498 /**
1499  * Determines if a module can be imported, allowing to create optional
1500  * static branches.
1501  *
1502  * Params:
1503  *      mod = The module to be optionally imported, as a string.
1504  */
1505 enum bool canImport(string mod) = is(typeof({mixin("import " ~ mod ~ ";");}));
1506 ///
1507 unittest
1508 {
1509     // likely importable...
1510     static if (canImport!"std.stdio") {} else {assert(false);}
1511     // not so much...
1512     static if (canImport!"std.experimental.xml") {assert(false);}
1513     static if (canImport!"std.experimental.color") {assert(false);}
1514 }
1515 
1516 /**
1517  * Allows to call a non $(D const) method as if it was $(D const).
1518  *
1519  * Params:
1520  *      func = The member function to call.
1521  *      aggr = The aggregate that contains $(D_Param func).
1522  *      a = The parameters passed when calling $(D_Param func).
1523  *
1524  * Returns:
1525  *      Depends on $(D_Param func) return type.
1526  */
1527 auto constCall(string func, Aggr, A...)(Aggr aggr, auto ref A a)
1528 if (__traits(hasMember, Aggr, func))
1529 {
1530     mixin(
1531         "auto p = cast() aggr;" ~
1532         "alias Dg = typeof(&p." ~ func ~ ");" ~
1533         "return p." ~ func ~ "(a);"
1534     );
1535 }
1536 ///
1537 unittest
1538 {
1539     static struct Foo
1540     {
1541         int a;
1542 
1543         void nonConstFunc()  { a = 1;}
1544         void constFunc() const {constCall!"nonConstFunc"(this);}
1545     }
1546     Foo foo;
1547     foo.constFunc();
1548 }
1549 
1550 
1551 /**
1552  * Allows to build access chains of class members as done with the $(D ?.) operator
1553  * in other languages. In the chain, any $(D null) member that is a class instance
1554  * or that returns one, has for effect to shortcut the complete evaluation.
1555  *
1556  * Params:
1557  *      M = The class type of the chain entry point.
1558  *
1559  * Bugs:
1560  *      Assigning a member only works with $(D unwrap).
1561  */
1562 struct SafeAccess(M)
1563 if (is(M == class))
1564 {
1565     M m;
1566 
1567     @disable this();
1568 
1569     /**
1570      * Instantiate.
1571      *
1572      * Params:
1573      *      m = An instance of the entry point type. It is usually only
1574      *      $(D null) when the constructor is used internally, to build
1575      *      the chain.
1576      */
1577     this(M m)
1578     {
1579         this.m = m;
1580     }
1581 
1582     //TODO-cbugfix: assignation at the end of the chain only works with unwrap
1583 
1584     alias m this;
1585     /// Unprotect the class instance.
1586     alias unwrap = m;
1587 
1588     /// Handles safe access.
1589     auto ref opDispatch(string member, A...)(auto ref A a)
1590     {
1591         alias T = typeof(__traits(getMember, m, member));
1592         static if (is(T == class))
1593         {
1594             return (!m || !__traits(getMember, m, member))
1595                 ? SafeAccess!T(null)
1596                 : SafeAccess!T(__traits(getMember, m, member));
1597         }
1598         else
1599         {
1600             static if (isFunction!T)
1601             {
1602                 // otherwise there's a missing return statement.
1603                 alias R = ReturnType!T;
1604                 static if (!is(R == void) &&
1605                     !(is(R == class) && Parameters!T.length == 0))
1606                         pragma(msg, __FILE__ ~ "(" ~ __LINE__.stringof ~ "): error, " ~
1607                         "only `void function`s or `class` getters can be called without unwrap");
1608 
1609                 static if (is(R == class))
1610                 {
1611                     return (m is null)
1612                         ? SafeAccess!R(null)
1613                         : SafeAccess!R(__traits(getMember, m, member)(a));
1614                 }
1615                 else
1616                 {
1617                     if (m)
1618                         __traits(getMember, m, member)(a);
1619                 }
1620             }
1621             else
1622             {
1623                 if (m)
1624                     __traits(getMember, m, member) = a;
1625             }
1626         }
1627     }
1628 }
1629 /// General usage
1630 @safe unittest
1631 {
1632     import std.exception;
1633 
1634     class LongLineOfIdent3{int foo; void setFoo(int v) @safe{foo = v;}}
1635     class LongLineOfIdent2{LongLineOfIdent3 longLineOfIdent3;}
1636     class LongLineOfIdent1{LongLineOfIdent2 longLineOfIdent2;}
1637     class Root {LongLineOfIdent1 longLineOfIdent1;}
1638 
1639     SafeAccess!Root sar = SafeAccess!Root(new Root);
1640     // without the SafeAccess we would receive a SIGSEGV here
1641     sar.longLineOfIdent1.longLineOfIdent2.longLineOfIdent3.setFoo(0xDEADBEEF);
1642 
1643     bool notAccessed = true;
1644     // the same with `&&` whould be much longer
1645     if (LongLineOfIdent3 a = sar.longLineOfIdent1.longLineOfIdent2.longLineOfIdent3)
1646     {
1647         notAccessed = false;
1648     }
1649     assert(notAccessed);
1650 
1651     // checks that forwarding actually works
1652     sar.m.longLineOfIdent1 = new LongLineOfIdent1;
1653     sar.m.longLineOfIdent1.longLineOfIdent2 = new LongLineOfIdent2;
1654     sar.m.longLineOfIdent1.longLineOfIdent2.longLineOfIdent3 = new LongLineOfIdent3;
1655 
1656     sar.longLineOfIdent1.longLineOfIdent2.longLineOfIdent3.setFoo(42);
1657     assert(sar.longLineOfIdent1.longLineOfIdent2.longLineOfIdent3.unwrap.foo == 42);
1658 }
1659 
1660 /// Getters are also supported
1661 unittest
1662 {
1663     class Second {}
1664     class First
1665     {
1666         Second _second;
1667         Second second(){return _second;}
1668         this(){_second = new Second;}
1669     }
1670     bool accessed;
1671     if (Second s = safeAccess(new First).second)
1672     {
1673         assert(s);
1674         accessed = true;
1675     }
1676     assert(accessed);
1677 }
1678 
1679 unittest
1680 {
1681     class Second {}
1682     class First
1683     {
1684         Second _second;
1685         Second second(){return _second;}
1686     }
1687     bool notAccessed = true;
1688     if (Second a = safeAccess(new First).second)
1689     {
1690         notAccessed = false;
1691     }
1692     assert(notAccessed);
1693 }
1694 
1695 /**
1696  * IFTI helper for $(D SafeAccess).
1697  *
1698  * Returns:
1699  *      $(D m) with the ability to safely access its members that are class
1700  *      instances.
1701  */
1702 auto ref safeAccess(M)(M m)
1703 {
1704     return SafeAccess!M(m);
1705 }
1706