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