Worldstone
 All Classes Files Functions Variables Enumerations Enumerator Macros Pages
SystemUtils.h
Go to the documentation of this file.
1 
6 #pragma once
7 
8 #include <stddef.h>
9 #include <stdint.h>
10 #include <limits.h>
11 #include <type_traits>
12 
13 #include "Platform.h"
14 
15 // Don't bring in huge headers for nothing (only used as fallback for popCount)
16 #if !defined(WS_GCC_FAMILY) && !(defined(WS_MSC) && defined(WS_64BITS))
17 #include <bitset>
18 #endif
19 
21 #define WS_UNUSED(x) (void)x
22 
23 namespace WorldStone
24 {
25 namespace Utils
26 {
27 
36 template<typename SignedResult, unsigned NbBits, typename InputType>
37 inline SignedResult signExtend(const InputType value)
38 {
39  static_assert(std::is_integral<SignedResult>::value && std::is_integral<InputType>::value, "");
40  static_assert(NbBits > 0, "Can not represent a signed value on 0 bit.");
41  static_assert(NbBits <= sizeof(SignedResult) * CHAR_BIT,
42  "Result type is not big enough to hold the values.");
43  static_assert(std::is_signed<SignedResult>::value, "Result type must be signed");
44  struct
45  {
46  SignedResult x : NbBits;
47  } s;
48  return s.x = static_cast<SignedResult>(value);
49 }
50 
51 #if 0
52 // Safe version of signExtend that does not rely on implementation defined unions.
53 template <typename SignedResult, unsigned NbBits, typename InputType>
54 inline SignedResult signExtendS(InputType value)
55 {
56  static_assert(std::is_integral<SignedResult>::value && std::is_integral<InputType>::value, "");
57  static_assert(NbBits > 1, "Can not represent a signed value on 1 bit.");
58  static_assert(NbBits <= sizeof(SignedResult) * CHAR_BIT, "Result type is not big enough to hold the values.");
59  static_assert(std::is_signed<SignedResult>::value, "Result type must be signed");
60  // Note: Since c++14, `int32_t(1) << 32` is no more undefined, so InputType can be signed.
61  const InputType signBitMask = (InputType(1) << (NbBits - 1) ); // Highest bit mask, also 2^bits
62  const bool signBit = value & signBitMask; // Signed or not
63  const InputType valWithoutSignBit = value & (signBitMask - 1);
64  // Note that this does not rely on the current platform using 2's complement
65  // valWithoutSignBit - 2^bits is the 2's complement value.
66  // Multiplying by signBit avoids branching. ie no 'if(signBit)'.
67  return valWithoutSignBit - signBit * signBitMask;
68 }
69 #endif
70 
75 template<typename T>
76 inline T reverseBits(T bits)
77 {
78  constexpr size_t nbBits = sizeof(T) * CHAR_BIT;
79 #if defined(WS_CLANG)
80  switch (nbBits)
81  {
82 #if __has_builtin(__builtin_bitreverse8)
83  case 8: return __builtin_bitreverse8(bits);
84 #endif
85 #if __has_builtin(__builtin_bitreverse16)
86  case 16: return __builtin_bitreverse16(bits);
87 #endif
88 #if __has_builtin(__builtin_bitreverse32)
89  case 32: return __builtin_bitreverse32(bits);
90 #endif
91 #if __has_builtin(__builtin_bitreverse64)
92  case 64: return __builtin_bitreverse64(bits);
93 #endif
94  default: break;
95  }
96 #endif
97  T tmp = 0;
98  for (size_t bitIndex = 0; bitIndex < nbBits; bitIndex++)
99  {
100  tmp <<= 1;
101  tmp |= bits & 1;
102  bits >>= 1;
103  }
104  return tmp;
105 }
106 
111 inline uint16_t popCount(uint16_t value)
112 {
113 #if defined(WS_GCC_FAMILY)
114  return uint16_t(__builtin_popcount(value));
115 #elif defined(WS_MSC)
116  return __popcnt16(value);
117 #else
118  std::bitset<16> bset = value;
119  return uint16_t(bset.count());
120 #endif
121 }
122 
124 inline uint32_t popCount(uint32_t value)
125 {
126 #if defined(WS_GCC_FAMILY)
127  return uint32_t(__builtin_popcount(value));
128 #elif defined(WS_MSC)
129  return __popcnt(value);
130 #else
131  std::bitset<32> bset = value;
132  return uint32_t(bset.count());
133 #endif
134 }
135 
137 inline uint64_t popCount(uint64_t value)
138 {
139 #if defined(WS_GCC_FAMILY)
140  return uint64_t(__builtin_popcountll(value));
141 #elif defined(WS_MSC) && defined(WS_64BITS)
142  return __popcnt64(value);
143 #else
144  std::bitset<64> bset = value;
145  return uint64_t(bset.count());
146 #endif
147 }
148 
149 template<class T, std::size_t N>
150 constexpr size_t Size(const T (&array)[N]) noexcept
151 {
152  WS_UNUSED(array);
153  return N;
154 }
155 
168 template<class T, int ExpectedSize, int TSize = sizeof(T)>
169 static constexpr bool StaticCheckSize()
170 {
171  static_assert(ExpectedSize == TSize, "T has a bad size(see "
172  "StaticCheckEnsureSizeOf<T,ExpectedSize,ActualSize> in "
173  "error message)");
174  return true;
175 }
176 
177 } // namespace Utils
178 } // namespace WorldStone
#define WS_UNUSED(x)
Mark a variable as unused to shut warnings when it is unused on purpose.
Definition: SystemUtils.h:21
Platform specific tools and macros.