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