annotate win32-mingw/include/capnp/endian.h @ 141:1b5b6dfd0d0e

Add updated build of PortAudio for OSX
author Chris Cannam <cannam@all-day-breakfast.com>
date Tue, 03 Jan 2017 15:10:52 +0000
parents 38d1c0e7850b
children eccd51b72864
rev   line source
cannam@135 1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
cannam@135 2 // Licensed under the MIT License:
cannam@135 3 //
cannam@135 4 // Permission is hereby granted, free of charge, to any person obtaining a copy
cannam@135 5 // of this software and associated documentation files (the "Software"), to deal
cannam@135 6 // in the Software without restriction, including without limitation the rights
cannam@135 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
cannam@135 8 // copies of the Software, and to permit persons to whom the Software is
cannam@135 9 // furnished to do so, subject to the following conditions:
cannam@135 10 //
cannam@135 11 // The above copyright notice and this permission notice shall be included in
cannam@135 12 // all copies or substantial portions of the Software.
cannam@135 13 //
cannam@135 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
cannam@135 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
cannam@135 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
cannam@135 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
cannam@135 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
cannam@135 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
cannam@135 20 // THE SOFTWARE.
cannam@135 21
cannam@135 22 #ifndef CAPNP_ENDIAN_H_
cannam@135 23 #define CAPNP_ENDIAN_H_
cannam@135 24
cannam@135 25 #if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
cannam@135 26 #pragma GCC system_header
cannam@135 27 #endif
cannam@135 28
cannam@135 29 #include "common.h"
cannam@135 30 #include <inttypes.h>
cannam@135 31 #include <string.h> // memcpy
cannam@135 32
cannam@135 33 namespace capnp {
cannam@135 34 namespace _ { // private
cannam@135 35
cannam@135 36 // WireValue
cannam@135 37 //
cannam@135 38 // Wraps a primitive value as it appears on the wire. Namely, values are little-endian on the
cannam@135 39 // wire, because little-endian is the most common endianness in modern CPUs.
cannam@135 40 //
cannam@135 41 // Note: In general, code that depends cares about byte ordering is bad. See:
cannam@135 42 // http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
cannam@135 43 // Cap'n Proto is special because it is essentially doing compiler-like things, fussing over
cannam@135 44 // allocation and layout of memory, in order to squeeze out every last drop of performance.
cannam@135 45
cannam@135 46 #if _MSC_VER
cannam@135 47 // Assume Windows is little-endian.
cannam@135 48 //
cannam@135 49 // TODO(msvc): This is ugly. Maybe refactor later checks to be based on CAPNP_BYTE_ORDER or
cannam@135 50 // CAPNP_SWAP_BYTES or something, and define that in turn based on _MSC_VER or the GCC
cannam@135 51 // intrinsics.
cannam@135 52
cannam@135 53 #ifndef __ORDER_BIG_ENDIAN__
cannam@135 54 #define __ORDER_BIG_ENDIAN__ 4321
cannam@135 55 #endif
cannam@135 56 #ifndef __ORDER_LITTLE_ENDIAN__
cannam@135 57 #define __ORDER_LITTLE_ENDIAN__ 1234
cannam@135 58 #endif
cannam@135 59 #ifndef __BYTE_ORDER__
cannam@135 60 #define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
cannam@135 61 #endif
cannam@135 62 #endif
cannam@135 63
cannam@135 64 #if CAPNP_REVERSE_ENDIAN
cannam@135 65 #define CAPNP_WIRE_BYTE_ORDER __ORDER_BIG_ENDIAN__
cannam@135 66 #define CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER __ORDER_LITTLE_ENDIAN__
cannam@135 67 #else
cannam@135 68 #define CAPNP_WIRE_BYTE_ORDER __ORDER_LITTLE_ENDIAN__
cannam@135 69 #define CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER __ORDER_BIG_ENDIAN__
cannam@135 70 #endif
cannam@135 71
cannam@135 72 #if defined(__BYTE_ORDER__) && \
cannam@135 73 __BYTE_ORDER__ == CAPNP_WIRE_BYTE_ORDER && \
cannam@135 74 !CAPNP_DISABLE_ENDIAN_DETECTION
cannam@135 75 // CPU is little-endian. We can just read/write the memory directly.
cannam@135 76
cannam@135 77 template <typename T>
cannam@135 78 class DirectWireValue {
cannam@135 79 public:
cannam@135 80 KJ_ALWAYS_INLINE(T get() const) { return value; }
cannam@135 81 KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; }
cannam@135 82
cannam@135 83 private:
cannam@135 84 T value;
cannam@135 85 };
cannam@135 86
cannam@135 87 template <typename T>
cannam@135 88 using WireValue = DirectWireValue<T>;
cannam@135 89 // To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are
cannam@135 90 // linked together, we define each implementation with a different name and define an alias to the
cannam@135 91 // one we want to use.
cannam@135 92
cannam@135 93 #elif defined(__BYTE_ORDER__) && \
cannam@135 94 __BYTE_ORDER__ == CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER && \
cannam@135 95 defined(__GNUC__) && !CAPNP_DISABLE_ENDIAN_DETECTION
cannam@135 96 // Big-endian, but GCC's __builtin_bswap() is available.
cannam@135 97
cannam@135 98 // TODO(perf): Use dedicated instructions to read little-endian data on big-endian CPUs that have
cannam@135 99 // them.
cannam@135 100
cannam@135 101 // TODO(perf): Verify that this code optimizes reasonably. In particular, ensure that the
cannam@135 102 // compiler optimizes away the memcpy()s and keeps everything in registers.
cannam@135 103
cannam@135 104 template <typename T, size_t size = sizeof(T)>
cannam@135 105 class SwappingWireValue;
cannam@135 106
cannam@135 107 template <typename T>
cannam@135 108 class SwappingWireValue<T, 1> {
cannam@135 109 public:
cannam@135 110 KJ_ALWAYS_INLINE(T get() const) { return value; }
cannam@135 111 KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; }
cannam@135 112
cannam@135 113 private:
cannam@135 114 T value;
cannam@135 115 };
cannam@135 116
cannam@135 117 template <typename T>
cannam@135 118 class SwappingWireValue<T, 2> {
cannam@135 119 public:
cannam@135 120 KJ_ALWAYS_INLINE(T get() const) {
cannam@135 121 // Not all platforms have __builtin_bswap16() for some reason. In particular, it is missing
cannam@135 122 // on gcc-4.7.3-cygwin32 (but present on gcc-4.8.1-cygwin64).
cannam@135 123 uint16_t swapped = (value << 8) | (value >> 8);
cannam@135 124 T result;
cannam@135 125 memcpy(&result, &swapped, sizeof(T));
cannam@135 126 return result;
cannam@135 127 }
cannam@135 128 KJ_ALWAYS_INLINE(void set(T newValue)) {
cannam@135 129 uint16_t raw;
cannam@135 130 memcpy(&raw, &newValue, sizeof(T));
cannam@135 131 // Not all platforms have __builtin_bswap16() for some reason. In particular, it is missing
cannam@135 132 // on gcc-4.7.3-cygwin32 (but present on gcc-4.8.1-cygwin64).
cannam@135 133 value = (raw << 8) | (raw >> 8);
cannam@135 134 }
cannam@135 135
cannam@135 136 private:
cannam@135 137 uint16_t value;
cannam@135 138 };
cannam@135 139
cannam@135 140 template <typename T>
cannam@135 141 class SwappingWireValue<T, 4> {
cannam@135 142 public:
cannam@135 143 KJ_ALWAYS_INLINE(T get() const) {
cannam@135 144 uint32_t swapped = __builtin_bswap32(value);
cannam@135 145 T result;
cannam@135 146 memcpy(&result, &swapped, sizeof(T));
cannam@135 147 return result;
cannam@135 148 }
cannam@135 149 KJ_ALWAYS_INLINE(void set(T newValue)) {
cannam@135 150 uint32_t raw;
cannam@135 151 memcpy(&raw, &newValue, sizeof(T));
cannam@135 152 value = __builtin_bswap32(raw);
cannam@135 153 }
cannam@135 154
cannam@135 155 private:
cannam@135 156 uint32_t value;
cannam@135 157 };
cannam@135 158
cannam@135 159 template <typename T>
cannam@135 160 class SwappingWireValue<T, 8> {
cannam@135 161 public:
cannam@135 162 KJ_ALWAYS_INLINE(T get() const) {
cannam@135 163 uint64_t swapped = __builtin_bswap64(value);
cannam@135 164 T result;
cannam@135 165 memcpy(&result, &swapped, sizeof(T));
cannam@135 166 return result;
cannam@135 167 }
cannam@135 168 KJ_ALWAYS_INLINE(void set(T newValue)) {
cannam@135 169 uint64_t raw;
cannam@135 170 memcpy(&raw, &newValue, sizeof(T));
cannam@135 171 value = __builtin_bswap64(raw);
cannam@135 172 }
cannam@135 173
cannam@135 174 private:
cannam@135 175 uint64_t value;
cannam@135 176 };
cannam@135 177
cannam@135 178 template <typename T>
cannam@135 179 using WireValue = SwappingWireValue<T>;
cannam@135 180 // To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are
cannam@135 181 // linked together, we define each implementation with a different name and define an alias to the
cannam@135 182 // one we want to use.
cannam@135 183
cannam@135 184 #else
cannam@135 185 // Unknown endianness. Fall back to bit shifts.
cannam@135 186
cannam@135 187 #if !CAPNP_DISABLE_ENDIAN_DETECTION
cannam@135 188 #if _MSC_VER
cannam@135 189 #pragma message("Couldn't detect endianness of your platform. Using unoptimized fallback implementation.")
cannam@135 190 #pragma message("Consider changing this code to detect your platform and send us a patch!")
cannam@135 191 #else
cannam@135 192 #warning "Couldn't detect endianness of your platform. Using unoptimized fallback implementation."
cannam@135 193 #warning "Consider changing this code to detect your platform and send us a patch!"
cannam@135 194 #endif
cannam@135 195 #endif // !CAPNP_DISABLE_ENDIAN_DETECTION
cannam@135 196
cannam@135 197 template <typename T, size_t size = sizeof(T)>
cannam@135 198 class ShiftingWireValue;
cannam@135 199
cannam@135 200 template <typename T>
cannam@135 201 class ShiftingWireValue<T, 1> {
cannam@135 202 public:
cannam@135 203 KJ_ALWAYS_INLINE(T get() const) { return value; }
cannam@135 204 KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; }
cannam@135 205
cannam@135 206 private:
cannam@135 207 T value;
cannam@135 208 };
cannam@135 209
cannam@135 210 template <typename T>
cannam@135 211 class ShiftingWireValue<T, 2> {
cannam@135 212 public:
cannam@135 213 KJ_ALWAYS_INLINE(T get() const) {
cannam@135 214 uint16_t raw = (static_cast<uint16_t>(bytes[0]) ) |
cannam@135 215 (static_cast<uint16_t>(bytes[1]) << 8);
cannam@135 216 T result;
cannam@135 217 memcpy(&result, &raw, sizeof(T));
cannam@135 218 return result;
cannam@135 219 }
cannam@135 220 KJ_ALWAYS_INLINE(void set(T newValue)) {
cannam@135 221 uint16_t raw;
cannam@135 222 memcpy(&raw, &newValue, sizeof(T));
cannam@135 223 bytes[0] = raw;
cannam@135 224 bytes[1] = raw >> 8;
cannam@135 225 }
cannam@135 226
cannam@135 227 private:
cannam@135 228 union {
cannam@135 229 byte bytes[2];
cannam@135 230 uint16_t align;
cannam@135 231 };
cannam@135 232 };
cannam@135 233
cannam@135 234 template <typename T>
cannam@135 235 class ShiftingWireValue<T, 4> {
cannam@135 236 public:
cannam@135 237 KJ_ALWAYS_INLINE(T get() const) {
cannam@135 238 uint32_t raw = (static_cast<uint32_t>(bytes[0]) ) |
cannam@135 239 (static_cast<uint32_t>(bytes[1]) << 8) |
cannam@135 240 (static_cast<uint32_t>(bytes[2]) << 16) |
cannam@135 241 (static_cast<uint32_t>(bytes[3]) << 24);
cannam@135 242 T result;
cannam@135 243 memcpy(&result, &raw, sizeof(T));
cannam@135 244 return result;
cannam@135 245 }
cannam@135 246 KJ_ALWAYS_INLINE(void set(T newValue)) {
cannam@135 247 uint32_t raw;
cannam@135 248 memcpy(&raw, &newValue, sizeof(T));
cannam@135 249 bytes[0] = raw;
cannam@135 250 bytes[1] = raw >> 8;
cannam@135 251 bytes[2] = raw >> 16;
cannam@135 252 bytes[3] = raw >> 24;
cannam@135 253 }
cannam@135 254
cannam@135 255 private:
cannam@135 256 union {
cannam@135 257 byte bytes[4];
cannam@135 258 uint32_t align;
cannam@135 259 };
cannam@135 260 };
cannam@135 261
cannam@135 262 template <typename T>
cannam@135 263 class ShiftingWireValue<T, 8> {
cannam@135 264 public:
cannam@135 265 KJ_ALWAYS_INLINE(T get() const) {
cannam@135 266 uint64_t raw = (static_cast<uint64_t>(bytes[0]) ) |
cannam@135 267 (static_cast<uint64_t>(bytes[1]) << 8) |
cannam@135 268 (static_cast<uint64_t>(bytes[2]) << 16) |
cannam@135 269 (static_cast<uint64_t>(bytes[3]) << 24) |
cannam@135 270 (static_cast<uint64_t>(bytes[4]) << 32) |
cannam@135 271 (static_cast<uint64_t>(bytes[5]) << 40) |
cannam@135 272 (static_cast<uint64_t>(bytes[6]) << 48) |
cannam@135 273 (static_cast<uint64_t>(bytes[7]) << 56);
cannam@135 274 T result;
cannam@135 275 memcpy(&result, &raw, sizeof(T));
cannam@135 276 return result;
cannam@135 277 }
cannam@135 278 KJ_ALWAYS_INLINE(void set(T newValue)) {
cannam@135 279 uint64_t raw;
cannam@135 280 memcpy(&raw, &newValue, sizeof(T));
cannam@135 281 bytes[0] = raw;
cannam@135 282 bytes[1] = raw >> 8;
cannam@135 283 bytes[2] = raw >> 16;
cannam@135 284 bytes[3] = raw >> 24;
cannam@135 285 bytes[4] = raw >> 32;
cannam@135 286 bytes[5] = raw >> 40;
cannam@135 287 bytes[6] = raw >> 48;
cannam@135 288 bytes[7] = raw >> 56;
cannam@135 289 }
cannam@135 290
cannam@135 291 private:
cannam@135 292 union {
cannam@135 293 byte bytes[8];
cannam@135 294 uint64_t align;
cannam@135 295 };
cannam@135 296 };
cannam@135 297
cannam@135 298 template <typename T>
cannam@135 299 using WireValue = ShiftingWireValue<T>;
cannam@135 300 // To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are
cannam@135 301 // linked together, we define each implementation with a different name and define an alias to the
cannam@135 302 // one we want to use.
cannam@135 303
cannam@135 304 #endif
cannam@135 305
cannam@135 306 } // namespace _ (private)
cannam@135 307 } // namespace capnp
cannam@135 308
cannam@135 309 #endif // CAPNP_ENDIAN_H_