1 /*******************************************************************************
2 
3     Collection of utilities to modify arrays and buffers in-place.
4 
5     All functions in this module only work on mutable arguments and modify them
6     in place. New memory must never be allocated.
7 
8     Based on `tango.core.Array` module from Tango library.
9 
10     Copyright:
11         Copyright (C) 2005-2006 Sean Kelly.
12         Some parts copyright (c) 2009-2016 dunnhumby Germany GmbH.
13         All rights reserved.
14 
15     License:
16         Tango Dual License: 3-Clause BSD License / Academic Free License v3.0.
17         See LICENSE_TANGO.txt for details.
18 
19 *******************************************************************************/
20 
21 module ocean.core.array.Mutation;
22 
23 
24 import ocean.transition;
25 
26 import core.stdc.string; // memmove, memset
27 import core.stdc.math; // fabs;
28 
29 import ocean.meta.traits.Basic;
30 import ocean.meta.types.Function;
31 import ocean.meta.AliasSeq;
32 import ocean.core.Buffer;
33 import ocean.core.array.DefaultPredicates;
34 import ocean.core.Verify;
35 
36 version (UnitTest)
37 {
38     import ocean.core.Test;
39     import ocean.text.convert.Formatter;
40 }
41 
42 /*******************************************************************************
43 
44     Performs a linear scan of complete array, replacing occurrences of
45     specified element with the new element.  Comparisons will be performed
46     using the supplied predicate or '==' if none is supplied.
47 
48     Params:
49         array = The array to scan.
50         element = The pattern to match.
51         new_element = The value to substitute.
52         pred  = The evaluation predicate, which should return true if e1 is
53             equal to e2 and false if not.  This predicate may be any
54             callable type.
55 
56     Returns:
57         The number of elements replaced.
58 
59 *******************************************************************************/
60 
61 size_t replace ( T, Pred = DefaultPredicates.IsEqual!(T) )
62     ( T[] array, in T element, T new_element, Pred pred = Pred.init )
63 {
64     static assert( isCallableType!(Pred) );
65 
66     size_t cnt = 0;
67 
68     foreach( size_t pos, ref T cur; array )
69     {
70         if( pred( cur, element ) )
71         {
72             cur = new_element;
73             ++cnt;
74         }
75     }
76 
77     return cnt;
78 }
79 
80 ///
81 unittest
82 {
83     auto array = "abbbbc".dup;
84     test!("==")(replace(array, 'b', 'x'), 4);
85     test!("==")(array, "axxxxc");
86 }
87 
88 unittest
89 {
90     test!("==")( replace( "gbbbi".dup, 'a', 'b' ), 0 );
91     test!("==")( replace( "gbbbi".dup, 'g', 'h' ), 1 );
92     test!("==")( replace( "gbbbi".dup, 'b', 'c' ), 3 );
93     test!("==")( replace( "gbbbi".dup, 'i', 'j' ), 1 );
94     test!("==")( replace( "gbbbi".dup, 'd', 'e' ), 0 );
95 }
96 
97 /// ditto
98 size_t replace ( T, Pred = DefaultPredicates.IsEqual!(T) )
99     ( ref Buffer!(T) array, in T element, T new_element, Pred pred = Pred.init )
100 {
101     return replace(array[0..array.length], element, new_element, pred);
102 }
103 
104 ///
105 unittest
106 {
107     auto buffer = createBuffer("abbbbc");
108     test!("==")(replace(buffer, 'b', 'x'), 4);
109     test!("==")(buffer[], "axxxxc");
110 }
111 
112 /*******************************************************************************
113 
114     Performs a linear scan of the complete array, replacing elements where pred
115     returns true.
116 
117     Params:
118         array = The array to scan.
119         new_element = The value to substitute.
120         pred = The evaluation predicate, which should return true if the
121             element is a valid match and false if not.  This predicate
122             may be any callable type.
123 
124     Returns:
125     The number of elements replaced.
126 
127 *******************************************************************************/
128 
129 size_t replaceIf ( T, Pred ) ( T[] array, T new_element, Pred pred )
130 {
131     static assert( isCallableType!(Pred) );
132 
133     size_t cnt = 0;
134 
135     foreach( size_t pos, ref T cur; array )
136     {
137         if( pred( cur ) )
138         {
139             cur = new_element;
140             ++cnt;
141         }
142     }
143     return cnt;
144 }
145 
146 ///
147 unittest
148 {
149     auto array = "abbc".dup;
150     test!("==")(replaceIf(array, 'x', (char c) { return c > 'a'; }), 3);
151     test!("==")(array, "axxx");
152 }
153 
154 /// ditto
155 size_t replaceIf ( T, Pred ) ( ref Buffer!(T) array, T new_element, Pred pred )
156 {
157     return replaceIf(array[0..array.length], new_element, pred);
158 }
159 
160 ///
161 unittest
162 {
163     auto buffer = createBuffer("abbc");
164     test!("==")(replaceIf(buffer, 'x', (char c) { return c > 'a'; }), 3);
165     test!("==")(buffer[], "axxx");
166 }
167 
168 unittest
169 {
170     test!("==")( replaceIf( "gbbbi".dup, 'b', ( char c ) { return c == 'a'; } ), 0 );
171     test!("==")( replaceIf( "gbbbi".dup, 'h', ( char c ) { return c == 'g'; } ), 1 );
172     test!("==")( replaceIf( "gbbbi".dup, 'c', ( char c ) { return c == 'b'; } ), 3 );
173     test!("==")( replaceIf( "gbbbi".dup, 'j', ( char c ) { return c == 'i'; } ), 1 );
174     test!("==")( replaceIf( "gbbbi".dup, 'e', ( char c ) { return c == 'd'; } ), 0 );
175 }
176 
177 /*******************************************************************************
178 
179     Performs a linear scan of complete array, moving all items matching
180     element to the end of the sequence.  The relative order of items not
181     matching the matching element will be preserved.  Comparisons will be
182     performed using the supplied predicate or '==' if none is supplied.
183 
184     Params:
185         array = The array to scan. This parameter is not marked 'ref'
186             to allow temporary slices to be modified.  As array is not resized
187             in any way, omitting the 'ref' qualifier has no effect on the
188             result of this operation, even though it may be viewed as a
189             side-effect.
190         element = The element value to look for
191         pred = The evaluation predicate, which should return true if e1 is
192             equal to e2 and false if not.  This predicate may be any
193             callable type.
194 
195     Returns:
196         The number of elements that do not match element.
197 
198 *******************************************************************************/
199 
200 size_t moveToEnd ( T, Pred = DefaultPredicates.IsEqual!(T) )
201     ( T[] array, in T element, Pred pred = Pred.init )
202 {
203     static assert( isCallableType!(Pred) );
204 
205     // NOTE: Indexes are passed instead of references because DMD does
206     //       not inline the reference-based version.
207     void exch( size_t p1, size_t p2 )
208     {
209         T t = array[p1];
210         array[p1] = array[p2];
211         array[p2] = t;
212     }
213 
214     size_t cnt = 0;
215 
216     for( size_t pos = 0, len = array.length; pos < len; ++pos )
217     {
218         if( pred( array[pos], element ) )
219             ++cnt;
220         else
221             exch( pos, pos - cnt );
222     }
223     return array.length - cnt;
224 }
225 
226 /// ditto
227 size_t moveToEnd ( T, Pred = DefaultPredicates.IsEqual!(T) )
228     ( ref Buffer!(T) array, in T element, Pred pred = Pred.init )
229 {
230     return moveToEnd(array[0..array.length], element, pred);
231 }
232 
233 ///
234 unittest
235 {
236     auto buffer = createBuffer("abbcc");
237     test!("==")(moveToEnd(buffer, 'b'), 3);
238     test!("==")(buffer[], "accbb");
239 }
240 
241 unittest
242 {
243     static void testOne ( cstring _array,
244         char element, size_t num, int line = __LINE__ )
245     {
246         auto array = _array.dup;
247         auto t = new NamedTest(format("moveToEnd.testOne:{}", line));
248         t.test!("==")(moveToEnd(array, element), num);
249         foreach (pos, cur; array)
250             t.test(pos < num ? cur != element : cur == element);
251     }
252 
253     testOne("abcdefghij", 'x', 10);
254     testOne("xabcdefghi", 'x',  9);
255     testOne("abcdefghix", 'x',  9);
256     testOne("abxxcdefgh", 'x',  8);
257     testOne("xaxbcdxxex", 'x',  5);
258 }
259 
260 /*******************************************************************************
261 
262     Performs a linear scan of complete array, removing all elements that satisfy
263     pred from the sequence.  The relative order of elements that do not satisfy
264     pred will be preserved.
265 
266     Params:
267     array = The array to scan.  This parameter is not marked 'ref'
268            to allow temporary slices to be modified.  As array is not resized
269            in any way, omitting the 'ref' qualifier has no effect on the
270            result of this operation, even though it may be viewed as a
271            side-effect.
272     pred = The evaluation predicate, which should return true if the
273            element satisfies the condition and false if not.  This
274            predicate may be any callable type.
275 
276     Returns:
277         The number of elements that do not satisfy pred.
278 
279 *******************************************************************************/
280 
281 size_t removeIf ( T, Pred ) ( T[] array, Pred pred )
282 {
283     static assert( isCallableType!(Pred) );
284 
285     // NOTE: Indexes are passed instead of references because DMD does
286     //       not inline the reference-based version.
287     void exch( size_t p1, size_t p2 )
288     {
289         T t  = array[p1];
290         array[p1] = array[p2];
291         array[p2] = t;
292     }
293 
294     size_t cnt = 0;
295 
296     for( size_t pos = 0, len = array.length; pos < len; ++pos )
297     {
298         if( pred( array[pos] ) )
299             ++cnt;
300         else
301             exch( pos, pos - cnt );
302     }
303     return array.length - cnt;
304 }
305 
306 ///
307 unittest
308 {
309     auto array = "abbcc".dup;
310     test!("==")(removeIf(array, (char c) { return c == 'b'; }), 3);
311     test!("==")(array, "accbb");
312 }
313 
314 /// ditto
315 size_t removeIf ( T, Pred ) ( ref Buffer!(T) array, Pred pred )
316 {
317     return removeIf(array[0..array.length], pred);
318 }
319 
320 ///
321 unittest
322 {
323     auto buffer = createBuffer("abbcc");
324     test!("==")(removeIf(buffer, (char c) { return c == 'b'; }), 3);
325     test!("==")(buffer[], "accbb");
326 }
327 
328 unittest
329 {
330     static void testOne ( cstring _array,
331         scope bool delegate(char) dg, size_t num, int line = __LINE__ )
332     {
333         auto array = _array.dup;
334         auto t = new NamedTest(format("removeIf.testOne:{}", line));
335         t.test!("==")(removeIf( array, dg ), num);
336         foreach (pos, cur; array)
337             t.test(pos < num ? !dg( cur ) : dg( cur ));
338     }
339 
340     testOne("abcdefghij", ( char c ) { return c == 'x'; }, 10);
341     testOne("xabcdefghi", ( char c ) { return c == 'x'; },  9);
342     testOne("abcdefghix", ( char c ) { return c == 'x'; },  9);
343     testOne("abxxcdefgh", ( char c ) { return c == 'x'; },  8);
344     testOne("xaxbcdxxex", ( char c ) { return c == 'x'; },  5);
345 }
346 
347 /*******************************************************************************
348 
349     Performs a linear scan of complete array, moving all but the first element
350     of each consecutive group of duplicate elements to the end of the sequence.
351     The relative order of all remaining elements will be preserved.  Comparisons
352     will be performed using the supplied predicate or '==' if none is supplied.
353 
354     Params:
355         array = The array to scan.  This parameter is not marked 'ref'
356            to allow temporary slices to be modified.  As array is not resized
357            in any way, omitting the 'ref' qualifier has no effect on the
358            result of this operation, even though it may be viewed as a
359            side-effect.
360         pred = The evaluation predicate, which should return true if e1 is
361            equal to e2 and false if not.  This predicate may be any
362            callable type.
363 
364     Returns:
365         The number of distinct sub-sequences in array.
366 
367 *******************************************************************************/
368 
369 size_t distinct ( T, Pred = DefaultPredicates.IsEqual!(T) )
370     ( T[] array, Pred pred = Pred.init )
371 {
372     static assert( isCallableType!(Pred) );
373 
374     // NOTE: Indexes are passed instead of references because DMD does
375     //       not inline the reference-based version.
376     void exch( size_t p1, size_t p2 )
377     {
378         T t  = array[p1];
379         array[p1] = array[p2];
380         array[p2] = t;
381     }
382 
383     if( array.length < 2 )
384         return array.length;
385 
386     size_t cnt = 0;
387     T element = array[0];
388 
389     for( size_t pos = 1, len = array.length; pos < len; ++pos )
390     {
391         if( pred( array[pos], element ) )
392             ++cnt;
393         else
394         {
395             element = array[pos];
396             exch( pos, pos - cnt );
397         }
398     }
399     return array.length - cnt;
400 }
401 
402 ///
403 unittest
404 {
405     auto array = "aabbcdd".dup;
406     auto last = distinct(array);
407     test!("==")(array[0 .. last], "abcd");
408 }
409 
410 /// ditto
411 size_t distinct ( T, Pred = DefaultPredicates.IsEqual!(T) )
412     ( ref Buffer!(T) array, Pred pred = Pred.init )
413 {
414     return distinct(array[0..array.length], pred);
415 }
416 
417 ///
418 unittest
419 {
420     auto buffer = createBuffer("aabbcdd");
421     auto last = distinct(buffer);
422     test!("==")(buffer[0 .. last], "abcd");
423 }
424 
425 unittest
426 {
427     test!("==")(distinct("a".dup), 1);
428 
429     static void testOne ( cstring _array,
430         cstring expected, int line = __LINE__ )
431     {
432         auto array = _array.dup;
433         auto t = new NamedTest(format("distinct.testOne:{}", line));
434         t.test!("==")(distinct(array), expected.length);
435         t.test!("==")(array[0 .. expected.length], expected);
436     }
437 
438     testOne("abcdefghij", "abcdefghij");
439     testOne("aabcdefghi", "abcdefghi");
440     testOne("bcdefghijj", "bcdefghij");
441     testOne("abccdefghi", "abcdefghi");
442     testOne("abccdddefg", "abcdefg");
443 }
444 
445 /*******************************************************************************
446 
447     Partitions array such that all elements that satisfy pred will be placed
448     before the elements that do not satisfy pred.  The algorithm is not
449     required to be stable.
450 
451     Params:
452         array  = The array to partition.  This parameter is not marked 'ref'
453             to allow temporary slices to be sorted.  As array is not resized
454             in any way, omitting the 'ref' qualifier has no effect on
455             the result of this operation, even though it may be viewed
456             as a side-effect.
457         pred = The evaluation predicate, which should return true if the
458             element satisfies the condition and false if not.  This
459             predicate may be any callable type.
460 
461     Returns:
462         The number of elements that satisfy pred.
463 
464 *******************************************************************************/
465 
466 size_t partition ( T, Pred ) ( T[] array, Pred pred )
467 {
468     static assert( isCallableType!(Pred ) );
469 
470     // NOTE: Indexes are passed instead of references because DMD does
471     //       not inline the reference-based version.
472     void exch( size_t p1, size_t p2 )
473     {
474         T t = array[p1];
475         array[p1] = array[p2];
476         array[p2] = t;
477     }
478 
479     if( array.length == 0 )
480         return 0;
481 
482     size_t  l = 0,
483             r = array.length,
484             i = l,
485             j = r - 1;
486 
487     while( true )
488     {
489         while( i < r && pred( array[i] ) )
490             ++i;
491         while( j > l && !pred( array[j] ) )
492             --j;
493         if( i >= j )
494             break;
495         exch( i++, j-- );
496     }
497     return i;
498 }
499 
500 ///
501 unittest
502 {
503     auto array = "af242df56s2".dup;
504     test!("==")(partition(array, (char c) { return c >= '0' && c <= '9'; }), 6);
505 }
506 
507 /// ditto
508 size_t partition ( T, Pred ) ( ref Buffer!(T) array, Pred pred )
509 {
510     return partition(array[0..array.length], pred);
511 }
512 
513 ///
514 unittest
515 {
516     auto buffer = createBuffer("af242df56s2");
517     test!("==")(partition(buffer, (char c) { return c >= '0' && c <= '9'; }), 6);
518 }
519 
520 unittest
521 {
522     test!("==")(partition("".dup, (char c) { return true; }), 0);
523 
524     static void testOne ( cstring _array,
525         scope bool delegate(char) dg, size_t num, int line = __LINE__ )
526     {
527         auto array = _array.dup;
528         auto t = new NamedTest(format("partition.testOne:{}", line));
529         t.test!("==")(partition(array, dg), num);
530         for ( size_t pos = 0; pos < array.length; ++pos )
531             t.test( pos < num ? dg( array[pos] ) : !dg( array[pos] ) );
532     }
533 
534     testOne("abcdefg".dup, ( char c ) { return c < 'a'; }, 0);
535     testOne("gfedcba".dup, ( char c ) { return c < 'a'; }, 0);
536     testOne("abcdefg".dup, ( char c ) { return c < 'h'; }, 7);
537     testOne("gfedcba".dup, ( char c ) { return c < 'h'; }, 7);
538     testOne("abcdefg".dup, ( char c ) { return c < 'd'; }, 3);
539     testOne("gfedcba".dup, ( char c ) { return c < 'd'; }, 3);
540     testOne("bbdaabc".dup, ( char c ) { return c < 'c'; }, 5);
541     testOne("f".dup,       ( char c ) { return c == 'f'; }, 1);
542 }
543 
544 /*******************************************************************************
545 
546     Sorts array using the supplied predicate or '<' if none is supplied.  The
547     algorithm is not required to be stable.  The current implementation is
548     based on quicksort, but uses a three-way partitioning scheme to improve
549     performance for ranges containing duplicate values (Bentley and McIlroy,
550     1993).
551 
552     Params:
553         array = The array to sort.  This parameter is not marked 'ref' to
554             allow temporary slices to be sorted.  As array is not resized
555             in any way, omitting the 'ref' qualifier has no effect on
556             the result of this operation, even though it may be viewed
557             as a side-effect.
558         pred = The evaluation predicate, which should return true if e1 is
559             less than e2 and false if not.  This predicate may be any
560             callable type.
561 
562 *******************************************************************************/
563 
564 T[] sort ( T, Pred = DefaultPredicates.IsLess!(T) )
565     ( T[] array, Pred pred = Pred.init )
566 {
567     static assert( isCallableType!(Pred ) );
568 
569     bool equiv( T p1, T p2 )
570     {
571         return !pred( p1, p2 ) && !pred( p2, p1 );
572     }
573 
574     // NOTE: Indexes are passed instead of references because DMD does
575     //       not inline the reference-based version.
576     void exch( size_t p1, size_t p2 )
577     {
578         T t  = array[p1];
579         array[p1] = array[p2];
580         array[p2] = t;
581     }
582 
583     // NOTE: This algorithm operates on the inclusive range [l .. r].
584     void insertionSort( size_t l, size_t r )
585     {
586         for( size_t i = r; i > l; --i )
587         {
588             // swap the min element to array[0] to act as a sentinel
589             if( pred( array[i], array[i - 1] ) )
590                 exch( i, i - 1 );
591         }
592         for( size_t i = l + 2; i <= r; ++i )
593         {
594             size_t  j = i;
595             T    v = array[i];
596 
597             // don't need to test (j != l) because of the sentinel
598             while( pred( v, array[j - 1] ) )
599             {
600                 array[j] = array[j - 1];
601                 j--;
602             }
603             array[j] = v;
604         }
605     }
606 
607     size_t medianOf( size_t l, size_t m, size_t r )
608     {
609         if( pred( array[m], array[l] ) )
610         {
611             if( pred( array[r], array[m] ) )
612                 return m;
613             else
614             {
615                 if( pred( array[r], array[l] ) )
616                     return r;
617                 else
618                     return l;
619             }
620         }
621         else
622         {
623             if( pred( array[r], array[m] ) )
624             {
625                 if( pred( array[r], array[l] ) )
626                     return l;
627                 else
628                     return r;
629             }
630             else
631                 return m;
632         }
633     }
634 
635     // NOTE: This algorithm operates on the inclusive range [l .. r].
636     void quicksort( size_t l, size_t r, size_t d )
637     {
638         if( r <= l )
639             return;
640 
641         // HEURISTIC: Use insertion sort for sufficiently small arrays.
642         enum { MIN_LENGTH = 80 }
643         if( r - l < MIN_LENGTH )
644             return insertionSort( l, r );
645 
646         // HEURISTIC: Use the median-of-3 value as a pivot.  Swap this
647         //            into r so quicksort remains untouched.
648         exch( r, medianOf( l, l + (r - l) / 2, r ) );
649 
650         // This implementation of quicksort improves upon the classic
651         // algorithm by partitioning the array into three parts, one
652         // each for keys smaller than, equal to, and larger than the
653         // partitioning element, v:
654         //
655         // |--less than v--|--equal to v--|--greater than v--[v]
656         // l               j              i                   r
657         //
658         // This approach sorts ranges containing duplicate elements
659         // more quickly.  During processing, the following situation
660         // is maintained:
661         //
662         // |--equal--|--less--|--[###]--|--greater--|--equal--[v]
663         // l         p        i         j           q          r
664         //
665         // Please note that this implementation varies from the typical
666         // algorithm by replacing the use of signed index values with
667         // unsigned values.
668 
669         T v = array[r];
670         size_t  i = l,
671                 j = r,
672                 p = l,
673                 q = r;
674 
675         while( true )
676         {
677             while( pred( array[i], v ) )
678                 ++i;
679             while( pred( v, array[--j] ) )
680                 if( j == l ) break;
681             if( i >= j )
682                 break;
683             exch( i, j );
684             if( equiv( array[i], v ) )
685                 exch( p++, i );
686             if( equiv( v, array[j] ) )
687                 exch( --q, j );
688             ++i;
689         }
690         exch( i, r );
691         if( p < i )
692         {
693             j = i - 1;
694             for( size_t k = l; k < p; k++, j-- )
695                 exch( k, j );
696             quicksort( l, j, d );
697         }
698         if( ++i < q )
699         {
700             for( size_t k = r - 1; k >= q; k--, i++ )
701                 exch( k, i );
702             quicksort( i, r, d );
703         }
704     }
705 
706     size_t maxDepth( size_t x )
707     {
708         size_t d = 0;
709 
710         do
711         {
712             ++d;
713             x /= 2;
714         } while( x > 1 );
715         return d * 2; // same as "floor( log( x ) / log( 2 ) ) * 2"
716     }
717 
718     if( array.length > 1 )
719     {
720         quicksort( 0, array.length - 1, maxDepth( array.length ) );
721     }
722 
723     return array;
724 }
725 
726 unittest
727 {
728     static void testOne ( cstring _array, int line = __LINE__ )
729     {
730         auto array = _array.dup;
731         auto t = new NamedTest(format("sort.testOne:{}", line));
732         sort( array );
733         for ( ptrdiff_t i = 0; i + 1 < array.length; ++ i )
734             t.test!(">=")(array[i+1], array[i]);
735     }
736 
737     testOne("");
738     testOne("a");
739     testOne("mkcvalsidivjoaisjdvmzlksvdjioawmdsvmsdfefewv");
740     testOne("asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf");
741     testOne("the quick brown fox jumped over the lazy dog");
742     testOne("abcdefghijklmnopqrstuvwxyz");
743     testOne("zyxwvutsrqponmlkjihgfedcba");
744 
745     auto longer = new char[500];
746     foreach (i, ref c; longer)
747         c = cast(char) (i % 7);
748     testOne(longer);
749 
750     auto very_long = new char[100_000];
751     foreach (i, ref c; very_long)
752         c = cast(char) (i % 34);
753     testOne(very_long);
754 }
755 
756 // Test for static arrays
757 unittest
758 {
759     char[2][] arr = [ "EN", "FR", "DE" ];
760     sort(arr);
761     test!("==")(arr[0], "DE");
762     test!("==")(arr[1], "EN");
763     test!("==")(arr[2], "FR");
764     reverse(arr);
765     test!("==")(arr[2], "DE");
766     test!("==")(arr[1], "EN");
767     test!("==")(arr[0], "FR");
768 }
769 
770 /*******************************************************************************
771 
772     Swaps elements of argument array so they all come in reverse order
773 
774     Params:
775         array = array slice to reverse in-place
776 
777     Returns:
778         slice of the argument
779 
780 *******************************************************************************/
781 
782 T[] reverse (T) (T[] array)
783 {
784     for (ptrdiff_t i = 0; i < array.length / 2; ++i)
785     {
786         auto tmp = array[i];
787         array[i] = array[$-i-1];
788         array[$-i-1] = tmp;
789     }
790 
791     return array;
792 }
793 
794 ///
795 unittest
796 {
797     test (reverse((int[]).init) == (int[]).init);
798     test (reverse([1, 2, 3]) == [3, 2, 1]);
799     test (reverse([1, 2, 3, 4]) == [4, 3, 2, 1]);
800 }
801 
802 ////////////////////////////////////////////////////////////////////////////////
803 //          Functions below originally come from ocean.core.Array             //
804 ////////////////////////////////////////////////////////////////////////////////
805 
806 /*******************************************************************************
807 
808     Copies the contents of one element of arrays to another, starting at
809     dest[start], setting the length of the destination array first.
810     Note that start may be greater than the initial length of dest; dest will
811     then be extended appropriately.
812 
813     Template params:
814         func = function name for static assertion messages
815 
816     Params:
817         dest   = reference to the destination array
818         arrays = arrays to copy; a null parameter has the same effect as an
819                  empty array.
820 
821     Returns:
822         dest
823 
824     TODO: Could be made public but must then not rely on elements to be arrays.
825 
826 *******************************************************************************/
827 
828 public DE[] append ( DE, T... ) ( ref Buffer!(DE) dest, T arrays )
829 {
830     size_t appended_length = 0;
831     foreach (array; arrays)
832         appended_length += array.length;
833     dest.reserve(dest.length + appended_length);
834 
835     foreach (array; arrays)
836         dest ~= array;
837 
838     return dest[];
839 }
840 
841 public DE[] append ( DE, T... ) ( ref DE[] dest, T arrays )
842 {
843     return append( *(cast(Buffer!(DE)*) &dest), arrays);
844 }
845 
846 ///
847 unittest
848 {
849     auto buffer = createBuffer("zero");
850     append(buffer, "one", "two", "three");
851     test!("==")(buffer[], "zeroonetwothree");
852 }
853 
854 /*******************************************************************************
855 
856     Concatenates a list of arrays into a destination array. The function results
857     in at most a single memory allocation, if the destination array is too small
858     to contain the concatenation results.
859 
860     The destination array is passed as a reference, so its length can be
861     modified in-place as required. This avoids any per-element memory
862     allocation, which the normal ~ operator suffers from.
863 
864     Template params:
865         T = type of array element
866 
867     Params:
868         dest = reference to the destination array
869         arrays = variadic list of arrays to concatenate
870 
871     Returns:
872         dest
873 
874 ********************************************************************************/
875 
876 public DE[] concat ( DE, T... ) ( ref Buffer!(DE) dest, T arrays )
877 {
878     dest.reset();
879     return append(dest, arrays);
880 }
881 
882 ///
883 unittest
884 {
885     Buffer!(char) dest;
886     concat(dest, "hello "[], "world"[]);
887     test!("==")(dest[], "hello world");
888 }
889 
890 
891 public DE[] concat ( DE, T... ) ( ref DE[] dest, T arrays )
892 {
893     return concat(*(cast(Buffer!(DE)*) &dest), arrays);
894 }
895 
896 unittest
897 {
898     mstring dest;
899     concat(dest, "hello "[], "world"[]);
900     test!("==")(dest, "hello world");
901 }
902 
903 /*******************************************************************************
904 
905     Copies the contents of one array to another, setting the length of the
906     destination array first.
907 
908     This function is provided as a shorthand for this common operation.
909 
910     Template params:
911         T = type of array element
912 
913     Params:
914         dest = reference to the destination array
915         array = array to copy; null has the same effect as an empty array
916 
917     Returns:
918         dest
919 
920 *******************************************************************************/
921 
922 public T[] copy ( T, T2 ) ( ref Buffer!(T) dest, T2[] src )
923 {
924     static assert (is(typeof({ dest[] = src[]; })),
925                    "Type " ~ T2.stringof ~ " cannot be assigned to " ~ T.stringof);
926 
927     dest.length = src.length;
928     dest[] = src[];
929     return dest[];
930 }
931 
932 ///
933 unittest
934 {
935     Buffer!(char) dest;
936     cstring src = "hello";
937     copy(dest, src);
938     test!("==")(dest[], "hello"[]);
939 }
940 
941 unittest
942 {
943     Buffer!(cstring) dest;
944     mstring[] src = [ "Hello".dup, "World".dup ];
945     copy(dest, src);
946     // Doesn't compile in D2...
947     //test!("==")(dest[], src);
948 }
949 
950 public T[] copy ( T, T2 ) ( ref T[] dest, T2[] src )
951 {
952     return copy(*(cast(Buffer!(T)*) &dest), src);
953 }
954 
955 unittest
956 {
957     mstring dest;
958     cstring src = "hello";
959     copy(dest, src);
960     test!("==")(dest[], "hello"[]);
961 }
962 
963 /*******************************************************************************
964 
965     Copies the contents of src to dest, increasing dest.length if required.
966     Since dest.length will not be decreased, dest will contain tailing garbage
967     if src.length < dest.length.
968 
969     Template params:
970         T = type of array element
971 
972     Params:
973         dest  = reference to the destination array
974         array = array to copy; null has the same effect as an empty array
975 
976     Returns:
977         slice to copied elements in dest
978 
979 *******************************************************************************/
980 
981 public T[] copyExtend ( T, T2 ) ( ref Buffer!(T) dest, T2[] src )
982 {
983     static assert (is(typeof({ dest[] = src[]; })),
984                    "Type " ~ T2.stringof ~ " cannot be assigned to " ~ T.stringof);
985 
986     if (dest.length < src.length)
987         dest.length = src.length;
988     dest[0 .. src.length] = src[];
989     return dest[0 .. src.length];
990 }
991 
992 ///
993 unittest
994 {
995     auto dst = createBuffer("aa");
996     copyExtend(dst, "bbbb");
997     test!("==")(dst[], "bbbb");
998     copyExtend(dst, "ccc");
999     test!("==")(dst[], "cccb");
1000 }
1001 
1002 public T[] copyExtend ( T, T2 ) ( ref T[] dest, T2[] src )
1003 {
1004     return copyExtend(*(cast(Buffer!(T)*) &dest), src);
1005 }
1006 
1007 unittest
1008 {
1009     auto dst = "aa".dup;
1010     copyExtend(dst, "bbbb");
1011     test!("==")(dst[], "bbbb");
1012     copyExtend(dst, "ccc");
1013     test!("==")(dst[], "cccb");
1014 }
1015 
1016 /*******************************************************************************
1017 
1018     Appends an element to a list of arrays, and copies the contents of the
1019     passed source array into the new element, setting the length of the
1020     destination array first.
1021 
1022     This function is provided as a shorthand for this common operation.
1023 
1024     Template params:
1025         T = type of array element
1026 
1027     Params:
1028         dest = reference to the destination array list
1029         array = array to copy
1030 
1031     Returns:
1032         dest
1033 
1034 *******************************************************************************/
1035 
1036 public void appendCopy ( T, T2 ) ( ref Buffer!(T)[] dest, T2[] src )
1037 {
1038     dest.length = dest.length + 1;
1039     copy(dest[dest.length - 1], src);
1040 }
1041 
1042 ///
1043 unittest
1044 {
1045     Buffer!(char)[] dest;
1046     cstring src = "hello";
1047     appendCopy(dest, src);
1048     test!("==")(dest[0][], "hello");
1049 }
1050 
1051 unittest
1052 {
1053     Buffer!(cstring)[] dest;
1054     mstring[] src = [ "Hello".dup, "World".dup ];
1055     appendCopy(dest, src);
1056     // Doesn't compile in D2...
1057     //test!("==")(dest[0][], src);
1058 }
1059 
1060 
1061 public void appendCopy ( T, T2 ) ( ref T[][] dest, T2[] src )
1062 {
1063     appendCopy(*(cast(Buffer!(T)[]*) &dest), src);
1064 }
1065 
1066 ///
1067 unittest
1068 {
1069     mstring[] dest;
1070     cstring src = "hello";
1071     appendCopy(dest, src);
1072     test!("==")(dest[0][], "hello");
1073 }
1074 
1075 /*******************************************************************************
1076 
1077     Removes and returns (via the 'popped' out parameter) the last element in an
1078     array. If the provided array is empty, the function returns false.
1079 
1080     Template params:
1081         T = type of array element
1082 
1083     Params:
1084         buffer = buffer to pop an element from
1085         popped = popped element (if array contains > 0 elements)
1086 
1087     Returns:
1088         true if an element was popped
1089 
1090 *******************************************************************************/
1091 
1092 public bool pop ( T ) ( ref Buffer!(T) buffer, out T popped )
1093 {
1094     if (buffer.length == 0)
1095         return false;
1096 
1097     popped = *buffer[buffer.length - 1];
1098     buffer.length = buffer.length - 1;
1099     return true;
1100 }
1101 
1102 ///
1103 unittest
1104 {
1105     auto buffer = createBuffer("something");
1106     char elem;
1107     test(pop(buffer, elem));
1108     test!("==")(buffer[], "somethin"[]);
1109     test!("==")(elem, 'g');
1110 }
1111 
1112 public bool pop ( T ) ( ref T[] array, out T popped )
1113 {
1114     return pop (* cast(Buffer!(T)*) &array, popped);
1115 }
1116 
1117 unittest
1118 {
1119     auto buffer = "something".dup;
1120     char elem;
1121     test(pop(buffer, elem));
1122     test!("==")(buffer, "somethin"[]);
1123     test!("==")(elem, 'g');
1124 }
1125 
1126 /*******************************************************************************
1127 
1128     Removes elements from the middle of a buffer, maintaining the order of the
1129     remaining elements by shifting them left using memmove.
1130 
1131     Template params:
1132         T = type of buffer element
1133 
1134     Params:
1135         buffer = buffer to remove from
1136         index = position in buffer from which to remove elements
1137         remove_elems = number of elements to remove, defaults to one
1138 
1139     Returns:
1140         slice of buffer
1141 
1142 *******************************************************************************/
1143 
1144 public T[] removeShift ( T ) ( ref Buffer!(T) buffer, size_t index,
1145     size_t remove_elems = 1 )
1146 {
1147     if ( remove_elems == 0 )
1148         return buffer[];
1149 
1150     verify(index < buffer.length, "removeShift: index is >= buffer length");
1151     verify(index + remove_elems - 1 < buffer.length,
1152         "removeShift: end is >= buffer length");
1153 
1154     auto end = index + remove_elems - 1;
1155     auto shift_elems = (buffer.length - end) - 1;
1156 
1157     if ( shift_elems )
1158     {
1159         // shift after elements to the left
1160         void* src = buffer[].ptr + end + 1;
1161         void* dst = buffer[].ptr + index;
1162         size_t num = T.sizeof * shift_elems;
1163 
1164         memmove(dst, src, num);
1165     }
1166 
1167     // adjust buffer length
1168     buffer.length = buffer.length - remove_elems;
1169     return buffer[];
1170 }
1171 
1172 ///
1173 unittest
1174 {
1175     auto arr = createBuffer("something");
1176     removeShift(arr, 3, 4);
1177     test!("==")(arr[], "somng"[]);
1178 }
1179 
1180 public T[] removeShift ( T ) ( ref T[] buffer, size_t index,
1181     size_t remove_elems = 1 )
1182 {
1183     return removeShift(*cast(Buffer!(T)*) &buffer, index, remove_elems);
1184 }
1185 
1186 unittest
1187 {
1188     mstring arr = "something".dup;
1189     removeShift(arr, 3, 4);
1190     test!("==")(arr, "somng"[]);
1191 }
1192 
1193 /*******************************************************************************
1194 
1195     Inserts elements into the middle of a buffer, maintaining the order of the
1196     existing elements by shifting them right using memmove.
1197 
1198     Template params:
1199         T = type of buffer element
1200 
1201     Params:
1202         buffer = buffer to insert into
1203         index = position in buffer at which to insert new elements
1204         insert_elems = number of elements to insert, defaults to one
1205 
1206     Returns:
1207         slice of buffer
1208 
1209 *******************************************************************************/
1210 
1211 public T[] insertShift ( T ) ( ref Buffer!(T) buffer, size_t index,
1212     size_t insert_elems = 1)
1213 {
1214     verify(index <= buffer.length, "insertShift: index is > buffer length");
1215 
1216     if ( insert_elems == 0 )
1217         return buffer[];
1218 
1219     auto shift_elems = buffer.length - index;
1220 
1221     // adjust buffer length
1222     buffer.length = buffer.length + insert_elems;
1223 
1224     // shift required elements one place to the right
1225     if ( shift_elems )
1226     {
1227         void* src = buffer[].ptr + index;
1228         void* dst = buffer[].ptr + index + insert_elems;
1229         size_t num = T.sizeof * shift_elems;
1230         memmove(dst, src, num);
1231     }
1232 
1233     return buffer[];
1234 }
1235 
1236 ///
1237 unittest
1238 {
1239     auto arr = createBuffer("something");
1240     insertShift(arr, 2, 2);
1241     test!("==")(arr[], "somemething");
1242 }
1243 
1244 public T[] insertShift ( T ) ( ref T[] buffer, size_t index,
1245     size_t insert_elems = 1)
1246 {
1247     return insertShift(* cast(Buffer!(T)*) &buffer, index, insert_elems);
1248 }
1249 
1250 /*******************************************************************************
1251 
1252     Sorts array and removes all value duplicates.
1253 
1254     Template params:
1255         T    = type of array element
1256         sort = true: do array.sort first; false: array is already sorted
1257 
1258     Params:
1259         array = array to clean from duplicate values
1260 
1261     Returns:
1262         result
1263 
1264 *******************************************************************************/
1265 
1266 public T[] uniq ( T, bool sort = true ) ( T[] array )
1267 {
1268     if (array.length)
1269     {
1270         size_t n = 0;
1271 
1272         static if (sort)
1273         {
1274             .sort(array);
1275         }
1276 
1277         T item = array[n];
1278 
1279         foreach (element; array)
1280         {
1281             if (element != item)
1282             {
1283                 array[++n] = element;
1284                 item       = element;
1285             }
1286         }
1287 
1288         return array[0 .. n + 1];
1289     }
1290     else
1291     {
1292         return array;
1293     }
1294 }
1295 
1296 ///
1297 unittest
1298 {
1299     int[] arr = [ 42, 43, 43, 42, 2 ];
1300     auto slice = uniq(arr);
1301     test!("==")(slice, [ 2, 42, 43 ]);
1302     test!("==")(arr, [ 2, 42, 43, 43, 43 ]);
1303 }
1304 
1305 unittest
1306 {
1307     auto buffer = createBuffer([ 42, 43, 43, 42, 2 ]);
1308     auto slice = uniq(buffer[]);
1309     test!("==")(slice, [ 2, 42, 43 ][]);
1310     test!("==")(buffer[], [ 2, 42, 43, 43, 43 ][]);
1311 }
1312 
1313 /*******************************************************************************
1314 
1315     Sorts array and checks if it contains at least one duplicate.
1316 
1317     Template params:
1318         T    = type of array element
1319         sort = true: do array.sort first; false: array is already sorted
1320 
1321     Params:
1322         array = array to clean from duplicate values
1323 
1324     Returns:
1325         true if array contains a duplicate or false if not. Returns false if
1326         array is empty.
1327 
1328 *******************************************************************************/
1329 
1330 public bool containsDuplicate ( T, bool sort = true ) ( T[] array )
1331 {
1332     return !!findDuplicates!(T, sort)(
1333         array,
1334         delegate int(ref size_t index, ref T element) {return true;}
1335     );
1336 }
1337 
1338 /*******************************************************************************
1339 
1340     Sorts array and iterates over each array element that compares equal to the
1341     previous element.
1342 
1343     To just check for the existence of duplicates it's recommended to make
1344     found() return true (or some other value different from 0) to stop the
1345     iteration after the first duplicate.
1346 
1347     To assert array has no duplicates or throw an exception if it has, put the
1348     `assert(false)` or `throw ...` in `found()`:
1349     ---
1350         int[] array;
1351 
1352         findDuplicates(array,
1353                        (ref size_t index, ref int element)
1354                        {
1355                            throw new Exception("array contains duplicates");
1356                            return 0; // pacify the compiler
1357                        });
1358     ---
1359 
1360     Template params:
1361         T    = type of array element
1362         sort = true: do array.sort first; false: array is already sorted
1363 
1364     Params:
1365         array = array to clean from duplicate values
1366         found = `foreach`/`opApply()` style delegate, called with the index and
1367                 the value of each array element that is equal to the previous
1368                 element, returns 0 to continue or a value different from 0 to
1369                 stop iteration.
1370 
1371     Returns:
1372         - 0 if no duplicates were found so `found()` was not called or
1373         - 0 if `found()` returned 0 on each call or
1374         - the non-zero value returned by `found()` on the last call.
1375 
1376 *******************************************************************************/
1377 
1378 public int findDuplicates ( T, bool sort = true )
1379     ( T[] array, scope int delegate ( ref size_t index, ref T element ) found )
1380 {
1381     if (array.length)
1382     {
1383         static if (sort)
1384         {
1385             .sort(array);
1386         }
1387 
1388         foreach (i, ref element; array[1 .. $])
1389         {
1390             if (element == array[i])
1391             {
1392                 auto j = i + 1;
1393                 if (int x = found(j, element))
1394                 {
1395                     return x;
1396                 }
1397             }
1398         }
1399     }
1400 
1401     return 0;
1402 }
1403 
1404 unittest
1405 {
1406     uint n_iterations, n_duplicates;
1407 
1408     struct Found
1409     {
1410         int    value;
1411         size_t index;
1412     }
1413 
1414     Found[8] found;
1415     int[8] array;
1416     alias findDuplicates!(typeof(array[0]), false) fd;
1417 
1418     int found_cb ( ref size_t index, ref int element )
1419     in
1420     {
1421         test(n_iterations);
1422     }
1423     body
1424     {
1425         test(index);
1426         test(index < array.length);
1427         test(array[index] == array[index - 1]);
1428         found[n_duplicates++] = Found(element, index);
1429         return !--n_iterations;
1430     }
1431 
1432     array[] = 2;
1433 
1434     test(containsDuplicate(array));
1435 
1436     for (uint i = 1; i < array.length; i++)
1437     {
1438         n_iterations = i;
1439         n_duplicates = 0;
1440         int ret = fd(array, &found_cb);
1441         test(ret);
1442         test(n_duplicates == i);
1443     }
1444 
1445     n_iterations = array.length;
1446     n_duplicates = 0;
1447     {
1448         int ret = fd(array, &found_cb);
1449         test(!ret);
1450     }
1451     test(n_duplicates == array.length - 1);
1452 
1453     array[] = [2, 3, 5, 7, 11, 13, 17, 19];
1454 
1455     test(!containsDuplicate(array));
1456 
1457     n_duplicates = 0;
1458 
1459     for (uint i = 1; i <= array.length; i++)
1460     {
1461         n_iterations = i;
1462         int ret = fd(array, &found_cb);
1463         test(!ret);
1464         test(!n_duplicates);
1465     }
1466 
1467     n_iterations = array.length;
1468     array[] = 2;
1469     {
1470         n_duplicates = 0;
1471         int ret = fd(array[0 .. 0], &found_cb);
1472         test(!ret);
1473         test(!n_duplicates);
1474         ret = fd(array[0 .. 1], &found_cb);
1475         test(!ret);
1476         test(!n_duplicates);
1477         ret = fd(array[0 .. 2], &found_cb);
1478         test(!ret);
1479         test(n_duplicates == 1);
1480     }
1481 }
1482 
1483 /*******************************************************************************
1484 
1485     Moves all elements from array which match the exclusion criterum
1486     represented by exclude to the back of array so that the elements that do not
1487     match this criterium are in the front.
1488 
1489     array is modified in-place, the order of the elements may change.
1490 
1491     exclude is expected to be callable (function or delegate), accepting exactly
1492     one T argument and returning an integer (bool, (u)int, (u)short or (u)long).
1493     It is called with the element in question and should return true if that
1494     element should moved to the back or false if to the front.
1495 
1496     Params:
1497         array   = array to move values matching the exclusion criterum to the
1498                   back
1499         exclude = returns true if the element matches the exclusion criterium
1500 
1501     Returns:
1502         the index of the first excluded elements in array. This element and all
1503         following ones matched the exclusion criterum; all elements before it
1504         did not match.
1505         0 indicates that all elements matched the exclusion criterium
1506         and array.length that none matched.
1507 
1508         This allows the calling code to keep only the non-excluded items
1509         by calling: `arr.length = filterInPlace(arr, filterFunc);`
1510 
1511     Out:
1512         The returned index is at most array.length.
1513 
1514 *******************************************************************************/
1515 
1516 public size_t filterInPlace ( T, Exclude ) ( T[] array, Exclude exclude )
1517 out (end)
1518 {
1519     assert(end <= array.length, "result index out of bounds");
1520 }
1521 body
1522 {
1523     static assert (
1524         isCallableType!(Exclude),
1525         "exclude is expected to be callable, not \"" ~ Exclude.stringof ~ '"'
1526     );
1527 
1528     static assert(
1529         is(ParametersOf!(Exclude) == AliasSeq!(T)),
1530         "exclude is expected to accept one " ~ T.stringof ~ " argument"
1531     );
1532 
1533     static assert(
1534         is(ReturnTypeOf!(Exclude) : long),
1535         "the return type of exclude is expected to be an integer type"
1536     );
1537 
1538     return filterInPlaceCore(
1539         array.length,
1540         (size_t i)
1541         {
1542             return !!exclude(array[i]);
1543         },
1544         (size_t i, size_t j)
1545         {
1546             typeid(T).swap(&array[i], &array[j]);
1547         }
1548     );
1549 }
1550 
1551 unittest
1552 {
1553     auto arr = "something".dup;
1554     filterInPlace(arr, (char c) { return c / 2; });
1555 }
1556 
1557 /*******************************************************************************
1558 
1559     Moves all elements in an array which match the exclusion criterum
1560     represented by exclude to the back of array so that the elements that do not
1561     match this criterium are in the front.
1562 
1563     array is modified in-place, the order of the elements may change.
1564 
1565     exclude is called with the index of the element in question and should
1566     return true if array[index] should moved to the back or false if to the
1567     front. At the time exclude is called, the order of the array elements may
1568     have changed so exclude should index the same array instance this function
1569     is working on (i.e. not a copy).
1570 
1571     Params:
1572         length  = array length
1573         exclude = returns true if array)[index] matches the exclusion
1574                   criterium
1575         swap    = swaps array[i] and array[j]
1576 
1577     Returns:
1578         the index of the first excluded elements in the array. This element
1579         and all following ones matched the exclusion criterum; all elements
1580         before it did not match.
1581         length indicates that all elements matched the exclusion criterium and
1582         0 that none matched.
1583 
1584 *******************************************************************************/
1585 
1586 private size_t filterInPlaceCore ( size_t length,
1587     scope bool delegate ( size_t index ) exclude,
1588     scope void delegate ( size_t i, size_t j ) swap )
1589 out (end)
1590 {
1591     assert(end <= length, "result length out of bounds");
1592 }
1593 body
1594 {
1595     for (size_t i = 0; i < length; i++)
1596     {
1597         if (exclude(i))
1598         {
1599             length--;
1600 
1601             while (length > i)
1602             {
1603                 if (exclude(length))
1604                 {
1605                     length--;
1606                 }
1607                 else
1608                 {
1609                     swap(i, length);
1610                     break;
1611                 }
1612             }
1613         }
1614     }
1615 
1616     return length;
1617 }
1618 
1619 /******************************************************************************/
1620 
1621 unittest
1622 {
1623     uint[] array = [2, 3, 5, 8, 13, 21, 34, 55, 89, 144];
1624     size_t end;
1625 
1626     /***************************************************************************
1627 
1628         Returns true if array[0 .. end] contains n or false if not.
1629 
1630     ***************************************************************************/
1631 
1632     bool inIncluded ( uint n )
1633     {
1634         foreach (element; array[0 .. end])
1635         {
1636             if (element == n) return true;
1637         }
1638 
1639         return false;
1640     }
1641 
1642     /***************************************************************************
1643 
1644         Returns true if array[end .. $] contains n or false if not.
1645 
1646     ***************************************************************************/
1647 
1648     bool inExcluded ( uint n )
1649     {
1650         foreach (element; array[end .. $])
1651         {
1652             if (element == n) return true;
1653         }
1654 
1655         return false;
1656     }
1657 
1658     /***************************************************************************
1659 
1660         Returns true n is even or false if n is odd.
1661 
1662     ***************************************************************************/
1663 
1664     bool even ( uint n )
1665     {
1666         return !(n & 1);
1667     }
1668 
1669     end = .filterInPlace(array, &even);
1670     test(end == 6);
1671     test(inIncluded(3));
1672     test(inIncluded(5));
1673     test(inIncluded(13));
1674     test(inIncluded(21));
1675     test(inIncluded(55));
1676     test(inIncluded(89));
1677     test(inExcluded(2));
1678     test(inExcluded(8));
1679     test(inExcluded(34));
1680     test(inExcluded(144));
1681 
1682     array    = [2, 4, 6];
1683     end = .filterInPlace(array, &even);
1684     test(!end);
1685     test(inExcluded(2));
1686     test(inExcluded(4));
1687     test(inExcluded(6));
1688 
1689     array    = [8];
1690     end = .filterInPlace(array, &even);
1691     test(!end);
1692     test(array[end] == 8);
1693 
1694     array    = [12345];
1695     end = .filterInPlace(array, &even);
1696     test(end == array.length);
1697     test(array[0] == 12345);
1698 
1699     array = [1, 2, 4, 6];
1700     end = .filterInPlace(array, &even);
1701     test(end == 1);
1702     test(array[0] == 1);
1703     test(inExcluded(2));
1704     test(inExcluded(4));
1705     test(inExcluded(6));
1706 
1707     array = [1, 3, 5, 7];
1708     end = .filterInPlace(array, &even);
1709     test(end == array.length);
1710     test(inIncluded(1));
1711     test(inIncluded(3));
1712     test(inIncluded(5));
1713     test(inIncluded(7));
1714 
1715     array = [1, 2, 5, 7];
1716     end = .filterInPlace(array, &even);
1717     test(end == 3);
1718     test(inIncluded(1));
1719     test(inIncluded(5));
1720     test(inIncluded(7));
1721     test(inExcluded(2));
1722 }
1723 
1724 /*******************************************************************************
1725 
1726     Shuffles the elements of array in-place.
1727 
1728     Params:
1729         array = array with elements to shuffle
1730         rand  = random number generator whose generated numbers must have range
1731                 ]-1..0] or [0..1[, will be invoked array.length - 1 times
1732 
1733     Returns:
1734         shuffled array
1735 
1736 *******************************************************************************/
1737 
1738 public T[] shuffle ( T ) ( T[] array, lazy double rand )
1739 {
1740     auto result = shuffle(
1741         array,
1742         (size_t i) { return cast(size_t) (fabs(rand) * (i + 1)); }
1743     );
1744     return result;
1745 }
1746 
1747 ///
1748 unittest
1749 {
1750     int[] arr = [ 1, 2, 3, 4 ];
1751     auto random_generator = () { return 0.42; }; // not proven by the dice roll
1752     shuffle(arr, random_generator());
1753 }
1754 
1755 /*******************************************************************************
1756 
1757     Shuffles the elements of array in-place.
1758 
1759     Params:
1760         array     = array with elements to shuffle
1761         new_index = returns the new index for the array element whose index is
1762                     currently i. i is guaranteed to be in the range
1763                     [1 .. array.length - 1]; the returned index should be in the
1764                     range [0 .. i] and must be in range [0 .. array.length - 1].
1765 
1766     Returns:
1767         shuffled array
1768 
1769 *******************************************************************************/
1770 
1771 public T[] shuffle ( T ) ( T[] array, scope size_t delegate ( size_t i ) new_index )
1772 {
1773     for (auto i = array.length? array.length - 1 : 0; i; i--)
1774     {
1775         auto j = new_index(i);
1776         auto tmp = array[i];
1777         array[i] = array[j];
1778         array[j] = tmp;
1779     }
1780 
1781     return array;
1782 }
1783 
1784 ///
1785 unittest
1786 {
1787     int[] arr = [ 1, 2, 3, 4 ];
1788     int[] orig = arr.dup;
1789     auto modified = shuffle(arr, (size_t i) { return i; });
1790     test!("==")(modified, orig);
1791 }
1792 
1793 /******************************************************************************
1794 
1795     Resets each elements of array to its initial value.
1796 
1797     T.init must consist only of zero bytes.
1798 
1799     Params:
1800         array = array to clear elements
1801 
1802     Returns:
1803         array with cleared elements
1804 
1805  ******************************************************************************/
1806 
1807 public T[] clear ( T ) ( T[] array )
1808 {
1809     verify(isClearable!(T), T.stringof ~ ".init contains a non-zero byte so " ~
1810         (T[]).stringof ~ " cannot be simply cleared");
1811 
1812     memset(array.ptr, 0, array.length * array[0].sizeof);
1813 
1814     return array;
1815 }
1816 
1817 unittest
1818 {
1819     auto arr = [ 1, 2, 3 ];
1820     clear(arr);
1821 }
1822 
1823 /******************************************************************************
1824 
1825     Checks if T.init consists only of zero bytes so that a T[] array can be
1826     cleared by clear().
1827 
1828     Returns:
1829         true if a T[] array can be cleared by clear() or false if not.
1830 
1831  ******************************************************************************/
1832 
1833 bool isClearable ( T ) ( )
1834 {
1835     static immutable size_t n = T.sizeof;
1836 
1837     T init;
1838 
1839     ubyte[n] zero_data;
1840 
1841     return (cast (void*) &init)[0 .. n] == zero_data;
1842 }
1843 
1844 unittest
1845 {
1846     auto x = isClearable!(double);
1847 }
1848 
1849 /*******************************************************************************
1850 
1851     Selects the kth element of an array as defined by the given predicate.
1852 
1853     Notes:
1854         -> Uses the Quickselect selection algorithm
1855            (http://en.wikipedia.org/wiki/Quickselect)
1856         -> Typically, Quickselect is used to select the kth smallest element
1857            of an array, but this function can also be used to select elements
1858            ordered in any fashion, as defined by the given predicate.
1859         -> The array elements may be reordered during the selection process.
1860         -> The following would be true if the selection happens successfully
1861            (i.e. if no exception is thrown):
1862                * the kth element in the array as defined by the given
1863                  predicate would have been moved to index 'k'.
1864                * All elements before index 'k' are guaranteed to be passed by
1865                  the predicate compared to element 'k' (i.e. the predicate
1866                  would return true) whereas all elements after index 'k' are
1867                  guaranteed to not be passed by the predicate compared to
1868                  element 'k' (i.e.  the predicate would return false).  This
1869                  means that, if the kth smallest element is being selected,
1870                  then all elements before the kth smallest element would be
1871                  lesser than it and all elements after the kth smallest
1872                  element would be greater than or equal to it. However, no
1873                  guarantees are made about the sorting order of the elements
1874                  before/after the kth smallest element. In other words,
1875                  unordered partial sorting of the array will take place.
1876         -> The result is defined only if all values in the array are ordered
1877            (unordered values like floating-point NaNs could result in
1878            undefined behaviour).
1879 
1880     Params:
1881         arr  = the array being worked upon.
1882         k    = the order statistic being looked for (starting from zero). In
1883                particular, there should be 'k' elements in the array for which
1884                the predicate will return true.
1885         pred = predicate used for array element comparisons. Takes two array
1886                elements to be compared and returns true/false based upon the
1887                comparison.
1888                (defaults to a comparison using "<" if no predicate is given)
1889 
1890     Returns:
1891         the index of the kth element in the array as defined by the ordering
1892         predicate.
1893 
1894     Throws:
1895         new Exception if input array is empty.
1896 
1897 *******************************************************************************/
1898 
1899 size_t select ( T, Pred = DefaultPredicates.IsLess!(T) )
1900     ( T[] arr, size_t k, Pred pred = Pred.init )
1901 {
1902     /* For best results, i.e. to achieve O(n) performance from
1903      * Quickselect, it is recommended to choose a random initial pivot
1904      * value. But for now, for the sake of simplicity, the selection
1905      * function is called with its default value of zero which causes
1906      * the first value in the array to be treated as the initial pivot
1907      * value. */
1908 
1909     quickselect(arr, k, pred);
1910 
1911     if ( k >= arr.length )
1912     {
1913         k = arr.length - 1;
1914     }
1915 
1916     return k;
1917 }
1918 
1919 /*******************************************************************************
1920 
1921     Same as `select` with two changes:
1922 
1923     1. An additional input parameter:
1924            initial_pivot_index = the array index at which the first pivot
1925                                  value can be found. In theory, the pivot
1926                                  value can be chosen at random, but
1927                                  making an intelligent first guess close
1928                                  to the expected kth smallest (or
1929                                  largest) element is a good idea as that
1930                                  reduces the number of iterations needed
1931                                  to close-in on the target value
1932                                  (defaults to zero).
1933     2. The return value:
1934            returns the kth element in the array as defined by the
1935            ordering predicate.
1936 
1937 *******************************************************************************/
1938 
1939 T quickselect ( T, Pred = DefaultPredicates.IsLess!(T) )
1940     ( T[] arr, size_t k, Pred pred = Pred.init, size_t initial_pivot_index = 0 )
1941 {
1942     static assert (isCallableType!(Pred));
1943 
1944     /*
1945      * Partitions a range of elements within an array based on a pivot
1946      * value.
1947      *
1948      * At the end of the partition function in a typical Quickselect
1949      * example, the range of elements being worked upon would be
1950      * modified such that all elements before the pivot element will be
1951      * smaller than it, while all elements after the pivot element will
1952      * be greater than it. This function is capable of this typical
1953      * behaviour as well as the opposite behaviour depending upon the
1954      * given predicate.
1955      *
1956      * Params:
1957      *  arr         = array being worked upon.
1958      *  left        = leftmost index of the range of elements to
1959      *                partition.
1960      *  right       = rightmost index of the range of elements to
1961      *                partition.
1962      *  pivot_index = index of the pivot value to be used.
1963      *  pred        = predicate used for array element comparisons.
1964      *                Takes two array elements to be compared and
1965      *                returns true/false based upon the comparison.
1966      *
1967      * Returns:
1968      *  the new index to which the pivot value has moved.
1969      */
1970 
1971     static size_t partition( T[] arr, size_t left, size_t right,
1972                       size_t pivot_index, Pred pred )
1973     {
1974         if( left >= right )
1975         {
1976             return left;
1977         }
1978 
1979         if( pivot_index < left || pivot_index > right )
1980         {
1981             pivot_index = left;
1982         }
1983 
1984         auto pivot_value = arr[pivot_index];
1985 
1986         // Move the pivot value to the last index in the current range.
1987 
1988         if( pivot_index != right )
1989         {
1990             /* Note that the following line will result in a
1991              * compile-time error in D1 if 'Elem' is a static array.
1992              * This is because D1 does not allow assignment to a static
1993              * array. */
1994 
1995             arr[pivot_index] = arr[right];
1996             arr[right] = pivot_value;
1997         }
1998 
1999         auto store_index = left;
2000 
2001         for( auto i = left; i < right; ++i )
2002         {
2003             if( pred(arr[i], pivot_value) )
2004             {
2005                 if( i != store_index )
2006                 {
2007                     typeid(T).swap(&arr[i], &arr[store_index]);
2008                 }
2009 
2010                 ++store_index;
2011             }
2012         }
2013 
2014         // Move the pivot value from the last index to its rightful
2015         // place.
2016 
2017         if( store_index != right )
2018         {
2019             arr[right] = arr[store_index];
2020             arr[store_index] = pivot_value;
2021         }
2022 
2023         return store_index;
2024     }
2025 
2026     if( arr.length == 0 )
2027     {
2028         throw new Exception("Zero-length arrays are not supported");
2029     }
2030 
2031     if( arr.length == 1 )
2032     {
2033         return arr[0];
2034     }
2035 
2036     /* The initial pivot index must be a valid array index. */
2037 
2038     if( initial_pivot_index >= arr.length )
2039     {
2040         initial_pivot_index = 0;
2041     }
2042 
2043     /* One cannot have "the fifth largest element in an array" if the
2044      * array contains only three elements. In such a case, 'k' is set to
2045      * the largest valid index of the array. */
2046 
2047     if( k >= arr.length )
2048     {
2049         k = arr.length - 1;
2050     }
2051 
2052     /*
2053      * Important Note:
2054      * ---------------
2055      *     This function uses 'left' and 'right' markers to define a
2056      *     range of elements in the array being searched. At first
2057      *     glance, this may seem unnecessary as D's slicing operations
2058      *     could be used to inspect a range of elements in an array.
2059      *     However, the QuickSelect algorithm works in such a way that
2060      *     the kth element in the array will move to index 'k' of the
2061      *     original array at the end of computation. This makes it
2062      *     necessary for us to maintain the original length of the
2063      *     array, and not use slices.
2064      */
2065 
2066     /* The selection process works on a constantly reducing range of
2067      * elements within the given array, with the search range being
2068      * halved in each iteration. To begin with, the range is set to the
2069      * entire array. */
2070 
2071     size_t left = 0;
2072     size_t right = arr.length - 1;
2073 
2074     size_t pivot_index = initial_pivot_index;
2075 
2076     while( 1 )
2077     {
2078         pivot_index = partition(arr, left, right, pivot_index, pred);
2079 
2080         if( pivot_index == k )
2081         {
2082             /* The kth element in the array is the current pivot. */
2083 
2084             break;
2085         }
2086         else if( pivot_index > k )
2087         {
2088             /* The kth element is before the current pivot, so restrict
2089              * further searching to the first half of the current range
2090              * by shortening the range from the right. */
2091 
2092             right = pivot_index - 1;
2093             pivot_index = right;
2094         }
2095         else
2096         {
2097             /* The kth element is after the current pivot, so restrict
2098              * further searching to the second half of the current range
2099              * by shortening the range from the left. */
2100 
2101             left = pivot_index + 1;
2102             pivot_index = left;
2103         }
2104     }
2105 
2106     return arr[pivot_index];
2107 }
2108 
2109 version (UnitTest)
2110 {
2111     void verifySelect ( T, istring file = __FILE__, int line = __LINE__ )
2112         ( T[] buf, size_t k, T expected_value )
2113     {
2114         auto t = new NamedTest(file ~ ":" ~ line.stringof);
2115         auto kth_element_index = select(buf, k);
2116 
2117         t.test!("<")(kth_element_index, buf.length);
2118         t.test!("==")(buf[kth_element_index], expected_value);
2119 
2120         /* Confirm that unordered partial sorting of the array has also
2121          * happened as expected. */
2122 
2123         if( k > buf.length )
2124             k = buf.length;
2125 
2126         foreach (cur; buf[0 .. k])
2127             t.test!("<=")(cur, expected_value);
2128 
2129         foreach (cur; buf[k .. $])
2130             test!(">=")(cur, expected_value);
2131     }
2132 
2133 }
2134 
2135 unittest
2136 {
2137     testThrown!(Exception)(select((int[]).init, 0));
2138 
2139     verifySelect("efedcaabca".dup, 5, 'c');
2140 
2141     verifySelect(['x'], 0, 'x');
2142     verifySelect([42], 10, 42);
2143 
2144     verifySelect([7, 3, 4, 1, 9], 0, 1);
2145     verifySelect([7, 3, 4, 1, 9], 1, 3);
2146     verifySelect([7, 3, 4, 1, 9], 2, 4);
2147     verifySelect([7, 3, 4, 1, 9], 3, 7);
2148     verifySelect([7, 3, 4, 1, 9], 4, 9);
2149     verifySelect([7, 3, 4, 1, 9], 5, 9);
2150 
2151     verifySelect([7.4, 3.57, 4.2, 1.23, 3.56], 1, 3.56);
2152 
2153     struct Person
2154     {
2155         istring name;
2156         int age;
2157     }
2158 
2159     Person a = Person("Gautam", 18);
2160     Person b = Person("Tom",    52);
2161     Person c = Person("George", 53);
2162     Person d = Person("Arnold", 67);
2163 
2164     bool person_age_predicate( Person p1, Person p2 )
2165     {
2166         return p1.age < p2.age;
2167     }
2168 
2169     Person[] buf = [a, b, c, d];
2170 
2171     auto kth_element_index = select(buf, 0, &person_age_predicate);
2172     test!("==")(buf[kth_element_index].name, "Gautam");
2173 
2174     kth_element_index = select(buf, 2, &person_age_predicate);
2175     test!("==")(buf[kth_element_index].name, "George");
2176 
2177     test!("==")(quickselect([7, 3, 4, 1, 9][], 1), 3);
2178 
2179     bool greater_than_predicate( int a, int b )
2180     {
2181         return a > b;
2182     }
2183 
2184     test!("==")(quickselect([7, 3, 4, 1, 9][], 1, &greater_than_predicate), 7);
2185     test!("==")(quickselect([7, 3, 4, 1][], 1, &greater_than_predicate, 2), 4);
2186 }