1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mfbt/Endian.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,639 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* Functions for reading and writing integers in various endiannesses. */ 1.11 + 1.12 +/* 1.13 + * The classes LittleEndian and BigEndian expose static methods for 1.14 + * reading and writing 16-, 32-, and 64-bit signed and unsigned integers 1.15 + * in their respective endianness. The naming scheme is: 1.16 + * 1.17 + * {Little,Big}Endian::{read,write}{Uint,Int}<bitsize> 1.18 + * 1.19 + * For instance, LittleEndian::readInt32 will read a 32-bit signed 1.20 + * integer from memory in little endian format. Similarly, 1.21 + * BigEndian::writeUint16 will write a 16-bit unsigned integer to memory 1.22 + * in big-endian format. 1.23 + * 1.24 + * The class NativeEndian exposes methods for conversion of existing 1.25 + * data to and from the native endianness. These methods are intended 1.26 + * for cases where data needs to be transferred, serialized, etc. 1.27 + * swap{To,From}{Little,Big}Endian byteswap a single value if necessary. 1.28 + * Bulk conversion functions are also provided which optimize the 1.29 + * no-conversion-needed case: 1.30 + * 1.31 + * - copyAndSwap{To,From}{Little,Big}Endian; 1.32 + * - swap{To,From}{Little,Big}EndianInPlace. 1.33 + * 1.34 + * The *From* variants are intended to be used for reading data and the 1.35 + * *To* variants for writing data. 1.36 + * 1.37 + * Methods on NativeEndian work with integer data of any type. 1.38 + * Floating-point data is not supported. 1.39 + * 1.40 + * For clarity in networking code, "Network" may be used as a synonym 1.41 + * for "Big" in any of the above methods or class names. 1.42 + * 1.43 + * As an example, reading a file format header whose fields are stored 1.44 + * in big-endian format might look like: 1.45 + * 1.46 + * class ExampleHeader 1.47 + * { 1.48 + * private: 1.49 + * uint32_t magic; 1.50 + * uint32_t length; 1.51 + * uint32_t totalRecords; 1.52 + * uint64_t checksum; 1.53 + * 1.54 + * public: 1.55 + * ExampleHeader(const void* data) { 1.56 + * const uint8_t* ptr = static_cast<const uint8_t*>(data); 1.57 + * magic = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t); 1.58 + * length = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t); 1.59 + * totalRecords = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t); 1.60 + * checksum = BigEndian::readUint64(ptr); 1.61 + * } 1.62 + * ... 1.63 + * }; 1.64 + */ 1.65 + 1.66 +#ifndef mozilla_Endian_h 1.67 +#define mozilla_Endian_h 1.68 + 1.69 +#include "mozilla/Assertions.h" 1.70 +#include "mozilla/Attributes.h" 1.71 +#include "mozilla/Compiler.h" 1.72 +#include "mozilla/DebugOnly.h" 1.73 +#include "mozilla/TypeTraits.h" 1.74 + 1.75 +#include <stdint.h> 1.76 +#include <string.h> 1.77 + 1.78 +#if defined(_MSC_VER) && _MSC_VER >= 1300 1.79 +# include <stdlib.h> 1.80 +# pragma intrinsic(_byteswap_ushort) 1.81 +# pragma intrinsic(_byteswap_ulong) 1.82 +# pragma intrinsic(_byteswap_uint64) 1.83 +#endif 1.84 + 1.85 +#if defined(_WIN64) 1.86 +# if defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_) 1.87 +# define MOZ_LITTLE_ENDIAN 1 1.88 +# else 1.89 +# error "CPU type is unknown" 1.90 +# endif 1.91 +#elif defined(_WIN32) 1.92 +# if defined(_M_IX86) 1.93 +# define MOZ_LITTLE_ENDIAN 1 1.94 +# else 1.95 +# error "CPU type is unknown" 1.96 +# endif 1.97 +#elif defined(__APPLE__) || defined(__powerpc__) || defined(__ppc__) 1.98 +# if __LITTLE_ENDIAN__ 1.99 +# define MOZ_LITTLE_ENDIAN 1 1.100 +# elif __BIG_ENDIAN__ 1.101 +# define MOZ_BIG_ENDIAN 1 1.102 +# endif 1.103 +#elif defined(__GNUC__) && \ 1.104 + defined(__BYTE_ORDER__) && \ 1.105 + defined(__ORDER_LITTLE_ENDIAN__) && \ 1.106 + defined(__ORDER_BIG_ENDIAN__) 1.107 + /* 1.108 + * Some versions of GCC provide architecture-independent macros for 1.109 + * this. Yes, there are more than two values for __BYTE_ORDER__. 1.110 + */ 1.111 +# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 1.112 +# define MOZ_LITTLE_ENDIAN 1 1.113 +# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 1.114 +# define MOZ_BIG_ENDIAN 1 1.115 +# else 1.116 +# error "Can't handle mixed-endian architectures" 1.117 +# endif 1.118 +/* 1.119 + * We can't include useful headers like <endian.h> or <sys/isa_defs.h> 1.120 + * here because they're not present on all platforms. Instead we have 1.121 + * this big conditional that ideally will catch all the interesting 1.122 + * cases. 1.123 + */ 1.124 +#elif defined(__sparc) || defined(__sparc__) || \ 1.125 + defined(_POWER) || defined(__hppa) || \ 1.126 + defined(_MIPSEB) || defined(__ARMEB__) || \ 1.127 + defined(__s390__) || defined(__AARCH64EB__) || \ 1.128 + (defined(__sh__) && defined(__LITTLE_ENDIAN__)) || \ 1.129 + (defined(__ia64) && defined(__BIG_ENDIAN__)) 1.130 +# define MOZ_BIG_ENDIAN 1 1.131 +#elif defined(__i386) || defined(__i386__) || \ 1.132 + defined(__x86_64) || defined(__x86_64__) || \ 1.133 + defined(_MIPSEL) || defined(__ARMEL__) || \ 1.134 + defined(__alpha__) || defined(__AARCH64EL__) || \ 1.135 + (defined(__sh__) && defined(__BIG_ENDIAN__)) || \ 1.136 + (defined(__ia64) && !defined(__BIG_ENDIAN__)) 1.137 +# define MOZ_LITTLE_ENDIAN 1 1.138 +#endif 1.139 + 1.140 +#if MOZ_BIG_ENDIAN 1.141 +# define MOZ_LITTLE_ENDIAN 0 1.142 +#elif MOZ_LITTLE_ENDIAN 1.143 +# define MOZ_BIG_ENDIAN 0 1.144 +#else 1.145 +# error "Cannot determine endianness" 1.146 +#endif 1.147 + 1.148 +#if defined(__clang__) 1.149 +# if __has_builtin(__builtin_bswap16) 1.150 +# define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16 1.151 +# endif 1.152 +#elif defined(__GNUC__) 1.153 +# if MOZ_GCC_VERSION_AT_LEAST(4, 8, 0) 1.154 +# define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16 1.155 +# endif 1.156 +#elif defined(_MSC_VER) 1.157 +# define MOZ_HAVE_BUILTIN_BYTESWAP16 _byteswap_ushort 1.158 +#endif 1.159 + 1.160 +namespace mozilla { 1.161 + 1.162 +namespace detail { 1.163 + 1.164 +/* 1.165 + * We need wrappers here because free functions with default template 1.166 + * arguments and/or partial specialization of function templates are not 1.167 + * supported by all the compilers we use. 1.168 + */ 1.169 +template<typename T, size_t Size = sizeof(T)> 1.170 +struct Swapper; 1.171 + 1.172 +template<typename T> 1.173 +struct Swapper<T, 2> 1.174 +{ 1.175 + static T swap(T value) 1.176 + { 1.177 +#if defined(MOZ_HAVE_BUILTIN_BYTESWAP16) 1.178 + return MOZ_HAVE_BUILTIN_BYTESWAP16(value); 1.179 +#else 1.180 + return T(((value & 0x00ff) << 8) | ((value & 0xff00) >> 8)); 1.181 +#endif 1.182 + } 1.183 +}; 1.184 + 1.185 +template<typename T> 1.186 +struct Swapper<T, 4> 1.187 +{ 1.188 + static T swap(T value) 1.189 + { 1.190 +#if defined(__clang__) || defined(__GNUC__) 1.191 + return T(__builtin_bswap32(value)); 1.192 +#elif defined(_MSC_VER) 1.193 + return T(_byteswap_ulong(value)); 1.194 +#else 1.195 + return T(((value & 0x000000ffU) << 24) | 1.196 + ((value & 0x0000ff00U) << 8) | 1.197 + ((value & 0x00ff0000U) >> 8) | 1.198 + ((value & 0xff000000U) >> 24)); 1.199 +#endif 1.200 + } 1.201 +}; 1.202 + 1.203 +template<typename T> 1.204 +struct Swapper<T, 8> 1.205 +{ 1.206 + static inline T swap(T value) 1.207 + { 1.208 +#if defined(__clang__) || defined(__GNUC__) 1.209 + return T(__builtin_bswap64(value)); 1.210 +#elif defined(_MSC_VER) 1.211 + return T(_byteswap_uint64(value)); 1.212 +#else 1.213 + return T(((value & 0x00000000000000ffULL) << 56) | 1.214 + ((value & 0x000000000000ff00ULL) << 40) | 1.215 + ((value & 0x0000000000ff0000ULL) << 24) | 1.216 + ((value & 0x00000000ff000000ULL) << 8) | 1.217 + ((value & 0x000000ff00000000ULL) >> 8) | 1.218 + ((value & 0x0000ff0000000000ULL) >> 24) | 1.219 + ((value & 0x00ff000000000000ULL) >> 40) | 1.220 + ((value & 0xff00000000000000ULL) >> 56)); 1.221 +#endif 1.222 + } 1.223 +}; 1.224 + 1.225 +enum Endianness { Little, Big }; 1.226 + 1.227 +#if MOZ_BIG_ENDIAN 1.228 +# define MOZ_NATIVE_ENDIANNESS detail::Big 1.229 +#else 1.230 +# define MOZ_NATIVE_ENDIANNESS detail::Little 1.231 +#endif 1.232 + 1.233 +class EndianUtils 1.234 +{ 1.235 + /** 1.236 + * Assert that the memory regions [dest, dest+count) and [src, src+count] 1.237 + * do not overlap. count is given in bytes. 1.238 + */ 1.239 + static void assertNoOverlap(const void* dest, const void* src, size_t count) 1.240 + { 1.241 + DebugOnly<const uint8_t*> byteDestPtr = static_cast<const uint8_t*>(dest); 1.242 + DebugOnly<const uint8_t*> byteSrcPtr = static_cast<const uint8_t*>(src); 1.243 + MOZ_ASSERT((byteDestPtr <= byteSrcPtr && 1.244 + byteDestPtr + count <= byteSrcPtr) || 1.245 + (byteSrcPtr <= byteDestPtr && 1.246 + byteSrcPtr + count <= byteDestPtr)); 1.247 + } 1.248 + 1.249 + template<typename T> 1.250 + static void assertAligned(T* ptr) 1.251 + { 1.252 + MOZ_ASSERT((uintptr_t(ptr) % sizeof(T)) == 0, "Unaligned pointer!"); 1.253 + } 1.254 + 1.255 + protected: 1.256 + /** 1.257 + * Return |value| converted from SourceEndian encoding to DestEndian 1.258 + * encoding. 1.259 + */ 1.260 + template<Endianness SourceEndian, Endianness DestEndian, typename T> 1.261 + static inline T maybeSwap(T value) 1.262 + { 1.263 + if (SourceEndian == DestEndian) 1.264 + return value; 1.265 + 1.266 + return Swapper<T>::swap(value); 1.267 + } 1.268 + 1.269 + /** 1.270 + * Convert |count| elements at |ptr| from SourceEndian encoding to 1.271 + * DestEndian encoding. 1.272 + */ 1.273 + template<Endianness SourceEndian, Endianness DestEndian, typename T> 1.274 + static inline void maybeSwapInPlace(T* ptr, size_t count) 1.275 + { 1.276 + assertAligned(ptr); 1.277 + 1.278 + if (SourceEndian == DestEndian) 1.279 + return; 1.280 + 1.281 + for (size_t i = 0; i < count; i++) 1.282 + ptr[i] = Swapper<T>::swap(ptr[i]); 1.283 + } 1.284 + 1.285 + /** 1.286 + * Write |count| elements to the unaligned address |dest| in DestEndian 1.287 + * format, using elements found at |src| in SourceEndian format. 1.288 + */ 1.289 + template<Endianness SourceEndian, Endianness DestEndian, typename T> 1.290 + static void copyAndSwapTo(void* dest, const T* src, size_t count) 1.291 + { 1.292 + assertNoOverlap(dest, src, count * sizeof(T)); 1.293 + assertAligned(src); 1.294 + 1.295 + if (SourceEndian == DestEndian) { 1.296 + memcpy(dest, src, count * sizeof(T)); 1.297 + return; 1.298 + } 1.299 + 1.300 + uint8_t* byteDestPtr = static_cast<uint8_t*>(dest); 1.301 + for (size_t i = 0; i < count; ++i) { 1.302 + union { 1.303 + T val; 1.304 + uint8_t buffer[sizeof(T)]; 1.305 + } u; 1.306 + u.val = maybeSwap<SourceEndian, DestEndian>(src[i]); 1.307 + memcpy(byteDestPtr, u.buffer, sizeof(T)); 1.308 + byteDestPtr += sizeof(T); 1.309 + } 1.310 + } 1.311 + 1.312 + /** 1.313 + * Write |count| elements to |dest| in DestEndian format, using elements 1.314 + * found at the unaligned address |src| in SourceEndian format. 1.315 + */ 1.316 + template<Endianness SourceEndian, Endianness DestEndian, typename T> 1.317 + static void copyAndSwapFrom(T* dest, const void* src, size_t count) 1.318 + { 1.319 + assertNoOverlap(dest, src, count * sizeof(T)); 1.320 + assertAligned(dest); 1.321 + 1.322 + if (SourceEndian == DestEndian) { 1.323 + memcpy(dest, src, count * sizeof(T)); 1.324 + return; 1.325 + } 1.326 + 1.327 + const uint8_t* byteSrcPtr = static_cast<const uint8_t*>(src); 1.328 + for (size_t i = 0; i < count; ++i) { 1.329 + union { 1.330 + T val; 1.331 + uint8_t buffer[sizeof(T)]; 1.332 + } u; 1.333 + memcpy(u.buffer, byteSrcPtr, sizeof(T)); 1.334 + dest[i] = maybeSwap<SourceEndian, DestEndian>(u.val); 1.335 + byteSrcPtr += sizeof(T); 1.336 + } 1.337 + } 1.338 +}; 1.339 + 1.340 +template<Endianness ThisEndian> 1.341 +class Endian : private EndianUtils 1.342 +{ 1.343 + protected: 1.344 + /** Read a uint16_t in ThisEndian endianness from |p| and return it. */ 1.345 + static MOZ_WARN_UNUSED_RESULT uint16_t readUint16(const void* p) { 1.346 + return read<uint16_t>(p); 1.347 + } 1.348 + 1.349 + /** Read a uint32_t in ThisEndian endianness from |p| and return it. */ 1.350 + static MOZ_WARN_UNUSED_RESULT uint32_t readUint32(const void* p) { 1.351 + return read<uint32_t>(p); 1.352 + } 1.353 + 1.354 + /** Read a uint64_t in ThisEndian endianness from |p| and return it. */ 1.355 + static MOZ_WARN_UNUSED_RESULT uint64_t readUint64(const void* p) { 1.356 + return read<uint64_t>(p); 1.357 + } 1.358 + 1.359 + /** Read an int16_t in ThisEndian endianness from |p| and return it. */ 1.360 + static MOZ_WARN_UNUSED_RESULT int16_t readInt16(const void* p) { 1.361 + return read<int16_t>(p); 1.362 + } 1.363 + 1.364 + /** Read an int32_t in ThisEndian endianness from |p| and return it. */ 1.365 + static MOZ_WARN_UNUSED_RESULT int32_t readInt32(const void* p) { 1.366 + return read<uint32_t>(p); 1.367 + } 1.368 + 1.369 + /** Read an int64_t in ThisEndian endianness from |p| and return it. */ 1.370 + static MOZ_WARN_UNUSED_RESULT int64_t readInt64(const void* p) { 1.371 + return read<int64_t>(p); 1.372 + } 1.373 + 1.374 + /** Write |val| to |p| using ThisEndian endianness. */ 1.375 + static void writeUint16(void* p, uint16_t val) { 1.376 + write(p, val); 1.377 + } 1.378 + /** Write |val| to |p| using ThisEndian endianness. */ 1.379 + static void writeUint32(void* p, uint32_t val) { 1.380 + write(p, val); 1.381 + } 1.382 + /** Write |val| to |p| using ThisEndian endianness. */ 1.383 + static void writeUint64(void* p, uint64_t val) { 1.384 + write(p, val); 1.385 + } 1.386 + 1.387 + /** Write |val| to |p| using ThisEndian endianness. */ 1.388 + static void writeInt16(void* p, int16_t val) { 1.389 + write(p, val); 1.390 + } 1.391 + /** Write |val| to |p| using ThisEndian endianness. */ 1.392 + static void writeInt32(void* p, int32_t val) { 1.393 + write(p, val); 1.394 + } 1.395 + /** Write |val| to |p| using ThisEndian endianness. */ 1.396 + static void writeInt64(void* p, int64_t val) { 1.397 + write(p, val); 1.398 + } 1.399 + 1.400 + /* 1.401 + * Converts a value of type T to little-endian format. 1.402 + * 1.403 + * This function is intended for cases where you have data in your 1.404 + * native-endian format and you need it to appear in little-endian 1.405 + * format for transmission. 1.406 + */ 1.407 + template<typename T> 1.408 + MOZ_WARN_UNUSED_RESULT static T swapToLittleEndian(T value) { 1.409 + return maybeSwap<ThisEndian, Little>(value); 1.410 + } 1.411 + /* 1.412 + * Copies count values of type T starting at src to dest, converting 1.413 + * them to little-endian format if ThisEndian is Big. 1.414 + * As with memcpy, dest and src must not overlap. 1.415 + */ 1.416 + template<typename T> 1.417 + static void copyAndSwapToLittleEndian(void* dest, const T* src, 1.418 + size_t count) { 1.419 + copyAndSwapTo<ThisEndian, Little>(dest, src, count); 1.420 + } 1.421 + /* 1.422 + * Likewise, but converts values in place. 1.423 + */ 1.424 + template<typename T> 1.425 + static void swapToLittleEndianInPlace(T* p, size_t count) { 1.426 + maybeSwapInPlace<ThisEndian, Little>(p, count); 1.427 + } 1.428 + 1.429 + /* 1.430 + * Converts a value of type T to big-endian format. 1.431 + */ 1.432 + template<typename T> 1.433 + MOZ_WARN_UNUSED_RESULT static T swapToBigEndian(T value) { 1.434 + return maybeSwap<ThisEndian, Big>(value); 1.435 + } 1.436 + /* 1.437 + * Copies count values of type T starting at src to dest, converting 1.438 + * them to big-endian format if ThisEndian is Little. 1.439 + * As with memcpy, dest and src must not overlap. 1.440 + */ 1.441 + template<typename T> 1.442 + static void copyAndSwapToBigEndian(void* dest, const T* src, size_t count) { 1.443 + copyAndSwapTo<ThisEndian, Big>(dest, src, count); 1.444 + } 1.445 + /* 1.446 + * Likewise, but converts values in place. 1.447 + */ 1.448 + template<typename T> 1.449 + static void swapToBigEndianInPlace(T* p, size_t count) { 1.450 + maybeSwapInPlace<ThisEndian, Big>(p, count); 1.451 + } 1.452 + 1.453 + /* 1.454 + * Synonyms for the big-endian functions, for better readability 1.455 + * in network code. 1.456 + */ 1.457 + template<typename T> 1.458 + MOZ_WARN_UNUSED_RESULT static T swapToNetworkOrder(T value) { 1.459 + return swapToBigEndian(value); 1.460 + } 1.461 + template<typename T> 1.462 + static void 1.463 + copyAndSwapToNetworkOrder(void* dest, const T* src, size_t count) { 1.464 + copyAndSwapToBigEndian(dest, src, count); 1.465 + } 1.466 + template<typename T> 1.467 + static void 1.468 + swapToNetworkOrderInPlace(T* p, size_t count) { 1.469 + swapToBigEndianInPlace(p, count); 1.470 + } 1.471 + 1.472 + /* 1.473 + * Converts a value of type T from little-endian format. 1.474 + */ 1.475 + template<typename T> 1.476 + MOZ_WARN_UNUSED_RESULT static T swapFromLittleEndian(T value) { 1.477 + return maybeSwap<Little, ThisEndian>(value); 1.478 + } 1.479 + /* 1.480 + * Copies count values of type T starting at src to dest, converting 1.481 + * them to little-endian format if ThisEndian is Big. 1.482 + * As with memcpy, dest and src must not overlap. 1.483 + */ 1.484 + template<typename T> 1.485 + static void copyAndSwapFromLittleEndian(T* dest, const void* src, 1.486 + size_t count) { 1.487 + copyAndSwapFrom<Little, ThisEndian>(dest, src, count); 1.488 + } 1.489 + /* 1.490 + * Likewise, but converts values in place. 1.491 + */ 1.492 + template<typename T> 1.493 + static void swapFromLittleEndianInPlace(T* p, size_t count) { 1.494 + maybeSwapInPlace<Little, ThisEndian>(p, count); 1.495 + } 1.496 + 1.497 + /* 1.498 + * Converts a value of type T from big-endian format. 1.499 + */ 1.500 + template<typename T> 1.501 + MOZ_WARN_UNUSED_RESULT static T swapFromBigEndian(T value) { 1.502 + return maybeSwap<Big, ThisEndian>(value); 1.503 + } 1.504 + /* 1.505 + * Copies count values of type T starting at src to dest, converting 1.506 + * them to big-endian format if ThisEndian is Little. 1.507 + * As with memcpy, dest and src must not overlap. 1.508 + */ 1.509 + template<typename T> 1.510 + static void copyAndSwapFromBigEndian(T* dest, const void* src, 1.511 + size_t count) { 1.512 + copyAndSwapFrom<Big, ThisEndian>(dest, src, count); 1.513 + } 1.514 + /* 1.515 + * Likewise, but converts values in place. 1.516 + */ 1.517 + template<typename T> 1.518 + static void swapFromBigEndianInPlace(T* p, size_t count) { 1.519 + maybeSwapInPlace<Big, ThisEndian>(p, count); 1.520 + } 1.521 + 1.522 + /* 1.523 + * Synonyms for the big-endian functions, for better readability 1.524 + * in network code. 1.525 + */ 1.526 + template<typename T> 1.527 + MOZ_WARN_UNUSED_RESULT static T swapFromNetworkOrder(T value) { 1.528 + return swapFromBigEndian(value); 1.529 + } 1.530 + template<typename T> 1.531 + static void copyAndSwapFromNetworkOrder(T* dest, const void* src, 1.532 + size_t count) { 1.533 + copyAndSwapFromBigEndian(dest, src, count); 1.534 + } 1.535 + template<typename T> 1.536 + static void swapFromNetworkOrderInPlace(T* p, size_t count) { 1.537 + swapFromBigEndianInPlace(p, count); 1.538 + } 1.539 + 1.540 + private: 1.541 + /** 1.542 + * Read a value of type T, encoded in endianness ThisEndian from |p|. 1.543 + * Return that value encoded in native endianness. 1.544 + */ 1.545 + template<typename T> 1.546 + static T read(const void* p) { 1.547 + union { 1.548 + T val; 1.549 + uint8_t buffer[sizeof(T)]; 1.550 + } u; 1.551 + memcpy(u.buffer, p, sizeof(T)); 1.552 + return maybeSwap<ThisEndian, MOZ_NATIVE_ENDIANNESS>(u.val); 1.553 + } 1.554 + 1.555 + /** 1.556 + * Write a value of type T, in native endianness, to |p|, in ThisEndian 1.557 + * endianness. 1.558 + */ 1.559 + template<typename T> 1.560 + static void write(void* p, T value) { 1.561 + T tmp = maybeSwap<MOZ_NATIVE_ENDIANNESS, ThisEndian>(value); 1.562 + memcpy(p, &tmp, sizeof(T)); 1.563 + } 1.564 + 1.565 + Endian() MOZ_DELETE; 1.566 + Endian(const Endian& other) MOZ_DELETE; 1.567 + void operator=(const Endian& other) MOZ_DELETE; 1.568 +}; 1.569 + 1.570 +template<Endianness ThisEndian> 1.571 +class EndianReadWrite : public Endian<ThisEndian> 1.572 +{ 1.573 + private: 1.574 + typedef Endian<ThisEndian> super; 1.575 + 1.576 + public: 1.577 + using super::readUint16; 1.578 + using super::readUint32; 1.579 + using super::readUint64; 1.580 + using super::readInt16; 1.581 + using super::readInt32; 1.582 + using super::readInt64; 1.583 + using super::writeUint16; 1.584 + using super::writeUint32; 1.585 + using super::writeUint64; 1.586 + using super::writeInt16; 1.587 + using super::writeInt32; 1.588 + using super::writeInt64; 1.589 +}; 1.590 + 1.591 +} /* namespace detail */ 1.592 + 1.593 +class LittleEndian MOZ_FINAL : public detail::EndianReadWrite<detail::Little> 1.594 +{}; 1.595 + 1.596 +class BigEndian MOZ_FINAL : public detail::EndianReadWrite<detail::Big> 1.597 +{}; 1.598 + 1.599 +typedef BigEndian NetworkEndian; 1.600 + 1.601 +class NativeEndian MOZ_FINAL : public detail::Endian<MOZ_NATIVE_ENDIANNESS> 1.602 +{ 1.603 + private: 1.604 + typedef detail::Endian<MOZ_NATIVE_ENDIANNESS> super; 1.605 + 1.606 + public: 1.607 + /* 1.608 + * These functions are intended for cases where you have data in your 1.609 + * native-endian format and you need the data to appear in the appropriate 1.610 + * endianness for transmission, serialization, etc. 1.611 + */ 1.612 + using super::swapToLittleEndian; 1.613 + using super::copyAndSwapToLittleEndian; 1.614 + using super::swapToLittleEndianInPlace; 1.615 + using super::swapToBigEndian; 1.616 + using super::copyAndSwapToBigEndian; 1.617 + using super::swapToBigEndianInPlace; 1.618 + using super::swapToNetworkOrder; 1.619 + using super::copyAndSwapToNetworkOrder; 1.620 + using super::swapToNetworkOrderInPlace; 1.621 + 1.622 + /* 1.623 + * These functions are intended for cases where you have data in the 1.624 + * given endianness (e.g. reading from disk or a file-format) and you 1.625 + * need the data to appear in native-endian format for processing. 1.626 + */ 1.627 + using super::swapFromLittleEndian; 1.628 + using super::copyAndSwapFromLittleEndian; 1.629 + using super::swapFromLittleEndianInPlace; 1.630 + using super::swapFromBigEndian; 1.631 + using super::copyAndSwapFromBigEndian; 1.632 + using super::swapFromBigEndianInPlace; 1.633 + using super::swapFromNetworkOrder; 1.634 + using super::copyAndSwapFromNetworkOrder; 1.635 + using super::swapFromNetworkOrderInPlace; 1.636 +}; 1.637 + 1.638 +#undef MOZ_NATIVE_ENDIANNESS 1.639 + 1.640 +} /* namespace mozilla */ 1.641 + 1.642 +#endif /* mozilla_Endian_h */