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