module bitmanip; private import std.traits : isUnsigned; private import std.bitmanip : nativeToLittleEndian, littleEndianToNative; UIntType rotateLeft(UIntType)(in UIntType val, in size_t len) nothrow @nogc pure @safe if (isUnsigned!UIntType) { auto reducedLen = len % (8 * UIntType.sizeof); // TODO: ensure the compiler does not create different code paths here return cast(UIntType)((val << reducedLen) | (val >> (8 * UIntType.sizeof - reducedLen))); } unittest { ubyte[] test = [0, 1, 128]; assert(test[0].rotateLeft(1) == 0); assert(test[1].rotateLeft(1) == 2); assert(test[2].rotateLeft(1) == 1); assert(test[1].rotateLeft(7) == 128); } UIntType rotateRight(UIntType)(in UIntType val, in size_t len) nothrow @nogc pure @safe if (isUnsigned!UIntType) { auto reducedLen = len % (8 * UIntType.sizeof); // TODO: ensure the compiler does not create different code paths here return cast(UIntType)((val >> reducedLen) | (val << (8 * UIntType.sizeof - reducedLen))); } unittest { ubyte[] test = [0, 1, 128]; assert(test[0].rotateRight(1) == 0); assert(test[1].rotateRight(1) == 128); assert(test[2].rotateRight(1) == 64); assert(test[2].rotateRight(7) == 1); } alias littleEndianInv = nativeToLittleEndian; uint littleEndian(in ubyte[] input) @safe pure nothrow @nogc in { assert(input.length == uint.sizeof); } body { ubyte[uint.sizeof] buf = input; return littleEndianToNative!uint(buf); } unittest { ubyte[] test0 = [0, 0, 0, 0]; ubyte[] test1 = [86, 75, 30, 9]; ubyte[] test2 = [255, 255, 255, 250]; assert(littleEndian(test0) == 0x00000000); assert(littleEndian(test1) == 0x091e4b56); assert(littleEndian(test2) == 0xfaffffff); }