1 /**
2  * This module contains a packed bit array implementation in the style of D's
3  * built-in dynamic arrays.
4  *
5  * Copyright:
6  *     Copyright (C) 2005-2006 Digital Mars, www.digitalmars.com.
7  *     Some parts copyright (c) 2009-2016 dunnhumby Germany GmbH.
8  *     All rights reserved.
9  *
10  * License:
11  *     Tango Dual License: 3-Clause BSD License / Academic Free License v3.0.
12  *     See LICENSE_TANGO.txt for details.
13  *
14  * Authors: Walter Bright, Sean Kelly
15  *
16  */
17 module ocean.core.BitArray;
18 
19 import ocean.transition;
20 
21 import ocean.core.BitManip;
22 import ocean.core.Verify;
23 
24 version(UnitTest) import ocean.core.Test;
25 
26 /**
27  * This struct represents an array of boolean values, each of which occupy one
28  * bit of memory for storage.  Thus an array of 32 bits would occupy the same
29  * space as one integer value.  The typical array operations--such as indexing
30  * and sorting--are supported, as well as bitwise operations such as and, or,
31  * xor, and complement.
32  */
33 struct BitArray
34 {
35     size_t  len;
36     uint*   ptr;
37 
38 
39     /**
40      * This initializes a BitArray of bits.length bits, where each bit value
41      * matches the corresponding boolean value in bits.
42      *
43      * Params:
44      *  bits = The initialization value.
45      *
46      * Returns:
47      *  A BitArray with the same number and sequence of elements as bits.
48      */
49     static BitArray opCall( bool[] bits )
50     {
51         BitArray temp;
52 
53         temp.length = bits.length;
54         foreach( pos, val; bits )
55             temp[pos] = val;
56         return temp;
57     }
58 
59     /**
60      * Get the number of bits in this array.
61      *
62      * Returns:
63      *  The number of bits in this array.
64      */
65     size_t length()
66     {
67         return len;
68     }
69 
70 
71     /**
72      * Resizes this array to newlen bits.  If newlen is larger than the current
73      * length, the new bits will be initialized to zero.
74      *
75      * Params:
76      *  newlen = The number of bits this array should contain.
77      */
78     void length( size_t newlen )
79     {
80         if( newlen != len )
81         {
82             auto olddim = dim();
83             auto newdim = (newlen + 31) / 32;
84 
85             if( newdim != olddim )
86             {
87                 // Create a fake array so we can use D's realloc machinery
88                 uint[] buf = ptr[0 .. olddim];
89 
90                 buf.length = newdim; // realloc
91                 enableStomping(buf);
92 
93                 ptr = buf.ptr;
94             }
95 
96             if( auto pad_bits = (newlen & 31) )
97             {
98                 // Set any pad bits to 0
99                 ptr[newdim - 1] &= ~(~0 << pad_bits);
100             }
101 
102             len = newlen;
103         }
104     }
105 
106 
107     /**
108      * Gets the length of a uint array large enough to hold all stored bits.
109      *
110      * Returns:
111      *  The size a uint array would have to be to store this array.
112      */
113     size_t dim()
114     {
115         return (len + 31) / 32;
116     }
117 
118 
119     /**
120      * Duplicates this array, much like the dup property for built-in arrays.
121      *
122      * Returns:
123      *  A duplicate of this array.
124      */
125     BitArray dup()
126     {
127         BitArray ba;
128 
129         uint[] buf = ptr[0 .. dim].dup;
130         ba.len = len;
131         ba.ptr = buf.ptr;
132         return ba;
133     }
134 
135 
136     unittest
137     {
138         BitArray a;
139         BitArray b;
140 
141         a.length = 3;
142         a[0] = 1; a[1] = 0; a[2] = 1;
143         b = a.dup;
144         test( b.length == 3 );
145         for( int i = 0; i < 3; ++i )
146         {
147             test( b[i] == (((i ^ 1) & 1) ? true : false) );
148         }
149     }
150 
151     /**
152      * Resets the length of this array to bits.length and then initializes this
153      *
154      * Resizes this array to hold bits.length bits and initializes each bit
155      * value to match the corresponding boolean value in bits.
156      *
157      * Params:
158      *  bits = The initialization value.
159      */
160     void opAssign( bool[] bits )
161     {
162         length = bits.length;
163         foreach( i, b; bits )
164         {
165             this[i] = b;
166         }
167     }
168 
169     /**
170      * Copy the bits from one array into this array.  This is not a shallow
171      * copy.
172      *
173      * Params:
174      *  rhs = A BitArray with the same number of bits as this bit array.
175      *
176      * Returns:
177      *  A shallow copy of this array.
178      *
179      *  --------------------
180      *  BitArray ba = [0,1,0,1,0];
181      *  BitArray ba2;
182      *  ba2.length = ba.length;
183      *  ba2[] = ba; // perform the copy
184      *  ba[0] = true;
185      *  assert(ba2[0] == false);
186      *  -------------------
187      */
188     BitArray opSliceAssign(BitArray rhs)
189     {
190         verify(rhs.len == len);
191 
192         auto dimension = this.dim();
193         this.ptr[0..dimension] = rhs.ptr[0..dimension];
194         return this;
195     }
196 
197 
198     /**
199      * Map BitArray onto target, with numbits being the number of bits in the
200      * array. Does not copy the data.  This is the inverse of opCast.
201      *
202      * Params:
203      *  target  = The array to map.
204      *  numbits = The number of bits to map in target.
205      */
206     void init( void[] target, size_t numbits )
207     {
208         verify(numbits <= target.length * 8);
209         verify((target.length & 3) == 0);
210 
211         ptr = cast(uint*)target.ptr;
212         len = numbits;
213     }
214 
215 
216     unittest
217     {
218         BitArray a = [1,0,1,0,1];
219         BitArray b;
220         void[] buf;
221 
222         buf = cast(void[])a;
223         b.init( buf, a.length );
224 
225         test( b[0] == 1 );
226         test( b[1] == 0 );
227         test( b[2] == 1 );
228         test( b[3] == 0 );
229         test( b[4] == 1 );
230 
231         a[0] = 0;
232         test( b[0] == 0 );
233 
234         test( a == b );
235 
236         // test opSliceAssign
237         BitArray c;
238         c.length = a.length;
239         c[] = a;
240         test( c == a );
241         a[0] = 1;
242         test( c != a );
243     }
244 
245     /**
246      * Reverses the contents of this array in place, much like the reverse
247      * property for built-in arrays.
248      *
249      * Returns:
250      *  A shallow copy of this array.
251      */
252     BitArray reverse()
253     out( result )
254     {
255         assert(compare(result, this));
256     }
257     body
258     {
259         if( len >= 2 )
260         {
261             bool t;
262             size_t lo, hi;
263 
264             lo = 0;
265             hi = len - 1;
266             for( ; lo < hi; ++lo, --hi )
267             {
268                 t = this[lo];
269                 this[lo] = (this)[hi];
270                 this[hi] = t;
271             }
272         }
273         return this;
274     }
275 
276 
277     unittest
278     {
279         static bool[5] data = [1,0,1,1,0];
280         BitArray b = data;
281         b.reverse;
282 
283         for( size_t i = 0; i < data.length; ++i )
284         {
285             test( b[i] == data[4 - i] );
286         }
287     }
288 
289     /**
290      * Sorts this array in place, with zero entries sorting before one.  This
291      * is equivalent to the sort property for built-in arrays.
292      *
293      * Returns:
294      *  A shallow copy of this array.
295      */
296     BitArray sort()
297     out( result )
298     {
299         assert(compare(result, this));
300     }
301     body
302     {
303         if( len >= 2 )
304         {
305             size_t lo, hi;
306 
307             lo = 0;
308             hi = len - 1;
309             while( true )
310             {
311                 while( true )
312                 {
313                     if( lo >= hi )
314                         goto Ldone;
315                     if( this[lo] == true )
316                         break;
317                     ++lo;
318                 }
319 
320                 while( true )
321                 {
322                     if( lo >= hi )
323                         goto Ldone;
324                     if( this[hi] == false )
325                         break;
326                     --hi;
327                 }
328 
329                 this[lo] = false;
330                 this[hi] = true;
331 
332                 ++lo;
333                 --hi;
334             }
335             Ldone:
336             ;
337         }
338         return this;
339     }
340 
341 
342     unittest
343     {
344         uint x = 0b1100011000;
345         BitArray ba = { 10, &x };
346 
347         ba.sort;
348         for( size_t i = 0; i < 6; ++i )
349             test( ba[i] == false );
350         for( size_t i = 6; i < 10; ++i )
351             test( ba[i] == true );
352     }
353 
354     /**
355      * Operates on all bits in this array.
356      *
357      * Params:
358      *  dg = The supplied code as a delegate.
359      */
360     int opApply( scope int delegate(ref bool) dg )
361     {
362         int result;
363 
364         for( size_t i = 0; i < len; ++i )
365         {
366             bool b = opIndex( i );
367             result = dg( b );
368             opIndexAssign( b, i );
369             if( result )
370                 break;
371         }
372         return result;
373     }
374 
375 
376     /** ditto */
377     int opApply( scope int delegate(ref size_t, ref bool) dg )
378     {
379         int result;
380 
381         for( size_t i = 0; i < len; ++i )
382         {
383             bool b = opIndex( i );
384             result = dg( i, b );
385             opIndexAssign( b, i );
386             if( result )
387                 break;
388         }
389         return result;
390     }
391 
392 
393     unittest
394     {
395         BitArray a = [1,0,1];
396 
397         int i;
398         foreach( b; a )
399         {
400             switch( i )
401             {
402                 case 0: test( b == true );  break;
403                 case 1: test( b == false ); break;
404                 case 2: test( b == true );  break;
405                 default: test( false );
406             }
407             i++;
408         }
409 
410         foreach( j, b; a )
411         {
412             switch( j )
413             {
414                 case 0: test( b == true );  break;
415                 case 1: test( b == false ); break;
416                 case 2: test( b == true );  break;
417                 default: test( false );
418             }
419         }
420     }
421 
422     /**
423      * Compares this array to another for equality.  Two bit arrays are equal
424      * if they are the same size and contain the same series of bits.
425      *
426      * Params:
427      *  rhs = The array to compare against.
428      *
429      * Returns:
430      *  Zero if not equal and non-zero otherwise.
431      */
432     int opEquals( BitArray rhs )
433     {
434         return compare(this, rhs);
435     }
436 
437     // FIXME_IN_D2: allows comparing both mutable
438     // and immutable BitArray without actually defining
439     // bunch of const methods
440 
441     static private int compare(in BitArray lhs_,
442         in BitArray rhs_ )
443     {
444         // requirement for const methods propagates
445         // transitively, avoid it by casting const away
446         auto lhs = cast(BitArray*) &lhs_;
447         auto rhs = cast(BitArray*) &rhs_;
448 
449         if( lhs.length != rhs.length )
450             return 0; // not equal
451         auto p1 = lhs.ptr;
452         auto p2 = rhs.ptr;
453         size_t n = lhs.length / 32;
454         size_t i;
455         for( i = 0; i < n; ++i )
456         {
457             if( p1[i] != p2[i] )
458             return 0; // not equal
459         }
460         int rest = cast(int)(lhs.length & cast(size_t)31u);
461         uint mask = ~((~0u)<<rest);
462         return (rest == 0) || (p1[i] & mask) == (p2[i] & mask);
463     }
464 
465     unittest
466     {
467         BitArray a = [1,0,1,0,1];
468         BitArray b = [1,0,1];
469         BitArray c = [1,0,1,0,1,0,1];
470         BitArray d = [1,0,1,1,1];
471         BitArray e = [1,0,1,0,1];
472 
473         test(a != b);
474         test(a != c);
475         test(a != d);
476         test(a == e);
477     }
478 
479     /**
480      * Performs a lexicographical comparison of this array to the supplied
481      * array.
482      *
483      * Params:
484      *  rhs = The array to compare against.
485      *
486      * Returns:
487      *  A value less than zero if this array sorts before the supplied array,
488      *  zero if the arrays are equavalent, and a value greater than zero if
489      *  this array sorts after the supplied array.
490      */
491     int opCmp( BitArray rhs )
492     {
493         auto len = (&this).length;
494         if( rhs.length < len )
495             len = rhs.length;
496         uint* p1 = (&this).ptr;
497         uint* p2 = rhs.ptr;
498         size_t n = len / 32;
499         size_t i;
500         for( i = 0; i < n; ++i )
501         {
502             if( p1[i] != p2[i] ){
503                 return ((p1[i] < p2[i])?-1:1);
504             }
505         }
506         int rest=cast(int)(len & cast(size_t) 31u);
507         if (rest>0) {
508             uint mask=~((~0u)<<rest);
509             uint v1=p1[i] & mask;
510             uint v2=p2[i] & mask;
511             if (v1 != v2) return ((v1<v2)?-1:1);
512         }
513         return (((&this).length<rhs.length)?-1:(((&this).length==rhs.length)?0:1));
514     }
515 
516     unittest
517     {
518         BitArray a = [1,0,1,0,1];
519         BitArray b = [1,0,1];
520         BitArray c = [1,0,1,0,1,0,1];
521         BitArray d = [1,0,1,1,1];
522         BitArray e = [1,0,1,0,1];
523         BitArray f = [1,0,1,0];
524 
525         test( a >  b );
526         test( a >= b );
527         test( a <  c );
528         test( a <= c );
529         test( a <  d );
530         test( a <= d );
531         test( a == e );
532         test( a <= e );
533         test( a >= e );
534         test( f >  b );
535     }
536 
537     /**
538      * Convert this array to a void array.
539      *
540      * Returns:
541      *  This array represented as a void array.
542      */
543     void[] opCast()
544     {
545         return cast(void[])ptr[0 .. dim];
546     }
547 
548 
549     unittest
550     {
551         BitArray a = [1,0,1,0,1];
552         void[] v = cast(void[])a;
553 
554         test( v.length == a.dim * uint.sizeof );
555     }
556 
557     /**
558      * Support for index operations, much like the behavior of built-in arrays.
559      *
560      * Params:
561      *  pos = The desired index position.
562      *
563      * In:
564      *  pos must be less than the length of this array.
565      *
566      * Returns:
567      *  The value of the bit at pos.
568      */
569     bool opIndex( size_t pos )
570     {
571         verify(pos < len);
572         return cast(bool)bt( cast(size_t*)ptr, pos );
573     }
574 
575 
576     /**
577      * Generates a copy of this array with the unary complement operation
578      * applied.
579      *
580      * Returns:
581      *  A new array which is the complement of this array.
582      */
583     BitArray opCom()
584     {
585         auto dim = (&this).dim();
586 
587         BitArray result;
588 
589         result.length = len;
590         for( size_t i = 0; i < dim; ++i )
591             result.ptr[i] = ~(&this).ptr[i];
592         if( len & 31 )
593             result.ptr[dim - 1] &= ~(~0 << (len & 31));
594         return result;
595     }
596 
597 
598     unittest
599     {
600         BitArray a = [1,0,1,0,1];
601         BitArray b = ~a;
602 
603         test(b[0] == 0);
604         test(b[1] == 1);
605         test(b[2] == 0);
606         test(b[3] == 1);
607         test(b[4] == 0);
608     }
609 
610     /**
611      * Generates a new array which is the result of a bitwise and operation
612      * between this array and the supplied array.
613      *
614      * Params:
615      *  rhs = The array with which to perform the bitwise and operation.
616      *
617      * In:
618      *  rhs.length must equal the length of this array.
619      *
620      * Returns:
621      *  A new array which is the result of a bitwise and with this array and
622      *  the supplied array.
623      */
624     BitArray opAnd( BitArray rhs )
625     {
626         verify(len == rhs.length);
627 
628         auto dim = (&this).dim();
629 
630         BitArray result;
631 
632         result.length = len;
633         for( size_t i = 0; i < dim; ++i )
634             result.ptr[i] = (&this).ptr[i] & rhs.ptr[i];
635         return result;
636     }
637 
638 
639     unittest
640     {
641         BitArray a = [1,0,1,0,1];
642         BitArray b = [1,0,1,1,0];
643 
644         BitArray c = a & b;
645 
646         test(c[0] == 1);
647         test(c[1] == 0);
648         test(c[2] == 1);
649         test(c[3] == 0);
650         test(c[4] == 0);
651     }
652 
653     /**
654      * Generates a new array which is the result of a bitwise or operation
655      * between this array and the supplied array.
656      *
657      * Params:
658      *  rhs = The array with which to perform the bitwise or operation.
659      *
660      * In:
661      *  rhs.length must equal the length of this array.
662      *
663      * Returns:
664      *  A new array which is the result of a bitwise or with this array and
665      *  the supplied array.
666      */
667     BitArray opOr( BitArray rhs )
668     {
669         verify(len == rhs.length);
670 
671         auto dim = (&this).dim();
672 
673         BitArray result;
674 
675         result.length = len;
676         for( size_t i = 0; i < dim; ++i )
677             result.ptr[i] = (&this).ptr[i] | rhs.ptr[i];
678         return result;
679     }
680 
681 
682     unittest
683     {
684         BitArray a = [1,0,1,0,1];
685         BitArray b = [1,0,1,1,0];
686 
687         BitArray c = a | b;
688 
689         test(c[0] == 1);
690         test(c[1] == 0);
691         test(c[2] == 1);
692         test(c[3] == 1);
693         test(c[4] == 1);
694     }
695 
696     /**
697      * Generates a new array which is the result of a bitwise xor operation
698      * between this array and the supplied array.
699      *
700      * Params:
701      *  rhs = The array with which to perform the bitwise xor operation.
702      *
703      * In:
704      *  rhs.length must equal the length of this array.
705      *
706      * Returns:
707      *  A new array which is the result of a bitwise xor with this array and
708      *  the supplied array.
709      */
710     BitArray opXor( BitArray rhs )
711     {
712         verify(len == rhs.length);
713 
714         auto dim = (&this).dim();
715 
716         BitArray result;
717 
718         result.length = len;
719         for( size_t i = 0; i < dim; ++i )
720             result.ptr[i] = (&this).ptr[i] ^ rhs.ptr[i];
721         return result;
722     }
723 
724     unittest
725     {
726         BitArray a = [1,0,1,0,1];
727         BitArray b = [1,0,1,1,0];
728 
729         BitArray c = a ^ b;
730 
731         test(c[0] == 0);
732         test(c[1] == 0);
733         test(c[2] == 0);
734         test(c[3] == 1);
735         test(c[4] == 1);
736     }
737 
738     /**
739      * Generates a new array which is the result of this array minus the
740      * supplied array.  $(I a - b) for BitArrays means the same thing as
741      * $(I a &amp; ~b).
742      *
743      * Params:
744      *  rhs = The array with which to perform the subtraction operation.
745      *
746      * In:
747      *  rhs.length must equal the length of this array.
748      *
749      * Returns:
750      *  A new array which is the result of this array minus the supplied array.
751      */
752     BitArray opSub( BitArray rhs )
753     {
754         verify(len == rhs.length);
755 
756         auto dim = (&this).dim();
757 
758         BitArray result;
759 
760         result.length = len;
761         for( size_t i = 0; i < dim; ++i )
762             result.ptr[i] = (&this).ptr[i] & ~rhs.ptr[i];
763         return result;
764     }
765 
766     unittest
767     {
768         BitArray a = [1,0,1,0,1];
769         BitArray b = [1,0,1,1,0];
770 
771         BitArray c = a - b;
772 
773         test( c[0] == 0 );
774         test( c[1] == 0 );
775         test( c[2] == 0 );
776         test( c[3] == 0 );
777         test( c[4] == 1 );
778     }
779 
780     /**
781      * Generates a new array which is the result of this array concatenated
782      * with the supplied array.
783      *
784      * Params:
785      *  rhs = The array with which to perform the concatenation operation.
786      *
787      * Returns:
788      *  A new array which is the result of this array concatenated with the
789      *  supplied array.
790      */
791     BitArray opCat( bool rhs )
792     {
793         BitArray result;
794 
795         result = (&this).dup;
796         result.length = len + 1;
797         result[len] = rhs;
798         return result;
799     }
800 
801 
802     /** ditto */
803     BitArray opCat_r( bool lhs )
804     {
805         BitArray result;
806 
807         result.length = len + 1;
808         result[0] = lhs;
809         for( size_t i = 0; i < len; ++i )
810             result[1 + i] = this[i];
811         return result;
812     }
813 
814 
815     /** ditto */
816     BitArray opCat( BitArray rhs )
817     {
818         BitArray result;
819 
820         result = (&this).dup();
821         result ~= rhs;
822         return result;
823     }
824 
825     unittest
826     {
827         BitArray a = [1,0];
828         BitArray b = [0,1,0];
829         BitArray c;
830 
831         c = (a ~ b);
832         test( c.length == 5 );
833         test( c[0] == 1 );
834         test( c[1] == 0 );
835         test( c[2] == 0 );
836         test( c[3] == 1 );
837         test( c[4] == 0 );
838 
839         c = (a ~ true);
840         test( c.length == 3 );
841         test( c[0] == 1 );
842         test( c[1] == 0 );
843         test( c[2] == 1 );
844 
845         c = (false ~ a);
846         test( c.length == 3 );
847         test( c[0] == 0 );
848         test( c[1] == 1 );
849         test( c[2] == 0 );
850     }
851 
852     /**
853      * Support for index operations, much like the behavior of built-in arrays.
854      *
855      * Params:
856      *  b   = The new bit value to set.
857      *  pos = The desired index position.
858      *
859      * In:
860      *  pos must be less than the length of this array.
861      *
862      * Returns:
863      *  The new value of the bit at pos.
864      */
865     bool opIndexAssign( bool b, size_t pos )
866     {
867         verify(pos < len);
868 
869         if( b )
870             bts( cast(size_t*)ptr, pos );
871         else
872             btr( cast(size_t*)ptr, pos );
873         return b;
874     }
875 
876 
877     /**
878      * Updates the contents of this array with the result of a bitwise and
879      * operation between this array and the supplied array.
880      *
881      * Params:
882      *  rhs = The array with which to perform the bitwise and operation.
883      *
884      * In:
885      *  rhs.length must equal the length of this array.
886      *
887      * Returns:
888      *  A shallow copy of this array.
889      */
890     BitArray opAndAssign( BitArray rhs )
891     {
892         verify(len == rhs.length);
893 
894         auto dim = (&this).dim();
895 
896         for( size_t i = 0; i < dim; ++i )
897             ptr[i] &= rhs.ptr[i];
898         return this;
899     }
900 
901     unittest
902     {
903         BitArray a = [1,0,1,0,1];
904         BitArray b = [1,0,1,1,0];
905 
906         a &= b;
907         test( a[0] == 1 );
908         test( a[1] == 0 );
909         test( a[2] == 1 );
910         test( a[3] == 0 );
911         test( a[4] == 0 );
912     }
913 
914     /**
915      * Updates the contents of this array with the result of a bitwise or
916      * operation between this array and the supplied array.
917      *
918      * Params:
919      *  rhs = The array with which to perform the bitwise or operation.
920      *
921      * In:
922      *  rhs.length must equal the length of this array.
923      *
924      * Returns:
925      *  A shallow copy of this array.
926      */
927     BitArray opOrAssign( BitArray rhs )
928     {
929         verify(len == rhs.length);
930 
931         auto dim = (&this).dim();
932 
933         for( size_t i = 0; i < dim; ++i )
934             ptr[i] |= rhs.ptr[i];
935         return this;
936     }
937 
938 
939     unittest
940     {
941         BitArray a = [1,0,1,0,1];
942         BitArray b = [1,0,1,1,0];
943 
944         a |= b;
945         test( a[0] == 1 );
946         test( a[1] == 0 );
947         test( a[2] == 1 );
948         test( a[3] == 1 );
949         test( a[4] == 1 );
950     }
951 
952     /**
953      * Updates the contents of this array with the result of a bitwise xor
954      * operation between this array and the supplied array.
955      *
956      * Params:
957      *  rhs = The array with which to perform the bitwise xor operation.
958      *
959      * In:
960      *  rhs.length must equal the length of this array.
961      *
962      * Returns:
963      *  A shallow copy of this array.
964      */
965     BitArray opXorAssign( BitArray rhs )
966     {
967         verify(len == rhs.length);
968 
969         auto dim = (&this).dim();
970 
971         for( size_t i = 0; i < dim; ++i )
972             ptr[i] ^= rhs.ptr[i];
973         return this;
974     }
975 
976     unittest
977     {
978         BitArray a = [1,0,1,0,1];
979         BitArray b = [1,0,1,1,0];
980 
981         a ^= b;
982         test( a[0] == 0 );
983         test( a[1] == 0 );
984         test( a[2] == 0 );
985         test( a[3] == 1 );
986         test( a[4] == 1 );
987     }
988 
989     /**
990      * Updates the contents of this array with the result of this array minus
991      * the supplied array.  $(I a - b) for BitArrays means the same thing as
992      * $(I a &amp; ~b).
993      *
994      * Params:
995      *  rhs = The array with which to perform the subtraction operation.
996      *
997      * In:
998      *  rhs.length must equal the length of this array.
999      *
1000      * Returns:
1001      *  A shallow copy of this array.
1002      */
1003     BitArray opSubAssign( BitArray rhs )
1004     {
1005         verify(len == rhs.length);
1006 
1007         auto dim = (&this).dim();
1008 
1009         for( size_t i = 0; i < dim; ++i )
1010             ptr[i] &= ~rhs.ptr[i];
1011         return this;
1012     }
1013 
1014     unittest
1015     {
1016         BitArray a = [1,0,1,0,1];
1017         BitArray b = [1,0,1,1,0];
1018 
1019         a -= b;
1020         test( a[0] == 0 );
1021         test( a[1] == 0 );
1022         test( a[2] == 0 );
1023         test( a[3] == 0 );
1024         test( a[4] == 1 );
1025     }
1026 
1027     /**
1028      * Updates the contents of this array with the result of this array
1029      * concatenated with the supplied array.
1030      *
1031      * Params:
1032      *  rhs = The array with which to perform the concatenation operation.
1033      *
1034      * Returns:
1035      *  A shallow copy of this array.
1036      */
1037     BitArray opCatAssign( bool b )
1038     {
1039         length = len + 1;
1040         this[len - 1] = b;
1041         return this;
1042     }
1043 
1044     unittest
1045     {
1046         BitArray a = [1,0,1,0,1];
1047         BitArray b;
1048 
1049         b = (a ~= true);
1050         test( a[0] == 1 );
1051         test( a[1] == 0 );
1052         test( a[2] == 1 );
1053         test( a[3] == 0 );
1054         test( a[4] == 1 );
1055         test( a[5] == 1 );
1056 
1057         test( b == a );
1058     }
1059 
1060     /** ditto */
1061     BitArray opCatAssign( BitArray rhs )
1062     {
1063         auto istart = len;
1064         length = len + rhs.length;
1065         for( auto i = istart; i < len; ++i )
1066             this[i] = rhs[i - istart];
1067         return this;
1068     }
1069 
1070     unittest
1071     {
1072         BitArray a = [1,0];
1073         BitArray b = [0,1,0];
1074         BitArray c;
1075 
1076         c = (a ~= b);
1077         test( a.length == 5 );
1078         test( a[0] == 1 );
1079         test( a[1] == 0 );
1080         test( a[2] == 0 );
1081         test( a[3] == 1 );
1082         test( a[4] == 0 );
1083 
1084         test( c == a );
1085     }
1086 }
1087 
1088 version (UnitTest)
1089 {
1090     import ocean.core.Test : NamedTest;
1091 }
1092 
1093 unittest
1094 {
1095     auto t = new NamedTest("Test increase and decrease length of the BitArray");
1096 
1097     static immutable size_of_uint = uint.sizeof * 8;
1098     static immutable num_bits = (size_of_uint * 5) + 15;
1099 
1100     // Creates a BitArray and sets all the bits.
1101     scope bool_array = new bool[num_bits];
1102     bool_array[] = true;
1103 
1104     BitArray bit_array;
1105     bit_array = bool_array;
1106 
1107     // Self-verification of the BitArray.
1108     test(bit_array.length == bool_array.length);
1109     foreach (bit; bit_array)
1110         t.test!("==")(bit, true);
1111 
1112     // Increases the length of the BitArray and checks the former bits remain
1113     // set and the new ones are not.
1114     static immutable greater_length = size_of_uint * 7;
1115     static assert(greater_length > num_bits);
1116     bit_array.length = greater_length;
1117     foreach (pos, bit; bit_array)
1118     {
1119         if (pos < num_bits)
1120             t.test!("==")(bit, true);
1121         else
1122             t.test!("==")(bit, false);
1123     }
1124 
1125     // Decreases the length of the BitArray to a shorter length than the
1126     // initial one and checks all bits remain set.
1127     static immutable lower_length = size_of_uint * 5;
1128     static assert(lower_length < num_bits);
1129     bit_array.length = lower_length;
1130     foreach (bit; bit_array)
1131         t.test!("==")(bit, true);
1132 
1133     // Resizes back to the initial length of the BitArray to check the bits
1134     // reassigned after decreasing the length of the BitArray are not set.
1135     bit_array.length = num_bits;
1136     foreach (pos, bit; bit_array)
1137     {
1138         if (pos < lower_length)
1139             t.test!("==")(bit, true);
1140         else
1141             t.test!("==")(bit, false);
1142     }
1143 
1144     // Checks the bits are reset to zero resizing the BitArray without changing
1145     // its dimension (the BitArray is large enough to hold the new length).
1146     bit_array = [true, true, true, true];
1147 
1148     bit_array.length = 2;
1149     t.test!("==")(bit_array[0], true);
1150     t.test!("==")(bit_array[1], true);
1151 
1152     bit_array.length = 4;
1153     t.test!("==")(bit_array[0], true);
1154     t.test!("==")(bit_array[1], true);
1155     t.test!("==")(bit_array[2], false);
1156     t.test!("==")(bit_array[3], false);
1157 }