mfbt/Endian.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 /* Functions for reading and writing integers in various endiannesses. */
michael@0 8
michael@0 9 /*
michael@0 10 * The classes LittleEndian and BigEndian expose static methods for
michael@0 11 * reading and writing 16-, 32-, and 64-bit signed and unsigned integers
michael@0 12 * in their respective endianness. The naming scheme is:
michael@0 13 *
michael@0 14 * {Little,Big}Endian::{read,write}{Uint,Int}<bitsize>
michael@0 15 *
michael@0 16 * For instance, LittleEndian::readInt32 will read a 32-bit signed
michael@0 17 * integer from memory in little endian format. Similarly,
michael@0 18 * BigEndian::writeUint16 will write a 16-bit unsigned integer to memory
michael@0 19 * in big-endian format.
michael@0 20 *
michael@0 21 * The class NativeEndian exposes methods for conversion of existing
michael@0 22 * data to and from the native endianness. These methods are intended
michael@0 23 * for cases where data needs to be transferred, serialized, etc.
michael@0 24 * swap{To,From}{Little,Big}Endian byteswap a single value if necessary.
michael@0 25 * Bulk conversion functions are also provided which optimize the
michael@0 26 * no-conversion-needed case:
michael@0 27 *
michael@0 28 * - copyAndSwap{To,From}{Little,Big}Endian;
michael@0 29 * - swap{To,From}{Little,Big}EndianInPlace.
michael@0 30 *
michael@0 31 * The *From* variants are intended to be used for reading data and the
michael@0 32 * *To* variants for writing data.
michael@0 33 *
michael@0 34 * Methods on NativeEndian work with integer data of any type.
michael@0 35 * Floating-point data is not supported.
michael@0 36 *
michael@0 37 * For clarity in networking code, "Network" may be used as a synonym
michael@0 38 * for "Big" in any of the above methods or class names.
michael@0 39 *
michael@0 40 * As an example, reading a file format header whose fields are stored
michael@0 41 * in big-endian format might look like:
michael@0 42 *
michael@0 43 * class ExampleHeader
michael@0 44 * {
michael@0 45 * private:
michael@0 46 * uint32_t magic;
michael@0 47 * uint32_t length;
michael@0 48 * uint32_t totalRecords;
michael@0 49 * uint64_t checksum;
michael@0 50 *
michael@0 51 * public:
michael@0 52 * ExampleHeader(const void* data) {
michael@0 53 * const uint8_t* ptr = static_cast<const uint8_t*>(data);
michael@0 54 * magic = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t);
michael@0 55 * length = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t);
michael@0 56 * totalRecords = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t);
michael@0 57 * checksum = BigEndian::readUint64(ptr);
michael@0 58 * }
michael@0 59 * ...
michael@0 60 * };
michael@0 61 */
michael@0 62
michael@0 63 #ifndef mozilla_Endian_h
michael@0 64 #define mozilla_Endian_h
michael@0 65
michael@0 66 #include "mozilla/Assertions.h"
michael@0 67 #include "mozilla/Attributes.h"
michael@0 68 #include "mozilla/Compiler.h"
michael@0 69 #include "mozilla/DebugOnly.h"
michael@0 70 #include "mozilla/TypeTraits.h"
michael@0 71
michael@0 72 #include <stdint.h>
michael@0 73 #include <string.h>
michael@0 74
michael@0 75 #if defined(_MSC_VER) && _MSC_VER >= 1300
michael@0 76 # include <stdlib.h>
michael@0 77 # pragma intrinsic(_byteswap_ushort)
michael@0 78 # pragma intrinsic(_byteswap_ulong)
michael@0 79 # pragma intrinsic(_byteswap_uint64)
michael@0 80 #endif
michael@0 81
michael@0 82 #if defined(_WIN64)
michael@0 83 # if defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)
michael@0 84 # define MOZ_LITTLE_ENDIAN 1
michael@0 85 # else
michael@0 86 # error "CPU type is unknown"
michael@0 87 # endif
michael@0 88 #elif defined(_WIN32)
michael@0 89 # if defined(_M_IX86)
michael@0 90 # define MOZ_LITTLE_ENDIAN 1
michael@0 91 # else
michael@0 92 # error "CPU type is unknown"
michael@0 93 # endif
michael@0 94 #elif defined(__APPLE__) || defined(__powerpc__) || defined(__ppc__)
michael@0 95 # if __LITTLE_ENDIAN__
michael@0 96 # define MOZ_LITTLE_ENDIAN 1
michael@0 97 # elif __BIG_ENDIAN__
michael@0 98 # define MOZ_BIG_ENDIAN 1
michael@0 99 # endif
michael@0 100 #elif defined(__GNUC__) && \
michael@0 101 defined(__BYTE_ORDER__) && \
michael@0 102 defined(__ORDER_LITTLE_ENDIAN__) && \
michael@0 103 defined(__ORDER_BIG_ENDIAN__)
michael@0 104 /*
michael@0 105 * Some versions of GCC provide architecture-independent macros for
michael@0 106 * this. Yes, there are more than two values for __BYTE_ORDER__.
michael@0 107 */
michael@0 108 # if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
michael@0 109 # define MOZ_LITTLE_ENDIAN 1
michael@0 110 # elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
michael@0 111 # define MOZ_BIG_ENDIAN 1
michael@0 112 # else
michael@0 113 # error "Can't handle mixed-endian architectures"
michael@0 114 # endif
michael@0 115 /*
michael@0 116 * We can't include useful headers like <endian.h> or <sys/isa_defs.h>
michael@0 117 * here because they're not present on all platforms. Instead we have
michael@0 118 * this big conditional that ideally will catch all the interesting
michael@0 119 * cases.
michael@0 120 */
michael@0 121 #elif defined(__sparc) || defined(__sparc__) || \
michael@0 122 defined(_POWER) || defined(__hppa) || \
michael@0 123 defined(_MIPSEB) || defined(__ARMEB__) || \
michael@0 124 defined(__s390__) || defined(__AARCH64EB__) || \
michael@0 125 (defined(__sh__) && defined(__LITTLE_ENDIAN__)) || \
michael@0 126 (defined(__ia64) && defined(__BIG_ENDIAN__))
michael@0 127 # define MOZ_BIG_ENDIAN 1
michael@0 128 #elif defined(__i386) || defined(__i386__) || \
michael@0 129 defined(__x86_64) || defined(__x86_64__) || \
michael@0 130 defined(_MIPSEL) || defined(__ARMEL__) || \
michael@0 131 defined(__alpha__) || defined(__AARCH64EL__) || \
michael@0 132 (defined(__sh__) && defined(__BIG_ENDIAN__)) || \
michael@0 133 (defined(__ia64) && !defined(__BIG_ENDIAN__))
michael@0 134 # define MOZ_LITTLE_ENDIAN 1
michael@0 135 #endif
michael@0 136
michael@0 137 #if MOZ_BIG_ENDIAN
michael@0 138 # define MOZ_LITTLE_ENDIAN 0
michael@0 139 #elif MOZ_LITTLE_ENDIAN
michael@0 140 # define MOZ_BIG_ENDIAN 0
michael@0 141 #else
michael@0 142 # error "Cannot determine endianness"
michael@0 143 #endif
michael@0 144
michael@0 145 #if defined(__clang__)
michael@0 146 # if __has_builtin(__builtin_bswap16)
michael@0 147 # define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16
michael@0 148 # endif
michael@0 149 #elif defined(__GNUC__)
michael@0 150 # if MOZ_GCC_VERSION_AT_LEAST(4, 8, 0)
michael@0 151 # define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16
michael@0 152 # endif
michael@0 153 #elif defined(_MSC_VER)
michael@0 154 # define MOZ_HAVE_BUILTIN_BYTESWAP16 _byteswap_ushort
michael@0 155 #endif
michael@0 156
michael@0 157 namespace mozilla {
michael@0 158
michael@0 159 namespace detail {
michael@0 160
michael@0 161 /*
michael@0 162 * We need wrappers here because free functions with default template
michael@0 163 * arguments and/or partial specialization of function templates are not
michael@0 164 * supported by all the compilers we use.
michael@0 165 */
michael@0 166 template<typename T, size_t Size = sizeof(T)>
michael@0 167 struct Swapper;
michael@0 168
michael@0 169 template<typename T>
michael@0 170 struct Swapper<T, 2>
michael@0 171 {
michael@0 172 static T swap(T value)
michael@0 173 {
michael@0 174 #if defined(MOZ_HAVE_BUILTIN_BYTESWAP16)
michael@0 175 return MOZ_HAVE_BUILTIN_BYTESWAP16(value);
michael@0 176 #else
michael@0 177 return T(((value & 0x00ff) << 8) | ((value & 0xff00) >> 8));
michael@0 178 #endif
michael@0 179 }
michael@0 180 };
michael@0 181
michael@0 182 template<typename T>
michael@0 183 struct Swapper<T, 4>
michael@0 184 {
michael@0 185 static T swap(T value)
michael@0 186 {
michael@0 187 #if defined(__clang__) || defined(__GNUC__)
michael@0 188 return T(__builtin_bswap32(value));
michael@0 189 #elif defined(_MSC_VER)
michael@0 190 return T(_byteswap_ulong(value));
michael@0 191 #else
michael@0 192 return T(((value & 0x000000ffU) << 24) |
michael@0 193 ((value & 0x0000ff00U) << 8) |
michael@0 194 ((value & 0x00ff0000U) >> 8) |
michael@0 195 ((value & 0xff000000U) >> 24));
michael@0 196 #endif
michael@0 197 }
michael@0 198 };
michael@0 199
michael@0 200 template<typename T>
michael@0 201 struct Swapper<T, 8>
michael@0 202 {
michael@0 203 static inline T swap(T value)
michael@0 204 {
michael@0 205 #if defined(__clang__) || defined(__GNUC__)
michael@0 206 return T(__builtin_bswap64(value));
michael@0 207 #elif defined(_MSC_VER)
michael@0 208 return T(_byteswap_uint64(value));
michael@0 209 #else
michael@0 210 return T(((value & 0x00000000000000ffULL) << 56) |
michael@0 211 ((value & 0x000000000000ff00ULL) << 40) |
michael@0 212 ((value & 0x0000000000ff0000ULL) << 24) |
michael@0 213 ((value & 0x00000000ff000000ULL) << 8) |
michael@0 214 ((value & 0x000000ff00000000ULL) >> 8) |
michael@0 215 ((value & 0x0000ff0000000000ULL) >> 24) |
michael@0 216 ((value & 0x00ff000000000000ULL) >> 40) |
michael@0 217 ((value & 0xff00000000000000ULL) >> 56));
michael@0 218 #endif
michael@0 219 }
michael@0 220 };
michael@0 221
michael@0 222 enum Endianness { Little, Big };
michael@0 223
michael@0 224 #if MOZ_BIG_ENDIAN
michael@0 225 # define MOZ_NATIVE_ENDIANNESS detail::Big
michael@0 226 #else
michael@0 227 # define MOZ_NATIVE_ENDIANNESS detail::Little
michael@0 228 #endif
michael@0 229
michael@0 230 class EndianUtils
michael@0 231 {
michael@0 232 /**
michael@0 233 * Assert that the memory regions [dest, dest+count) and [src, src+count]
michael@0 234 * do not overlap. count is given in bytes.
michael@0 235 */
michael@0 236 static void assertNoOverlap(const void* dest, const void* src, size_t count)
michael@0 237 {
michael@0 238 DebugOnly<const uint8_t*> byteDestPtr = static_cast<const uint8_t*>(dest);
michael@0 239 DebugOnly<const uint8_t*> byteSrcPtr = static_cast<const uint8_t*>(src);
michael@0 240 MOZ_ASSERT((byteDestPtr <= byteSrcPtr &&
michael@0 241 byteDestPtr + count <= byteSrcPtr) ||
michael@0 242 (byteSrcPtr <= byteDestPtr &&
michael@0 243 byteSrcPtr + count <= byteDestPtr));
michael@0 244 }
michael@0 245
michael@0 246 template<typename T>
michael@0 247 static void assertAligned(T* ptr)
michael@0 248 {
michael@0 249 MOZ_ASSERT((uintptr_t(ptr) % sizeof(T)) == 0, "Unaligned pointer!");
michael@0 250 }
michael@0 251
michael@0 252 protected:
michael@0 253 /**
michael@0 254 * Return |value| converted from SourceEndian encoding to DestEndian
michael@0 255 * encoding.
michael@0 256 */
michael@0 257 template<Endianness SourceEndian, Endianness DestEndian, typename T>
michael@0 258 static inline T maybeSwap(T value)
michael@0 259 {
michael@0 260 if (SourceEndian == DestEndian)
michael@0 261 return value;
michael@0 262
michael@0 263 return Swapper<T>::swap(value);
michael@0 264 }
michael@0 265
michael@0 266 /**
michael@0 267 * Convert |count| elements at |ptr| from SourceEndian encoding to
michael@0 268 * DestEndian encoding.
michael@0 269 */
michael@0 270 template<Endianness SourceEndian, Endianness DestEndian, typename T>
michael@0 271 static inline void maybeSwapInPlace(T* ptr, size_t count)
michael@0 272 {
michael@0 273 assertAligned(ptr);
michael@0 274
michael@0 275 if (SourceEndian == DestEndian)
michael@0 276 return;
michael@0 277
michael@0 278 for (size_t i = 0; i < count; i++)
michael@0 279 ptr[i] = Swapper<T>::swap(ptr[i]);
michael@0 280 }
michael@0 281
michael@0 282 /**
michael@0 283 * Write |count| elements to the unaligned address |dest| in DestEndian
michael@0 284 * format, using elements found at |src| in SourceEndian format.
michael@0 285 */
michael@0 286 template<Endianness SourceEndian, Endianness DestEndian, typename T>
michael@0 287 static void copyAndSwapTo(void* dest, const T* src, size_t count)
michael@0 288 {
michael@0 289 assertNoOverlap(dest, src, count * sizeof(T));
michael@0 290 assertAligned(src);
michael@0 291
michael@0 292 if (SourceEndian == DestEndian) {
michael@0 293 memcpy(dest, src, count * sizeof(T));
michael@0 294 return;
michael@0 295 }
michael@0 296
michael@0 297 uint8_t* byteDestPtr = static_cast<uint8_t*>(dest);
michael@0 298 for (size_t i = 0; i < count; ++i) {
michael@0 299 union {
michael@0 300 T val;
michael@0 301 uint8_t buffer[sizeof(T)];
michael@0 302 } u;
michael@0 303 u.val = maybeSwap<SourceEndian, DestEndian>(src[i]);
michael@0 304 memcpy(byteDestPtr, u.buffer, sizeof(T));
michael@0 305 byteDestPtr += sizeof(T);
michael@0 306 }
michael@0 307 }
michael@0 308
michael@0 309 /**
michael@0 310 * Write |count| elements to |dest| in DestEndian format, using elements
michael@0 311 * found at the unaligned address |src| in SourceEndian format.
michael@0 312 */
michael@0 313 template<Endianness SourceEndian, Endianness DestEndian, typename T>
michael@0 314 static void copyAndSwapFrom(T* dest, const void* src, size_t count)
michael@0 315 {
michael@0 316 assertNoOverlap(dest, src, count * sizeof(T));
michael@0 317 assertAligned(dest);
michael@0 318
michael@0 319 if (SourceEndian == DestEndian) {
michael@0 320 memcpy(dest, src, count * sizeof(T));
michael@0 321 return;
michael@0 322 }
michael@0 323
michael@0 324 const uint8_t* byteSrcPtr = static_cast<const uint8_t*>(src);
michael@0 325 for (size_t i = 0; i < count; ++i) {
michael@0 326 union {
michael@0 327 T val;
michael@0 328 uint8_t buffer[sizeof(T)];
michael@0 329 } u;
michael@0 330 memcpy(u.buffer, byteSrcPtr, sizeof(T));
michael@0 331 dest[i] = maybeSwap<SourceEndian, DestEndian>(u.val);
michael@0 332 byteSrcPtr += sizeof(T);
michael@0 333 }
michael@0 334 }
michael@0 335 };
michael@0 336
michael@0 337 template<Endianness ThisEndian>
michael@0 338 class Endian : private EndianUtils
michael@0 339 {
michael@0 340 protected:
michael@0 341 /** Read a uint16_t in ThisEndian endianness from |p| and return it. */
michael@0 342 static MOZ_WARN_UNUSED_RESULT uint16_t readUint16(const void* p) {
michael@0 343 return read<uint16_t>(p);
michael@0 344 }
michael@0 345
michael@0 346 /** Read a uint32_t in ThisEndian endianness from |p| and return it. */
michael@0 347 static MOZ_WARN_UNUSED_RESULT uint32_t readUint32(const void* p) {
michael@0 348 return read<uint32_t>(p);
michael@0 349 }
michael@0 350
michael@0 351 /** Read a uint64_t in ThisEndian endianness from |p| and return it. */
michael@0 352 static MOZ_WARN_UNUSED_RESULT uint64_t readUint64(const void* p) {
michael@0 353 return read<uint64_t>(p);
michael@0 354 }
michael@0 355
michael@0 356 /** Read an int16_t in ThisEndian endianness from |p| and return it. */
michael@0 357 static MOZ_WARN_UNUSED_RESULT int16_t readInt16(const void* p) {
michael@0 358 return read<int16_t>(p);
michael@0 359 }
michael@0 360
michael@0 361 /** Read an int32_t in ThisEndian endianness from |p| and return it. */
michael@0 362 static MOZ_WARN_UNUSED_RESULT int32_t readInt32(const void* p) {
michael@0 363 return read<uint32_t>(p);
michael@0 364 }
michael@0 365
michael@0 366 /** Read an int64_t in ThisEndian endianness from |p| and return it. */
michael@0 367 static MOZ_WARN_UNUSED_RESULT int64_t readInt64(const void* p) {
michael@0 368 return read<int64_t>(p);
michael@0 369 }
michael@0 370
michael@0 371 /** Write |val| to |p| using ThisEndian endianness. */
michael@0 372 static void writeUint16(void* p, uint16_t val) {
michael@0 373 write(p, val);
michael@0 374 }
michael@0 375 /** Write |val| to |p| using ThisEndian endianness. */
michael@0 376 static void writeUint32(void* p, uint32_t val) {
michael@0 377 write(p, val);
michael@0 378 }
michael@0 379 /** Write |val| to |p| using ThisEndian endianness. */
michael@0 380 static void writeUint64(void* p, uint64_t val) {
michael@0 381 write(p, val);
michael@0 382 }
michael@0 383
michael@0 384 /** Write |val| to |p| using ThisEndian endianness. */
michael@0 385 static void writeInt16(void* p, int16_t val) {
michael@0 386 write(p, val);
michael@0 387 }
michael@0 388 /** Write |val| to |p| using ThisEndian endianness. */
michael@0 389 static void writeInt32(void* p, int32_t val) {
michael@0 390 write(p, val);
michael@0 391 }
michael@0 392 /** Write |val| to |p| using ThisEndian endianness. */
michael@0 393 static void writeInt64(void* p, int64_t val) {
michael@0 394 write(p, val);
michael@0 395 }
michael@0 396
michael@0 397 /*
michael@0 398 * Converts a value of type T to little-endian format.
michael@0 399 *
michael@0 400 * This function is intended for cases where you have data in your
michael@0 401 * native-endian format and you need it to appear in little-endian
michael@0 402 * format for transmission.
michael@0 403 */
michael@0 404 template<typename T>
michael@0 405 MOZ_WARN_UNUSED_RESULT static T swapToLittleEndian(T value) {
michael@0 406 return maybeSwap<ThisEndian, Little>(value);
michael@0 407 }
michael@0 408 /*
michael@0 409 * Copies count values of type T starting at src to dest, converting
michael@0 410 * them to little-endian format if ThisEndian is Big.
michael@0 411 * As with memcpy, dest and src must not overlap.
michael@0 412 */
michael@0 413 template<typename T>
michael@0 414 static void copyAndSwapToLittleEndian(void* dest, const T* src,
michael@0 415 size_t count) {
michael@0 416 copyAndSwapTo<ThisEndian, Little>(dest, src, count);
michael@0 417 }
michael@0 418 /*
michael@0 419 * Likewise, but converts values in place.
michael@0 420 */
michael@0 421 template<typename T>
michael@0 422 static void swapToLittleEndianInPlace(T* p, size_t count) {
michael@0 423 maybeSwapInPlace<ThisEndian, Little>(p, count);
michael@0 424 }
michael@0 425
michael@0 426 /*
michael@0 427 * Converts a value of type T to big-endian format.
michael@0 428 */
michael@0 429 template<typename T>
michael@0 430 MOZ_WARN_UNUSED_RESULT static T swapToBigEndian(T value) {
michael@0 431 return maybeSwap<ThisEndian, Big>(value);
michael@0 432 }
michael@0 433 /*
michael@0 434 * Copies count values of type T starting at src to dest, converting
michael@0 435 * them to big-endian format if ThisEndian is Little.
michael@0 436 * As with memcpy, dest and src must not overlap.
michael@0 437 */
michael@0 438 template<typename T>
michael@0 439 static void copyAndSwapToBigEndian(void* dest, const T* src, size_t count) {
michael@0 440 copyAndSwapTo<ThisEndian, Big>(dest, src, count);
michael@0 441 }
michael@0 442 /*
michael@0 443 * Likewise, but converts values in place.
michael@0 444 */
michael@0 445 template<typename T>
michael@0 446 static void swapToBigEndianInPlace(T* p, size_t count) {
michael@0 447 maybeSwapInPlace<ThisEndian, Big>(p, count);
michael@0 448 }
michael@0 449
michael@0 450 /*
michael@0 451 * Synonyms for the big-endian functions, for better readability
michael@0 452 * in network code.
michael@0 453 */
michael@0 454 template<typename T>
michael@0 455 MOZ_WARN_UNUSED_RESULT static T swapToNetworkOrder(T value) {
michael@0 456 return swapToBigEndian(value);
michael@0 457 }
michael@0 458 template<typename T>
michael@0 459 static void
michael@0 460 copyAndSwapToNetworkOrder(void* dest, const T* src, size_t count) {
michael@0 461 copyAndSwapToBigEndian(dest, src, count);
michael@0 462 }
michael@0 463 template<typename T>
michael@0 464 static void
michael@0 465 swapToNetworkOrderInPlace(T* p, size_t count) {
michael@0 466 swapToBigEndianInPlace(p, count);
michael@0 467 }
michael@0 468
michael@0 469 /*
michael@0 470 * Converts a value of type T from little-endian format.
michael@0 471 */
michael@0 472 template<typename T>
michael@0 473 MOZ_WARN_UNUSED_RESULT static T swapFromLittleEndian(T value) {
michael@0 474 return maybeSwap<Little, ThisEndian>(value);
michael@0 475 }
michael@0 476 /*
michael@0 477 * Copies count values of type T starting at src to dest, converting
michael@0 478 * them to little-endian format if ThisEndian is Big.
michael@0 479 * As with memcpy, dest and src must not overlap.
michael@0 480 */
michael@0 481 template<typename T>
michael@0 482 static void copyAndSwapFromLittleEndian(T* dest, const void* src,
michael@0 483 size_t count) {
michael@0 484 copyAndSwapFrom<Little, ThisEndian>(dest, src, count);
michael@0 485 }
michael@0 486 /*
michael@0 487 * Likewise, but converts values in place.
michael@0 488 */
michael@0 489 template<typename T>
michael@0 490 static void swapFromLittleEndianInPlace(T* p, size_t count) {
michael@0 491 maybeSwapInPlace<Little, ThisEndian>(p, count);
michael@0 492 }
michael@0 493
michael@0 494 /*
michael@0 495 * Converts a value of type T from big-endian format.
michael@0 496 */
michael@0 497 template<typename T>
michael@0 498 MOZ_WARN_UNUSED_RESULT static T swapFromBigEndian(T value) {
michael@0 499 return maybeSwap<Big, ThisEndian>(value);
michael@0 500 }
michael@0 501 /*
michael@0 502 * Copies count values of type T starting at src to dest, converting
michael@0 503 * them to big-endian format if ThisEndian is Little.
michael@0 504 * As with memcpy, dest and src must not overlap.
michael@0 505 */
michael@0 506 template<typename T>
michael@0 507 static void copyAndSwapFromBigEndian(T* dest, const void* src,
michael@0 508 size_t count) {
michael@0 509 copyAndSwapFrom<Big, ThisEndian>(dest, src, count);
michael@0 510 }
michael@0 511 /*
michael@0 512 * Likewise, but converts values in place.
michael@0 513 */
michael@0 514 template<typename T>
michael@0 515 static void swapFromBigEndianInPlace(T* p, size_t count) {
michael@0 516 maybeSwapInPlace<Big, ThisEndian>(p, count);
michael@0 517 }
michael@0 518
michael@0 519 /*
michael@0 520 * Synonyms for the big-endian functions, for better readability
michael@0 521 * in network code.
michael@0 522 */
michael@0 523 template<typename T>
michael@0 524 MOZ_WARN_UNUSED_RESULT static T swapFromNetworkOrder(T value) {
michael@0 525 return swapFromBigEndian(value);
michael@0 526 }
michael@0 527 template<typename T>
michael@0 528 static void copyAndSwapFromNetworkOrder(T* dest, const void* src,
michael@0 529 size_t count) {
michael@0 530 copyAndSwapFromBigEndian(dest, src, count);
michael@0 531 }
michael@0 532 template<typename T>
michael@0 533 static void swapFromNetworkOrderInPlace(T* p, size_t count) {
michael@0 534 swapFromBigEndianInPlace(p, count);
michael@0 535 }
michael@0 536
michael@0 537 private:
michael@0 538 /**
michael@0 539 * Read a value of type T, encoded in endianness ThisEndian from |p|.
michael@0 540 * Return that value encoded in native endianness.
michael@0 541 */
michael@0 542 template<typename T>
michael@0 543 static T read(const void* p) {
michael@0 544 union {
michael@0 545 T val;
michael@0 546 uint8_t buffer[sizeof(T)];
michael@0 547 } u;
michael@0 548 memcpy(u.buffer, p, sizeof(T));
michael@0 549 return maybeSwap<ThisEndian, MOZ_NATIVE_ENDIANNESS>(u.val);
michael@0 550 }
michael@0 551
michael@0 552 /**
michael@0 553 * Write a value of type T, in native endianness, to |p|, in ThisEndian
michael@0 554 * endianness.
michael@0 555 */
michael@0 556 template<typename T>
michael@0 557 static void write(void* p, T value) {
michael@0 558 T tmp = maybeSwap<MOZ_NATIVE_ENDIANNESS, ThisEndian>(value);
michael@0 559 memcpy(p, &tmp, sizeof(T));
michael@0 560 }
michael@0 561
michael@0 562 Endian() MOZ_DELETE;
michael@0 563 Endian(const Endian& other) MOZ_DELETE;
michael@0 564 void operator=(const Endian& other) MOZ_DELETE;
michael@0 565 };
michael@0 566
michael@0 567 template<Endianness ThisEndian>
michael@0 568 class EndianReadWrite : public Endian<ThisEndian>
michael@0 569 {
michael@0 570 private:
michael@0 571 typedef Endian<ThisEndian> super;
michael@0 572
michael@0 573 public:
michael@0 574 using super::readUint16;
michael@0 575 using super::readUint32;
michael@0 576 using super::readUint64;
michael@0 577 using super::readInt16;
michael@0 578 using super::readInt32;
michael@0 579 using super::readInt64;
michael@0 580 using super::writeUint16;
michael@0 581 using super::writeUint32;
michael@0 582 using super::writeUint64;
michael@0 583 using super::writeInt16;
michael@0 584 using super::writeInt32;
michael@0 585 using super::writeInt64;
michael@0 586 };
michael@0 587
michael@0 588 } /* namespace detail */
michael@0 589
michael@0 590 class LittleEndian MOZ_FINAL : public detail::EndianReadWrite<detail::Little>
michael@0 591 {};
michael@0 592
michael@0 593 class BigEndian MOZ_FINAL : public detail::EndianReadWrite<detail::Big>
michael@0 594 {};
michael@0 595
michael@0 596 typedef BigEndian NetworkEndian;
michael@0 597
michael@0 598 class NativeEndian MOZ_FINAL : public detail::Endian<MOZ_NATIVE_ENDIANNESS>
michael@0 599 {
michael@0 600 private:
michael@0 601 typedef detail::Endian<MOZ_NATIVE_ENDIANNESS> super;
michael@0 602
michael@0 603 public:
michael@0 604 /*
michael@0 605 * These functions are intended for cases where you have data in your
michael@0 606 * native-endian format and you need the data to appear in the appropriate
michael@0 607 * endianness for transmission, serialization, etc.
michael@0 608 */
michael@0 609 using super::swapToLittleEndian;
michael@0 610 using super::copyAndSwapToLittleEndian;
michael@0 611 using super::swapToLittleEndianInPlace;
michael@0 612 using super::swapToBigEndian;
michael@0 613 using super::copyAndSwapToBigEndian;
michael@0 614 using super::swapToBigEndianInPlace;
michael@0 615 using super::swapToNetworkOrder;
michael@0 616 using super::copyAndSwapToNetworkOrder;
michael@0 617 using super::swapToNetworkOrderInPlace;
michael@0 618
michael@0 619 /*
michael@0 620 * These functions are intended for cases where you have data in the
michael@0 621 * given endianness (e.g. reading from disk or a file-format) and you
michael@0 622 * need the data to appear in native-endian format for processing.
michael@0 623 */
michael@0 624 using super::swapFromLittleEndian;
michael@0 625 using super::copyAndSwapFromLittleEndian;
michael@0 626 using super::swapFromLittleEndianInPlace;
michael@0 627 using super::swapFromBigEndian;
michael@0 628 using super::copyAndSwapFromBigEndian;
michael@0 629 using super::swapFromBigEndianInPlace;
michael@0 630 using super::swapFromNetworkOrder;
michael@0 631 using super::copyAndSwapFromNetworkOrder;
michael@0 632 using super::swapFromNetworkOrderInPlace;
michael@0 633 };
michael@0 634
michael@0 635 #undef MOZ_NATIVE_ENDIANNESS
michael@0 636
michael@0 637 } /* namespace mozilla */
michael@0 638
michael@0 639 #endif /* mozilla_Endian_h */

mercurial