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