1 #!/usr/bin/env rdmd-dev-module 2 3 /** Various extensions to core.bitop and std.bitmanip. 4 Copyright: Per Nordlöw 2014-. 5 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 6 Authors: $(WEB Per Nordlöw) 7 */ 8 module bitop_ex; 9 10 import std.traits: isIntegral; 11 import std.meta: allSatisfy; 12 13 /** Get an Unsigned Type of size as $(D T) if possible. */ 14 template UnsignedOfSameSizeAs(T) 15 { 16 enum nBits = 8*T.sizeof; 17 static if (nBits == 8) alias UnsignedOfSameSizeAs = ubyte; 18 else static if (nBits == 16) alias UnsignedOfSameSizeAs = ushort; 19 else static if (nBits == 32) alias UnsignedOfSameSizeAs = uint; 20 else static if (nBits == 64) alias UnsignedOfSameSizeAs = ulong; 21 else static if (nBits == 128) alias UnsignedOfSameSizeAs = ucent; 22 else { 23 import std.conv: to; 24 static assert(false, "No Unsigned type of size " ~ to!string(nBits) ~ " found"); 25 } 26 } 27 28 /** Returns: Zero Instance T with $(D bix):th Bit set. */ 29 T makeBit(T, I...)(I bixs) @safe @nogc pure nothrow if (isIntegral!T && 30 allSatisfy!(isIntegral, I)) 31 in { foreach (bix; bixs) { assert(0 <= bix && bix < 8*T.sizeof); } } 32 body { 33 typeof(return) x; 34 foreach (bix; bixs) 35 x |= cast(T)((cast(T)1) << bix); 36 return x; 37 } 38 alias btm = makeBit; 39 unittest { 40 assert(makeBit!int(2) == 4); 41 assert(makeBit!int(2, 3) == 12); 42 } 43 44 /** Returns: Check if all $(D bix):th Bits Of $(D a) are set. */ 45 bool getBit(T, I...)(in T a, I bixs) @safe @nogc pure nothrow if (isIntegral!T && 46 allSatisfy!(isIntegral, I)) 47 { 48 return a & makeBit!T(bixs) ? true : false; 49 } 50 /** Returns: Check if all $(D bix):th Bits Of $(D a) are set. */ 51 bool getBit(T, I)(in T a, I bix) @trusted @nogc pure nothrow if ((!(isIntegral!T)) && 52 allSatisfy!(isIntegral, I)) 53 { 54 return (*(cast(UnsignedOfSameSizeAs!T*)&a)).getBit(bix); // reuse integer variant 55 } 56 alias bt = getBit; 57 void testGetBit(T)() 58 { 59 const mn = T.min, mx = T.max; 60 enum nBits = 8*T.sizeof; 61 foreach (ix; 0..nBits-1) 62 { 63 assert(!mn.bt(ix)); 64 } 65 assert(mn.bt(nBits - 1)); 66 foreach (ix; 0..T.sizeof) 67 { 68 assert(mx.bt(ix)); 69 } 70 } 71 unittest { 72 testGetBit!byte; 73 testGetBit!short; 74 testGetBit!int; 75 testGetBit!long; 76 } 77 78 /** Test and sets the $(D bix):th Bit Of $(D a) to one. 79 Returns: A non-zero value if the bit was set, and a zero if it was clear. 80 */ 81 void setBit(T, I...)(ref T a, I bixs) @safe @nogc pure nothrow if (isIntegral!T && 82 allSatisfy!(isIntegral, I)) 83 { 84 a |= makeBit!T(bixs); 85 } 86 87 /** Returns: Check if all $(D bix):th Bits Of $(D a) are set. */ 88 void setBit(T, I...)(ref T a, I bixs) @trusted @nogc pure nothrow if ((!(isIntegral!T)) && 89 allSatisfy!(isIntegral, I)) 90 { 91 alias U = UnsignedOfSameSizeAs!T; 92 (*(cast(U*)&a)) |= makeBit!U(bixs); // reuse integer variant 93 } 94 95 alias bts = setBit; 96 97 /* alias btc = complementBit; */ 98 /* alias btr = resetBit; */ 99 100 void setLowestBit(T)(ref T a) @safe @nogc pure nothrow if (isIntegral!T) 101 { 102 setBit(a, 0); 103 } 104 alias setBottomBit = setLowestBit; 105 106 void setHighestBit(T)(ref T a) @safe @nogc pure nothrow if (isIntegral!T) 107 { 108 setBit(a, 8*T.sizeof - 1); 109 } 110 alias setTopBit = setHighestBit; 111 112 bool getLowBit(T)(T a) @safe @nogc pure nothrow if (isIntegral!T) 113 { 114 return (a & (1 << 0)) != 0; 115 } 116 alias getBottomBit = getLowBit; 117 118 bool getHighBit(T)(T a) @safe @nogc pure nothrow if (isIntegral!T) 119 { 120 return (a & (1 << 8*T.sizeof - 1)) != 0; 121 } 122 alias getTopBit = getHighBit; 123 124 unittest 125 { 126 const ubyte x = 1; 127 assert(!x.getTopBit); 128 assert(x.getLowBit); 129 } 130 131 unittest 132 { 133 const ubyte x = 128; 134 assert(x.getTopBit); 135 assert(!x.getLowBit); 136 } 137 138 void resetBit(T, I...)(ref T a, I bixs) @safe @nogc pure nothrow if (isIntegral!T && 139 allSatisfy!(isIntegral, I)) 140 { 141 a &= ~makeBit!T(bixs); 142 } 143 144 void resetBit(T, I...)(ref T a, I bixs) @trusted @nogc pure nothrow if ((!(isIntegral!T)) && 145 allSatisfy!(isIntegral, I)) 146 { 147 alias U = UnsignedOfSameSizeAs!T; 148 (*(cast(U*)&a)) &= ~makeBit!U(bixs); // reuse integer variant 149 } 150 151 void resetLowestBit(T)(ref T a) @safe @nogc pure nothrow if (isIntegral!T) 152 { 153 resetBit(a, 0); 154 } 155 alias resetBottomBit = resetLowestBit; 156 157 void resetHighestBit(T)(ref T a) @safe @nogc pure nothrow if (isIntegral!T) 158 { 159 resetBit(a, 8*T.sizeof - 1); 160 } 161 alias resetTopBit = resetHighestBit; 162 163 alias btr = resetBit; 164 165 unittest 166 { 167 alias T = int; 168 enum nBits = 8*T.sizeof; 169 T a = 0; 170 171 a.bts(0); assert(a == 1); 172 a.bts(1); assert(a == 3); 173 a.bts(2); assert(a == 7); 174 175 a.btr(0); assert(a == 6); 176 a.btr(1); assert(a == 4); 177 a.btr(2); assert(a == 0); 178 179 a.bts(8*T.sizeof - 1); assert(a != 0); 180 a.btr(8*T.sizeof - 1); assert(a == 0); 181 182 T b = 0; 183 b.bts(nBits - 1); 184 assert(b == T.min); 185 } 186 187 unittest 188 { 189 static void test(T)() 190 { 191 enum nBits = 8*T.sizeof; 192 T x = 0; 193 x.bts(0); 194 } 195 196 test!float; 197 test!double; 198 }