1 module zgrf.bits;
2 
3 import std.bitmanip;
4 
5 /**
6  * Allocates a new [BitArray] of given count.
7  *
8  * Params:
9  *  count = The amount of bits in the [BitArray]
10  *
11  * Returns:
12  *  The new [BitArray]
13  */
14 BitArray bitArrayOfSize(ulong count) pure
15 {
16     bool[] buffer = new bool[count];
17     return BitArray(buffer);
18 }
19 
20 /**
21  * Converts ubyte[] to [BitArray].
22  *
23  * Params:
24  *  byteArr = The input ubyte[] to convert to a [BitArray]
25  *
26  * Returns:
27  *  The converted [BitArray]
28  *
29  * See_Also:
30  *  [toByteArray]
31  */
32 BitArray toBitArray(const ubyte[] byteArr) pure
33 {
34     auto bitArr = bitArrayOfSize(8 * byteArr.length);
35     for (int i = 0; i < byteArr.length; ++i)
36     {
37         bitArr[8 * i + 0] = (byteArr[i] & 128) != 0;
38         bitArr[8 * i + 1] = (byteArr[i] & 64) != 0;
39         bitArr[8 * i + 2] = (byteArr[i] & 32) != 0;
40         bitArr[8 * i + 3] = (byteArr[i] & 16) != 0;
41         bitArr[8 * i + 4] = (byteArr[i] & 8) != 0;
42         bitArr[8 * i + 5] = (byteArr[i] & 4) != 0;
43         bitArr[8 * i + 6] = (byteArr[i] & 2) != 0;
44         bitArr[8 * i + 7] = (byteArr[i] & 1) != 0;
45     }
46     return bitArr;
47 }
48 
49 /**
50  * Converts a [BitArray] to ubyte[].
51  *
52  * The input must be a multiple of 8 bytes. There is no bounds
53  * check and no padding will be done.
54  *
55  * Params:
56  *  bitArr = The [BitArray] to convert to ubyte[]
57  *
58  * Returns:
59  *  Converted byte array
60  *
61  * See_Also:
62  *  [toBitArray]
63  */
64 ubyte[] toByteArray(const ref BitArray bitArr) pure
65 in (bitArr.length % 8 == 0, "Length of BitArray must be multiple of 8 bytes")
66 {
67     const size_t length = bitArr.length / 8;
68     ubyte[] arr = new ubyte[length];
69     foreach (i; 0 .. length)
70     {
71         const j = i * 8;
72         arr[i] = bitArr[j] << 7 |
73             bitArr[j + 1] << 6 |
74             bitArr[j + 2] << 5 |
75             bitArr[j + 3] << 4 |
76             bitArr[j + 4] << 3 |
77             bitArr[j + 5] << 2 |
78             bitArr[j + 6] << 1 |
79             bitArr[j + 7];
80     }
81 
82     return arr;
83 }
84 
85 /**
86  * Shifts the first length bits of the source [BitArray] by numBits
87  * and stores it into the target [BitArray].
88  *
89  * Parameter length must be less than or equal to the source and target length.
90  *
91  * Params:
92  *  source = Shift the bits given by this [BitArray]
93  *  length = Defines how many bits to shift from the source. Cannot be higher than source/target length
94  *  numBits = Defines the shift amount for each bit
95  *  target = The output [BitArray] to store the shifted result to
96  */
97 void shiftLeft(const ref BitArray source, size_t length, size_t numBits, ref BitArray target) pure
98 in (source.length >= length, "Source length is too short")
99 in (target.length >= length, "Target length is too short")
100 {
101     for (size_t p = 0; p < length; ++p)
102     {
103         target[p] = source[(p + numBits) % length];
104     }
105 }
106 
107 /**
108  * Swaps the nibbles of the input data.
109  *
110  * E.g. 0xABCDEF becomes 0xBADCFE
111  *
112  * Params:
113  *  data = Input/Output that will be modified
114  */
115 void swapNibbles(ref ubyte[] data) pure nothrow @safe @nogc
116 {
117     foreach (i; 0 .. data.length)
118     {
119         data[i] = ((data[i] << 4) & 0xFF) | ((data[i] >> 4) & 0xFF);
120     }
121 }