std.bitmanip
Bit-level manipulation facilities. License:Boost License 1.0. Authors:
Walter Bright, Andrei Alexandrescu, Jonathan M Davis, Alex Rønne Petersen Source:
std/bitmanip.d
- Allows creating bit fields inside structs and classes.
Example:
struct A { int a; mixin(bitfields!( uint, "x", 2, int, "y", 3, uint, "z", 2, bool, "flag", 1)); } A obj; obj.x = 2; obj.z = obj.x;
The example above creates a bitfield pack of eight bits, which fit in one ubyte. The bitfields are allocated starting from the least significant bit, i.e. x occupies the two least significant bits of the bitfields storage. The sum of all bit lengths in one bitfield instantiation must be exactly 8, 16, 32, or 64. If padding is needed, just allocate one bitfield with an empty name. Example:
struct A { mixin(bitfields!( bool, "flag1", 1, bool, "flag2", 1, uint, "", 6)); }
The type of a bit field can be any integral type or enumerated type. The most efficient type to store in bitfields is bool, followed by unsigned types, followed by signed types. - Allows manipulating the fraction, exponent, and sign parts of a
float separately. The definition is:
struct FloatRep { union { float value; mixin(bitfields!( uint, "fraction", 23, ubyte, "exponent", 8, bool, "sign", 1)); } enum uint bias = 127, fractionBits = 23, exponentBits = 8, signBits = 1; }
- Allows manipulating the fraction, exponent, and sign parts of a
double separately. The definition is:
struct DoubleRep { union { double value; mixin(bitfields!( ulong, "fraction", 52, ushort, "exponent", 11, bool, "sign", 1)); } enum uint bias = 1023, signBits = 1, fractionBits = 52, exponentBits = 11; }
- An array of bits.
- Gets the amount of native words backing this BitArray.
- Gets the amount of bits in the BitArray.
- Sets the amount of bits in the BitArray.
- Gets the i'th bit in the BitArray.
- Sets the i'th bit in the BitArray.
- Duplicates the BitArray and its contents.
- Support for foreach loops for BitArray.
- Reverses the bits of the BitArray.
- Sorts the BitArray's elements.
- Support for operators == and != for BitArray.
- Supports comparison operators for BitArray.
- Support for hashing for BitArray.
- Set this BitArray to the contents of ba.
- Map the BitArray onto v, with numbits being the number of bits in the array. Does not copy the data. This is the inverse of opCast.
- Convert to void[].
- Convert to size_t[].
- Support for unary operator ~ for BitArray.
- Support for binary operator & for BitArray.
- Support for binary operator | for BitArray.
- Support for binary operator ^ for BitArray.
- Support for binary operator - for BitArray. a - b for BitArray means the same thing as a & ~b.
- Support for operator &= for BitArray.
- Support for operator |= for BitArray.
- Support for operator ^= for BitArray.
- Support for operator -= for BitArray. a -= b for BitArray means the same thing as a &= ~b.
- Support for operator ~= for BitArray.
- Support for binary operator ~ for BitArray.
- Swaps the endianness of the given integral value or character.
- Converts the given value from the native endianness to big endian and
returns it as a ubyte[n] where n is the size of the given type.
Returning a ubyte[n] helps prevent accidentally using a swapped value
as a regular one (and in the case of floating point values, it's necessary,
because the FPU will mess up any swapped floating point values. So, you
can't actually have swapped floating point values as floating point values).
real is not supported, because its size is implementation-dependent
and therefore could vary from machine to machine (which could make it
unusable if you tried to transfer it to another machine).
Examples:
int i = 12345; ubyte[4] swappedI = nativeToBigEndian(i); assert(i == bigEndianToNative!int(swappedI)); double d = 123.45; ubyte[8] swappedD = nativeToBigEndian(d); assert(d == bigEndianToNative!double(swappedD));
- Converts the given value from big endian to the native endianness and
returns it. The value is given as a ubyte[n] where n is the size
of the target type. You must give the target type as a template argument,
because there are multiple types with the same size and so the type of the
argument is not enough to determine the return type.
Taking a ubyte[n] helps prevent accidentally using a swapped value
as a regular one (and in the case of floating point values, it's necessary,
because the FPU will mess up any swapped floating point values. So, you
can't actually have swapped floating point values as floating point values).
Examples:
ushort i = 12345; ubyte[2] swappedI = nativeToBigEndian(i); assert(i == bigEndianToNative!ushort(swappedI)); dchar c = 'D'; ubyte[4] swappedC = nativeToBigEndian(c); assert(c == bigEndianToNative!dchar(swappedC));
- Converts the given value from the native endianness to little endian and
returns it as a ubyte[n] where n is the size of the given type.
Returning a ubyte[n] helps prevent accidentally using a swapped value
as a regular one (and in the case of floating point values, it's necessary,
because the FPU will mess up any swapped floating point values. So, you
can't actually have swapped floating point values as floating point values).
Examples:
int i = 12345; ubyte[4] swappedI = nativeToLittleEndian(i); assert(i == littleEndianToNative!int(swappedI)); double d = 123.45; ubyte[8] swappedD = nativeToLittleEndian(d); assert(d == littleEndianToNative!double(swappedD));
- Converts the given value from little endian to the native endianness and
returns it. The value is given as a ubyte[n] where n is the size
of the target type. You must give the target type as a template argument,
because there are multiple types with the same size and so the type of the
argument is not enough to determine the return type.
Taking a ubyte[n] helps prevent accidentally using a swapped value
as a regular one (and in the case of floating point values, it's necessary,
because the FPU will mess up any swapped floating point values. So, you
can't actually have swapped floating point values as floating point values).
real is not supported, because its size is implementation-dependent
and therefore could vary from machine to machine (which could make it
unusable if you tried to transfer it to another machine).
Examples:
ushort i = 12345; ubyte[2] swappedI = nativeToLittleEndian(i); assert(i == littleEndianToNative!ushort(swappedI)); dchar c = 'D'; ubyte[4] swappedC = nativeToLittleEndian(c); assert(c == littleEndianToNative!dchar(swappedC));
- Takes a range of ubytes and converts the first T.sizeof bytes to
T. The value returned is converted from the given endianness to the
native endianness. The range is not consumed.
Parems:
T = The integral type to convert the first T.sizeof bytes to. endianness = The endianness that the bytes are assumed to be in. range = The range to read from. index = The index to start reading from (instead of starting at the front). If index is a pointer, then it is updated to the index after the bytes read. The overloads with index are only available if hasSlicing!R is true. Examples:ubyte[] buffer = [1, 5, 22, 9, 44, 255, 8]; assert(buffer.peek!uint() == 17110537); assert(buffer.peek!ushort() == 261); assert(buffer.peek!ubyte() == 1); assert(buffer.peek!uint(2) == 369700095); assert(buffer.peek!ushort(2) == 5641); assert(buffer.peek!ubyte(2) == 22); size_t index = 0; assert(buffer.peek!ushort(&index) == 261); assert(index == 2); assert(buffer.peek!uint(&index) == 369700095); assert(index == 6); assert(buffer.peek!ubyte(&index) == 8); assert(index == 7);
- Takes a range of ubytes and converts the first T.sizeof bytes to
T. The value returned is converted from the given endianness to the
native endianness. The T.sizeof bytes which are read are consumed from
the range.
Parems:
T = The integral type to convert the first T.sizeof bytes to. endianness = The endianness that the bytes are assumed to be in. range = The range to read from. Examples:ubyte[] buffer = [1, 5, 22, 9, 44, 255, 8]; assert(buffer.length == 7); assert(buffer.read!ushort() == 261); assert(buffer.length == 5); assert(buffer.read!uint() == 369700095); assert(buffer.length == 1); assert(buffer.read!ubyte() == 8); assert(buffer.empty);
- Takes an integral value, converts it to the given endianness, and writes it
to the given range of ubytes as a sequence of T.sizeof ubytes
starting at index. hasSlicing!R must be true.
Parems:
T = The integral type to convert the first T.sizeof bytes to. endianness = The endianness to write the bytes in. range = The range to write to. index = The index to start writing to. If index is a pointer, then it is updated to the index after the bytes read. Examples://Bug# 8129 forces the casts. They shouldn't be necessary. { ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0]; buffer.write!uint(29110231u, 0); assert(buffer == [1, 188, 47, 215, 0, 0, 0]); buffer.write!ushort(cast(ushort)927, 0); assert(buffer == [3, 159, 47, 215, 0, 0, 0]); buffer.write!ubyte(cast(ubyte)42, 0); assert(buffer == [42, 159, 47, 215, 0, 0, 0]); } { ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0]; buffer.write!uint(142700095u, 2); assert(buffer == [0, 0, 8, 129, 110, 63, 0]); buffer.write!ushort(cast(ushort)19839, 2); assert(buffer == [0, 0, 77, 127, 110, 63, 0]); buffer.write!ubyte(cast(ubyte)132, 2); assert(buffer == [0, 0, 132, 127, 110, 63, 0]); } { ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0]; size_t index = 0; buffer.write!ushort(cast(ushort)261, &index); assert(buffer == [1, 5, 0, 0, 0, 0, 0]); assert(index == 2); buffer.write!uint(369700095u, &index); assert(buffer == [1, 5, 22, 9, 44, 255, 0]); assert(index == 6); buffer.write!ubyte(cast(ubyte)8, &index); assert(buffer == [1, 5, 22, 9, 44, 255, 8]); assert(index == 7); }
- Takes an integral value, converts it to the given endianness, and appends
it to the given range of ubytes (using put) as a sequence of
T.sizeof ubytes starting at index. hasSlicing!R must be
true.
Parems:
T = The integral type to convert the first T.sizeof bytes to. endianness = The endianness to write the bytes in. range = The range to append to. Examples://Bug# 8129 forces the casts. They shouldn't be necessary. auto buffer = appender!(const ubyte[])(); buffer.append!ushort(cast(ushort)261); assert(buffer.data == [1, 5]); buffer.append!uint(369700095u); assert(buffer.data == [1, 5, 22, 9, 44, 255]); buffer.append!ubyte(cast(ubyte)8); assert(buffer.data == [1, 5, 22, 9, 44, 255, 8]);