|  | #ifndef __H_ByteOrder | 
|  | #define __H_ByteOrder | 
|  | /* | 
|  | * Copyright 2008 Google Inc. | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); you may not | 
|  | * use this file except in compliance with the License. You may obtain a copy of | 
|  | * the License at | 
|  | * | 
|  | * http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | 
|  | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | 
|  | * License for the specific language governing permissions and limitations under | 
|  | * the License. | 
|  | */ | 
|  |  | 
|  | #include "Platform.h" | 
|  | #include <cstring> | 
|  |  | 
|  | class ByteOrder { | 
|  | private: | 
|  | enum FloatByteOrder { | 
|  | FLOAT_BIG_ENDIAN, | 
|  | FLOAT_LITTLE_ENDIAN, | 
|  | // TODO(jat): do we need to consider anything other than straight | 
|  | // big-endian or little-endian?  PDP-11 (irrelevant), ARM (probably | 
|  | // relevant for mobile devices), MIPS (probably not relevant, but maybe) | 
|  | // and others have some intermediate endianess.  Also, FP-endianess is not | 
|  | // necessarily the same as that for integers. | 
|  | }; | 
|  | #ifdef PLATFORM_FLOAT_ENDIANESS | 
|  | static const FloatByteOrder floatByteOrder = PLATFORM_FLOAT_ENDIANESS; | 
|  | #else | 
|  | FloatByteOrder floatByteOrder; | 
|  | #endif | 
|  |  | 
|  | typedef union { | 
|  | float v; | 
|  | char b[sizeof(float)]; | 
|  | } FloatUnion; | 
|  |  | 
|  | typedef union { | 
|  | double v; | 
|  | char b[sizeof(double)]; | 
|  | } DoubleUnion; | 
|  |  | 
|  | /** | 
|  | * Copy src to dest, reversing the order of the bytes. | 
|  | * Assumes src and dest do not overlap. | 
|  | */ | 
|  | void memcpyrev(char* dest, const char* src, size_t n) { | 
|  | src += n; | 
|  | while (n-- > 0) { | 
|  | *dest++ = *--src; | 
|  | } | 
|  | } | 
|  | public: | 
|  | ByteOrder() { | 
|  | #ifndef PLATFORM_FLOAT_ENDIANESS | 
|  | DoubleUnion u; | 
|  | memset(u.b, 0, sizeof(u.b)); | 
|  | u.b[0] = (char) 0x80; | 
|  | u.b[7] = (char) 0x02; | 
|  | // TODO(jat): add more tests here if we support other endianess | 
|  | floatByteOrder = u.v > 0 ? FLOAT_LITTLE_ENDIAN : FLOAT_BIG_ENDIAN; | 
|  | if (Debug::level(Debug::Debugging)) { | 
|  | std::string str = "Unknown"; | 
|  | switch (floatByteOrder) { | 
|  | case FLOAT_LITTLE_ENDIAN: | 
|  | str = "little-endian"; | 
|  | break; | 
|  | case FLOAT_BIG_ENDIAN: | 
|  | str = "big-endian"; | 
|  | break; | 
|  | } | 
|  | Debug::log(Debug::Debugging) << "Dynamically detected float byte order: " | 
|  | << str << Debug::flush; | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  | void bytesFromDouble(double v, char* bytes) { | 
|  | DoubleUnion u; | 
|  | u.v = v; | 
|  | switch (floatByteOrder) { | 
|  | case FLOAT_LITTLE_ENDIAN: | 
|  | memcpyrev(bytes, u.b, sizeof(u.b)); | 
|  | break; | 
|  | case FLOAT_BIG_ENDIAN: | 
|  | memcpy(bytes, u.b, sizeof(u.b)); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | void bytesFromFloat(float v, char* bytes) { | 
|  | FloatUnion u; | 
|  | u.v = v; | 
|  | switch (floatByteOrder) { | 
|  | case FLOAT_LITTLE_ENDIAN: | 
|  | memcpyrev(bytes, u.b, sizeof(u.b)); | 
|  | break; | 
|  | case FLOAT_BIG_ENDIAN: | 
|  | memcpy(bytes, u.b, sizeof(u.b)); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | double doubleFromBytes(const char* bytes) { | 
|  | DoubleUnion u; | 
|  | switch (floatByteOrder) { | 
|  | case FLOAT_LITTLE_ENDIAN: | 
|  | memcpyrev(u.b, bytes, sizeof(u.b)); | 
|  | break; | 
|  | case FLOAT_BIG_ENDIAN: | 
|  | // TODO(jat): find a way to avoid the extra copy while keeping the | 
|  | // compiler happy. | 
|  | memcpy(u.b, bytes, sizeof(u.b)); | 
|  | break; | 
|  | } | 
|  | return u.v; | 
|  | } | 
|  |  | 
|  | float floatFromBytes(const char* bytes) { | 
|  | FloatUnion u; | 
|  | switch (floatByteOrder) { | 
|  | case FLOAT_LITTLE_ENDIAN: | 
|  | memcpyrev(u.b, bytes, sizeof(u.b)); | 
|  | break; | 
|  | case FLOAT_BIG_ENDIAN: | 
|  | // TODO(jat): find a way to avoid the extra copy while keeping the | 
|  | // compiler happy. | 
|  | memcpy(u.b, bytes, sizeof(u.b)); | 
|  | break; | 
|  | } | 
|  | return u.v; | 
|  | } | 
|  | }; | 
|  |  | 
|  | #endif |