Byte Order Swapping Function
Jonathan M Davis
jmdavisProg at gmx.com
Sat Jul 16 14:51:50 PDT 2011
On Saturday 16 July 2011 15:38:29 Andrei Alexandrescu wrote:
> Just paste the code here.
This is what I have at the moment:
import core.bitop;
/++
Swaps the endianness of the given value. Any integral value,
character, or floating point value is accepted.
+/
T swapEndian(T)(T val)
if(isNumeric!T || isSomeChar!T)
{
static if(val.sizeof == 1)
return val;
else static if(isUnsigned!T || isFloatingPoint!T)
return swapEndianImpl(val);
else static if(isIntegral!T)
return swapEndianImpl(cast(Unsigned!T) val);
else static if(is(Unqual!T == wchar))
return cast(T)swapEndian(cast(ushort)val);
else static if(is(Unqual!T == dchar))
return cast(T)swapEndian(cast(uint)val);
else
static assert(0, T.stringof ~ " unsupported by swapEndian.");
}
private T swapEndianImpl(T)(T val)
if(is(Unqual!T == ushort))
{
return ((val & 0xff00U) >> 8) |
((val & 0x00ffU) << 8);
}
private T swapEndianImpl(T)(T val)
if(is(Unqual!T == uint))
{
return bswap(val);
}
private T swapEndianImpl(T)(T val)
if(is(Unqual!T == ulong))
{
return ((val & 0xff00000000000000UL) >> 56) |
((val & 0x00ff000000000000UL) >> 40) |
((val & 0x0000ff0000000000UL) >> 24) |
((val & 0x000000ff00000000UL) >> 8) |
((val & 0x00000000ff000000UL) << 8) |
((val & 0x0000000000ff0000UL) << 24) |
((val & 0x000000000000ff00UL) << 40) |
((val & 0x00000000000000ffUL) << 56);
}
private T swapEndianImpl(T)(T val)
if(isFloatingPoint!T)
{
import std.algorithm;
union Union
{
Unqual!T _floating;
ubyte[T.sizeof] _array;
}
Union u;
u._floating = val;
std.algorithm.reverse(u._array[]);
return u._floating;
}
unittest
{
import std.stdio;
import std.typetuple;
foreach(T; TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong,
char, wchar, dchar, float, double, real))
{
scope(failure) writefln("Failed type: %s", T.stringof);
T val;
const T cval;
immutable T ival;
assert(swapEndian(swapEndian(val)) == val);
assert(swapEndian(swapEndian(cval)) == cval);
assert(swapEndian(swapEndian(ival)) == ival);
assert(swapEndian(swapEndian(T.min)) == T.min);
assert(swapEndian(swapEndian(T.max)) == T.max);
static if(isSigned!T) assert(swapEndian(swapEndian(cast(T)0)) == 0);
}
}
I think that the problem is a combination of NaN and real. If I change the
first three tests (which all test using init) to use is, then all of the tests
pass until real is tested with T.max, and it's doesn't survive being swapped
twice). So, maybe something special needs to be done for NaN, and the issue
with real may involve issues with padding. I don't know.
- Jonathan M Davis
More information about the Digitalmars-d
mailing list