Mercurial > hg > sv-dependency-builds
diff osx/include/capnp/endian.h @ 62:0994c39f1e94
Cap'n Proto v0.6 + build for OSX
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Mon, 22 May 2017 10:01:37 +0100 |
parents | 3ab5a40c4e3b |
children |
line wrap: on
line diff
--- a/osx/include/capnp/endian.h Mon Mar 06 13:29:58 2017 +0000 +++ b/osx/include/capnp/endian.h Mon May 22 10:01:37 2017 +0100 @@ -1,309 +1,309 @@ -// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -// Licensed under the MIT License: -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef CAPNP_ENDIAN_H_ -#define CAPNP_ENDIAN_H_ - -#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) -#pragma GCC system_header -#endif - -#include "common.h" -#include <inttypes.h> -#include <string.h> // memcpy - -namespace capnp { -namespace _ { // private - -// WireValue -// -// Wraps a primitive value as it appears on the wire. Namely, values are little-endian on the -// wire, because little-endian is the most common endianness in modern CPUs. -// -// Note: In general, code that depends cares about byte ordering is bad. See: -// http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html -// Cap'n Proto is special because it is essentially doing compiler-like things, fussing over -// allocation and layout of memory, in order to squeeze out every last drop of performance. - -#if _MSC_VER -// Assume Windows is little-endian. -// -// TODO(msvc): This is ugly. Maybe refactor later checks to be based on CAPNP_BYTE_ORDER or -// CAPNP_SWAP_BYTES or something, and define that in turn based on _MSC_VER or the GCC -// intrinsics. - -#ifndef __ORDER_BIG_ENDIAN__ -#define __ORDER_BIG_ENDIAN__ 4321 -#endif -#ifndef __ORDER_LITTLE_ENDIAN__ -#define __ORDER_LITTLE_ENDIAN__ 1234 -#endif -#ifndef __BYTE_ORDER__ -#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ -#endif -#endif - -#if CAPNP_REVERSE_ENDIAN -#define CAPNP_WIRE_BYTE_ORDER __ORDER_BIG_ENDIAN__ -#define CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER __ORDER_LITTLE_ENDIAN__ -#else -#define CAPNP_WIRE_BYTE_ORDER __ORDER_LITTLE_ENDIAN__ -#define CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER __ORDER_BIG_ENDIAN__ -#endif - -#if defined(__BYTE_ORDER__) && \ - __BYTE_ORDER__ == CAPNP_WIRE_BYTE_ORDER && \ - !CAPNP_DISABLE_ENDIAN_DETECTION -// CPU is little-endian. We can just read/write the memory directly. - -template <typename T> -class DirectWireValue { -public: - KJ_ALWAYS_INLINE(T get() const) { return value; } - KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; } - -private: - T value; -}; - -template <typename T> -using WireValue = DirectWireValue<T>; -// To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are -// linked together, we define each implementation with a different name and define an alias to the -// one we want to use. - -#elif defined(__BYTE_ORDER__) && \ - __BYTE_ORDER__ == CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER && \ - defined(__GNUC__) && !CAPNP_DISABLE_ENDIAN_DETECTION -// Big-endian, but GCC's __builtin_bswap() is available. - -// TODO(perf): Use dedicated instructions to read little-endian data on big-endian CPUs that have -// them. - -// TODO(perf): Verify that this code optimizes reasonably. In particular, ensure that the -// compiler optimizes away the memcpy()s and keeps everything in registers. - -template <typename T, size_t size = sizeof(T)> -class SwappingWireValue; - -template <typename T> -class SwappingWireValue<T, 1> { -public: - KJ_ALWAYS_INLINE(T get() const) { return value; } - KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; } - -private: - T value; -}; - -template <typename T> -class SwappingWireValue<T, 2> { -public: - KJ_ALWAYS_INLINE(T get() const) { - // Not all platforms have __builtin_bswap16() for some reason. In particular, it is missing - // on gcc-4.7.3-cygwin32 (but present on gcc-4.8.1-cygwin64). - uint16_t swapped = (value << 8) | (value >> 8); - T result; - memcpy(&result, &swapped, sizeof(T)); - return result; - } - KJ_ALWAYS_INLINE(void set(T newValue)) { - uint16_t raw; - memcpy(&raw, &newValue, sizeof(T)); - // Not all platforms have __builtin_bswap16() for some reason. In particular, it is missing - // on gcc-4.7.3-cygwin32 (but present on gcc-4.8.1-cygwin64). - value = (raw << 8) | (raw >> 8); - } - -private: - uint16_t value; -}; - -template <typename T> -class SwappingWireValue<T, 4> { -public: - KJ_ALWAYS_INLINE(T get() const) { - uint32_t swapped = __builtin_bswap32(value); - T result; - memcpy(&result, &swapped, sizeof(T)); - return result; - } - KJ_ALWAYS_INLINE(void set(T newValue)) { - uint32_t raw; - memcpy(&raw, &newValue, sizeof(T)); - value = __builtin_bswap32(raw); - } - -private: - uint32_t value; -}; - -template <typename T> -class SwappingWireValue<T, 8> { -public: - KJ_ALWAYS_INLINE(T get() const) { - uint64_t swapped = __builtin_bswap64(value); - T result; - memcpy(&result, &swapped, sizeof(T)); - return result; - } - KJ_ALWAYS_INLINE(void set(T newValue)) { - uint64_t raw; - memcpy(&raw, &newValue, sizeof(T)); - value = __builtin_bswap64(raw); - } - -private: - uint64_t value; -}; - -template <typename T> -using WireValue = SwappingWireValue<T>; -// To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are -// linked together, we define each implementation with a different name and define an alias to the -// one we want to use. - -#else -// Unknown endianness. Fall back to bit shifts. - -#if !CAPNP_DISABLE_ENDIAN_DETECTION -#if _MSC_VER -#pragma message("Couldn't detect endianness of your platform. Using unoptimized fallback implementation.") -#pragma message("Consider changing this code to detect your platform and send us a patch!") -#else -#warning "Couldn't detect endianness of your platform. Using unoptimized fallback implementation." -#warning "Consider changing this code to detect your platform and send us a patch!" -#endif -#endif // !CAPNP_DISABLE_ENDIAN_DETECTION - -template <typename T, size_t size = sizeof(T)> -class ShiftingWireValue; - -template <typename T> -class ShiftingWireValue<T, 1> { -public: - KJ_ALWAYS_INLINE(T get() const) { return value; } - KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; } - -private: - T value; -}; - -template <typename T> -class ShiftingWireValue<T, 2> { -public: - KJ_ALWAYS_INLINE(T get() const) { - uint16_t raw = (static_cast<uint16_t>(bytes[0]) ) | - (static_cast<uint16_t>(bytes[1]) << 8); - T result; - memcpy(&result, &raw, sizeof(T)); - return result; - } - KJ_ALWAYS_INLINE(void set(T newValue)) { - uint16_t raw; - memcpy(&raw, &newValue, sizeof(T)); - bytes[0] = raw; - bytes[1] = raw >> 8; - } - -private: - union { - byte bytes[2]; - uint16_t align; - }; -}; - -template <typename T> -class ShiftingWireValue<T, 4> { -public: - KJ_ALWAYS_INLINE(T get() const) { - uint32_t raw = (static_cast<uint32_t>(bytes[0]) ) | - (static_cast<uint32_t>(bytes[1]) << 8) | - (static_cast<uint32_t>(bytes[2]) << 16) | - (static_cast<uint32_t>(bytes[3]) << 24); - T result; - memcpy(&result, &raw, sizeof(T)); - return result; - } - KJ_ALWAYS_INLINE(void set(T newValue)) { - uint32_t raw; - memcpy(&raw, &newValue, sizeof(T)); - bytes[0] = raw; - bytes[1] = raw >> 8; - bytes[2] = raw >> 16; - bytes[3] = raw >> 24; - } - -private: - union { - byte bytes[4]; - uint32_t align; - }; -}; - -template <typename T> -class ShiftingWireValue<T, 8> { -public: - KJ_ALWAYS_INLINE(T get() const) { - uint64_t raw = (static_cast<uint64_t>(bytes[0]) ) | - (static_cast<uint64_t>(bytes[1]) << 8) | - (static_cast<uint64_t>(bytes[2]) << 16) | - (static_cast<uint64_t>(bytes[3]) << 24) | - (static_cast<uint64_t>(bytes[4]) << 32) | - (static_cast<uint64_t>(bytes[5]) << 40) | - (static_cast<uint64_t>(bytes[6]) << 48) | - (static_cast<uint64_t>(bytes[7]) << 56); - T result; - memcpy(&result, &raw, sizeof(T)); - return result; - } - KJ_ALWAYS_INLINE(void set(T newValue)) { - uint64_t raw; - memcpy(&raw, &newValue, sizeof(T)); - bytes[0] = raw; - bytes[1] = raw >> 8; - bytes[2] = raw >> 16; - bytes[3] = raw >> 24; - bytes[4] = raw >> 32; - bytes[5] = raw >> 40; - bytes[6] = raw >> 48; - bytes[7] = raw >> 56; - } - -private: - union { - byte bytes[8]; - uint64_t align; - }; -}; - -template <typename T> -using WireValue = ShiftingWireValue<T>; -// To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are -// linked together, we define each implementation with a different name and define an alias to the -// one we want to use. - -#endif - -} // namespace _ (private) -} // namespace capnp - -#endif // CAPNP_ENDIAN_H_ +// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +// Licensed under the MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CAPNP_ENDIAN_H_ +#define CAPNP_ENDIAN_H_ + +#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) +#pragma GCC system_header +#endif + +#include "common.h" +#include <inttypes.h> +#include <string.h> // memcpy + +namespace capnp { +namespace _ { // private + +// WireValue +// +// Wraps a primitive value as it appears on the wire. Namely, values are little-endian on the +// wire, because little-endian is the most common endianness in modern CPUs. +// +// Note: In general, code that depends cares about byte ordering is bad. See: +// http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html +// Cap'n Proto is special because it is essentially doing compiler-like things, fussing over +// allocation and layout of memory, in order to squeeze out every last drop of performance. + +#if _MSC_VER +// Assume Windows is little-endian. +// +// TODO(msvc): This is ugly. Maybe refactor later checks to be based on CAPNP_BYTE_ORDER or +// CAPNP_SWAP_BYTES or something, and define that in turn based on _MSC_VER or the GCC +// intrinsics. + +#ifndef __ORDER_BIG_ENDIAN__ +#define __ORDER_BIG_ENDIAN__ 4321 +#endif +#ifndef __ORDER_LITTLE_ENDIAN__ +#define __ORDER_LITTLE_ENDIAN__ 1234 +#endif +#ifndef __BYTE_ORDER__ +#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ +#endif +#endif + +#if CAPNP_REVERSE_ENDIAN +#define CAPNP_WIRE_BYTE_ORDER __ORDER_BIG_ENDIAN__ +#define CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER __ORDER_LITTLE_ENDIAN__ +#else +#define CAPNP_WIRE_BYTE_ORDER __ORDER_LITTLE_ENDIAN__ +#define CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER __ORDER_BIG_ENDIAN__ +#endif + +#if defined(__BYTE_ORDER__) && \ + __BYTE_ORDER__ == CAPNP_WIRE_BYTE_ORDER && \ + !CAPNP_DISABLE_ENDIAN_DETECTION +// CPU is little-endian. We can just read/write the memory directly. + +template <typename T> +class DirectWireValue { +public: + KJ_ALWAYS_INLINE(T get() const) { return value; } + KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; } + +private: + T value; +}; + +template <typename T> +using WireValue = DirectWireValue<T>; +// To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are +// linked together, we define each implementation with a different name and define an alias to the +// one we want to use. + +#elif defined(__BYTE_ORDER__) && \ + __BYTE_ORDER__ == CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER && \ + defined(__GNUC__) && !CAPNP_DISABLE_ENDIAN_DETECTION +// Big-endian, but GCC's __builtin_bswap() is available. + +// TODO(perf): Use dedicated instructions to read little-endian data on big-endian CPUs that have +// them. + +// TODO(perf): Verify that this code optimizes reasonably. In particular, ensure that the +// compiler optimizes away the memcpy()s and keeps everything in registers. + +template <typename T, size_t size = sizeof(T)> +class SwappingWireValue; + +template <typename T> +class SwappingWireValue<T, 1> { +public: + KJ_ALWAYS_INLINE(T get() const) { return value; } + KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; } + +private: + T value; +}; + +template <typename T> +class SwappingWireValue<T, 2> { +public: + KJ_ALWAYS_INLINE(T get() const) { + // Not all platforms have __builtin_bswap16() for some reason. In particular, it is missing + // on gcc-4.7.3-cygwin32 (but present on gcc-4.8.1-cygwin64). + uint16_t swapped = (value << 8) | (value >> 8); + T result; + memcpy(&result, &swapped, sizeof(T)); + return result; + } + KJ_ALWAYS_INLINE(void set(T newValue)) { + uint16_t raw; + memcpy(&raw, &newValue, sizeof(T)); + // Not all platforms have __builtin_bswap16() for some reason. In particular, it is missing + // on gcc-4.7.3-cygwin32 (but present on gcc-4.8.1-cygwin64). + value = (raw << 8) | (raw >> 8); + } + +private: + uint16_t value; +}; + +template <typename T> +class SwappingWireValue<T, 4> { +public: + KJ_ALWAYS_INLINE(T get() const) { + uint32_t swapped = __builtin_bswap32(value); + T result; + memcpy(&result, &swapped, sizeof(T)); + return result; + } + KJ_ALWAYS_INLINE(void set(T newValue)) { + uint32_t raw; + memcpy(&raw, &newValue, sizeof(T)); + value = __builtin_bswap32(raw); + } + +private: + uint32_t value; +}; + +template <typename T> +class SwappingWireValue<T, 8> { +public: + KJ_ALWAYS_INLINE(T get() const) { + uint64_t swapped = __builtin_bswap64(value); + T result; + memcpy(&result, &swapped, sizeof(T)); + return result; + } + KJ_ALWAYS_INLINE(void set(T newValue)) { + uint64_t raw; + memcpy(&raw, &newValue, sizeof(T)); + value = __builtin_bswap64(raw); + } + +private: + uint64_t value; +}; + +template <typename T> +using WireValue = SwappingWireValue<T>; +// To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are +// linked together, we define each implementation with a different name and define an alias to the +// one we want to use. + +#else +// Unknown endianness. Fall back to bit shifts. + +#if !CAPNP_DISABLE_ENDIAN_DETECTION +#if _MSC_VER +#pragma message("Couldn't detect endianness of your platform. Using unoptimized fallback implementation.") +#pragma message("Consider changing this code to detect your platform and send us a patch!") +#else +#warning "Couldn't detect endianness of your platform. Using unoptimized fallback implementation." +#warning "Consider changing this code to detect your platform and send us a patch!" +#endif +#endif // !CAPNP_DISABLE_ENDIAN_DETECTION + +template <typename T, size_t size = sizeof(T)> +class ShiftingWireValue; + +template <typename T> +class ShiftingWireValue<T, 1> { +public: + KJ_ALWAYS_INLINE(T get() const) { return value; } + KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; } + +private: + T value; +}; + +template <typename T> +class ShiftingWireValue<T, 2> { +public: + KJ_ALWAYS_INLINE(T get() const) { + uint16_t raw = (static_cast<uint16_t>(bytes[0]) ) | + (static_cast<uint16_t>(bytes[1]) << 8); + T result; + memcpy(&result, &raw, sizeof(T)); + return result; + } + KJ_ALWAYS_INLINE(void set(T newValue)) { + uint16_t raw; + memcpy(&raw, &newValue, sizeof(T)); + bytes[0] = raw; + bytes[1] = raw >> 8; + } + +private: + union { + byte bytes[2]; + uint16_t align; + }; +}; + +template <typename T> +class ShiftingWireValue<T, 4> { +public: + KJ_ALWAYS_INLINE(T get() const) { + uint32_t raw = (static_cast<uint32_t>(bytes[0]) ) | + (static_cast<uint32_t>(bytes[1]) << 8) | + (static_cast<uint32_t>(bytes[2]) << 16) | + (static_cast<uint32_t>(bytes[3]) << 24); + T result; + memcpy(&result, &raw, sizeof(T)); + return result; + } + KJ_ALWAYS_INLINE(void set(T newValue)) { + uint32_t raw; + memcpy(&raw, &newValue, sizeof(T)); + bytes[0] = raw; + bytes[1] = raw >> 8; + bytes[2] = raw >> 16; + bytes[3] = raw >> 24; + } + +private: + union { + byte bytes[4]; + uint32_t align; + }; +}; + +template <typename T> +class ShiftingWireValue<T, 8> { +public: + KJ_ALWAYS_INLINE(T get() const) { + uint64_t raw = (static_cast<uint64_t>(bytes[0]) ) | + (static_cast<uint64_t>(bytes[1]) << 8) | + (static_cast<uint64_t>(bytes[2]) << 16) | + (static_cast<uint64_t>(bytes[3]) << 24) | + (static_cast<uint64_t>(bytes[4]) << 32) | + (static_cast<uint64_t>(bytes[5]) << 40) | + (static_cast<uint64_t>(bytes[6]) << 48) | + (static_cast<uint64_t>(bytes[7]) << 56); + T result; + memcpy(&result, &raw, sizeof(T)); + return result; + } + KJ_ALWAYS_INLINE(void set(T newValue)) { + uint64_t raw; + memcpy(&raw, &newValue, sizeof(T)); + bytes[0] = raw; + bytes[1] = raw >> 8; + bytes[2] = raw >> 16; + bytes[3] = raw >> 24; + bytes[4] = raw >> 32; + bytes[5] = raw >> 40; + bytes[6] = raw >> 48; + bytes[7] = raw >> 56; + } + +private: + union { + byte bytes[8]; + uint64_t align; + }; +}; + +template <typename T> +using WireValue = ShiftingWireValue<T>; +// To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are +// linked together, we define each implementation with a different name and define an alias to the +// one we want to use. + +#endif + +} // namespace _ (private) +} // namespace capnp + +#endif // CAPNP_ENDIAN_H_