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 & ~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 & ~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 }