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