1 /* 2 * bitleveld - datatypes.d 3 * by Laszlo Szeremi 4 * 5 * Copyright under Boost Software License. 6 */ 7 8 module bitleveld.datatypes; 9 10 import std.bitmanip; 11 12 /** 13 * Used for template initialization. 14 * Reverses the order of data elements whithin a byte if false. 15 */ 16 public enum ByteEndianness : bool { 17 normal = true, 18 reverse = false, 19 } 20 /** 21 * Implements a 4bit nibble array. 22 */ 23 public struct NibbleArrayTemplt (bool Endianness = ByteEndianness.normal) { 24 private ubyte[] src; 25 private size_t _length; 26 27 public const size_t length() @nogc nothrow @safe pure @property { 28 return _length; 29 } 30 public size_t length(size_t val) nothrow @safe pure @property { 31 src.length = val>>>1 + (val & 1); 32 return _length = val; 33 } 34 public size_t reserve(size_t val) nothrow @safe pure { 35 return src.reserve(val>>>1)<<1; 36 } 37 ubyte opIndex (size_t i) @nogc nothrow @safe pure { 38 static if (Endianness) { 39 if (i & 1) { 40 return src[i>>>1]>>>4; 41 } else { 42 return src[i>>>1] & 0x0F; 43 } 44 } else { 45 if (i & 1) { 46 return src[i>>>1] & 0x0F; 47 } else { 48 return src[i>>>1]>>>4; 49 } 50 } 51 } 52 ubyte opIndexAssign (ubyte val, size_t i) @nogc nothrow @safe pure { 53 val &= 0x0F; 54 static if (Endianness) { 55 if (i & 1) { 56 src[i>>>1] |= val<<4; 57 } else { 58 src[i>>>1] |= val & 0x0F; 59 } 60 } else { 61 if (i & 1) { 62 src[i>>>1] |= val & 0x0F; 63 } else { 64 src[i>>>1] |= val<<4; 65 } 66 } 67 return opIndex(i); 68 } 69 } 70 alias NibbleArray = NibbleArrayTemplt!(ByteEndianness.normal); 71 alias NibbleArrayR = NibbleArrayTemplt!(ByteEndianness.reverse); 72 /** 73 * Implements a 2bit quad array. 74 */ 75 public struct QuadArrayTemplt (bool Endianness = ByteEndianness.normal) { 76 private ubyte[] src; 77 private size_t _length; 78 public const size_t length() @nogc nothrow @safe pure @property { 79 return _length; 80 } 81 public size_t length(size_t val) nothrow @safe pure @property { 82 src.length = val>>>2 + ((val & 1) | (val>>>1 & 1)); 83 return _length = val; 84 } 85 public size_t reserve(size_t val) nothrow @safe pure { 86 return src.reserve(val>>>1)<<1; 87 } 88 ubyte opIndex (size_t i) @nogc nothrow @safe pure { 89 static if (Endianness) { 90 switch (i & 3) { 91 case 1: 92 return (src[i>>>2] & 0b0000_1100)>>>2; 93 case 2: 94 return (src[i>>>2] & 0b0011_0000)>>>4; 95 case 3: 96 return src[i>>>2]>>>6; 97 default: 98 return src[i>>>2] & 0b0000_0011; 99 } 100 } else { 101 switch (i & 3) { 102 case 1: 103 return (src[i>>>2] & 0b0011_0000)>>>4; 104 case 2: 105 return (src[i>>>2] & 0b0000_1100)>>>2; 106 case 3: 107 return src[i>>>2] & 0b0000_0011; 108 default: 109 return src[i>>>2]>>>6; 110 } 111 } 112 } 113 ubyte opIndexAssign (ubyte val, size_t i) @nogc nothrow @safe pure { 114 val &= 0b0000_0011; 115 static if (Endianness) { 116 switch (i & 3) { 117 case 1: 118 src[i>>>2] |= val<<2; 119 break; 120 case 2: 121 src[i>>>2] |= val<<4; 122 break; 123 case 3: 124 src[i>>>2] |= val<<6; 125 break; 126 default: 127 src[i>>>2] |= val; 128 break; 129 } 130 } else { 131 switch (i & 3) { 132 case 1: 133 src[i>>>2] |= val<<4; 134 break; 135 case 2: 136 src[i>>>2] |= val<<2; 137 break; 138 case 3: 139 src[i>>>2] |= val; 140 break; 141 default: 142 src[i>>>2] |= val<<6; 143 break; 144 } 145 } 146 return opIndex(i); 147 } 148 } 149 alias QuadArray = QuadArrayTemplt!(ByteEndianness.normal); 150 alias QuadArrayR = QuadArrayTemplt!(ByteEndianness.reverse); 151 152 unittest { 153 import std.conv : to; 154 ubyte[] test = [0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef]; 155 ubyte[] output; 156 NibbleArray na = NibbleArray(test, 16); 157 for (int i ; i < na.length ; i++) { 158 output ~= na[i]; 159 } 160 assert(output == [1,0,3,2,5,4,7,6,9,8,11,10,13,12,15,14], "Error in result : " ~ to!string(output)); 161 output.length = 0; 162 NibbleArrayR nar = NibbleArrayR(test, 16); 163 for (int i ; i < nar.length ; i++) { 164 output ~= nar[i]; 165 } 166 assert(output == [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], "Error in result : " ~ to!string(output)); 167 output.length = 0; 168 QuadArray qa = QuadArray(test, 32); 169 for (int i ; i < qa.length ; i++) { 170 output ~= qa[i]; 171 } 172 assert(output == [1,0, 0,0, 3,0, 2,0, 1,1, 0,1, 3,1, 2,1, 1,2, 0,2, 3,2, 2,2, 1,3, 0,3, 3,3, 2,3], "Error in result : " 173 ~ to!string(output)); 174 output.length = 0; 175 QuadArrayR qar = QuadArrayR(test, 32); 176 for (int i ; i < qar.length ; i++) { 177 output ~= qar[i]; 178 } 179 assert(output == [0,0, 0,1, 0,2, 0,3, 1,0, 1,1, 1,2, 1,3, 2,0, 2,1, 2,2, 2,3, 3,0, 3,1, 3,2, 3,3], "Error in result : " 180 ~ to!string(output)); 181 } 182 183 /** 184 * Implements a bitplane reader/writer, that reads/writes multiple bitplanes at once. 185 * Between 1-8 planes, ubyte is used as the return/input type, between 9-16 it's ushort. 186 */ 187 public struct Bitplane (int NOfBitplanes) 188 if (NOfBitplanes <= 16 && NOfBitplanes > 0) { 189 private BitArray[NOfBitplanes] src; 190 private size_t _length; 191 public const size_t length () @property @nogc nothrow @safe pure { 192 return length; 193 } 194 public size_t length (size_t val) @property nothrow @trusted pure { 195 for (int i ; i < NOfBitplanes ; i++) { 196 src[i].length = val; 197 } 198 return length = val; 199 } 200 static if (NOfBitplanes <= 8) { 201 ubyte opIndex(size_t i) @nogc pure nothrow { 202 ubyte result; 203 for (int b ; b < NOfBitplanes ; b++){ 204 result>>>=1; 205 result |= src[b][i] ? 1 : 0; 206 } 207 return result; 208 } 209 ubyte opIndexAssign(ubyte val, size_t i) @nogc pure nothrow { 210 for (int b ; b < NOfBitplanes ; b++){ 211 src[b][i] = (val&1) == 1; 212 val>>>=1; 213 } 214 return opIndex(i); 215 } 216 } else { 217 ushort opIndex(size_t i) @nogc pure nothrow { 218 ushort result; 219 for (int b ; b < NOfBitplanes ; b++){ 220 result>>>=1; 221 result |= src[b][i] ? 1 : 0; 222 } 223 return result; 224 } 225 ushort opIndexAssign(ushort val, size_t i) @nogc pure nothrow { 226 for (int b ; b < NOfBitplanes ; b++){ 227 src[b][i] = (val&1) == 1; 228 val>>>=1; 229 } 230 return opIndex(i); 231 } 232 } 233 } 234 unittest{ 235 ubyte[] plane0 = [0x51,0x31,0x05,0x08,0x60,0x00,0x00,0x00]; 236 ubyte[] plane1 = [0x00,0x05,0x00,0x22,0x60,0x00,0x00,0x00]; 237 ubyte[] plane2 = [0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00]; 238 Bitplane!3 plane = Bitplane!3([BitArray(plane0, 8*8), BitArray(plane1, 8*8), BitArray(plane2, 8*8)], 8*8); 239 }