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