LCOV - code coverage report
Current view: top level - mfbt - EndianUtils.h (source / functions) Hit Total Coverage
Test: output.info Lines: 53 102 52.0 %
Date: 2017-07-14 16:53:18 Functions: 47 100 47.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13