On Sat, Jul 16, 2011 at 2:51 PM, Jonathan M Davis <jmdavisp...@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.