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