PageRenderTime 24ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/src/beast/beast/ByteOrder.h

https://gitlab.com/vectorci/rippled
C Header | 298 lines | 182 code | 46 blank | 70 comment | 6 complexity | e96e5051644ddaf61f64dcefbcf77fd8 MD5 | raw file
  1. //------------------------------------------------------------------------------
  2. /*
  3. This file is part of Beast: https://github.com/vinniefalco/Beast
  4. Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
  5. Portions of this file are from JUCE.
  6. Copyright (c) 2013 - Raw Material Software Ltd.
  7. Please visit http://www.juce.com
  8. Permission to use, copy, modify, and/or distribute this software for any
  9. purpose with or without fee is hereby granted, provided that the above
  10. copyright notice and this permission notice appear in all copies.
  11. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  12. WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  13. MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  14. ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  15. WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  16. ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  17. OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  18. */
  19. //==============================================================================
  20. #ifndef BEAST_BYTEORDER_H_INCLUDED
  21. #define BEAST_BYTEORDER_H_INCLUDED
  22. #include <beast/Config.h>
  23. #include <cstdint>
  24. namespace beast {
  25. //==============================================================================
  26. /** Contains static methods for converting the byte order between different
  27. endiannesses.
  28. */
  29. class ByteOrder
  30. {
  31. public:
  32. //==============================================================================
  33. /** Swaps the upper and lower bytes of a 16-bit integer. */
  34. static std::uint16_t swap (std::uint16_t value);
  35. /** Reverses the order of the 4 bytes in a 32-bit integer. */
  36. static std::uint32_t swap (std::uint32_t value);
  37. /** Reverses the order of the 8 bytes in a 64-bit integer. */
  38. static std::uint64_t swap (std::uint64_t value);
  39. //==============================================================================
  40. /** Swaps the byte order of a 16-bit int if the CPU is big-endian */
  41. static std::uint16_t swapIfBigEndian (std::uint16_t value);
  42. /** Swaps the byte order of a 32-bit int if the CPU is big-endian */
  43. static std::uint32_t swapIfBigEndian (std::uint32_t value);
  44. /** Swaps the byte order of a 64-bit int if the CPU is big-endian */
  45. static std::uint64_t swapIfBigEndian (std::uint64_t value);
  46. /** Swaps the byte order of a 16-bit int if the CPU is little-endian */
  47. static std::uint16_t swapIfLittleEndian (std::uint16_t value);
  48. /** Swaps the byte order of a 32-bit int if the CPU is little-endian */
  49. static std::uint32_t swapIfLittleEndian (std::uint32_t value);
  50. /** Swaps the byte order of a 64-bit int if the CPU is little-endian */
  51. static std::uint64_t swapIfLittleEndian (std::uint64_t value);
  52. //==============================================================================
  53. /** Turns 2 bytes into a little-endian integer. */
  54. static std::uint16_t littleEndianShort (const void* bytes);
  55. /** Turns 4 bytes into a little-endian integer. */
  56. static std::uint32_t littleEndianInt (const void* bytes);
  57. /** Turns 4 bytes into a little-endian integer. */
  58. static std::uint64_t littleEndianInt64 (const void* bytes);
  59. /** Turns 2 bytes into a big-endian integer. */
  60. static std::uint16_t bigEndianShort (const void* bytes);
  61. /** Turns 4 bytes into a big-endian integer. */
  62. static std::uint32_t bigEndianInt (const void* bytes);
  63. /** Turns 4 bytes into a big-endian integer. */
  64. static std::uint64_t bigEndianInt64 (const void* bytes);
  65. //==============================================================================
  66. /** Converts 3 little-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */
  67. static int littleEndian24Bit (const char* bytes);
  68. /** Converts 3 big-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */
  69. static int bigEndian24Bit (const char* bytes);
  70. /** Copies a 24-bit number to 3 little-endian bytes. */
  71. static void littleEndian24BitToChars (int value, char* destBytes);
  72. /** Copies a 24-bit number to 3 big-endian bytes. */
  73. static void bigEndian24BitToChars (int value, char* destBytes);
  74. //==============================================================================
  75. /** Returns true if the current CPU is big-endian. */
  76. static bool isBigEndian();
  77. private:
  78. ByteOrder();
  79. ByteOrder(ByteOrder const&) = delete;
  80. ByteOrder& operator= (ByteOrder const&) = delete;
  81. };
  82. //==============================================================================
  83. #if BEAST_USE_INTRINSICS && ! defined (__INTEL_COMPILER)
  84. #pragma intrinsic (_byteswap_ulong)
  85. #endif
  86. inline std::uint16_t ByteOrder::swap (std::uint16_t n)
  87. {
  88. #if BEAST_USE_INTRINSICSxxx // agh - the MS compiler has an internal error when you try to use this intrinsic!
  89. return static_cast <std::uint16_t> (_byteswap_ushort (n));
  90. #else
  91. return static_cast <std::uint16_t> ((n << 8) | (n >> 8));
  92. #endif
  93. }
  94. inline std::uint32_t ByteOrder::swap (std::uint32_t n)
  95. {
  96. #if BEAST_MAC || BEAST_IOS
  97. return OSSwapInt32 (n);
  98. #elif BEAST_GCC && BEAST_INTEL && ! BEAST_NO_INLINE_ASM
  99. asm("bswap %%eax" : "=a"(n) : "a"(n));
  100. return n;
  101. #elif BEAST_USE_INTRINSICS
  102. return _byteswap_ulong (n);
  103. #elif BEAST_MSVC && ! BEAST_NO_INLINE_ASM
  104. __asm {
  105. mov eax, n
  106. bswap eax
  107. mov n, eax
  108. }
  109. return n;
  110. #elif BEAST_ANDROID
  111. return bswap_32 (n);
  112. #else
  113. return (n << 24) | (n >> 24) | ((n & 0xff00) << 8) | ((n & 0xff0000) >> 8);
  114. #endif
  115. }
  116. inline std::uint64_t ByteOrder::swap (std::uint64_t value)
  117. {
  118. #if BEAST_MAC || BEAST_IOS
  119. return OSSwapInt64 (value);
  120. #elif BEAST_USE_INTRINSICS
  121. return _byteswap_uint64 (value);
  122. #else
  123. return (((std::int64_t) swap ((std::uint32_t) value)) << 32) | swap ((std::uint32_t) (value >> 32));
  124. #endif
  125. }
  126. #if BEAST_LITTLE_ENDIAN
  127. inline std::uint16_t ByteOrder::swapIfBigEndian (const std::uint16_t v) { return v; }
  128. inline std::uint32_t ByteOrder::swapIfBigEndian (const std::uint32_t v) { return v; }
  129. inline std::uint64_t ByteOrder::swapIfBigEndian (const std::uint64_t v) { return v; }
  130. inline std::uint16_t ByteOrder::swapIfLittleEndian (const std::uint16_t v) { return swap (v); }
  131. inline std::uint32_t ByteOrder::swapIfLittleEndian (const std::uint32_t v) { return swap (v); }
  132. inline std::uint64_t ByteOrder::swapIfLittleEndian (const std::uint64_t v) { return swap (v); }
  133. inline std::uint16_t ByteOrder::littleEndianShort (const void* const bytes) { return *static_cast <const std::uint16_t*> (bytes); }
  134. inline std::uint32_t ByteOrder::littleEndianInt (const void* const bytes) { return *static_cast <const std::uint32_t*> (bytes); }
  135. inline std::uint64_t ByteOrder::littleEndianInt64 (const void* const bytes) { return *static_cast <const std::uint64_t*> (bytes); }
  136. inline std::uint16_t ByteOrder::bigEndianShort (const void* const bytes) { return swap (*static_cast <const std::uint16_t*> (bytes)); }
  137. inline std::uint32_t ByteOrder::bigEndianInt (const void* const bytes) { return swap (*static_cast <const std::uint32_t*> (bytes)); }
  138. inline std::uint64_t ByteOrder::bigEndianInt64 (const void* const bytes) { return swap (*static_cast <const std::uint64_t*> (bytes)); }
  139. inline bool ByteOrder::isBigEndian() { return false; }
  140. #else
  141. inline std::uint16_t ByteOrder::swapIfBigEndian (const std::uint16_t v) { return swap (v); }
  142. inline std::uint32_t ByteOrder::swapIfBigEndian (const std::uint32_t v) { return swap (v); }
  143. inline std::uint64_t ByteOrder::swapIfBigEndian (const std::uint64_t v) { return swap (v); }
  144. inline std::uint16_t ByteOrder::swapIfLittleEndian (const std::uint16_t v) { return v; }
  145. inline std::uint32_t ByteOrder::swapIfLittleEndian (const std::uint32_t v) { return v; }
  146. inline std::uint64_t ByteOrder::swapIfLittleEndian (const std::uint64_t v) { return v; }
  147. inline std::uint32_t ByteOrder::littleEndianInt (const void* const bytes) { return swap (*static_cast <const std::uint32_t*> (bytes)); }
  148. inline std::uint16_t ByteOrder::littleEndianShort (const void* const bytes) { return swap (*static_cast <const std::uint16_t*> (bytes)); }
  149. inline std::uint16_t ByteOrder::bigEndianShort (const void* const bytes) { return *static_cast <const std::uint16_t*> (bytes); }
  150. inline std::uint32_t ByteOrder::bigEndianInt (const void* const bytes) { return *static_cast <const std::uint32_t*> (bytes); }
  151. inline std::uint64_t ByteOrder::bigEndianInt64 (const void* const bytes) { return *static_cast <const std::uint64_t*> (bytes); }
  152. inline bool ByteOrder::isBigEndian() { return true; }
  153. #endif
  154. inline int ByteOrder::littleEndian24Bit (const char* const bytes) { return (((int) bytes[2]) << 16) | (((int) (std::uint8_t) bytes[1]) << 8) | ((int) (std::uint8_t) bytes[0]); }
  155. inline int ByteOrder::bigEndian24Bit (const char* const bytes) { return (((int) bytes[0]) << 16) | (((int) (std::uint8_t) bytes[1]) << 8) | ((int) (std::uint8_t) bytes[2]); }
  156. inline void ByteOrder::littleEndian24BitToChars (const int value, char* const destBytes) { destBytes[0] = (char)(value & 0xff); destBytes[1] = (char)((value >> 8) & 0xff); destBytes[2] = (char)((value >> 16) & 0xff); }
  157. inline void ByteOrder::bigEndian24BitToChars (const int value, char* const destBytes) { destBytes[0] = (char)((value >> 16) & 0xff); destBytes[1] = (char)((value >> 8) & 0xff); destBytes[2] = (char)(value & 0xff); }
  158. namespace detail
  159. {
  160. /** Specialized helper class template for swapping bytes.
  161. Normally you won't use this directly, use the helper function
  162. byteSwap instead. You can specialize this class for your
  163. own user defined types, as was done for uint24.
  164. @see swapBytes, uint24
  165. */
  166. template <typename IntegralType>
  167. struct SwapBytes
  168. {
  169. inline IntegralType operator() (IntegralType value) const noexcept
  170. {
  171. return ByteOrder::swap (value);
  172. }
  173. };
  174. // Specializations for signed integers
  175. template <>
  176. struct SwapBytes <std::int16_t>
  177. {
  178. inline std::int16_t operator() (std::int16_t value) const noexcept
  179. {
  180. return static_cast <std::int16_t> (ByteOrder::swap (static_cast <std::uint16_t> (value)));
  181. }
  182. };
  183. template <>
  184. struct SwapBytes <std::int32_t>
  185. {
  186. inline std::int32_t operator() (std::int32_t value) const noexcept
  187. {
  188. return static_cast <std::int32_t> (ByteOrder::swap (static_cast <std::uint32_t> (value)));
  189. }
  190. };
  191. template <>
  192. struct SwapBytes <std::int64_t>
  193. {
  194. inline std::int64_t operator() (std::int64_t value) const noexcept
  195. {
  196. return static_cast <std::int64_t> (ByteOrder::swap (static_cast <std::uint64_t> (value)));
  197. }
  198. };
  199. }
  200. //------------------------------------------------------------------------------
  201. /** Returns a type with the bytes swapped.
  202. Little endian becomes big endian and vice versa. The underlying
  203. type must be an integral type or behave like one.
  204. */
  205. template <class IntegralType>
  206. inline IntegralType swapBytes (IntegralType value) noexcept
  207. {
  208. return detail::SwapBytes <IntegralType> () (value);
  209. }
  210. /** Returns the machine byte-order value to little-endian byte order. */
  211. template <typename IntegralType>
  212. inline IntegralType toLittleEndian (IntegralType value) noexcept
  213. {
  214. #if BEAST_LITTLE_ENDIAN
  215. return value;
  216. #else
  217. return swapBytes (value);
  218. #endif
  219. }
  220. /** Returns the machine byte-order value to big-endian byte order. */
  221. template <typename IntegralType>
  222. inline IntegralType toBigEndian (IntegralType value) noexcept
  223. {
  224. #if BEAST_LITTLE_ENDIAN
  225. return swapBytes (value);
  226. #else
  227. return value;
  228. #endif
  229. }
  230. /** Returns the machine byte-order value to network byte order. */
  231. template <typename IntegralType>
  232. inline IntegralType toNetworkByteOrder (IntegralType value) noexcept
  233. {
  234. return toBigEndian (value);
  235. }
  236. /** Converts from network byte order to machine byte order. */
  237. template <typename IntegralType>
  238. inline IntegralType fromNetworkByteOrder (IntegralType value) noexcept
  239. {
  240. #if BEAST_LITTLE_ENDIAN
  241. return swapBytes (value);
  242. #else
  243. return value;
  244. #endif
  245. }
  246. }
  247. #endif