Byte Order Swapping Function

Andrew Wiley wiley.andrew.j at gmail.com
Sat Jul 16 23:31:09 PDT 2011


On Sat, Jul 16, 2011 at 2:51 PM, Jonathan M Davis <jmdavisProg at gmx.com>wrote:

> 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
>


Take a look at http://www.dmh2000.com/cpp/dswap.shtml . It made the odd
behavior make a lot more sense to me.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20110716/7889a3be/attachment.html>


More information about the Digitalmars-d mailing list