LCOV - code coverage report
Current view: top level - core/core/string - SPByteOrder.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 16 16 100.0 %
Date: 2024-05-12 00:16:13 Functions: 16 18 88.9 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2016-2022 Roman Katuntsev <sbkarr@stappler.org>
       3             : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       4             : 
       5             : Permission is hereby granted, free of charge, to any person obtaining a copy
       6             : of this software and associated documentation files (the "Software"), to deal
       7             : in the Software without restriction, including without limitation the rights
       8             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9             : copies of the Software, and to permit persons to whom the Software is
      10             : furnished to do so, subject to the following conditions:
      11             : 
      12             : The above copyright notice and this permission notice shall be included in
      13             : all copies or substantial portions of the Software.
      14             : 
      15             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      21             : THE SOFTWARE.
      22             : **/
      23             : 
      24             : #ifndef STAPPLER_CORE_STRING_SPBYTEORDER_H_
      25             : #define STAPPLER_CORE_STRING_SPBYTEORDER_H_
      26             : 
      27             : #include "SPCore.h"
      28             : 
      29             : #ifndef __CDT_PARSER__
      30             : #ifndef SPINLINE
      31             : #define SPINLINE __attribute__((always_inline))
      32             : #endif
      33             : #endif
      34             : 
      35             : #ifndef __has_builtin         // Optional of course
      36             :   #define __has_builtin(x) 0  // Compatibility with non-clang compilers
      37             : #endif
      38             : 
      39             : //  Adapted code from BOOST_ENDIAN_INTRINSICS
      40             : //  GCC and Clang recent versions provide intrinsic byte swaps via builtins
      41             : #if (defined(__clang__) && __has_builtin(__builtin_bswap32) && __has_builtin(__builtin_bswap64)) \
      42             :   || (defined(__GNUC__ ) && \
      43             :   (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
      44             : 
      45             : // prior to 4.8, gcc did not provide __builtin_bswap16 on some platforms so we emulate it
      46             : // see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52624
      47             : // Clang has a similar problem, but their feature test macros make it easier to detect
      48             : namespace STAPPLER_VERSIONIZED stappler::byteorder {
      49             : # if (defined(__clang__) && __has_builtin(__builtin_bswap16)) \
      50             :   || (defined(__GNUC__) &&(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))
      51     6547721 : static SPINLINE inline uint16_t bswap16(uint16_t x) { return __builtin_bswap16(x); }
      52             : # else
      53             : static SPINLINE inline uint16_t bswap16(uint16_t x) { return __builtin_bswap32(x) << 16; }
      54             : # endif
      55    21743236 : static SPINLINE inline uint32_t bswap32(uint32_t x) { return __builtin_bswap32(x); }
      56       13125 : static SPINLINE inline uint64_t bswap64(uint64_t x) { return __builtin_bswap64(x); }
      57             : }
      58             : 
      59             : //  Linux systems provide the byteswap.h header, with
      60             : #elif defined(__linux__)
      61             : //  don't check for obsolete forms defined(linux) and defined(__linux) on the theory that
      62             : //  compilers that predefine only these are so old that byteswap.h probably isn't present.
      63             : # include <byteswap.h>
      64             : namespace STAPPLER_VERSIONIZED stappler::byteorder {
      65             : static SPINLINE inline uint16_t bswap16(uint16_t x) { return bswap_16(x); }
      66             : static SPINLINE inline uint32_t bswap32(uint32_t x) { return bswap_32(x); }
      67             : static SPINLINE inline uint64_t bswap64(uint64_t x) { return bswap_64(x); }
      68             : }
      69             : 
      70             : #elif defined(_MSC_VER)
      71             : //  Microsoft documents these as being compatible since Windows 95 and specificly
      72             : //  lists runtime library support since Visual Studio 2003 (aka 7.1).
      73             : # include <cstdlib>
      74             : namespace STAPPLER_VERSIONIZED stappler::byteorder {
      75             : static SPINLINE inline uint16_t bswap16(uint16_t x) { return _byteswap_ushort(x); }
      76             : static SPINLINE inline uint32_t bswap32(uint32_t x) { return _byteswap_ulong(x); }
      77             : static SPINLINE inline uint64_t bswap64(uint64_t x) { return _byteswap_uint64(x); }
      78             : }
      79             : #else
      80             : namespace STAPPLER_VERSIONIZED stappler::byteorder {
      81             : static SPINLINE inline uint16_t bswap16(uint16_t x) {
      82             :         return (x & 0xFF) << 8 | ((x >> 8) & 0xFF);
      83             : }
      84             : 
      85             : static SPINLINE inline uint32_t bswap32(uint32_t x) {
      86             :         return x & 0xFF << 24
      87             :                 | (x >> 8 & 0xFF) << 16
      88             :                 | (x >> 16 & 0xFF) << 8
      89             :                 | (x >> 24 & 0xFF);
      90             : }
      91             : static SPINLINE inline uint64_t bswap64(uint64_t x) {
      92             :         return x & 0xFF << 56
      93             :                 | (x >> 8 & 0xFF) << 48
      94             :                 | (x >> 16 & 0xFF) << 40
      95             :                 | (x >> 24 & 0xFF) << 32
      96             :                 | (x >> 32 & 0xFF) << 24
      97             :                 | (x >> 40 & 0xFF) << 16
      98             :                 | (x >> 48 & 0xFF) << 8
      99             :                 | (x >> 56 & 0xFF);
     100             : }
     101             : }
     102             : #endif
     103             : 
     104             : namespace STAPPLER_VERSIONIZED stappler {
     105             : 
     106             : #if __cpp_lib_endian >= 201907L
     107             : enum class Endian {
     108             :         Big,
     109             :         Little,
     110             :         Mixed,
     111             :         Network = Big,
     112             :         Host = (std::endian::native == std::endian::little) ? Little : ((std::endian::native == std::endian::big) ? Big : Mixed), // no support for custom endian
     113             : };
     114             : #else
     115             : enum class Endian {
     116             :         Big,
     117             :         Little,
     118             :         Mixed,
     119             :         Network = Big,
     120             : #if (__i386__) || (_M_IX86) || (__x86_64__) || (_M_X64) || (__arm__) || (_M_ARM) || (__arm64__) || (__arm64) || defined(__aarch64__) || defined(__e2k__)
     121             :         Host = Little,
     122             : #else
     123             :         Host = Big,
     124             : #endif
     125             : };
     126             : #endif
     127             : 
     128             : }
     129             : 
     130             : namespace STAPPLER_VERSIONIZED stappler::byteorder {
     131             : 
     132             : enum class ShouldSwap {
     133             :         NoSwap,
     134             :         DoSwap,
     135             :         CustomSwap,
     136             : };
     137             : 
     138             : static constexpr size_t Bit8Size = 1;
     139             : static constexpr size_t Bit16Size = 2;
     140             : static constexpr size_t Bit32Size = 4;
     141             : static constexpr size_t Bit64Size = 8;
     142             : 
     143             : template <class T, ShouldSwap ByteSwap, size_t Size>
     144             : struct Converter;
     145             : 
     146             : template <class T>
     147             : struct Converter<T, ShouldSwap::DoSwap, Bit8Size> {
     148             :         static inline T Swap(T value) {
     149             :                 return value;
     150             :         }
     151             : };
     152             : 
     153             : template <class T>
     154             : struct Converter<T, ShouldSwap::DoSwap, Bit16Size> {
     155     6547721 :         static inline T Swap(T value) {
     156    13095442 :                 return reinterpretValue<T>(bswap16(reinterpretValue<uint16_t>(value)));
     157             :         }
     158             : };
     159             : 
     160             : template <class T>
     161             : struct Converter<T, ShouldSwap::DoSwap, Bit32Size> {
     162    21743236 :         static inline T Swap(T value) {
     163    43486472 :                 return reinterpretValue<T>(bswap32(reinterpretValue<uint32_t>(value)));
     164             :         }
     165             : };
     166             : 
     167             : template <class T>
     168             : struct Converter<T, ShouldSwap::DoSwap, Bit64Size> {
     169       13125 :         static inline T Swap(T value) {
     170       26250 :                 return reinterpretValue<T>(bswap64(reinterpretValue<uint64_t>(value)));
     171             :         }
     172             : };
     173             : 
     174             : template <class T, size_t Size>
     175             : struct Converter<T, ShouldSwap::DoSwap, Size> {
     176             :         static inline T Swap(T value) {
     177             :                 T ret;
     178             :                 char *ptr = (char *)&ret;
     179             :                 ::memcpy((void *)ptr, (const void *)&value, sizeof(T));
     180             :                 std::reverse(ptr, ptr + sizeof(T));
     181             :                 return ret;
     182             :         }
     183             : };
     184             : 
     185             : template <class T, size_t Size>
     186             : struct Converter<T, ShouldSwap::NoSwap, Size> {
     187       60434 :         static inline T Swap(T value) { return value; }
     188             : };
     189             : 
     190             : 
     191             : static constexpr ShouldSwap hostToNetwork() {
     192             :         if constexpr (Endian::Host == Endian::Network) { return ShouldSwap::NoSwap; }
     193             :         if constexpr (Endian::Host == Endian::Little) { return ShouldSwap::DoSwap; }
     194             :         return ShouldSwap::CustomSwap;
     195             : }
     196             : 
     197             : static constexpr ShouldSwap hostToLittle() {
     198             :         if constexpr (Endian::Host == Endian::Little) { return ShouldSwap::NoSwap; }
     199             :         if constexpr (Endian::Host == Endian::Big) { return ShouldSwap::DoSwap; }
     200             :         return ShouldSwap::CustomSwap;
     201             : }
     202             : 
     203             : static constexpr ShouldSwap hostToBig() {
     204             :         if constexpr (Endian::Host == Endian::Big) { return ShouldSwap::NoSwap; }
     205             :         if constexpr (Endian::Host == Endian::Little) { return ShouldSwap::DoSwap; }
     206             :         return ShouldSwap::CustomSwap;
     207             : }
     208             : 
     209             : static constexpr bool isLittleEndian() {
     210             :         return Endian::Host == Endian::Little;
     211             : }
     212             : 
     213             : template <class T>
     214             : using NetworkConverter = Converter<T, hostToNetwork(), sizeof(T)>;
     215             : 
     216             : template <class T>
     217             : using LittleConverter = Converter<T, hostToLittle(), sizeof(T)>;
     218             : 
     219             : template <class T>
     220             : using BigConverter = Converter<T, hostToBig(), sizeof(T)>;
     221             : 
     222             : template <class T>
     223             : using HostConverter = Converter<T, ShouldSwap::NoSwap, sizeof(T)>;
     224             : 
     225             : template <class T>
     226     4961036 : static inline T HostToNetwork(T value) {
     227     4961036 :         return NetworkConverter<T>::Swap(value);
     228             : }
     229             : 
     230             : template <class T>
     231             : static inline T NetworkToHost(T value) {
     232             :         return NetworkConverter<T>::Swap(value);
     233             : }
     234             : 
     235             : template <class T>
     236        4200 : static inline T HostToLittle(T value) {
     237        4200 :         return LittleConverter<T>::Swap(value);
     238             : }
     239             : 
     240             : template <class T>
     241             : static inline T LittleToHost(T value) {
     242             :         return LittleConverter<T>::Swap(value);
     243             : }
     244             : 
     245             : template <class T>
     246         400 : static inline T HostToBig(T value) {
     247         400 :         return BigConverter<T>::Swap(value);
     248             : }
     249             : 
     250             : template <class T>
     251             : static inline T BigToHost(T value) {
     252             :         return BigConverter<T>::Swap(value);
     253             : }
     254             : 
     255             : template <Endian Endianess, typename T>
     256             : struct ConverterTraits;
     257             : 
     258             : template <typename T>
     259             : struct ConverterTraits<Endian::Big, T> : BigConverter<T> { };
     260             : 
     261             : template <typename T>
     262             : struct ConverterTraits<Endian::Little, T> : LittleConverter<T> { };
     263             : 
     264             : }
     265             : 
     266             : #endif /* STAPPLER_CORE_STRING_SPBYTEORDER_H_ */

Generated by: LCOV version 1.14