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