1// Written in the D programming language. 2 3/** 4Bit-level manipulation facilities. 5 6$(SCRIPT inhibitQuickIndex = 1;) 7$(BOOKTABLE, 8$(TR $(TH Category) $(TH Functions)) 9$(TR $(TD Bit constructs) $(TD 10 $(LREF BitArray) 11 $(LREF bitfields) 12 $(LREF bitsSet) 13)) 14$(TR $(TD Endianness conversion) $(TD 15 $(LREF bigEndianToNative) 16 $(LREF littleEndianToNative) 17 $(LREF nativeToBigEndian) 18 $(LREF nativeToLittleEndian) 19 $(LREF swapEndian) 20)) 21$(TR $(TD Integral ranges) $(TD 22 $(LREF append) 23 $(LREF peek) 24 $(LREF read) 25 $(LREF write) 26)) 27$(TR $(TD Floating-Point manipulation) $(TD 28 $(LREF DoubleRep) 29 $(LREF FloatRep) 30)) 31$(TR $(TD Tagging) $(TD 32 $(LREF taggedClassRef) 33 $(LREF taggedPointer) 34)) 35) 36 37Copyright: Copyright Digital Mars 2007 - 2011. 38License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 39Authors: $(HTTP digitalmars.com, Walter Bright), 40 $(HTTP erdani.org, Andrei Alexandrescu), 41 Jonathan M Davis, 42 Alex R��nne Petersen, 43 Damian Ziemba, 44 Amaury SECHET 45Source: $(PHOBOSSRC std/_bitmanip.d) 46*/ 47/* 48 Copyright Digital Mars 2007 - 2012. 49Distributed under the Boost Software License, Version 1.0. 50 (See accompanying file LICENSE_1_0.txt or copy at 51 http://www.boost.org/LICENSE_1_0.txt) 52*/ 53module std.bitmanip; 54 55//debug = bitarray; // uncomment to turn on debugging printf's 56 57import std.range.primitives; 58public import std.system : Endian; 59import std.traits; 60 61version (unittest) 62{ 63 import std.stdio; 64} 65 66 67private string myToString(ulong n) 68{ 69 import core.internal.string : UnsignedStringBuf, unsignedToTempString; 70 UnsignedStringBuf buf; 71 auto s = unsignedToTempString(n, buf); 72 return cast(string) s ~ (n > uint.max ? "UL" : "U"); 73} 74 75private template createAccessors( 76 string store, T, string name, size_t len, size_t offset) 77{ 78 static if (!name.length) 79 { 80 // No need to create any accessor 81 enum result = ""; 82 } 83 else static if (len == 0) 84 { 85 // Fields of length 0 are always zero 86 enum result = "enum "~T.stringof~" "~name~" = 0;\n"; 87 } 88 else 89 { 90 enum ulong 91 maskAllElse = ((~0uL) >> (64 - len)) << offset, 92 signBitCheck = 1uL << (len - 1); 93 94 static if (T.min < 0) 95 { 96 enum long minVal = -(1uL << (len - 1)); 97 enum ulong maxVal = (1uL << (len - 1)) - 1; 98 alias UT = Unsigned!(T); 99 enum UT extendSign = cast(UT)~((~0uL) >> (64 - len)); 100 } 101 else 102 { 103 enum ulong minVal = 0; 104 enum ulong maxVal = (~0uL) >> (64 - len); 105 enum extendSign = 0; 106 } 107 108 static if (is(T == bool)) 109 { 110 static assert(len == 1); 111 enum result = 112 // getter 113 "@property bool " ~ name ~ "() @safe pure nothrow @nogc const { return " 114 ~"("~store~" & "~myToString(maskAllElse)~") != 0;}\n" 115 // setter 116 ~"@property void " ~ name ~ "(bool v) @safe pure nothrow @nogc { " 117 ~"if (v) "~store~" |= "~myToString(maskAllElse)~";" 118 ~"else "~store~" &= cast(typeof("~store~"))(-1-cast(typeof("~store~"))"~myToString(maskAllElse)~");}\n"; 119 } 120 else 121 { 122 // getter 123 enum result = "@property "~T.stringof~" "~name~"() @safe pure nothrow @nogc const { auto result = " 124 ~"("~store~" & " 125 ~ myToString(maskAllElse) ~ ") >>" 126 ~ myToString(offset) ~ ";" 127 ~ (T.min < 0 128 ? "if (result >= " ~ myToString(signBitCheck) 129 ~ ") result |= " ~ myToString(extendSign) ~ ";" 130 : "") 131 ~ " return cast("~T.stringof~") result;}\n" 132 // setter 133 ~"@property void "~name~"("~T.stringof~" v) @safe pure nothrow @nogc { " 134 ~"assert(v >= "~name~`_min, "Value is smaller than the minimum value of bitfield '`~name~`'"); ` 135 ~"assert(v <= "~name~`_max, "Value is greater than the maximum value of bitfield '`~name~`'"); ` 136 ~store~" = cast(typeof("~store~"))" 137 ~" (("~store~" & (-1-cast(typeof("~store~"))"~myToString(maskAllElse)~"))" 138 ~" | ((cast(typeof("~store~")) v << "~myToString(offset)~")" 139 ~" & "~myToString(maskAllElse)~"));}\n" 140 // constants 141 ~"enum "~T.stringof~" "~name~"_min = cast("~T.stringof~")" 142 ~myToString(minVal)~"; " 143 ~" enum "~T.stringof~" "~name~"_max = cast("~T.stringof~")" 144 ~myToString(maxVal)~"; "; 145 } 146 } 147} 148 149private template createStoreName(Ts...) 150{ 151 static if (Ts.length < 2) 152 enum createStoreName = ""; 153 else 154 enum createStoreName = "_" ~ Ts[1] ~ createStoreName!(Ts[3 .. $]); 155} 156 157private template createStorageAndFields(Ts...) 158{ 159 enum Name = createStoreName!Ts; 160 enum Size = sizeOfBitField!Ts; 161 static if (Size == ubyte.sizeof * 8) 162 alias StoreType = ubyte; 163 else static if (Size == ushort.sizeof * 8) 164 alias StoreType = ushort; 165 else static if (Size == uint.sizeof * 8) 166 alias StoreType = uint; 167 else static if (Size == ulong.sizeof * 8) 168 alias StoreType = ulong; 169 else 170 { 171 static assert(false, "Field widths must sum to 8, 16, 32, or 64"); 172 alias StoreType = ulong; // just to avoid another error msg 173 } 174 enum result 175 = "private " ~ StoreType.stringof ~ " " ~ Name ~ ";" 176 ~ createFields!(Name, 0, Ts).result; 177} 178 179private template createFields(string store, size_t offset, Ts...) 180{ 181 static if (Ts.length > 0) 182 enum result 183 = createAccessors!(store, Ts[0], Ts[1], Ts[2], offset).result 184 ~ createFields!(store, offset + Ts[2], Ts[3 .. $]).result; 185 else 186 enum result = ""; 187} 188 189private ulong getBitsForAlign(ulong a) 190{ 191 ulong bits = 0; 192 while ((a & 0x01) == 0) 193 { 194 bits++; 195 a >>= 1; 196 } 197 198 assert(a == 1, "alignment is not a power of 2"); 199 return bits; 200} 201 202private template createReferenceAccessor(string store, T, ulong bits, string name) 203{ 204 enum storage = "private void* " ~ store ~ "_ptr;\n"; 205 enum storage_accessor = "@property ref size_t " ~ store ~ "() return @trusted pure nothrow @nogc const { " 206 ~ "return *cast(size_t*) &" ~ store ~ "_ptr;}\n" 207 ~ "@property void " ~ store ~ "(size_t v) @trusted pure nothrow @nogc { " 208 ~ "" ~ store ~ "_ptr = cast(void*) v;}\n"; 209 210 enum mask = (1UL << bits) - 1; 211 // getter 212 enum ref_accessor = "@property "~T.stringof~" "~name~"() @trusted pure nothrow @nogc const { auto result = " 213 ~ "("~store~" & "~myToString(~mask)~"); " 214 ~ "return cast("~T.stringof~") cast(void*) result;}\n" 215 // setter 216 ~"@property void "~name~"("~T.stringof~" v) @trusted pure nothrow @nogc { " 217 ~"assert(((cast(typeof("~store~")) cast(void*) v) & "~myToString(mask) 218 ~`) == 0, "Value not properly aligned for '`~name~`'"); ` 219 ~store~" = cast(typeof("~store~"))" 220 ~" (("~store~" & (cast(typeof("~store~")) "~myToString(mask)~"))" 221 ~" | ((cast(typeof("~store~")) cast(void*) v) & (cast(typeof("~store~")) "~myToString(~mask)~")));}\n"; 222 223 enum result = storage ~ storage_accessor ~ ref_accessor; 224} 225 226private template sizeOfBitField(T...) 227{ 228 static if (T.length < 2) 229 enum sizeOfBitField = 0; 230 else 231 enum sizeOfBitField = T[2] + sizeOfBitField!(T[3 .. $]); 232} 233 234private template createTaggedReference(T, ulong a, string name, Ts...) 235{ 236 static assert( 237 sizeOfBitField!Ts <= getBitsForAlign(a), 238 "Fields must fit in the bits know to be zero because of alignment." 239 ); 240 enum StoreName = createStoreName!(T, name, 0, Ts); 241 enum result 242 = createReferenceAccessor!(StoreName, T, sizeOfBitField!Ts, name).result 243 ~ createFields!(StoreName, 0, Ts, size_t, "", T.sizeof * 8 - sizeOfBitField!Ts).result; 244} 245 246/** 247Allows creating bit fields inside $(D_PARAM struct)s and $(D_PARAM 248class)es. 249 250Example: 251 252---- 253struct A 254{ 255 int a; 256 mixin(bitfields!( 257 uint, "x", 2, 258 int, "y", 3, 259 uint, "z", 2, 260 bool, "flag", 1)); 261} 262A obj; 263obj.x = 2; 264obj.z = obj.x; 265---- 266 267The example above creates a bitfield pack of eight bits, which fit in 268one $(D_PARAM ubyte). The bitfields are allocated starting from the 269least significant bit, i.e. x occupies the two least significant bits 270of the bitfields storage. 271 272The sum of all bit lengths in one $(D_PARAM bitfield) instantiation 273must be exactly 8, 16, 32, or 64. If padding is needed, just allocate 274one bitfield with an empty name. 275 276Example: 277 278---- 279struct A 280{ 281 mixin(bitfields!( 282 bool, "flag1", 1, 283 bool, "flag2", 1, 284 uint, "", 6)); 285} 286---- 287 288The type of a bit field can be any integral type or enumerated 289type. The most efficient type to store in bitfields is $(D_PARAM 290bool), followed by unsigned types, followed by signed types. 291*/ 292 293template bitfields(T...) 294{ 295 enum { bitfields = createStorageAndFields!T.result } 296} 297 298/** 299This string mixin generator allows one to create tagged pointers inside $(D_PARAM struct)s and $(D_PARAM class)es. 300 301A tagged pointer uses the bits known to be zero in a normal pointer or class reference to store extra information. 302For example, a pointer to an integer must be 4-byte aligned, so there are 2 bits that are always known to be zero. 303One can store a 2-bit integer there. 304 305The example above creates a tagged pointer in the struct A. The pointer is of type 306$(D uint*) as specified by the first argument, and is named x, as specified by the second 307argument. 308 309Following arguments works the same way as $(D bitfield)'s. The bitfield must fit into the 310bits known to be zero because of the pointer alignment. 311*/ 312 313template taggedPointer(T : T*, string name, Ts...) { 314 enum taggedPointer = createTaggedReference!(T*, T.alignof, name, Ts).result; 315} 316 317/// 318@safe unittest 319{ 320 struct A 321 { 322 int a; 323 mixin(taggedPointer!( 324 uint*, "x", 325 bool, "b1", 1, 326 bool, "b2", 1)); 327 } 328 A obj; 329 obj.x = new uint; 330 obj.b1 = true; 331 obj.b2 = false; 332} 333 334/** 335This string mixin generator allows one to create tagged class reference inside $(D_PARAM struct)s and $(D_PARAM class)es. 336 337A tagged class reference uses the bits known to be zero in a normal class reference to store extra information. 338For example, a pointer to an integer must be 4-byte aligned, so there are 2 bits that are always known to be zero. 339One can store a 2-bit integer there. 340 341The example above creates a tagged reference to an Object in the struct A. This expects the same parameters 342as $(D taggedPointer), except the first argument which must be a class type instead of a pointer type. 343*/ 344 345template taggedClassRef(T, string name, Ts...) 346if (is(T == class)) 347{ 348 enum taggedClassRef = createTaggedReference!(T, 8, name, Ts).result; 349} 350 351/// 352@safe unittest 353{ 354 struct A 355 { 356 int a; 357 mixin(taggedClassRef!( 358 Object, "o", 359 uint, "i", 2)); 360 } 361 A obj; 362 obj.o = new Object(); 363 obj.i = 3; 364} 365 366@safe pure nothrow @nogc 367unittest 368{ 369 // Degenerate bitfields (#8474 / #11160) tests mixed with range tests 370 struct Test1 371 { 372 mixin(bitfields!(uint, "a", 32, 373 uint, "b", 4, 374 uint, "c", 4, 375 uint, "d", 8, 376 uint, "e", 16,)); 377 378 static assert(Test1.b_min == 0); 379 static assert(Test1.b_max == 15); 380 } 381 382 struct Test2 383 { 384 mixin(bitfields!(bool, "a", 0, 385 ulong, "b", 64)); 386 387 static assert(Test2.b_min == ulong.min); 388 static assert(Test2.b_max == ulong.max); 389 } 390 391 struct Test1b 392 { 393 mixin(bitfields!(bool, "a", 0, 394 int, "b", 8)); 395 } 396 397 struct Test2b 398 { 399 mixin(bitfields!(int, "a", 32, 400 int, "b", 4, 401 int, "c", 4, 402 int, "d", 8, 403 int, "e", 16,)); 404 405 static assert(Test2b.b_min == -8); 406 static assert(Test2b.b_max == 7); 407 } 408 409 struct Test3b 410 { 411 mixin(bitfields!(bool, "a", 0, 412 long, "b", 64)); 413 414 static assert(Test3b.b_min == long.min); 415 static assert(Test3b.b_max == long.max); 416 } 417 418 struct Test4b 419 { 420 mixin(bitfields!(long, "a", 32, 421 int, "b", 32)); 422 } 423 424 // Sign extension tests 425 Test2b t2b; 426 Test4b t4b; 427 t2b.b = -5; assert(t2b.b == -5); 428 t2b.d = -5; assert(t2b.d == -5); 429 t2b.e = -5; assert(t2b.e == -5); 430 t4b.a = -5; assert(t4b.a == -5L); 431} 432 433@system unittest 434{ 435 struct Test5 436 { 437 mixin(taggedPointer!( 438 int*, "a", 439 uint, "b", 2)); 440 } 441 442 Test5 t5; 443 t5.a = null; 444 t5.b = 3; 445 assert(t5.a is null); 446 assert(t5.b == 3); 447 448 int myint = 42; 449 t5.a = &myint; 450 assert(t5.a is &myint); 451 assert(t5.b == 3); 452 453 struct Test6 454 { 455 mixin(taggedClassRef!( 456 Object, "o", 457 bool, "b", 1)); 458 } 459 460 Test6 t6; 461 t6.o = null; 462 t6.b = false; 463 assert(t6.o is null); 464 assert(t6.b == false); 465 466 auto o = new Object(); 467 t6.o = o; 468 t6.b = true; 469 assert(t6.o is o); 470 assert(t6.b == true); 471} 472 473@safe unittest 474{ 475 static assert(!__traits(compiles, 476 taggedPointer!( 477 int*, "a", 478 uint, "b", 3))); 479 480 static assert(!__traits(compiles, 481 taggedClassRef!( 482 Object, "a", 483 uint, "b", 4))); 484 485 struct S { 486 mixin(taggedClassRef!( 487 Object, "a", 488 bool, "b", 1)); 489 } 490 491 const S s; 492 void bar(S s) {} 493 494 static assert(!__traits(compiles, bar(s))); 495} 496 497@safe unittest 498{ 499 // Bug #6686 500 union S { 501 ulong bits = ulong.max; 502 mixin (bitfields!( 503 ulong, "back", 31, 504 ulong, "front", 33) 505 ); 506 } 507 S num; 508 509 num.bits = ulong.max; 510 num.back = 1; 511 assert(num.bits == 0xFFFF_FFFF_8000_0001uL); 512} 513 514@safe unittest 515{ 516 // Bug #5942 517 struct S 518 { 519 mixin(bitfields!( 520 int, "a" , 32, 521 int, "b" , 32 522 )); 523 } 524 525 S data; 526 data.b = 42; 527 data.a = 1; 528 assert(data.b == 42); 529} 530 531@safe unittest 532{ 533 struct Test 534 { 535 mixin(bitfields!(bool, "a", 1, 536 uint, "b", 3, 537 short, "c", 4)); 538 } 539 540 @safe void test() pure nothrow 541 { 542 Test t; 543 544 t.a = true; 545 t.b = 5; 546 t.c = 2; 547 548 assert(t.a); 549 assert(t.b == 5); 550 assert(t.c == 2); 551 } 552 553 test(); 554} 555 556@safe unittest 557{ 558 { 559 static struct Integrals { 560 bool checkExpectations(bool eb, int ei, short es) { return b == eb && i == ei && s == es; } 561 562 mixin(bitfields!( 563 bool, "b", 1, 564 uint, "i", 3, 565 short, "s", 4)); 566 } 567 Integrals i; 568 assert(i.checkExpectations(false, 0, 0)); 569 i.b = true; 570 assert(i.checkExpectations(true, 0, 0)); 571 i.i = 7; 572 assert(i.checkExpectations(true, 7, 0)); 573 i.s = -8; 574 assert(i.checkExpectations(true, 7, -8)); 575 i.s = 7; 576 assert(i.checkExpectations(true, 7, 7)); 577 } 578 579 //Bug# 8876 580 { 581 struct MoreIntegrals { 582 bool checkExpectations(uint eu, ushort es, uint ei) { return u == eu && s == es && i == ei; } 583 584 mixin(bitfields!( 585 uint, "u", 24, 586 short, "s", 16, 587 int, "i", 24)); 588 } 589 590 MoreIntegrals i; 591 assert(i.checkExpectations(0, 0, 0)); 592 i.s = 20; 593 assert(i.checkExpectations(0, 20, 0)); 594 i.i = 72; 595 assert(i.checkExpectations(0, 20, 72)); 596 i.u = 8; 597 assert(i.checkExpectations(8, 20, 72)); 598 i.s = 7; 599 assert(i.checkExpectations(8, 7, 72)); 600 } 601 602 enum A { True, False } 603 enum B { One, Two, Three, Four } 604 static struct Enums { 605 bool checkExpectations(A ea, B eb) { return a == ea && b == eb; } 606 607 mixin(bitfields!( 608 A, "a", 1, 609 B, "b", 2, 610 uint, "", 5)); 611 } 612 Enums e; 613 assert(e.checkExpectations(A.True, B.One)); 614 e.a = A.False; 615 assert(e.checkExpectations(A.False, B.One)); 616 e.b = B.Three; 617 assert(e.checkExpectations(A.False, B.Three)); 618 619 static struct SingleMember { 620 bool checkExpectations(bool eb) { return b == eb; } 621 622 mixin(bitfields!( 623 bool, "b", 1, 624 uint, "", 7)); 625 } 626 SingleMember f; 627 assert(f.checkExpectations(false)); 628 f.b = true; 629 assert(f.checkExpectations(true)); 630} 631 632// Issue 12477 633@system unittest 634{ 635 import core.exception : AssertError; 636 import std.algorithm.searching : canFind; 637 import std.bitmanip : bitfields; 638 639 static struct S 640 { 641 mixin(bitfields!( 642 uint, "a", 6, 643 int, "b", 2)); 644 } 645 646 S s; 647 648 try { s.a = uint.max; assert(0); } 649 catch (AssertError ae) 650 { assert(ae.msg.canFind("Value is greater than the maximum value of bitfield 'a'"), ae.msg); } 651 652 try { s.b = int.min; assert(0); } 653 catch (AssertError ae) 654 { assert(ae.msg.canFind("Value is smaller than the minimum value of bitfield 'b'"), ae.msg); } 655} 656 657/** 658 Allows manipulating the fraction, exponent, and sign parts of a 659 $(D_PARAM float) separately. The definition is: 660 661---- 662struct FloatRep 663{ 664 union 665 { 666 float value; 667 mixin(bitfields!( 668 uint, "fraction", 23, 669 ubyte, "exponent", 8, 670 bool, "sign", 1)); 671 } 672 enum uint bias = 127, fractionBits = 23, exponentBits = 8, signBits = 1; 673} 674---- 675*/ 676 677struct FloatRep 678{ 679 union 680 { 681 float value; 682 mixin(bitfields!( 683 uint, "fraction", 23, 684 ubyte, "exponent", 8, 685 bool, "sign", 1)); 686 } 687 enum uint bias = 127, fractionBits = 23, exponentBits = 8, signBits = 1; 688} 689 690/** 691 Allows manipulating the fraction, exponent, and sign parts of a 692 $(D_PARAM double) separately. The definition is: 693 694---- 695struct DoubleRep 696{ 697 union 698 { 699 double value; 700 mixin(bitfields!( 701 ulong, "fraction", 52, 702 ushort, "exponent", 11, 703 bool, "sign", 1)); 704 } 705 enum uint bias = 1023, signBits = 1, fractionBits = 52, exponentBits = 11; 706} 707---- 708*/ 709 710struct DoubleRep 711{ 712 union 713 { 714 double value; 715 mixin(bitfields!( 716 ulong, "fraction", 52, 717 ushort, "exponent", 11, 718 bool, "sign", 1)); 719 } 720 enum uint bias = 1023, signBits = 1, fractionBits = 52, exponentBits = 11; 721} 722 723@safe unittest 724{ 725 // test reading 726 DoubleRep x; 727 x.value = 1.0; 728 assert(x.fraction == 0 && x.exponent == 1023 && !x.sign); 729 x.value = -0.5; 730 assert(x.fraction == 0 && x.exponent == 1022 && x.sign); 731 x.value = 0.5; 732 assert(x.fraction == 0 && x.exponent == 1022 && !x.sign); 733 734 // test writing 735 x.fraction = 1125899906842624; 736 x.exponent = 1025; 737 x.sign = true; 738 assert(x.value == -5.0); 739 740 // test enums 741 enum ABC { A, B, C } 742 struct EnumTest 743 { 744 mixin(bitfields!( 745 ABC, "x", 2, 746 bool, "y", 1, 747 ubyte, "z", 5)); 748 } 749} 750 751@safe unittest 752{ 753 // Issue #15305 754 struct S { 755 mixin(bitfields!( 756 bool, "alice", 1, 757 ulong, "bob", 63, 758 )); 759 } 760 761 S s; 762 s.bob = long.max - 1; 763 s.alice = false; 764 assert(s.bob == long.max - 1); 765} 766 767/** 768 * An array of bits. 769 */ 770 771struct BitArray 772{ 773private: 774 775 import core.bitop : bts, btr, bsf, bt; 776 import std.format : FormatSpec; 777 778 size_t _len; 779 size_t* _ptr; 780 enum bitsPerSizeT = size_t.sizeof * 8; 781 782 @property size_t fullWords() const @nogc pure nothrow 783 { 784 return _len / bitsPerSizeT; 785 } 786 // Number of bits after the last full word 787 @property size_t endBits() const @nogc pure nothrow 788 { 789 return _len % bitsPerSizeT; 790 } 791 // Bit mask to extract the bits after the last full word 792 @property size_t endMask() const @nogc pure nothrow 793 { 794 return (size_t(1) << endBits) - 1; 795 } 796 static size_t lenToDim(size_t len) @nogc pure nothrow @safe 797 { 798 return (len + (bitsPerSizeT-1)) / bitsPerSizeT; 799 } 800 801public: 802 /********************************************** 803 * Gets the amount of native words backing this $(D BitArray). 804 */ 805 @property size_t dim() const @nogc pure nothrow @safe 806 { 807 return lenToDim(_len); 808 } 809 810 /********************************************** 811 * Gets the amount of bits in the $(D BitArray). 812 */ 813 @property size_t length() const @nogc pure nothrow @safe 814 { 815 return _len; 816 } 817 818 /********************************************** 819 * Sets the amount of bits in the $(D BitArray). 820 * $(RED Warning: increasing length may overwrite bits in 821 * final word up to the next word boundary. i.e. D dynamic 822 * array extension semantics are not followed.) 823 */ 824 @property size_t length(size_t newlen) pure nothrow @system 825 { 826 if (newlen != _len) 827 { 828 size_t olddim = dim; 829 immutable newdim = lenToDim(newlen); 830 831 if (newdim != olddim) 832 { 833 // Create a fake array so we can use D's realloc machinery 834 auto b = _ptr[0 .. olddim]; 835 b.length = newdim; // realloc 836 _ptr = b.ptr; 837 } 838 839 _len = newlen; 840 } 841 return _len; 842 } 843 844 /********************************************** 845 * Gets the $(D i)'th bit in the $(D BitArray). 846 */ 847 bool opIndex(size_t i) const @nogc pure nothrow 848 in 849 { 850 assert(i < _len); 851 } 852 body 853 { 854 return cast(bool) bt(_ptr, i); 855 } 856 857 @system unittest 858 { 859 debug(bitarray) printf("BitArray.opIndex.unittest\n"); 860 861 void Fun(const BitArray arr) 862 { 863 auto x = arr[0]; 864 assert(x == 1); 865 } 866 BitArray a; 867 a.length = 3; 868 a[0] = 1; 869 Fun(a); 870 } 871 872 /********************************************** 873 * Sets the $(D i)'th bit in the $(D BitArray). 874 */ 875 bool opIndexAssign(bool b, size_t i) @nogc pure nothrow 876 in 877 { 878 assert(i < _len); 879 } 880 body 881 { 882 if (b) 883 bts(_ptr, i); 884 else 885 btr(_ptr, i); 886 return b; 887 } 888 889 /********************************************** 890 * Duplicates the $(D BitArray) and its contents. 891 */ 892 @property BitArray dup() const pure nothrow 893 { 894 BitArray ba; 895 896 auto b = _ptr[0 .. dim].dup; 897 ba._len = _len; 898 ba._ptr = b.ptr; 899 return ba; 900 } 901 902 @system unittest 903 { 904 BitArray a; 905 BitArray b; 906 int i; 907 908 debug(bitarray) printf("BitArray.dup.unittest\n"); 909 910 a.length = 3; 911 a[0] = 1; a[1] = 0; a[2] = 1; 912 b = a.dup; 913 assert(b.length == 3); 914 for (i = 0; i < 3; i++) 915 { debug(bitarray) printf("b[%d] = %d\n", i, b[i]); 916 assert(b[i] == (((i ^ 1) & 1) ? true : false)); 917 } 918 } 919 920 /********************************************** 921 * Support for $(D foreach) loops for $(D BitArray). 922 */ 923 int opApply(scope int delegate(ref bool) dg) 924 { 925 int result; 926 927 foreach (i; 0 .. _len) 928 { 929 bool b = opIndex(i); 930 result = dg(b); 931 this[i] = b; 932 if (result) 933 break; 934 } 935 return result; 936 } 937 938 /** ditto */ 939 int opApply(scope int delegate(bool) dg) const 940 { 941 int result; 942 943 foreach (i; 0 .. _len) 944 { 945 immutable b = opIndex(i); 946 result = dg(b); 947 if (result) 948 break; 949 } 950 return result; 951 } 952 953 /** ditto */ 954 int opApply(scope int delegate(size_t, ref bool) dg) 955 { 956 int result; 957 958 foreach (i; 0 .. _len) 959 { 960 bool b = opIndex(i); 961 result = dg(i, b); 962 this[i] = b; 963 if (result) 964 break; 965 } 966 return result; 967 } 968 969 /** ditto */ 970 int opApply(scope int delegate(size_t, bool) dg) const 971 { 972 int result; 973 974 foreach (i; 0 .. _len) 975 { 976 immutable b = opIndex(i); 977 result = dg(i, b); 978 if (result) 979 break; 980 } 981 return result; 982 } 983 984 @system unittest 985 { 986 debug(bitarray) printf("BitArray.opApply unittest\n"); 987 988 static bool[] ba = [1,0,1]; 989 990 auto a = BitArray(ba); 991 992 int i; 993 foreach (b;a) 994 { 995 switch (i) 996 { 997 case 0: assert(b == true); break; 998 case 1: assert(b == false); break; 999 case 2: assert(b == true); break; 1000 default: assert(0); 1001 } 1002 i++; 1003 } 1004 1005 foreach (j,b;a) 1006 { 1007 switch (j) 1008 { 1009 case 0: assert(b == true); break; 1010 case 1: assert(b == false); break; 1011 case 2: assert(b == true); break; 1012 default: assert(0); 1013 } 1014 } 1015 } 1016 1017 1018 /********************************************** 1019 * Reverses the bits of the $(D BitArray). 1020 */ 1021 @property BitArray reverse() @nogc pure nothrow 1022 out (result) 1023 { 1024 assert(result == this); 1025 } 1026 body 1027 { 1028 if (_len >= 2) 1029 { 1030 bool t; 1031 size_t lo, hi; 1032 1033 lo = 0; 1034 hi = _len - 1; 1035 for (; lo < hi; lo++, hi--) 1036 { 1037 t = this[lo]; 1038 this[lo] = this[hi]; 1039 this[hi] = t; 1040 } 1041 } 1042 return this; 1043 } 1044 1045 @system unittest 1046 { 1047 debug(bitarray) printf("BitArray.reverse.unittest\n"); 1048 1049 BitArray b; 1050 static bool[5] data = [1,0,1,1,0]; 1051 int i; 1052 1053 b = BitArray(data); 1054 b.reverse; 1055 for (i = 0; i < data.length; i++) 1056 { 1057 assert(b[i] == data[4 - i]); 1058 } 1059 } 1060 1061 1062 /********************************************** 1063 * Sorts the $(D BitArray)'s elements. 1064 */ 1065 @property BitArray sort() @nogc pure nothrow 1066 out (result) 1067 { 1068 assert(result == this); 1069 } 1070 body 1071 { 1072 if (_len >= 2) 1073 { 1074 size_t lo, hi; 1075 1076 lo = 0; 1077 hi = _len - 1; 1078 while (1) 1079 { 1080 while (1) 1081 { 1082 if (lo >= hi) 1083 goto Ldone; 1084 if (this[lo] == true) 1085 break; 1086 lo++; 1087 } 1088 1089 while (1) 1090 { 1091 if (lo >= hi) 1092 goto Ldone; 1093 if (this[hi] == false) 1094 break; 1095 hi--; 1096 } 1097 1098 this[lo] = false; 1099 this[hi] = true; 1100 1101 lo++; 1102 hi--; 1103 } 1104 } 1105 Ldone: 1106 return this; 1107 } 1108 1109 @system unittest 1110 { 1111 debug(bitarray) printf("BitArray.sort.unittest\n"); 1112 1113 __gshared size_t x = 0b1100011000; 1114 __gshared ba = BitArray(10, &x); 1115 ba.sort; 1116 for (size_t i = 0; i < 6; i++) 1117 assert(ba[i] == false); 1118 for (size_t i = 6; i < 10; i++) 1119 assert(ba[i] == true); 1120 } 1121 1122 1123 /*************************************** 1124 * Support for operators == and != for $(D BitArray). 1125 */ 1126 bool opEquals(const ref BitArray a2) const @nogc pure nothrow 1127 { 1128 if (this.length != a2.length) 1129 return false; 1130 auto p1 = this._ptr; 1131 auto p2 = a2._ptr; 1132 1133 if (p1[0 .. fullWords] != p2[0 .. fullWords]) 1134 return false; 1135 1136 if (!endBits) 1137 return true; 1138 1139 auto i = fullWords; 1140 return (p1[i] & endMask) == (p2[i] & endMask); 1141 } 1142 1143 @system unittest 1144 { 1145 debug(bitarray) printf("BitArray.opEquals unittest\n"); 1146 1147 static bool[] ba = [1,0,1,0,1]; 1148 static bool[] bb = [1,0,1]; 1149 static bool[] bc = [1,0,1,0,1,0,1]; 1150 static bool[] bd = [1,0,1,1,1]; 1151 static bool[] be = [1,0,1,0,1]; 1152 static bool[] bf = [1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; 1153 static bool[] bg = [1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]; 1154 1155 auto a = BitArray(ba); 1156 auto b = BitArray(bb); 1157 auto c = BitArray(bc); 1158 auto d = BitArray(bd); 1159 auto e = BitArray(be); 1160 auto f = BitArray(bf); 1161 auto g = BitArray(bg); 1162 1163 assert(a != b); 1164 assert(a != c); 1165 assert(a != d); 1166 assert(a == e); 1167 assert(f != g); 1168 } 1169 1170 /*************************************** 1171 * Supports comparison operators for $(D BitArray). 1172 */ 1173 int opCmp(BitArray a2) const @nogc pure nothrow 1174 { 1175 const lesser = this.length < a2.length ? &this : &a2; 1176 immutable fullWords = lesser.fullWords; 1177 immutable endBits = lesser.endBits; 1178 auto p1 = this._ptr; 1179 auto p2 = a2._ptr; 1180 1181 foreach (i; 0 .. fullWords) 1182 { 1183 if (p1[i] != p2[i]) 1184 { 1185 return p1[i] & (size_t(1) << bsf(p1[i] ^ p2[i])) ? 1 : -1; 1186 } 1187 } 1188 1189 if (endBits) 1190 { 1191 immutable i = fullWords; 1192 immutable diff = p1[i] ^ p2[i]; 1193 if (diff) 1194 { 1195 immutable index = bsf(diff); 1196 if (index < endBits) 1197 { 1198 return p1[i] & (size_t(1) << index) ? 1 : -1; 1199 } 1200 } 1201 } 1202 1203 // Standard: 1204 // A bool value can be implicitly converted to any integral type, 1205 // with false becoming 0 and true becoming 1 1206 return (this.length > a2.length) - (this.length < a2.length); 1207 } 1208 1209 @system unittest 1210 { 1211 debug(bitarray) printf("BitArray.opCmp unittest\n"); 1212 1213 static bool[] ba = [1,0,1,0,1]; 1214 static bool[] bb = [1,0,1]; 1215 static bool[] bc = [1,0,1,0,1,0,1]; 1216 static bool[] bd = [1,0,1,1,1]; 1217 static bool[] be = [1,0,1,0,1]; 1218 static bool[] bf = [1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]; 1219 static bool[] bg = [1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0]; 1220 1221 auto a = BitArray(ba); 1222 auto b = BitArray(bb); 1223 auto c = BitArray(bc); 1224 auto d = BitArray(bd); 1225 auto e = BitArray(be); 1226 auto f = BitArray(bf); 1227 auto g = BitArray(bg); 1228 1229 assert(a > b); 1230 assert(a >= b); 1231 assert(a < c); 1232 assert(a <= c); 1233 assert(a < d); 1234 assert(a <= d); 1235 assert(a == e); 1236 assert(a <= e); 1237 assert(a >= e); 1238 assert(f < g); 1239 assert(g <= g); 1240 1241 bool[] v; 1242 foreach (i; 1 .. 256) 1243 { 1244 v.length = i; 1245 v[] = false; 1246 auto x = BitArray(v); 1247 v[i-1] = true; 1248 auto y = BitArray(v); 1249 assert(x < y); 1250 assert(x <= y); 1251 } 1252 1253 BitArray a1, a2; 1254 1255 for (size_t len = 4; len <= 256; len <<= 1) 1256 { 1257 a1.length = a2.length = len; 1258 a1[len-2] = a2[len-1] = true; 1259 assert(a1 > a2); 1260 a1[len-2] = a2[len-1] = false; 1261 } 1262 1263 foreach (j; 1 .. a1.length) 1264 { 1265 a1[j-1] = a2[j] = true; 1266 assert(a1 > a2); 1267 a1[j-1] = a2[j] = false; 1268 } 1269 } 1270 1271 /*************************************** 1272 * Support for hashing for $(D BitArray). 1273 */ 1274 size_t toHash() const @nogc pure nothrow 1275 { 1276 size_t hash = 3557; 1277 auto fullBytes = _len / 8; 1278 foreach (i; 0 .. fullBytes) 1279 { 1280 hash *= 3559; 1281 hash += (cast(byte*) this._ptr)[i]; 1282 } 1283 foreach (i; 8*fullBytes .. _len) 1284 { 1285 hash *= 3571; 1286 hash += this[i]; 1287 } 1288 return hash; 1289 } 1290 1291 /*************************************** 1292 * Set this $(D BitArray) to the contents of $(D ba). 1293 */ 1294 this(bool[] ba) pure nothrow @system 1295 { 1296 length = ba.length; 1297 foreach (i, b; ba) 1298 { 1299 this[i] = b; 1300 } 1301 } 1302 1303 // Deliberately undocumented: raw initialization of bit array. 1304 this(size_t len, size_t* ptr) 1305 { 1306 _len = len; 1307 _ptr = ptr; 1308 } 1309 1310 /*************************************** 1311 * Map the $(D BitArray) onto $(D v), with $(D numbits) being the number of bits 1312 * in the array. Does not copy the data. $(D v.length) must be a multiple of 1313 * $(D size_t.sizeof). If there are unmapped bits in the final mapped word then 1314 * these will be set to 0. 1315 * 1316 * This is the inverse of $(D opCast). 1317 */ 1318 this(void[] v, size_t numbits) pure nothrow 1319 in 1320 { 1321 assert(numbits <= v.length * 8); 1322 assert(v.length % size_t.sizeof == 0); 1323 } 1324 body 1325 { 1326 _ptr = cast(size_t*) v.ptr; 1327 _len = numbits; 1328 if (endBits) 1329 { 1330 // Need to mask away extraneous bits from v. 1331 _ptr[dim - 1] &= endMask; 1332 } 1333 } 1334 1335 @system unittest 1336 { 1337 debug(bitarray) printf("BitArray.init unittest\n"); 1338 1339 static bool[] ba = [1,0,1,0,1]; 1340 1341 auto a = BitArray(ba); 1342 void[] v; 1343 1344 v = cast(void[]) a; 1345 auto b = BitArray(v, a.length); 1346 1347 assert(b[0] == 1); 1348 assert(b[1] == 0); 1349 assert(b[2] == 1); 1350 assert(b[3] == 0); 1351 assert(b[4] == 1); 1352 1353 a[0] = 0; 1354 assert(b[0] == 0); 1355 1356 assert(a == b); 1357 } 1358 1359 /*************************************** 1360 * Convert to $(D void[]). 1361 */ 1362 void[] opCast(T : void[])() @nogc pure nothrow 1363 { 1364 return cast(void[])_ptr[0 .. dim]; 1365 } 1366 1367 /*************************************** 1368 * Convert to $(D size_t[]). 1369 */ 1370 size_t[] opCast(T : size_t[])() @nogc pure nothrow 1371 { 1372 return _ptr[0 .. dim]; 1373 } 1374 1375 @system unittest 1376 { 1377 debug(bitarray) printf("BitArray.opCast unittest\n"); 1378 1379 static bool[] ba = [1,0,1,0,1]; 1380 1381 auto a = BitArray(ba); 1382 void[] v = cast(void[]) a; 1383 1384 assert(v.length == a.dim * size_t.sizeof); 1385 } 1386 1387 /*************************************** 1388 * Support for unary operator ~ for $(D BitArray). 1389 */ 1390 BitArray opCom() const pure nothrow 1391 { 1392 auto dim = this.dim; 1393 1394 BitArray result; 1395 result.length = _len; 1396 1397 result._ptr[0 .. dim] = ~this._ptr[0 .. dim]; 1398 1399 // Avoid putting garbage in extra bits 1400 // Remove once we zero on length extension 1401 if (endBits) 1402 result._ptr[dim - 1] &= endMask; 1403 1404 return result; 1405 } 1406 1407 @system unittest 1408 { 1409 debug(bitarray) printf("BitArray.opCom unittest\n"); 1410 1411 static bool[] ba = [1,0,1,0,1]; 1412 1413 auto a = BitArray(ba); 1414 BitArray b = ~a; 1415 1416 assert(b[0] == 0); 1417 assert(b[1] == 1); 1418 assert(b[2] == 0); 1419 assert(b[3] == 1); 1420 assert(b[4] == 0); 1421 } 1422 1423 1424 /*************************************** 1425 * Support for binary bitwise operators for $(D BitArray). 1426 */ 1427 BitArray opBinary(string op)(const BitArray e2) const pure nothrow 1428 if (op == "-" || op == "&" || op == "|" || op == "^") 1429 in 1430 { 1431 assert(_len == e2.length); 1432 } 1433 body 1434 { 1435 auto dim = this.dim; 1436 1437 BitArray result; 1438 result.length = _len; 1439 1440 static if (op == "-") 1441 result._ptr[0 .. dim] = this._ptr[0 .. dim] & ~e2._ptr[0 .. dim]; 1442 else 1443 mixin("result._ptr[0 .. dim] = this._ptr[0 .. dim]"~op~" e2._ptr[0 .. dim];"); 1444 1445 // Avoid putting garbage in extra bits 1446 // Remove once we zero on length extension 1447 if (endBits) 1448 result._ptr[dim - 1] &= endMask; 1449 1450 return result; 1451 } 1452 1453 @system unittest 1454 { 1455 debug(bitarray) printf("BitArray.opAnd unittest\n"); 1456 1457 static bool[] ba = [1,0,1,0,1]; 1458 static bool[] bb = [1,0,1,1,0]; 1459 1460 auto a = BitArray(ba); 1461 auto b = BitArray(bb); 1462 1463 BitArray c = a & b; 1464 1465 assert(c[0] == 1); 1466 assert(c[1] == 0); 1467 assert(c[2] == 1); 1468 assert(c[3] == 0); 1469 assert(c[4] == 0); 1470 } 1471 1472 @system unittest 1473 { 1474 debug(bitarray) printf("BitArray.opOr unittest\n"); 1475 1476 static bool[] ba = [1,0,1,0,1]; 1477 static bool[] bb = [1,0,1,1,0]; 1478 1479 auto a = BitArray(ba); 1480 auto b = BitArray(bb); 1481 1482 BitArray c = a | b; 1483 1484 assert(c[0] == 1); 1485 assert(c[1] == 0); 1486 assert(c[2] == 1); 1487 assert(c[3] == 1); 1488 assert(c[4] == 1); 1489 } 1490 1491 @system unittest 1492 { 1493 debug(bitarray) printf("BitArray.opXor unittest\n"); 1494 1495 static bool[] ba = [1,0,1,0,1]; 1496 static bool[] bb = [1,0,1,1,0]; 1497 1498 auto a = BitArray(ba); 1499 auto b = BitArray(bb); 1500 1501 BitArray c = a ^ b; 1502 1503 assert(c[0] == 0); 1504 assert(c[1] == 0); 1505 assert(c[2] == 0); 1506 assert(c[3] == 1); 1507 assert(c[4] == 1); 1508 } 1509 1510 @system unittest 1511 { 1512 debug(bitarray) printf("BitArray.opSub unittest\n"); 1513 1514 static bool[] ba = [1,0,1,0,1]; 1515 static bool[] bb = [1,0,1,1,0]; 1516 1517 auto a = BitArray(ba); 1518 auto b = BitArray(bb); 1519 1520 BitArray c = a - b; 1521 1522 assert(c[0] == 0); 1523 assert(c[1] == 0); 1524 assert(c[2] == 0); 1525 assert(c[3] == 0); 1526 assert(c[4] == 1); 1527 } 1528 1529 1530 /*************************************** 1531 * Support for operator op= for $(D BitArray). 1532 */ 1533 BitArray opOpAssign(string op)(const BitArray e2) @nogc pure nothrow 1534 if (op == "-" || op == "&" || op == "|" || op == "^") 1535 in 1536 { 1537 assert(_len == e2.length); 1538 } 1539 body 1540 { 1541 foreach (i; 0 .. fullWords) 1542 { 1543 static if (op == "-") 1544 _ptr[i] &= ~e2._ptr[i]; 1545 else 1546 mixin("_ptr[i] "~op~"= e2._ptr[i];"); 1547 } 1548 if (!endBits) 1549 return this; 1550 1551 size_t i = fullWords; 1552 size_t endWord = _ptr[i]; 1553 static if (op == "-") 1554 endWord &= ~e2._ptr[i]; 1555 else 1556 mixin("endWord "~op~"= e2._ptr[i];"); 1557 _ptr[i] = (_ptr[i] & ~endMask) | (endWord & endMask); 1558 1559 return this; 1560 } 1561 1562 @system unittest 1563 { 1564 static bool[] ba = [1,0,1,0,1,1,0,1,0,1]; 1565 static bool[] bb = [1,0,1,1,0]; 1566 auto a = BitArray(ba); 1567 auto b = BitArray(bb); 1568 BitArray c = a; 1569 c.length = 5; 1570 c &= b; 1571 assert(a[5] == 1); 1572 assert(a[6] == 0); 1573 assert(a[7] == 1); 1574 assert(a[8] == 0); 1575 assert(a[9] == 1); 1576 } 1577 1578 @system unittest 1579 { 1580 debug(bitarray) printf("BitArray.opAndAssign unittest\n"); 1581 1582 static bool[] ba = [1,0,1,0,1]; 1583 static bool[] bb = [1,0,1,1,0]; 1584 1585 auto a = BitArray(ba); 1586 auto b = BitArray(bb); 1587 1588 a &= b; 1589 assert(a[0] == 1); 1590 assert(a[1] == 0); 1591 assert(a[2] == 1); 1592 assert(a[3] == 0); 1593 assert(a[4] == 0); 1594 } 1595 1596 @system unittest 1597 { 1598 debug(bitarray) printf("BitArray.opOrAssign unittest\n"); 1599 1600 static bool[] ba = [1,0,1,0,1]; 1601 static bool[] bb = [1,0,1,1,0]; 1602 1603 auto a = BitArray(ba); 1604 auto b = BitArray(bb); 1605 1606 a |= b; 1607 assert(a[0] == 1); 1608 assert(a[1] == 0); 1609 assert(a[2] == 1); 1610 assert(a[3] == 1); 1611 assert(a[4] == 1); 1612 } 1613 1614 @system unittest 1615 { 1616 debug(bitarray) printf("BitArray.opXorAssign unittest\n"); 1617 1618 static bool[] ba = [1,0,1,0,1]; 1619 static bool[] bb = [1,0,1,1,0]; 1620 1621 auto a = BitArray(ba); 1622 auto b = BitArray(bb); 1623 1624 a ^= b; 1625 assert(a[0] == 0); 1626 assert(a[1] == 0); 1627 assert(a[2] == 0); 1628 assert(a[3] == 1); 1629 assert(a[4] == 1); 1630 } 1631 1632 @system unittest 1633 { 1634 debug(bitarray) printf("BitArray.opSubAssign unittest\n"); 1635 1636 static bool[] ba = [1,0,1,0,1]; 1637 static bool[] bb = [1,0,1,1,0]; 1638 1639 auto a = BitArray(ba); 1640 auto b = BitArray(bb); 1641 1642 a -= b; 1643 assert(a[0] == 0); 1644 assert(a[1] == 0); 1645 assert(a[2] == 0); 1646 assert(a[3] == 0); 1647 assert(a[4] == 1); 1648 } 1649 1650 /*************************************** 1651 * Support for operator ~= for $(D BitArray). 1652 * $(RED Warning: This will overwrite a bit in the final word 1653 * of the current underlying data regardless of whether it is 1654 * shared between BitArray objects. i.e. D dynamic array 1655 * concatenation semantics are not followed) 1656 */ 1657 1658 BitArray opCatAssign(bool b) pure nothrow 1659 { 1660 length = _len + 1; 1661 this[_len - 1] = b; 1662 return this; 1663 } 1664 1665 @system unittest 1666 { 1667 debug(bitarray) printf("BitArray.opCatAssign unittest\n"); 1668 1669 static bool[] ba = [1,0,1,0,1]; 1670 1671 auto a = BitArray(ba); 1672 BitArray b; 1673 1674 b = (a ~= true); 1675 assert(a[0] == 1); 1676 assert(a[1] == 0); 1677 assert(a[2] == 1); 1678 assert(a[3] == 0); 1679 assert(a[4] == 1); 1680 assert(a[5] == 1); 1681 1682 assert(b == a); 1683 } 1684 1685 /*************************************** 1686 * ditto 1687 */ 1688 1689 BitArray opCatAssign(BitArray b) pure nothrow 1690 { 1691 auto istart = _len; 1692 length = _len + b.length; 1693 for (auto i = istart; i < _len; i++) 1694 this[i] = b[i - istart]; 1695 return this; 1696 } 1697 1698 @system unittest 1699 { 1700 debug(bitarray) printf("BitArray.opCatAssign unittest\n"); 1701 1702 static bool[] ba = [1,0]; 1703 static bool[] bb = [0,1,0]; 1704 1705 auto a = BitArray(ba); 1706 auto b = BitArray(bb); 1707 BitArray c; 1708 1709 c = (a ~= b); 1710 assert(a.length == 5); 1711 assert(a[0] == 1); 1712 assert(a[1] == 0); 1713 assert(a[2] == 0); 1714 assert(a[3] == 1); 1715 assert(a[4] == 0); 1716 1717 assert(c == a); 1718 } 1719 1720 /*************************************** 1721 * Support for binary operator ~ for $(D BitArray). 1722 */ 1723 BitArray opCat(bool b) const pure nothrow 1724 { 1725 BitArray r; 1726 1727 r = this.dup; 1728 r.length = _len + 1; 1729 r[_len] = b; 1730 return r; 1731 } 1732 1733 /** ditto */ 1734 BitArray opCat_r(bool b) const pure nothrow 1735 { 1736 BitArray r; 1737 1738 r.length = _len + 1; 1739 r[0] = b; 1740 foreach (i; 0 .. _len) 1741 r[1 + i] = this[i]; 1742 return r; 1743 } 1744 1745 /** ditto */ 1746 BitArray opCat(BitArray b) const pure nothrow 1747 { 1748 BitArray r; 1749 1750 r = this.dup; 1751 r ~= b; 1752 return r; 1753 } 1754 1755 @system unittest 1756 { 1757 debug(bitarray) printf("BitArray.opCat unittest\n"); 1758 1759 static bool[] ba = [1,0]; 1760 static bool[] bb = [0,1,0]; 1761 1762 auto a = BitArray(ba); 1763 auto b = BitArray(bb); 1764 BitArray c; 1765 1766 c = (a ~ b); 1767 assert(c.length == 5); 1768 assert(c[0] == 1); 1769 assert(c[1] == 0); 1770 assert(c[2] == 0); 1771 assert(c[3] == 1); 1772 assert(c[4] == 0); 1773 1774 c = (a ~ true); 1775 assert(c.length == 3); 1776 assert(c[0] == 1); 1777 assert(c[1] == 0); 1778 assert(c[2] == 1); 1779 1780 c = (false ~ a); 1781 assert(c.length == 3); 1782 assert(c[0] == 0); 1783 assert(c[1] == 1); 1784 assert(c[2] == 0); 1785 } 1786 1787 // Rolls double word (upper, lower) to the right by n bits and returns the 1788 // lower word of the result. 1789 private static size_t rollRight()(size_t upper, size_t lower, size_t nbits) 1790 pure @safe nothrow @nogc 1791 in 1792 { 1793 assert(nbits < bitsPerSizeT); 1794 } 1795 body 1796 { 1797 return (upper << (bitsPerSizeT - nbits)) | (lower >> nbits); 1798 } 1799 1800 @safe unittest 1801 { 1802 static if (size_t.sizeof == 8) 1803 { 1804 size_t x = 0x12345678_90ABCDEF; 1805 size_t y = 0xFEDBCA09_87654321; 1806 1807 assert(rollRight(x, y, 32) == 0x90ABCDEF_FEDBCA09); 1808 assert(rollRight(y, x, 4) == 0x11234567_890ABCDE); 1809 } 1810 else static if (size_t.sizeof == 4) 1811 { 1812 size_t x = 0x12345678; 1813 size_t y = 0x90ABCDEF; 1814 1815 assert(rollRight(x, y, 16) == 0x567890AB); 1816 assert(rollRight(y, x, 4) == 0xF1234567); 1817 } 1818 else 1819 static assert(0, "Unsupported size_t width"); 1820 } 1821 1822 // Rolls double word (upper, lower) to the left by n bits and returns the 1823 // upper word of the result. 1824 private static size_t rollLeft()(size_t upper, size_t lower, size_t nbits) 1825 pure @safe nothrow @nogc 1826 in 1827 { 1828 assert(nbits < bitsPerSizeT); 1829 } 1830 body 1831 { 1832 return (upper << nbits) | (lower >> (bitsPerSizeT - nbits)); 1833 } 1834 1835 @safe unittest 1836 { 1837 static if (size_t.sizeof == 8) 1838 { 1839 size_t x = 0x12345678_90ABCDEF; 1840 size_t y = 0xFEDBCA09_87654321; 1841 1842 assert(rollLeft(x, y, 32) == 0x90ABCDEF_FEDBCA09); 1843 assert(rollLeft(y, x, 4) == 0xEDBCA098_76543211); 1844 } 1845 else static if (size_t.sizeof == 4) 1846 { 1847 size_t x = 0x12345678; 1848 size_t y = 0x90ABCDEF; 1849 1850 assert(rollLeft(x, y, 16) == 0x567890AB); 1851 assert(rollLeft(y, x, 4) == 0x0ABCDEF1); 1852 } 1853 } 1854 1855 /** 1856 * Operator $(D <<=) support. 1857 * 1858 * Shifts all the bits in the array to the left by the given number of 1859 * bits. The leftmost bits are dropped, and 0's are appended to the end 1860 * to fill up the vacant bits. 1861 * 1862 * $(RED Warning: unused bits in the final word up to the next word 1863 * boundary may be overwritten by this operation. It does not attempt to 1864 * preserve bits past the end of the array.) 1865 */ 1866 void opOpAssign(string op)(size_t nbits) @nogc pure nothrow 1867 if (op == "<<") 1868 { 1869 size_t wordsToShift = nbits / bitsPerSizeT; 1870 size_t bitsToShift = nbits % bitsPerSizeT; 1871 1872 if (wordsToShift < dim) 1873 { 1874 foreach_reverse (i; 1 .. dim - wordsToShift) 1875 { 1876 _ptr[i + wordsToShift] = rollLeft(_ptr[i], _ptr[i-1], 1877 bitsToShift); 1878 } 1879 _ptr[wordsToShift] = rollLeft(_ptr[0], 0, bitsToShift); 1880 } 1881 1882 import std.algorithm.comparison : min; 1883 foreach (i; 0 .. min(wordsToShift, dim)) 1884 { 1885 _ptr[i] = 0; 1886 } 1887 } 1888 1889 /** 1890 * Operator $(D >>=) support. 1891 * 1892 * Shifts all the bits in the array to the right by the given number of 1893 * bits. The rightmost bits are dropped, and 0's are inserted at the back 1894 * to fill up the vacant bits. 1895 * 1896 * $(RED Warning: unused bits in the final word up to the next word 1897 * boundary may be overwritten by this operation. It does not attempt to 1898 * preserve bits past the end of the array.) 1899 */ 1900 void opOpAssign(string op)(size_t nbits) @nogc pure nothrow 1901 if (op == ">>") 1902 { 1903 size_t wordsToShift = nbits / bitsPerSizeT; 1904 size_t bitsToShift = nbits % bitsPerSizeT; 1905 1906 if (wordsToShift + 1 < dim) 1907 { 1908 foreach (i; 0 .. dim - wordsToShift - 1) 1909 { 1910 _ptr[i] = rollRight(_ptr[i + wordsToShift + 1], 1911 _ptr[i + wordsToShift], bitsToShift); 1912 } 1913 } 1914 1915 // The last word needs some care, as it must shift in 0's from past the 1916 // end of the array. 1917 if (wordsToShift < dim) 1918 { 1919 _ptr[dim - wordsToShift - 1] = rollRight(0, _ptr[dim - 1] & endMask, 1920 bitsToShift); 1921 } 1922 1923 import std.algorithm.comparison : min; 1924 foreach (i; 0 .. min(wordsToShift, dim)) 1925 { 1926 _ptr[dim - i - 1] = 0; 1927 } 1928 } 1929 1930 @system unittest 1931 { 1932 import std.format : format; 1933 1934 auto b = BitArray([1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1]); 1935 1936 b <<= 1; 1937 assert(format("%b", b) == "01100_10101101"); 1938 1939 b >>= 1; 1940 assert(format("%b", b) == "11001_01011010"); 1941 1942 b <<= 4; 1943 assert(format("%b", b) == "00001_10010101"); 1944 1945 b >>= 5; 1946 assert(format("%b", b) == "10010_10100000"); 1947 1948 b <<= 13; 1949 assert(format("%b", b) == "00000_00000000"); 1950 1951 b = BitArray([1, 0, 1, 1, 0, 1, 1, 1]); 1952 b >>= 8; 1953 assert(format("%b", b) == "00000000"); 1954 1955 } 1956 1957 // Test multi-word case 1958 @system unittest 1959 { 1960 import std.format : format; 1961 1962 // This has to be long enough to occupy more than one size_t. On 64-bit 1963 // machines, this would be at least 64 bits. 1964 auto b = BitArray([ 1965 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1966 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1967 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1968 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1969 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1970 ]); 1971 b <<= 8; 1972 assert(format("%b", b) == 1973 "00000000_10000000_"~ 1974 "11000000_11100000_"~ 1975 "11110000_11111000_"~ 1976 "11111100_11111110_"~ 1977 "11111111_10101010"); 1978 1979 // Test right shift of more than one size_t's worth of bits 1980 b <<= 68; 1981 assert(format("%b", b) == 1982 "00000000_00000000_"~ 1983 "00000000_00000000_"~ 1984 "00000000_00000000_"~ 1985 "00000000_00000000_"~ 1986 "00000000_00001000"); 1987 1988 b = BitArray([ 1989 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1990 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1991 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1992 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1993 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1994 ]); 1995 b >>= 8; 1996 assert(format("%b", b) == 1997 "11000000_11100000_"~ 1998 "11110000_11111000_"~ 1999 "11111100_11111110_"~ 2000 "11111111_10101010_"~ 2001 "01010101_00000000"); 2002 2003 // Test left shift of more than 1 size_t's worth of bits 2004 b >>= 68; 2005 assert(format("%b", b) == 2006 "01010000_00000000_"~ 2007 "00000000_00000000_"~ 2008 "00000000_00000000_"~ 2009 "00000000_00000000_"~ 2010 "00000000_00000000"); 2011 } 2012 2013 /*************************************** 2014 * Return a string representation of this BitArray. 2015 * 2016 * Two format specifiers are supported: 2017 * $(LI $(B %s) which prints the bits as an array, and) 2018 * $(LI $(B %b) which prints the bits as 8-bit byte packets) 2019 * separated with an underscore. 2020 */ 2021 void toString(scope void delegate(const(char)[]) sink, 2022 FormatSpec!char fmt) const 2023 { 2024 switch (fmt.spec) 2025 { 2026 case 'b': 2027 return formatBitString(sink); 2028 case 's': 2029 return formatBitArray(sink); 2030 default: 2031 throw new Exception("Unknown format specifier: %" ~ fmt.spec); 2032 } 2033 } 2034 2035 /// 2036 @system unittest 2037 { 2038 import std.format : format; 2039 2040 debug(bitarray) printf("BitArray.toString unittest\n"); 2041 auto b = BitArray([0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]); 2042 2043 auto s1 = format("%s", b); 2044 assert(s1 == "[0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]"); 2045 2046 auto s2 = format("%b", b); 2047 assert(s2 == "00001111_00001111"); 2048 } 2049 2050 /*************************************** 2051 * Return a lazy range of the indices of set bits. 2052 */ 2053 @property auto bitsSet() const nothrow 2054 { 2055 import std.algorithm.iteration : filter, map, joiner; 2056 import std.range : iota; 2057 2058 return iota(dim). 2059 filter!(i => _ptr[i])(). 2060 map!(i => BitsSet!size_t(_ptr[i], i * bitsPerSizeT))(). 2061 joiner(); 2062 } 2063 2064 /// 2065 @system unittest 2066 { 2067 import std.algorithm.comparison : equal; 2068 2069 auto b1 = BitArray([0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]); 2070 assert(b1.bitsSet.equal([4, 5, 6, 7, 12, 13, 14, 15])); 2071 2072 BitArray b2; 2073 b2.length = 1000; 2074 b2[333] = true; 2075 b2[666] = true; 2076 b2[999] = true; 2077 assert(b2.bitsSet.equal([333, 666, 999])); 2078 } 2079 2080 @system unittest 2081 { 2082 import std.algorithm.comparison : equal; 2083 import std.range : iota; 2084 2085 debug(bitarray) printf("BitArray.bitsSet unittest\n"); 2086 BitArray b; 2087 enum wordBits = size_t.sizeof * 8; 2088 b = BitArray([size_t.max], 0); 2089 assert(b.bitsSet.empty); 2090 b = BitArray([size_t.max], 1); 2091 assert(b.bitsSet.equal([0])); 2092 b = BitArray([size_t.max], wordBits); 2093 assert(b.bitsSet.equal(iota(wordBits))); 2094 b = BitArray([size_t.max, size_t.max], wordBits); 2095 assert(b.bitsSet.equal(iota(wordBits))); 2096 b = BitArray([size_t.max, size_t.max], wordBits + 1); 2097 assert(b.bitsSet.equal(iota(wordBits + 1))); 2098 b = BitArray([size_t.max, size_t.max], wordBits * 2); 2099 assert(b.bitsSet.equal(iota(wordBits * 2))); 2100 } 2101 2102 private void formatBitString(scope void delegate(const(char)[]) sink) const 2103 { 2104 if (!length) 2105 return; 2106 2107 auto leftover = _len % 8; 2108 foreach (idx; 0 .. leftover) 2109 { 2110 char[1] res = cast(char)(this[idx] + '0'); 2111 sink.put(res[]); 2112 } 2113 2114 if (leftover && _len > 8) 2115 sink.put("_"); 2116 2117 size_t count; 2118 foreach (idx; leftover .. _len) 2119 { 2120 char[1] res = cast(char)(this[idx] + '0'); 2121 sink.put(res[]); 2122 if (++count == 8 && idx != _len - 1) 2123 { 2124 sink.put("_"); 2125 count = 0; 2126 } 2127 } 2128 } 2129 2130 private void formatBitArray(scope void delegate(const(char)[]) sink) const 2131 { 2132 sink("["); 2133 foreach (idx; 0 .. _len) 2134 { 2135 char[1] res = cast(char)(this[idx] + '0'); 2136 sink(res[]); 2137 if (idx+1 < _len) 2138 sink(", "); 2139 } 2140 sink("]"); 2141 } 2142} 2143 2144@system unittest 2145{ 2146 import std.format : format; 2147 2148 BitArray b; 2149 2150 b = BitArray([]); 2151 assert(format("%s", b) == "[]"); 2152 assert(format("%b", b) is null); 2153 2154 b = BitArray([1]); 2155 assert(format("%s", b) == "[1]"); 2156 assert(format("%b", b) == "1"); 2157 2158 b = BitArray([0, 0, 0, 0]); 2159 assert(format("%b", b) == "0000"); 2160 2161 b = BitArray([0, 0, 0, 0, 1, 1, 1, 1]); 2162 assert(format("%s", b) == "[0, 0, 0, 0, 1, 1, 1, 1]"); 2163 assert(format("%b", b) == "00001111"); 2164 2165 b = BitArray([0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]); 2166 assert(format("%s", b) == "[0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]"); 2167 assert(format("%b", b) == "00001111_00001111"); 2168 2169 b = BitArray([1, 0, 0, 0, 0, 1, 1, 1, 1]); 2170 assert(format("%b", b) == "1_00001111"); 2171 2172 b = BitArray([1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]); 2173 assert(format("%b", b) == "1_00001111_00001111"); 2174} 2175 2176/++ 2177 Swaps the endianness of the given integral value or character. 2178 +/ 2179T swapEndian(T)(T val) @safe pure nothrow @nogc 2180if (isIntegral!T || isSomeChar!T || isBoolean!T) 2181{ 2182 static if (val.sizeof == 1) 2183 return val; 2184 else static if (isUnsigned!T) 2185 return swapEndianImpl(val); 2186 else static if (isIntegral!T) 2187 return cast(T) swapEndianImpl(cast(Unsigned!T) val); 2188 else static if (is(Unqual!T == wchar)) 2189 return cast(T) swapEndian(cast(ushort) val); 2190 else static if (is(Unqual!T == dchar)) 2191 return cast(T) swapEndian(cast(uint) val); 2192 else 2193 static assert(0, T.stringof ~ " unsupported by swapEndian."); 2194} 2195 2196private ushort swapEndianImpl(ushort val) @safe pure nothrow @nogc 2197{ 2198 return ((val & 0xff00U) >> 8) | 2199 ((val & 0x00ffU) << 8); 2200} 2201 2202private uint swapEndianImpl(uint val) @trusted pure nothrow @nogc 2203{ 2204 import core.bitop : bswap; 2205 return bswap(val); 2206} 2207 2208private ulong swapEndianImpl(ulong val) @trusted pure nothrow @nogc 2209{ 2210 import core.bitop : bswap; 2211 immutable ulong res = bswap(cast(uint) val); 2212 return res << 32 | bswap(cast(uint)(val >> 32)); 2213} 2214 2215@safe unittest 2216{ 2217 import std.meta; 2218 foreach (T; AliasSeq!(bool, byte, ubyte, short, ushort, int, uint, long, ulong, char, wchar, dchar)) 2219 { 2220 scope(failure) writefln("Failed type: %s", T.stringof); 2221 T val; 2222 const T cval; 2223 immutable T ival; 2224 2225 assert(swapEndian(swapEndian(val)) == val); 2226 assert(swapEndian(swapEndian(cval)) == cval); 2227 assert(swapEndian(swapEndian(ival)) == ival); 2228 assert(swapEndian(swapEndian(T.min)) == T.min); 2229 assert(swapEndian(swapEndian(T.max)) == T.max); 2230 2231 foreach (i; 2 .. 10) 2232 { 2233 immutable T maxI = cast(T)(T.max / i); 2234 immutable T minI = cast(T)(T.min / i); 2235 2236 assert(swapEndian(swapEndian(maxI)) == maxI); 2237 2238 static if (isSigned!T) 2239 assert(swapEndian(swapEndian(minI)) == minI); 2240 } 2241 2242 static if (isSigned!T) 2243 assert(swapEndian(swapEndian(cast(T) 0)) == 0); 2244 2245 // used to trigger BUG6354 2246 static if (T.sizeof > 1 && isUnsigned!T) 2247 { 2248 T left = 0xffU; 2249 left <<= (T.sizeof - 1) * 8; 2250 T right = 0xffU; 2251 2252 for (size_t i = 1; i < T.sizeof; ++i) 2253 { 2254 assert(swapEndian(left) == right); 2255 assert(swapEndian(right) == left); 2256 left >>= 8; 2257 right <<= 8; 2258 } 2259 } 2260 } 2261} 2262 2263 2264private union EndianSwapper(T) 2265if (canSwapEndianness!T) 2266{ 2267 Unqual!T value; 2268 ubyte[T.sizeof] array; 2269 2270 static if (is(FloatingPointTypeOf!T == float)) 2271 uint intValue; 2272 else static if (is(FloatingPointTypeOf!T == double)) 2273 ulong intValue; 2274 2275} 2276 2277 2278/++ 2279 Converts the given value from the native endianness to big endian and 2280 returns it as a $(D ubyte[n]) where $(D n) is the size of the given type. 2281 2282 Returning a $(D ubyte[n]) helps prevent accidentally using a swapped value 2283 as a regular one (and in the case of floating point values, it's necessary, 2284 because the FPU will mess up any swapped floating point values. So, you 2285 can't actually have swapped floating point values as floating point values). 2286 2287 $(D real) is not supported, because its size is implementation-dependent 2288 and therefore could vary from machine to machine (which could make it 2289 unusable if you tried to transfer it to another machine). 2290 +/ 2291auto nativeToBigEndian(T)(T val) @safe pure nothrow @nogc 2292if (canSwapEndianness!T) 2293{ 2294 return nativeToBigEndianImpl(val); 2295} 2296 2297/// 2298@safe unittest 2299{ 2300 int i = 12345; 2301 ubyte[4] swappedI = nativeToBigEndian(i); 2302 assert(i == bigEndianToNative!int(swappedI)); 2303 2304 double d = 123.45; 2305 ubyte[8] swappedD = nativeToBigEndian(d); 2306 assert(d == bigEndianToNative!double(swappedD)); 2307} 2308 2309private auto nativeToBigEndianImpl(T)(T val) @safe pure nothrow @nogc 2310if (isIntegral!T || isSomeChar!T || isBoolean!T) 2311{ 2312 EndianSwapper!T es = void; 2313 2314 version (LittleEndian) 2315 es.value = swapEndian(val); 2316 else 2317 es.value = val; 2318 2319 return es.array; 2320} 2321 2322private auto nativeToBigEndianImpl(T)(T val) @safe pure nothrow @nogc 2323if (isFloatOrDouble!T) 2324{ 2325 version (LittleEndian) 2326 return floatEndianImpl!(T, true)(val); 2327 else 2328 return floatEndianImpl!(T, false)(val); 2329} 2330 2331@safe unittest 2332{ 2333 import std.meta; 2334 foreach (T; AliasSeq!(bool, byte, ubyte, short, ushort, int, uint, long, ulong, 2335 char, wchar, dchar 2336 /* The trouble here is with floats and doubles being compared against nan 2337 * using a bit compare. There are two kinds of nans, quiet and signaling. 2338 * When a nan passes through the x87, it converts signaling to quiet. 2339 * When a nan passes through the XMM, it does not convert signaling to quiet. 2340 * float.init is a signaling nan. 2341 * The binary API sometimes passes the data through the XMM, sometimes through 2342 * the x87, meaning these will fail the 'is' bit compare under some circumstances. 2343 * I cannot think of a fix for this that makes consistent sense. 2344 */ 2345 /*,float, double*/)) 2346 { 2347 scope(failure) writefln("Failed type: %s", T.stringof); 2348 T val; 2349 const T cval; 2350 immutable T ival; 2351 2352 //is instead of == because of NaN for floating point values. 2353 assert(bigEndianToNative!T(nativeToBigEndian(val)) is val); 2354 assert(bigEndianToNative!T(nativeToBigEndian(cval)) is cval); 2355 assert(bigEndianToNative!T(nativeToBigEndian(ival)) is ival); 2356 assert(bigEndianToNative!T(nativeToBigEndian(T.min)) == T.min); 2357 assert(bigEndianToNative!T(nativeToBigEndian(T.max)) == T.max); 2358 2359 static if (isSigned!T) 2360 assert(bigEndianToNative!T(nativeToBigEndian(cast(T) 0)) == 0); 2361 2362 static if (!is(T == bool)) 2363 { 2364 foreach (i; [2, 4, 6, 7, 9, 11]) 2365 { 2366 immutable T maxI = cast(T)(T.max / i); 2367 immutable T minI = cast(T)(T.min / i); 2368 2369 assert(bigEndianToNative!T(nativeToBigEndian(maxI)) == maxI); 2370 2371 static if (T.sizeof > 1) 2372 assert(nativeToBigEndian(maxI) != nativeToLittleEndian(maxI)); 2373 else 2374 assert(nativeToBigEndian(maxI) == nativeToLittleEndian(maxI)); 2375 2376 static if (isSigned!T) 2377 { 2378 assert(bigEndianToNative!T(nativeToBigEndian(minI)) == minI); 2379 2380 static if (T.sizeof > 1) 2381 assert(nativeToBigEndian(minI) != nativeToLittleEndian(minI)); 2382 else 2383 assert(nativeToBigEndian(minI) == nativeToLittleEndian(minI)); 2384 } 2385 } 2386 } 2387 2388 static if (isUnsigned!T || T.sizeof == 1 || is(T == wchar)) 2389 assert(nativeToBigEndian(T.max) == nativeToLittleEndian(T.max)); 2390 else 2391 assert(nativeToBigEndian(T.max) != nativeToLittleEndian(T.max)); 2392 2393 static if (isUnsigned!T || T.sizeof == 1 || isSomeChar!T) 2394 assert(nativeToBigEndian(T.min) == nativeToLittleEndian(T.min)); 2395 else 2396 assert(nativeToBigEndian(T.min) != nativeToLittleEndian(T.min)); 2397 } 2398} 2399 2400 2401/++ 2402 Converts the given value from big endian to the native endianness and 2403 returns it. The value is given as a $(D ubyte[n]) where $(D n) is the size 2404 of the target type. You must give the target type as a template argument, 2405 because there are multiple types with the same size and so the type of the 2406 argument is not enough to determine the return type. 2407 2408 Taking a $(D ubyte[n]) helps prevent accidentally using a swapped value 2409 as a regular one (and in the case of floating point values, it's necessary, 2410 because the FPU will mess up any swapped floating point values. So, you 2411 can't actually have swapped floating point values as floating point values). 2412 +/ 2413T bigEndianToNative(T, size_t n)(ubyte[n] val) @safe pure nothrow @nogc 2414if (canSwapEndianness!T && n == T.sizeof) 2415{ 2416 return bigEndianToNativeImpl!(T, n)(val); 2417} 2418 2419/// 2420@safe unittest 2421{ 2422 ushort i = 12345; 2423 ubyte[2] swappedI = nativeToBigEndian(i); 2424 assert(i == bigEndianToNative!ushort(swappedI)); 2425 2426 dchar c = 'D'; 2427 ubyte[4] swappedC = nativeToBigEndian(c); 2428 assert(c == bigEndianToNative!dchar(swappedC)); 2429} 2430 2431private T bigEndianToNativeImpl(T, size_t n)(ubyte[n] val) @safe pure nothrow @nogc 2432if ((isIntegral!T || isSomeChar!T || isBoolean!T) && 2433 n == T.sizeof) 2434{ 2435 EndianSwapper!T es = void; 2436 es.array = val; 2437 2438 version (LittleEndian) 2439 immutable retval = swapEndian(es.value); 2440 else 2441 immutable retval = es.value; 2442 2443 return retval; 2444} 2445 2446private T bigEndianToNativeImpl(T, size_t n)(ubyte[n] val) @safe pure nothrow @nogc 2447if (isFloatOrDouble!T && n == T.sizeof) 2448{ 2449 version (LittleEndian) 2450 return cast(T) floatEndianImpl!(n, true)(val); 2451 else 2452 return cast(T) floatEndianImpl!(n, false)(val); 2453} 2454 2455 2456/++ 2457 Converts the given value from the native endianness to little endian and 2458 returns it as a $(D ubyte[n]) where $(D n) is the size of the given type. 2459 2460 Returning a $(D ubyte[n]) helps prevent accidentally using a swapped value 2461 as a regular one (and in the case of floating point values, it's necessary, 2462 because the FPU will mess up any swapped floating point values. So, you 2463 can't actually have swapped floating point values as floating point values). 2464 +/ 2465auto nativeToLittleEndian(T)(T val) @safe pure nothrow @nogc 2466if (canSwapEndianness!T) 2467{ 2468 return nativeToLittleEndianImpl(val); 2469} 2470 2471/// 2472@safe unittest 2473{ 2474 int i = 12345; 2475 ubyte[4] swappedI = nativeToLittleEndian(i); 2476 assert(i == littleEndianToNative!int(swappedI)); 2477 2478 double d = 123.45; 2479 ubyte[8] swappedD = nativeToLittleEndian(d); 2480 assert(d == littleEndianToNative!double(swappedD)); 2481} 2482 2483private auto nativeToLittleEndianImpl(T)(T val) @safe pure nothrow @nogc 2484if (isIntegral!T || isSomeChar!T || isBoolean!T) 2485{ 2486 EndianSwapper!T es = void; 2487 2488 version (BigEndian) 2489 es.value = swapEndian(val); 2490 else 2491 es.value = val; 2492 2493 return es.array; 2494} 2495 2496private auto nativeToLittleEndianImpl(T)(T val) @safe pure nothrow @nogc 2497if (isFloatOrDouble!T) 2498{ 2499 version (BigEndian) 2500 return floatEndianImpl!(T, true)(val); 2501 else 2502 return floatEndianImpl!(T, false)(val); 2503} 2504 2505@safe unittest 2506{ 2507 import std.meta; 2508 foreach (T; AliasSeq!(bool, byte, ubyte, short, ushort, int, uint, long, ulong, 2509 char, wchar, dchar/*, 2510 float, double*/)) 2511 { 2512 scope(failure) writefln("Failed type: %s", T.stringof); 2513 T val; 2514 const T cval; 2515 immutable T ival; 2516 2517 //is instead of == because of NaN for floating point values. 2518 assert(littleEndianToNative!T(nativeToLittleEndian(val)) is val); 2519 assert(littleEndianToNative!T(nativeToLittleEndian(cval)) is cval); 2520 assert(littleEndianToNative!T(nativeToLittleEndian(ival)) is ival); 2521 assert(littleEndianToNative!T(nativeToLittleEndian(T.min)) == T.min); 2522 assert(littleEndianToNative!T(nativeToLittleEndian(T.max)) == T.max); 2523 2524 static if (isSigned!T) 2525 assert(littleEndianToNative!T(nativeToLittleEndian(cast(T) 0)) == 0); 2526 2527 static if (!is(T == bool)) 2528 { 2529 foreach (i; 2 .. 10) 2530 { 2531 immutable T maxI = cast(T)(T.max / i); 2532 immutable T minI = cast(T)(T.min / i); 2533 2534 assert(littleEndianToNative!T(nativeToLittleEndian(maxI)) == maxI); 2535 2536 static if (isSigned!T) 2537 assert(littleEndianToNative!T(nativeToLittleEndian(minI)) == minI); 2538 } 2539 } 2540 } 2541} 2542 2543 2544/++ 2545 Converts the given value from little endian to the native endianness and 2546 returns it. The value is given as a $(D ubyte[n]) where $(D n) is the size 2547 of the target type. You must give the target type as a template argument, 2548 because there are multiple types with the same size and so the type of the 2549 argument is not enough to determine the return type. 2550 2551 Taking a $(D ubyte[n]) helps prevent accidentally using a swapped value 2552 as a regular one (and in the case of floating point values, it's necessary, 2553 because the FPU will mess up any swapped floating point values. So, you 2554 can't actually have swapped floating point values as floating point values). 2555 2556 $(D real) is not supported, because its size is implementation-dependent 2557 and therefore could vary from machine to machine (which could make it 2558 unusable if you tried to transfer it to another machine). 2559 +/ 2560T littleEndianToNative(T, size_t n)(ubyte[n] val) @safe pure nothrow @nogc 2561if (canSwapEndianness!T && n == T.sizeof) 2562{ 2563 return littleEndianToNativeImpl!T(val); 2564} 2565 2566/// 2567@safe unittest 2568{ 2569 ushort i = 12345; 2570 ubyte[2] swappedI = nativeToLittleEndian(i); 2571 assert(i == littleEndianToNative!ushort(swappedI)); 2572 2573 dchar c = 'D'; 2574 ubyte[4] swappedC = nativeToLittleEndian(c); 2575 assert(c == littleEndianToNative!dchar(swappedC)); 2576} 2577 2578private T littleEndianToNativeImpl(T, size_t n)(ubyte[n] val) @safe pure nothrow @nogc 2579if ((isIntegral!T || isSomeChar!T || isBoolean!T) && 2580 n == T.sizeof) 2581{ 2582 EndianSwapper!T es = void; 2583 es.array = val; 2584 2585 version (BigEndian) 2586 immutable retval = swapEndian(es.value); 2587 else 2588 immutable retval = es.value; 2589 2590 return retval; 2591} 2592 2593private T littleEndianToNativeImpl(T, size_t n)(ubyte[n] val) @safe pure nothrow @nogc 2594if (((isFloatOrDouble!T) && 2595 n == T.sizeof)) 2596{ 2597 version (BigEndian) 2598 return floatEndianImpl!(n, true)(val); 2599 else 2600 return floatEndianImpl!(n, false)(val); 2601} 2602 2603private auto floatEndianImpl(T, bool swap)(T val) @safe pure nothrow @nogc 2604if (isFloatOrDouble!T) 2605{ 2606 EndianSwapper!T es = void; 2607 es.value = val; 2608 2609 static if (swap) 2610 es.intValue = swapEndian(es.intValue); 2611 2612 return es.array; 2613} 2614 2615private auto floatEndianImpl(size_t n, bool swap)(ubyte[n] val) @safe pure nothrow @nogc 2616if (n == 4 || n == 8) 2617{ 2618 static if (n == 4) EndianSwapper!float es = void; 2619 else static if (n == 8) EndianSwapper!double es = void; 2620 2621 es.array = val; 2622 2623 static if (swap) 2624 es.intValue = swapEndian(es.intValue); 2625 2626 return es.value; 2627} 2628 2629private template isFloatOrDouble(T) 2630{ 2631 enum isFloatOrDouble = isFloatingPoint!T && 2632 !is(Unqual!(FloatingPointTypeOf!T) == real); 2633} 2634 2635@safe unittest 2636{ 2637 import std.meta; 2638 foreach (T; AliasSeq!(float, double)) 2639 { 2640 static assert(isFloatOrDouble!(T)); 2641 static assert(isFloatOrDouble!(const T)); 2642 static assert(isFloatOrDouble!(immutable T)); 2643 static assert(isFloatOrDouble!(shared T)); 2644 static assert(isFloatOrDouble!(shared(const T))); 2645 static assert(isFloatOrDouble!(shared(immutable T))); 2646 } 2647 2648 static assert(!isFloatOrDouble!(real)); 2649 static assert(!isFloatOrDouble!(const real)); 2650 static assert(!isFloatOrDouble!(immutable real)); 2651 static assert(!isFloatOrDouble!(shared real)); 2652 static assert(!isFloatOrDouble!(shared(const real))); 2653 static assert(!isFloatOrDouble!(shared(immutable real))); 2654} 2655 2656private template canSwapEndianness(T) 2657{ 2658 enum canSwapEndianness = isIntegral!T || 2659 isSomeChar!T || 2660 isBoolean!T || 2661 isFloatOrDouble!T; 2662} 2663 2664@safe unittest 2665{ 2666 import std.meta; 2667 foreach (T; AliasSeq!(bool, ubyte, byte, ushort, short, uint, int, ulong, 2668 long, char, wchar, dchar, float, double)) 2669 { 2670 static assert(canSwapEndianness!(T)); 2671 static assert(canSwapEndianness!(const T)); 2672 static assert(canSwapEndianness!(immutable T)); 2673 static assert(canSwapEndianness!(shared(T))); 2674 static assert(canSwapEndianness!(shared(const T))); 2675 static assert(canSwapEndianness!(shared(immutable T))); 2676 } 2677 2678 //! 2679 foreach (T; AliasSeq!(real, string, wstring, dstring)) 2680 { 2681 static assert(!canSwapEndianness!(T)); 2682 static assert(!canSwapEndianness!(const T)); 2683 static assert(!canSwapEndianness!(immutable T)); 2684 static assert(!canSwapEndianness!(shared(T))); 2685 static assert(!canSwapEndianness!(shared(const T))); 2686 static assert(!canSwapEndianness!(shared(immutable T))); 2687 } 2688} 2689 2690/++ 2691 Takes a range of $(D ubyte)s and converts the first $(D T.sizeof) bytes to 2692 $(D T). The value returned is converted from the given endianness to the 2693 native endianness. The range is not consumed. 2694 2695 Params: 2696 T = The integral type to convert the first $(D T.sizeof) bytes to. 2697 endianness = The endianness that the bytes are assumed to be in. 2698 range = The range to read from. 2699 index = The index to start reading from (instead of starting at the 2700 front). If index is a pointer, then it is updated to the index 2701 after the bytes read. The overloads with index are only 2702 available if $(D hasSlicing!R) is $(D true). 2703 +/ 2704 2705T peek(T, Endian endianness = Endian.bigEndian, R)(R range) 2706if (canSwapEndianness!T && 2707 isForwardRange!R && 2708 is(ElementType!R : const ubyte)) 2709{ 2710 static if (hasSlicing!R) 2711 const ubyte[T.sizeof] bytes = range[0 .. T.sizeof]; 2712 else 2713 { 2714 ubyte[T.sizeof] bytes; 2715 //Make sure that range is not consumed, even if it's a class. 2716 range = range.save; 2717 2718 foreach (ref e; bytes) 2719 { 2720 e = range.front; 2721 range.popFront(); 2722 } 2723 } 2724 2725 static if (endianness == Endian.bigEndian) 2726 return bigEndianToNative!T(bytes); 2727 else 2728 return littleEndianToNative!T(bytes); 2729} 2730 2731/++ Ditto +/ 2732T peek(T, Endian endianness = Endian.bigEndian, R)(R range, size_t index) 2733if (canSwapEndianness!T && 2734 isForwardRange!R && 2735 hasSlicing!R && 2736 is(ElementType!R : const ubyte)) 2737{ 2738 return peek!(T, endianness)(range, &index); 2739} 2740 2741/++ Ditto +/ 2742T peek(T, Endian endianness = Endian.bigEndian, R)(R range, size_t* index) 2743if (canSwapEndianness!T && 2744 isForwardRange!R && 2745 hasSlicing!R && 2746 is(ElementType!R : const ubyte)) 2747{ 2748 assert(index); 2749 2750 immutable begin = *index; 2751 immutable end = begin + T.sizeof; 2752 const ubyte[T.sizeof] bytes = range[begin .. end]; 2753 *index = end; 2754 2755 static if (endianness == Endian.bigEndian) 2756 return bigEndianToNative!T(bytes); 2757 else 2758 return littleEndianToNative!T(bytes); 2759} 2760 2761/// 2762@system unittest 2763{ 2764 ubyte[] buffer = [1, 5, 22, 9, 44, 255, 8]; 2765 assert(buffer.peek!uint() == 17110537); 2766 assert(buffer.peek!ushort() == 261); 2767 assert(buffer.peek!ubyte() == 1); 2768 2769 assert(buffer.peek!uint(2) == 369700095); 2770 assert(buffer.peek!ushort(2) == 5641); 2771 assert(buffer.peek!ubyte(2) == 22); 2772 2773 size_t index = 0; 2774 assert(buffer.peek!ushort(&index) == 261); 2775 assert(index == 2); 2776 2777 assert(buffer.peek!uint(&index) == 369700095); 2778 assert(index == 6); 2779 2780 assert(buffer.peek!ubyte(&index) == 8); 2781 assert(index == 7); 2782} 2783 2784@system unittest 2785{ 2786 { 2787 //bool 2788 ubyte[] buffer = [0, 1]; 2789 assert(buffer.peek!bool() == false); 2790 assert(buffer.peek!bool(1) == true); 2791 2792 size_t index = 0; 2793 assert(buffer.peek!bool(&index) == false); 2794 assert(index == 1); 2795 2796 assert(buffer.peek!bool(&index) == true); 2797 assert(index == 2); 2798 } 2799 2800 { 2801 //char (8bit) 2802 ubyte[] buffer = [97, 98, 99, 100]; 2803 assert(buffer.peek!char() == 'a'); 2804 assert(buffer.peek!char(1) == 'b'); 2805 2806 size_t index = 0; 2807 assert(buffer.peek!char(&index) == 'a'); 2808 assert(index == 1); 2809 2810 assert(buffer.peek!char(&index) == 'b'); 2811 assert(index == 2); 2812 } 2813 2814 { 2815 //wchar (16bit - 2x ubyte) 2816 ubyte[] buffer = [1, 5, 32, 29, 1, 7]; 2817 assert(buffer.peek!wchar() == '��'); 2818 assert(buffer.peek!wchar(2) == '���'); 2819 assert(buffer.peek!wchar(4) == '��'); 2820 2821 size_t index = 0; 2822 assert(buffer.peek!wchar(&index) == '��'); 2823 assert(index == 2); 2824 2825 assert(buffer.peek!wchar(&index) == '���'); 2826 assert(index == 4); 2827 2828 assert(buffer.peek!wchar(&index) == '��'); 2829 assert(index == 6); 2830 } 2831 2832 { 2833 //dchar (32bit - 4x ubyte) 2834 ubyte[] buffer = [0, 0, 1, 5, 0, 0, 32, 29, 0, 0, 1, 7]; 2835 assert(buffer.peek!dchar() == '��'); 2836 assert(buffer.peek!dchar(4) == '���'); 2837 assert(buffer.peek!dchar(8) == '��'); 2838 2839 size_t index = 0; 2840 assert(buffer.peek!dchar(&index) == '��'); 2841 assert(index == 4); 2842 2843 assert(buffer.peek!dchar(&index) == '���'); 2844 assert(index == 8); 2845 2846 assert(buffer.peek!dchar(&index) == '��'); 2847 assert(index == 12); 2848 } 2849 2850 { 2851 //float (32bit - 4x ubyte) 2852 ubyte[] buffer = [66, 0, 0, 0, 65, 200, 0, 0]; 2853 assert(buffer.peek!float()== 32.0); 2854 assert(buffer.peek!float(4) == 25.0f); 2855 2856 size_t index = 0; 2857 assert(buffer.peek!float(&index) == 32.0f); 2858 assert(index == 4); 2859 2860 assert(buffer.peek!float(&index) == 25.0f); 2861 assert(index == 8); 2862 } 2863 2864 { 2865 //double (64bit - 8x ubyte) 2866 ubyte[] buffer = [64, 64, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]; 2867 assert(buffer.peek!double() == 32.0); 2868 assert(buffer.peek!double(8) == 25.0); 2869 2870 size_t index = 0; 2871 assert(buffer.peek!double(&index) == 32.0); 2872 assert(index == 8); 2873 2874 assert(buffer.peek!double(&index) == 25.0); 2875 assert(index == 16); 2876 } 2877 2878 { 2879 //enum 2880 ubyte[] buffer = [0, 0, 0, 10, 0, 0, 0, 20, 0, 0, 0, 30]; 2881 2882 enum Foo 2883 { 2884 one = 10, 2885 two = 20, 2886 three = 30 2887 } 2888 2889 assert(buffer.peek!Foo() == Foo.one); 2890 assert(buffer.peek!Foo(0) == Foo.one); 2891 assert(buffer.peek!Foo(4) == Foo.two); 2892 assert(buffer.peek!Foo(8) == Foo.three); 2893 2894 size_t index = 0; 2895 assert(buffer.peek!Foo(&index) == Foo.one); 2896 assert(index == 4); 2897 2898 assert(buffer.peek!Foo(&index) == Foo.two); 2899 assert(index == 8); 2900 2901 assert(buffer.peek!Foo(&index) == Foo.three); 2902 assert(index == 12); 2903 } 2904 2905 { 2906 //enum - bool 2907 ubyte[] buffer = [0, 1]; 2908 2909 enum Bool: bool 2910 { 2911 bfalse = false, 2912 btrue = true, 2913 } 2914 2915 assert(buffer.peek!Bool() == Bool.bfalse); 2916 assert(buffer.peek!Bool(0) == Bool.bfalse); 2917 assert(buffer.peek!Bool(1) == Bool.btrue); 2918 2919 size_t index = 0; 2920 assert(buffer.peek!Bool(&index) == Bool.bfalse); 2921 assert(index == 1); 2922 2923 assert(buffer.peek!Bool(&index) == Bool.btrue); 2924 assert(index == 2); 2925 } 2926 2927 { 2928 //enum - float 2929 ubyte[] buffer = [66, 0, 0, 0, 65, 200, 0, 0]; 2930 2931 enum Float: float 2932 { 2933 one = 32.0f, 2934 two = 25.0f 2935 } 2936 2937 assert(buffer.peek!Float() == Float.one); 2938 assert(buffer.peek!Float(0) == Float.one); 2939 assert(buffer.peek!Float(4) == Float.two); 2940 2941 size_t index = 0; 2942 assert(buffer.peek!Float(&index) == Float.one); 2943 assert(index == 4); 2944 2945 assert(buffer.peek!Float(&index) == Float.two); 2946 assert(index == 8); 2947 } 2948 2949 { 2950 //enum - double 2951 ubyte[] buffer = [64, 64, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]; 2952 2953 enum Double: double 2954 { 2955 one = 32.0, 2956 two = 25.0 2957 } 2958 2959 assert(buffer.peek!Double() == Double.one); 2960 assert(buffer.peek!Double(0) == Double.one); 2961 assert(buffer.peek!Double(8) == Double.two); 2962 2963 size_t index = 0; 2964 assert(buffer.peek!Double(&index) == Double.one); 2965 assert(index == 8); 2966 2967 assert(buffer.peek!Double(&index) == Double.two); 2968 assert(index == 16); 2969 } 2970 2971 { 2972 //enum - real 2973 ubyte[] buffer = [64, 64, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]; 2974 2975 enum Real: real 2976 { 2977 one = 32.0, 2978 two = 25.0 2979 } 2980 2981 static assert(!__traits(compiles, buffer.peek!Real())); 2982 } 2983} 2984 2985@safe unittest 2986{ 2987 import std.algorithm.iteration : filter; 2988 ubyte[] buffer = [1, 5, 22, 9, 44, 255, 7]; 2989 auto range = filter!"true"(buffer); 2990 assert(range.peek!uint() == 17110537); 2991 assert(range.peek!ushort() == 261); 2992 assert(range.peek!ubyte() == 1); 2993} 2994 2995 2996/++ 2997 Takes a range of $(D ubyte)s and converts the first $(D T.sizeof) bytes to 2998 $(D T). The value returned is converted from the given endianness to the 2999 native endianness. The $(D T.sizeof) bytes which are read are consumed from 3000 the range. 3001 3002 Params: 3003 T = The integral type to convert the first $(D T.sizeof) bytes to. 3004 endianness = The endianness that the bytes are assumed to be in. 3005 range = The range to read from. 3006 +/ 3007T read(T, Endian endianness = Endian.bigEndian, R)(ref R range) 3008if (canSwapEndianness!T && isInputRange!R && is(ElementType!R : const ubyte)) 3009{ 3010 static if (hasSlicing!R && is(typeof(R.init[0 .. 0]) : const(ubyte)[])) 3011 { 3012 const ubyte[T.sizeof] bytes = range[0 .. T.sizeof]; 3013 range.popFrontN(T.sizeof); 3014 } 3015 else 3016 { 3017 ubyte[T.sizeof] bytes; 3018 3019 foreach (ref e; bytes) 3020 { 3021 e = range.front; 3022 range.popFront(); 3023 } 3024 } 3025 3026 static if (endianness == Endian.bigEndian) 3027 return bigEndianToNative!T(bytes); 3028 else 3029 return littleEndianToNative!T(bytes); 3030} 3031 3032/// 3033@safe unittest 3034{ 3035 import std.range.primitives : empty; 3036 ubyte[] buffer = [1, 5, 22, 9, 44, 255, 8]; 3037 assert(buffer.length == 7); 3038 3039 assert(buffer.read!ushort() == 261); 3040 assert(buffer.length == 5); 3041 3042 assert(buffer.read!uint() == 369700095); 3043 assert(buffer.length == 1); 3044 3045 assert(buffer.read!ubyte() == 8); 3046 assert(buffer.empty); 3047} 3048 3049@safe unittest 3050{ 3051 { 3052 //bool 3053 ubyte[] buffer = [0, 1]; 3054 assert(buffer.length == 2); 3055 3056 assert(buffer.read!bool() == false); 3057 assert(buffer.length == 1); 3058 3059 assert(buffer.read!bool() == true); 3060 assert(buffer.empty); 3061 } 3062 3063 { 3064 //char (8bit) 3065 ubyte[] buffer = [97, 98, 99]; 3066 assert(buffer.length == 3); 3067 3068 assert(buffer.read!char() == 'a'); 3069 assert(buffer.length == 2); 3070 3071 assert(buffer.read!char() == 'b'); 3072 assert(buffer.length == 1); 3073 3074 assert(buffer.read!char() == 'c'); 3075 assert(buffer.empty); 3076 } 3077 3078 { 3079 //wchar (16bit - 2x ubyte) 3080 ubyte[] buffer = [1, 5, 32, 29, 1, 7]; 3081 assert(buffer.length == 6); 3082 3083 assert(buffer.read!wchar() == '��'); 3084 assert(buffer.length == 4); 3085 3086 assert(buffer.read!wchar() == '���'); 3087 assert(buffer.length == 2); 3088 3089 assert(buffer.read!wchar() == '��'); 3090 assert(buffer.empty); 3091 } 3092 3093 { 3094 //dchar (32bit - 4x ubyte) 3095 ubyte[] buffer = [0, 0, 1, 5, 0, 0, 32, 29, 0, 0, 1, 7]; 3096 assert(buffer.length == 12); 3097 3098 assert(buffer.read!dchar() == '��'); 3099 assert(buffer.length == 8); 3100 3101 assert(buffer.read!dchar() == '���'); 3102 assert(buffer.length == 4); 3103 3104 assert(buffer.read!dchar() == '��'); 3105 assert(buffer.empty); 3106 } 3107 3108 { 3109 //float (32bit - 4x ubyte) 3110 ubyte[] buffer = [66, 0, 0, 0, 65, 200, 0, 0]; 3111 assert(buffer.length == 8); 3112 3113 assert(buffer.read!float()== 32.0); 3114 assert(buffer.length == 4); 3115 3116 assert(buffer.read!float() == 25.0f); 3117 assert(buffer.empty); 3118 } 3119 3120 { 3121 //double (64bit - 8x ubyte) 3122 ubyte[] buffer = [64, 64, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]; 3123 assert(buffer.length == 16); 3124 3125 assert(buffer.read!double() == 32.0); 3126 assert(buffer.length == 8); 3127 3128 assert(buffer.read!double() == 25.0); 3129 assert(buffer.empty); 3130 } 3131 3132 { 3133 //enum - uint 3134 ubyte[] buffer = [0, 0, 0, 10, 0, 0, 0, 20, 0, 0, 0, 30]; 3135 assert(buffer.length == 12); 3136 3137 enum Foo 3138 { 3139 one = 10, 3140 two = 20, 3141 three = 30 3142 } 3143 3144 assert(buffer.read!Foo() == Foo.one); 3145 assert(buffer.length == 8); 3146 3147 assert(buffer.read!Foo() == Foo.two); 3148 assert(buffer.length == 4); 3149 3150 assert(buffer.read!Foo() == Foo.three); 3151 assert(buffer.empty); 3152 } 3153 3154 { 3155 //enum - bool 3156 ubyte[] buffer = [0, 1]; 3157 assert(buffer.length == 2); 3158 3159 enum Bool: bool 3160 { 3161 bfalse = false, 3162 btrue = true, 3163 } 3164 3165 assert(buffer.read!Bool() == Bool.bfalse); 3166 assert(buffer.length == 1); 3167 3168 assert(buffer.read!Bool() == Bool.btrue); 3169 assert(buffer.empty); 3170 } 3171 3172 { 3173 //enum - float 3174 ubyte[] buffer = [66, 0, 0, 0, 65, 200, 0, 0]; 3175 assert(buffer.length == 8); 3176 3177 enum Float: float 3178 { 3179 one = 32.0f, 3180 two = 25.0f 3181 } 3182 3183 assert(buffer.read!Float() == Float.one); 3184 assert(buffer.length == 4); 3185 3186 assert(buffer.read!Float() == Float.two); 3187 assert(buffer.empty); 3188 } 3189 3190 { 3191 //enum - double 3192 ubyte[] buffer = [64, 64, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]; 3193 assert(buffer.length == 16); 3194 3195 enum Double: double 3196 { 3197 one = 32.0, 3198 two = 25.0 3199 } 3200 3201 assert(buffer.read!Double() == Double.one); 3202 assert(buffer.length == 8); 3203 3204 assert(buffer.read!Double() == Double.two); 3205 assert(buffer.empty); 3206 } 3207 3208 { 3209 //enum - real 3210 ubyte[] buffer = [64, 64, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]; 3211 3212 enum Real: real 3213 { 3214 one = 32.0, 3215 two = 25.0 3216 } 3217 3218 static assert(!__traits(compiles, buffer.read!Real())); 3219 } 3220} 3221 3222@safe unittest 3223{ 3224 import std.algorithm.iteration : filter; 3225 ubyte[] buffer = [1, 5, 22, 9, 44, 255, 8]; 3226 auto range = filter!"true"(buffer); 3227 assert(walkLength(range) == 7); 3228 3229 assert(range.read!ushort() == 261); 3230 assert(walkLength(range) == 5); 3231 3232 assert(range.read!uint() == 369700095); 3233 assert(walkLength(range) == 1); 3234 3235 assert(range.read!ubyte() == 8); 3236 assert(range.empty); 3237} 3238 3239// issue 17247 3240@safe unittest 3241{ 3242 struct UbyteRange 3243 { 3244 ubyte[] impl; 3245 @property bool empty() { return impl.empty; } 3246 @property ubyte front() { return impl.front; } 3247 void popFront() { impl.popFront(); } 3248 @property UbyteRange save() { return this; } 3249 3250 // N.B. support slicing but do not return ubyte[] slices. 3251 UbyteRange opSlice(size_t start, size_t end) 3252 { 3253 return UbyteRange(impl[start .. end]); 3254 } 3255 @property size_t length() { return impl.length; } 3256 size_t opDollar() { return impl.length; } 3257 } 3258 static assert(hasSlicing!UbyteRange); 3259 3260 auto r = UbyteRange([0x01, 0x00, 0x00, 0x00]); 3261 int x = r.read!(int, Endian.littleEndian)(); 3262 assert(x == 1); 3263} 3264 3265 3266/++ 3267 Takes an integral value, converts it to the given endianness, and writes it 3268 to the given range of $(D ubyte)s as a sequence of $(D T.sizeof) $(D ubyte)s 3269 starting at index. $(D hasSlicing!R) must be $(D true). 3270 3271 Params: 3272 T = The integral type to convert the first $(D T.sizeof) bytes to. 3273 endianness = The endianness to _write the bytes in. 3274 range = The range to _write to. 3275 value = The value to _write. 3276 index = The index to start writing to. If index is a pointer, then it 3277 is updated to the index after the bytes read. 3278 +/ 3279void write(T, Endian endianness = Endian.bigEndian, R)(R range, T value, size_t index) 3280if (canSwapEndianness!T && 3281 isForwardRange!R && 3282 hasSlicing!R && 3283 is(ElementType!R : ubyte)) 3284{ 3285 write!(T, endianness)(range, value, &index); 3286} 3287 3288/++ Ditto +/ 3289void write(T, Endian endianness = Endian.bigEndian, R)(R range, T value, size_t* index) 3290if (canSwapEndianness!T && 3291 isForwardRange!R && 3292 hasSlicing!R && 3293 is(ElementType!R : ubyte)) 3294{ 3295 assert(index); 3296 3297 static if (endianness == Endian.bigEndian) 3298 immutable bytes = nativeToBigEndian!T(value); 3299 else 3300 immutable bytes = nativeToLittleEndian!T(value); 3301 3302 immutable begin = *index; 3303 immutable end = begin + T.sizeof; 3304 *index = end; 3305 range[begin .. end] = bytes[0 .. T.sizeof]; 3306} 3307 3308/// 3309@system unittest 3310{ 3311 { 3312 ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0]; 3313 buffer.write!uint(29110231u, 0); 3314 assert(buffer == [1, 188, 47, 215, 0, 0, 0, 0]); 3315 3316 buffer.write!ushort(927, 0); 3317 assert(buffer == [3, 159, 47, 215, 0, 0, 0, 0]); 3318 3319 buffer.write!ubyte(42, 0); 3320 assert(buffer == [42, 159, 47, 215, 0, 0, 0, 0]); 3321 } 3322 3323 { 3324 ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0, 0]; 3325 buffer.write!uint(142700095u, 2); 3326 assert(buffer == [0, 0, 8, 129, 110, 63, 0, 0, 0]); 3327 3328 buffer.write!ushort(19839, 2); 3329 assert(buffer == [0, 0, 77, 127, 110, 63, 0, 0, 0]); 3330 3331 buffer.write!ubyte(132, 2); 3332 assert(buffer == [0, 0, 132, 127, 110, 63, 0, 0, 0]); 3333 } 3334 3335 { 3336 ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0]; 3337 size_t index = 0; 3338 buffer.write!ushort(261, &index); 3339 assert(buffer == [1, 5, 0, 0, 0, 0, 0, 0]); 3340 assert(index == 2); 3341 3342 buffer.write!uint(369700095u, &index); 3343 assert(buffer == [1, 5, 22, 9, 44, 255, 0, 0]); 3344 assert(index == 6); 3345 3346 buffer.write!ubyte(8, &index); 3347 assert(buffer == [1, 5, 22, 9, 44, 255, 8, 0]); 3348 assert(index == 7); 3349 } 3350} 3351 3352@system unittest 3353{ 3354 { 3355 //bool 3356 ubyte[] buffer = [0, 0]; 3357 3358 buffer.write!bool(false, 0); 3359 assert(buffer == [0, 0]); 3360 3361 buffer.write!bool(true, 0); 3362 assert(buffer == [1, 0]); 3363 3364 buffer.write!bool(true, 1); 3365 assert(buffer == [1, 1]); 3366 3367 buffer.write!bool(false, 1); 3368 assert(buffer == [1, 0]); 3369 3370 size_t index = 0; 3371 buffer.write!bool(false, &index); 3372 assert(buffer == [0, 0]); 3373 assert(index == 1); 3374 3375 buffer.write!bool(true, &index); 3376 assert(buffer == [0, 1]); 3377 assert(index == 2); 3378 } 3379 3380 { 3381 //char (8bit) 3382 ubyte[] buffer = [0, 0, 0]; 3383 3384 buffer.write!char('a', 0); 3385 assert(buffer == [97, 0, 0]); 3386 3387 buffer.write!char('b', 1); 3388 assert(buffer == [97, 98, 0]); 3389 3390 size_t index = 0; 3391 buffer.write!char('a', &index); 3392 assert(buffer == [97, 98, 0]); 3393 assert(index == 1); 3394 3395 buffer.write!char('b', &index); 3396 assert(buffer == [97, 98, 0]); 3397 assert(index == 2); 3398 3399 buffer.write!char('c', &index); 3400 assert(buffer == [97, 98, 99]); 3401 assert(index == 3); 3402 } 3403 3404 { 3405 //wchar (16bit - 2x ubyte) 3406 ubyte[] buffer = [0, 0, 0, 0]; 3407 3408 buffer.write!wchar('��', 0); 3409 assert(buffer == [1, 5, 0, 0]); 3410 3411 buffer.write!wchar('���', 2); 3412 assert(buffer == [1, 5, 32, 29]); 3413 3414 size_t index = 0; 3415 buffer.write!wchar('��', &index); 3416 assert(buffer == [1, 7, 32, 29]); 3417 assert(index == 2); 3418 3419 buffer.write!wchar('��', &index); 3420 assert(buffer == [1, 7, 1, 5]); 3421 assert(index == 4); 3422 } 3423 3424 { 3425 //dchar (32bit - 4x ubyte) 3426 ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0]; 3427 3428 buffer.write!dchar('��', 0); 3429 assert(buffer == [0, 0, 1, 5, 0, 0, 0, 0]); 3430 3431 buffer.write!dchar('���', 4); 3432 assert(buffer == [0, 0, 1, 5, 0, 0, 32, 29]); 3433 3434 size_t index = 0; 3435 buffer.write!dchar('��', &index); 3436 assert(buffer == [0, 0, 1, 7, 0, 0, 32, 29]); 3437 assert(index == 4); 3438 3439 buffer.write!dchar('��', &index); 3440 assert(buffer == [0, 0, 1, 7, 0, 0, 1, 5]); 3441 assert(index == 8); 3442 } 3443 3444 { 3445 //float (32bit - 4x ubyte) 3446 ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0]; 3447 3448 buffer.write!float(32.0f, 0); 3449 assert(buffer == [66, 0, 0, 0, 0, 0, 0, 0]); 3450 3451 buffer.write!float(25.0f, 4); 3452 assert(buffer == [66, 0, 0, 0, 65, 200, 0, 0]); 3453 3454 size_t index = 0; 3455 buffer.write!float(25.0f, &index); 3456 assert(buffer == [65, 200, 0, 0, 65, 200, 0, 0]); 3457 assert(index == 4); 3458 3459 buffer.write!float(32.0f, &index); 3460 assert(buffer == [65, 200, 0, 0, 66, 0, 0, 0]); 3461 assert(index == 8); 3462 } 3463 3464 { 3465 //double (64bit - 8x ubyte) 3466 ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; 3467 3468 buffer.write!double(32.0, 0); 3469 assert(buffer == [64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); 3470 3471 buffer.write!double(25.0, 8); 3472 assert(buffer == [64, 64, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]); 3473 3474 size_t index = 0; 3475 buffer.write!double(25.0, &index); 3476 assert(buffer == [64, 57, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]); 3477 assert(index == 8); 3478 3479 buffer.write!double(32.0, &index); 3480 assert(buffer == [64, 57, 0, 0, 0, 0, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0]); 3481 assert(index == 16); 3482 } 3483 3484 { 3485 //enum 3486 ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; 3487 3488 enum Foo 3489 { 3490 one = 10, 3491 two = 20, 3492 three = 30 3493 } 3494 3495 buffer.write!Foo(Foo.one, 0); 3496 assert(buffer == [0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0]); 3497 3498 buffer.write!Foo(Foo.two, 4); 3499 assert(buffer == [0, 0, 0, 10, 0, 0, 0, 20, 0, 0, 0, 0]); 3500 3501 buffer.write!Foo(Foo.three, 8); 3502 assert(buffer == [0, 0, 0, 10, 0, 0, 0, 20, 0, 0, 0, 30]); 3503 3504 size_t index = 0; 3505 buffer.write!Foo(Foo.three, &index); 3506 assert(buffer == [0, 0, 0, 30, 0, 0, 0, 20, 0, 0, 0, 30]); 3507 assert(index == 4); 3508 3509 buffer.write!Foo(Foo.one, &index); 3510 assert(buffer == [0, 0, 0, 30, 0, 0, 0, 10, 0, 0, 0, 30]); 3511 assert(index == 8); 3512 3513 buffer.write!Foo(Foo.two, &index); 3514 assert(buffer == [0, 0, 0, 30, 0, 0, 0, 10, 0, 0, 0, 20]); 3515 assert(index == 12); 3516 } 3517 3518 { 3519 //enum - bool 3520 ubyte[] buffer = [0, 0]; 3521 3522 enum Bool: bool 3523 { 3524 bfalse = false, 3525 btrue = true, 3526 } 3527 3528 buffer.write!Bool(Bool.btrue, 0); 3529 assert(buffer == [1, 0]); 3530 3531 buffer.write!Bool(Bool.btrue, 1); 3532 assert(buffer == [1, 1]); 3533 3534 size_t index = 0; 3535 buffer.write!Bool(Bool.bfalse, &index); 3536 assert(buffer == [0, 1]); 3537 assert(index == 1); 3538 3539 buffer.write!Bool(Bool.bfalse, &index); 3540 assert(buffer == [0, 0]); 3541 assert(index == 2); 3542 } 3543 3544 { 3545 //enum - float 3546 ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0]; 3547 3548 enum Float: float 3549 { 3550 one = 32.0f, 3551 two = 25.0f 3552 } 3553 3554 buffer.write!Float(Float.one, 0); 3555 assert(buffer == [66, 0, 0, 0, 0, 0, 0, 0]); 3556 3557 buffer.write!Float(Float.two, 4); 3558 assert(buffer == [66, 0, 0, 0, 65, 200, 0, 0]); 3559 3560 size_t index = 0; 3561 buffer.write!Float(Float.two, &index); 3562 assert(buffer == [65, 200, 0, 0, 65, 200, 0, 0]); 3563 assert(index == 4); 3564 3565 buffer.write!Float(Float.one, &index); 3566 assert(buffer == [65, 200, 0, 0, 66, 0, 0, 0]); 3567 assert(index == 8); 3568 } 3569 3570 { 3571 //enum - double 3572 ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; 3573 3574 enum Double: double 3575 { 3576 one = 32.0, 3577 two = 25.0 3578 } 3579 3580 buffer.write!Double(Double.one, 0); 3581 assert(buffer == [64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); 3582 3583 buffer.write!Double(Double.two, 8); 3584 assert(buffer == [64, 64, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]); 3585 3586 size_t index = 0; 3587 buffer.write!Double(Double.two, &index); 3588 assert(buffer == [64, 57, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]); 3589 assert(index == 8); 3590 3591 buffer.write!Double(Double.one, &index); 3592 assert(buffer == [64, 57, 0, 0, 0, 0, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0]); 3593 assert(index == 16); 3594 } 3595 3596 { 3597 //enum - real 3598 ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; 3599 3600 enum Real: real 3601 { 3602 one = 32.0, 3603 two = 25.0 3604 } 3605 3606 static assert(!__traits(compiles, buffer.write!Real(Real.one))); 3607 } 3608} 3609 3610 3611/++ 3612 Takes an integral value, converts it to the given endianness, and appends 3613 it to the given range of $(D ubyte)s (using $(D put)) as a sequence of 3614 $(D T.sizeof) $(D ubyte)s starting at index. $(D hasSlicing!R) must be 3615 $(D true). 3616 3617 Params: 3618 T = The integral type to convert the first $(D T.sizeof) bytes to. 3619 endianness = The endianness to write the bytes in. 3620 range = The range to _append to. 3621 value = The value to _append. 3622 +/ 3623void append(T, Endian endianness = Endian.bigEndian, R)(R range, T value) 3624if (canSwapEndianness!T && isOutputRange!(R, ubyte)) 3625{ 3626 static if (endianness == Endian.bigEndian) 3627 immutable bytes = nativeToBigEndian!T(value); 3628 else 3629 immutable bytes = nativeToLittleEndian!T(value); 3630 3631 put(range, bytes[]); 3632} 3633 3634/// 3635@safe unittest 3636{ 3637 import std.array; 3638 auto buffer = appender!(const ubyte[])(); 3639 buffer.append!ushort(261); 3640 assert(buffer.data == [1, 5]); 3641 3642 buffer.append!uint(369700095u); 3643 assert(buffer.data == [1, 5, 22, 9, 44, 255]); 3644 3645 buffer.append!ubyte(8); 3646 assert(buffer.data == [1, 5, 22, 9, 44, 255, 8]); 3647} 3648 3649@safe unittest 3650{ 3651 import std.array; 3652 { 3653 //bool 3654 auto buffer = appender!(const ubyte[])(); 3655 3656 buffer.append!bool(true); 3657 assert(buffer.data == [1]); 3658 3659 buffer.append!bool(false); 3660 assert(buffer.data == [1, 0]); 3661 } 3662 3663 { 3664 //char wchar dchar 3665 auto buffer = appender!(const ubyte[])(); 3666 3667 buffer.append!char('a'); 3668 assert(buffer.data == [97]); 3669 3670 buffer.append!char('b'); 3671 assert(buffer.data == [97, 98]); 3672 3673 buffer.append!wchar('��'); 3674 assert(buffer.data == [97, 98, 1, 5]); 3675 3676 buffer.append!dchar('��'); 3677 assert(buffer.data == [97, 98, 1, 5, 0, 0, 1, 5]); 3678 } 3679 3680 { 3681 //float double 3682 auto buffer = appender!(const ubyte[])(); 3683 3684 buffer.append!float(32.0f); 3685 assert(buffer.data == [66, 0, 0, 0]); 3686 3687 buffer.append!double(32.0); 3688 assert(buffer.data == [66, 0, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0]); 3689 } 3690 3691 { 3692 //enum 3693 auto buffer = appender!(const ubyte[])(); 3694 3695 enum Foo 3696 { 3697 one = 10, 3698 two = 20, 3699 three = 30 3700 } 3701 3702 buffer.append!Foo(Foo.one); 3703 assert(buffer.data == [0, 0, 0, 10]); 3704 3705 buffer.append!Foo(Foo.two); 3706 assert(buffer.data == [0, 0, 0, 10, 0, 0, 0, 20]); 3707 3708 buffer.append!Foo(Foo.three); 3709 assert(buffer.data == [0, 0, 0, 10, 0, 0, 0, 20, 0, 0, 0, 30]); 3710 } 3711 3712 { 3713 //enum - bool 3714 auto buffer = appender!(const ubyte[])(); 3715 3716 enum Bool: bool 3717 { 3718 bfalse = false, 3719 btrue = true, 3720 } 3721 3722 buffer.append!Bool(Bool.btrue); 3723 assert(buffer.data == [1]); 3724 3725 buffer.append!Bool(Bool.bfalse); 3726 assert(buffer.data == [1, 0]); 3727 3728 buffer.append!Bool(Bool.btrue); 3729 assert(buffer.data == [1, 0, 1]); 3730 } 3731 3732 { 3733 //enum - float 3734 auto buffer = appender!(const ubyte[])(); 3735 3736 enum Float: float 3737 { 3738 one = 32.0f, 3739 two = 25.0f 3740 } 3741 3742 buffer.append!Float(Float.one); 3743 assert(buffer.data == [66, 0, 0, 0]); 3744 3745 buffer.append!Float(Float.two); 3746 assert(buffer.data == [66, 0, 0, 0, 65, 200, 0, 0]); 3747 } 3748 3749 { 3750 //enum - double 3751 auto buffer = appender!(const ubyte[])(); 3752 3753 enum Double: double 3754 { 3755 one = 32.0, 3756 two = 25.0 3757 } 3758 3759 buffer.append!Double(Double.one); 3760 assert(buffer.data == [64, 64, 0, 0, 0, 0, 0, 0]); 3761 3762 buffer.append!Double(Double.two); 3763 assert(buffer.data == [64, 64, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]); 3764 } 3765 3766 { 3767 //enum - real 3768 auto buffer = appender!(const ubyte[])(); 3769 3770 enum Real: real 3771 { 3772 one = 32.0, 3773 two = 25.0 3774 } 3775 3776 static assert(!__traits(compiles, buffer.append!Real(Real.one))); 3777 } 3778} 3779 3780@system unittest 3781{ 3782 import std.array; 3783 import std.format : format; 3784 import std.meta; 3785 foreach (endianness; AliasSeq!(Endian.bigEndian, Endian.littleEndian)) 3786 { 3787 auto toWrite = appender!(ubyte[])(); 3788 alias Types = AliasSeq!(uint, int, long, ulong, short, ubyte, ushort, byte, uint); 3789 ulong[] values = [42, -11, long.max, 1098911981329L, 16, 255, 19012, 2, 17]; 3790 assert(Types.length == values.length); 3791 3792 size_t index = 0; 3793 size_t length = 0; 3794 foreach (T; Types) 3795 { 3796 toWrite.append!(T, endianness)(cast(T) values[index++]); 3797 length += T.sizeof; 3798 } 3799 3800 auto toRead = toWrite.data; 3801 assert(toRead.length == length); 3802 3803 index = 0; 3804 foreach (T; Types) 3805 { 3806 assert(toRead.peek!(T, endianness)() == values[index], format("Failed Index: %s", index)); 3807 assert(toRead.peek!(T, endianness)(0) == values[index], format("Failed Index: %s", index)); 3808 assert(toRead.length == length, 3809 format("Failed Index [%s], Actual Length: %s", index, toRead.length)); 3810 assert(toRead.read!(T, endianness)() == values[index], format("Failed Index: %s", index)); 3811 length -= T.sizeof; 3812 assert(toRead.length == length, 3813 format("Failed Index [%s], Actual Length: %s", index, toRead.length)); 3814 ++index; 3815 } 3816 assert(toRead.empty); 3817 } 3818} 3819 3820/** 3821Counts the number of set bits in the binary representation of $(D value). 3822For signed integers, the sign bit is included in the count. 3823*/ 3824private uint countBitsSet(T)(T value) @nogc pure nothrow 3825if (isIntegral!T) 3826{ 3827 // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel 3828 static if (T.sizeof == 8) 3829 { 3830 T c = value - ((value >> 1) & 0x55555555_55555555); 3831 c = ((c >> 2) & 0x33333333_33333333) + (c & 0x33333333_33333333); 3832 c = ((c >> 4) + c) & 0x0F0F0F0F_0F0F0F0F; 3833 c = ((c >> 8) + c) & 0x00FF00FF_00FF00FF; 3834 c = ((c >> 16) + c) & 0x0000FFFF_0000FFFF; 3835 c = ((c >> 32) + c) & 0x00000000_FFFFFFFF; 3836 } 3837 else static if (T.sizeof == 4) 3838 { 3839 T c = value - ((value >> 1) & 0x55555555); 3840 c = ((c >> 2) & 0x33333333) + (c & 0x33333333); 3841 c = ((c >> 4) + c) & 0x0F0F0F0F; 3842 c = ((c >> 8) + c) & 0x00FF00FF; 3843 c = ((c >> 16) + c) & 0x0000FFFF; 3844 } 3845 else static if (T.sizeof == 2) 3846 { 3847 uint c = value - ((value >> 1) & 0x5555); 3848 c = ((c >> 2) & 0x3333) + (c & 0X3333); 3849 c = ((c >> 4) + c) & 0x0F0F; 3850 c = ((c >> 8) + c) & 0x00FF; 3851 } 3852 else static if (T.sizeof == 1) 3853 { 3854 uint c = value - ((value >> 1) & 0x55); 3855 c = ((c >> 2) & 0x33) + (c & 0X33); 3856 c = ((c >> 4) + c) & 0x0F; 3857 } 3858 else 3859 { 3860 static assert(false, "countBitsSet only supports 1, 2, 4, or 8 byte sized integers."); 3861 } 3862 return cast(uint) c; 3863} 3864 3865@safe unittest 3866{ 3867 assert(countBitsSet(1) == 1); 3868 assert(countBitsSet(0) == 0); 3869 assert(countBitsSet(int.min) == 1); 3870 assert(countBitsSet(uint.max) == 32); 3871} 3872 3873@safe unittest 3874{ 3875 import std.meta; 3876 foreach (T; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong)) 3877 { 3878 assert(countBitsSet(cast(T) 0) == 0); 3879 assert(countBitsSet(cast(T) 1) == 1); 3880 assert(countBitsSet(cast(T) 2) == 1); 3881 assert(countBitsSet(cast(T) 3) == 2); 3882 assert(countBitsSet(cast(T) 4) == 1); 3883 assert(countBitsSet(cast(T) 5) == 2); 3884 assert(countBitsSet(cast(T) 127) == 7); 3885 static if (isSigned!T) 3886 { 3887 assert(countBitsSet(cast(T)-1) == 8 * T.sizeof); 3888 assert(countBitsSet(T.min) == 1); 3889 } 3890 else 3891 { 3892 assert(countBitsSet(T.max) == 8 * T.sizeof); 3893 } 3894 } 3895 assert(countBitsSet(1_000_000) == 7); 3896 foreach (i; 0 .. 63) 3897 assert(countBitsSet(1UL << i) == 1); 3898} 3899 3900private struct BitsSet(T) 3901{ 3902 static assert(T.sizeof <= 8, "bitsSet assumes T is no more than 64-bit."); 3903 3904@nogc pure nothrow: 3905 3906 this(T value, size_t startIndex = 0) 3907 { 3908 _value = value; 3909 // Further calculation is only valid and needed when the range is non-empty. 3910 if (!_value) 3911 return; 3912 3913 import core.bitop : bsf; 3914 immutable trailingZerosCount = bsf(value); 3915 _value >>>= trailingZerosCount; 3916 _index = startIndex + trailingZerosCount; 3917 } 3918 3919 @property size_t front() 3920 { 3921 return _index; 3922 } 3923 3924 @property bool empty() const 3925 { 3926 return !_value; 3927 } 3928 3929 void popFront() 3930 { 3931 assert(_value, "Cannot call popFront on empty range."); 3932 3933 _value >>>= 1; 3934 // Further calculation is only valid and needed when the range is non-empty. 3935 if (!_value) 3936 return; 3937 3938 import core.bitop : bsf; 3939 immutable trailingZerosCount = bsf(_value); 3940 _value >>>= trailingZerosCount; 3941 _index += trailingZerosCount + 1; 3942 } 3943 3944 @property auto save() 3945 { 3946 return this; 3947 } 3948 3949 @property size_t length() 3950 { 3951 return countBitsSet(_value); 3952 } 3953 3954 private T _value; 3955 private size_t _index; 3956} 3957 3958/** 3959Range that iterates the indices of the set bits in $(D value). 3960Index 0 corresponds to the least significant bit. 3961For signed integers, the highest index corresponds to the sign bit. 3962*/ 3963auto bitsSet(T)(T value) @nogc pure nothrow 3964if (isIntegral!T) 3965{ 3966 return BitsSet!T(value); 3967} 3968 3969/// 3970@safe unittest 3971{ 3972 import std.algorithm.comparison : equal; 3973 import std.range : iota; 3974 3975 assert(bitsSet(1).equal([0])); 3976 assert(bitsSet(5).equal([0, 2])); 3977 assert(bitsSet(-1).equal(iota(32))); 3978 assert(bitsSet(int.min).equal([31])); 3979} 3980 3981@safe unittest 3982{ 3983 import std.algorithm.comparison : equal; 3984 import std.range : iota; 3985 3986 import std.meta; 3987 foreach (T; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong)) 3988 { 3989 assert(bitsSet(cast(T) 0).empty); 3990 assert(bitsSet(cast(T) 1).equal([0])); 3991 assert(bitsSet(cast(T) 2).equal([1])); 3992 assert(bitsSet(cast(T) 3).equal([0, 1])); 3993 assert(bitsSet(cast(T) 4).equal([2])); 3994 assert(bitsSet(cast(T) 5).equal([0, 2])); 3995 assert(bitsSet(cast(T) 127).equal(iota(7))); 3996 static if (isSigned!T) 3997 { 3998 assert(bitsSet(cast(T)-1).equal(iota(8 * T.sizeof))); 3999 assert(bitsSet(T.min).equal([8 * T.sizeof - 1])); 4000 } 4001 else 4002 { 4003 assert(bitsSet(T.max).equal(iota(8 * T.sizeof))); 4004 } 4005 } 4006 assert(bitsSet(1_000_000).equal([6, 9, 14, 16, 17, 18, 19])); 4007 foreach (i; 0 .. 63) 4008 assert(bitsSet(1UL << i).equal([i])); 4009} 4010