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