1 module barcode.util; 2 3 import std.exception; 4 import std.typecons : Flag; 5 import std.bitmanip : bitfields; 6 7 public import std.typecons : tuple; 8 public import std.bitmanip : BitArray; 9 10 alias AppendCheckSum = Flag!"appendCheckSum"; 11 12 /// 13 struct Bits(T=ulong) 14 if (is(T==ubyte) || is(T==ushort) || is(T==uint) || is(T==ulong)) 15 { 16 static if (is(T==ubyte)) enum COUNTBITS = 3; 17 else static if (is(T==ushort)) enum COUNTBITS = 4; 18 else static if (is(T==uint)) enum COUNTBITS = 5; 19 else static if (is(T==ulong)) enum COUNTBITS = 6; 20 21 enum VALUEBITS = T.sizeof * 8 - COUNTBITS; 22 23 mixin(bitfields!(ubyte, "count", COUNTBITS, 24 T, "value", VALUEBITS)); 25 26 alias value this; 27 28 29 pure nothrow @nogc @safe: 30 31 /// 32 this(ulong cnt, ulong val) 33 { 34 count = cast(ubyte)cnt; 35 value = cast(T)val; 36 } 37 38 /// 39 bool opIndex(size_t i) const 40 { return cast(bool)((value>>i)&1); } 41 42 /// 43 bool opEquals(X)(auto ref const Bits!X v) const 44 { return v.value == value && v.count == count; } 45 46 /// 47 bool opEquals(X)(X v) const 48 if (!is(X : Bits!U, U)) 49 { return v == value; } 50 } 51 52 @safe 53 unittest 54 { 55 static assert(bitsStr!"---".count == 3); 56 static assert(bitsStr!"--".count == 2); 57 static assert(bitsStr!"---" != bitsStr!"--"); 58 } 59 60 void addBits(ref BitArray ba, size_t value, int bits) @safe pure 61 { 62 enforce(bits <= size_t.sizeof*8, "so many bits"); 63 enforce(bits >= 0, "bits must be more that 0"); 64 addBits(ba, Bits!ulong(bits, value)); 65 } 66 67 @trusted // BitArray 68 unittest 69 { 70 BitArray ba; 71 ba.addBits(0b11000111010, 11); 72 const tst = BitArray([1,1,0,0,0,1,1,1,0,1,0]); 73 assert (ba == tst); 74 } 75 76 void addBits(T)(ref BitArray ba, auto ref const(Bits!T) bits) @trusted pure 77 { foreach_reverse (i; 0 .. bits.count) ba ~= bits[i]; } 78 79 @trusted // BitArray 80 unittest 81 { 82 BitArray ba; 83 ba.addBits(bitsStr!"##---###-#-"); 84 auto tst = BitArray([1,1,0,0,0,1,1,1,0,1,0]); 85 assert (ba == tst); 86 } 87 88 // for more readable bits writing 89 template bitsStr(string mask, char ONE='#') 90 if (mask.length <= 58) 91 { 92 static pure auto bitsImpl(T)() nothrow @nogc 93 { 94 ulong ret; 95 foreach (i; 0 .. mask.length) 96 ret |= cast(ulong)(mask[i] == ONE) << (mask.length - 1 - i); 97 return Bits!T(mask.length, ret); 98 } 99 100 static if (mask.length < 6) alias S = ubyte; 101 else static if (mask.length < 13) alias S = ushort; 102 else static if (mask.length < 28) alias S = uint; 103 else alias S = ulong; 104 105 static if (mask.length >= 1) enum bitsStr = bitsImpl!S(); 106 else static assert(0, "can't create 0 bits value"); 107 } 108 109 @safe 110 unittest 111 { 112 assert(1 == bitsStr!"#"); 113 assert(0 == bitsStr!"-"); 114 assert(0b1100011101011 == bitsStr!"##---###-#-##"); 115 assert(bitsStr!"---".count == 3); 116 } 117 118 auto getDict(alias F, T)(T[] arr) 119 { 120 alias frt = typeof(F(size_t(0), T.init)); 121 alias KEY = typeof(frt.init[0]); 122 alias VAL = typeof(frt.init[1]); 123 124 VAL[KEY] ret; 125 foreach (i, e; arr) 126 { 127 auto tmp = F(i, e); 128 ret[tmp[0]] = tmp[1]; 129 } 130 return ret; 131 } 132 133 @safe 134 unittest 135 { 136 static struct X { char ch; ushort mask; } 137 enum data = [ X('0', 0b001), X('1', 0b010), X('2', 0b100), ]; 138 139 { 140 enum ushort[char] t = getDict!((i,a) => tuple(a.ch, a.mask))(data); 141 static assert(t.keys.length == 3); 142 assert('0' in t); 143 assert(t['0'] == 0b001); 144 assert('1' in t); 145 assert(t['1'] == 0b010); 146 assert('2' in t); 147 assert(t['2'] == 0b100); 148 } 149 150 { 151 enum ushort[char] t = getDict!((i,a) => tuple(a.ch, i))(data); 152 static assert(t.keys.length == 3); 153 assert('0' in t); 154 assert(t['0'] == 0); 155 assert('1' in t); 156 assert(t['1'] == 1); 157 assert('2' in t); 158 assert(t['2'] == 2); 159 } 160 161 { 162 enum char[ubyte] t = getDict!((i,a) => tuple(cast(ubyte)i, a.ch))(data); 163 static assert(t.keys.length == 3); 164 assert(0 in t); 165 assert(t[0] == '0'); 166 assert(1 in t); 167 assert(t[1] == '1'); 168 assert(2 in t); 169 assert(t[2] == '2'); 170 } 171 }