1 // license:GPL-2.0+ 2 // copyright-holders:Couriersud 3 4 #ifndef PTYPES_H_ 5 #define PTYPES_H_ 6 7 /// 8 /// \file ptypes.h 9 /// 10 11 #include "pconfig.h" 12 13 #include <limits> 14 #include <string> 15 #include <type_traits> 16 17 #if (PUSE_FLOAT128) 18 #if defined(__has_include) 19 #if __has_include(<quadmath.h>) 20 #include <quadmath.h> 21 #endif 22 #endif 23 #endif 24 25 // noexcept on move operator -> issue with macosx clang 26 #define PCOPYASSIGNMOVE(name, def) \ 27 PCOPYASSIGN(name, def) \ 28 PMOVEASSIGN(name, def) 29 30 #define PCOPYASSIGN(name, def) \ 31 name(const name &) = def; \ 32 name &operator=(const name &) = def; 33 34 #define PMOVEASSIGN(name, def) \ 35 name(name &&) /*noexcept*/ = def; \ 36 name &operator=(name &&) /*noexcept*/ = def; 37 38 #if defined(EMSCRIPTEN) 39 #undef EMSCRIPTEN 40 #endif 41 42 // ----------------------------------------------------------------------------- 43 // forward definitions 44 // ----------------------------------------------------------------------------- 45 46 namespace plib 47 { 48 template <typename BASEARENA, std::size_t MINALIGN> 49 class mempool_arena; 50 51 struct aligned_arena; 52 class dynlib_base; 53 54 template<bool debug_enabled> 55 class plog_base; 56 57 struct plog_level; 58 59 namespace detail 60 { 61 class token_store; 62 } // namespace detail 63 64 } // namespace plib 65 66 namespace plib 67 { 68 //============================================================ 69 // compile time information 70 //============================================================ 71 72 /// \brief Dummy 128 bit types for platforms which don't support 128 bit 73 /// 74 /// Users should always consult compile_info::has_int128 prior to 75 /// using the UINT128/INT128 data type. 76 /// 77 struct UINT128_DUMMY {}; 78 struct INT128_DUMMY {}; 79 80 enum class ci_compiler 81 { 82 UNKNOWN, 83 CLANG, 84 GCC, 85 MSC 86 }; 87 88 enum class ci_os 89 { 90 UNKNOWN, 91 LINUX, 92 FREEBSD, 93 OPENBSD, 94 WINDOWS, 95 MACOSX, 96 EMSCRIPTEN 97 }; 98 99 enum class ci_arch 100 { 101 UNKNOWN, 102 X86, 103 ARM, 104 MIPS 105 }; 106 107 struct compile_info 108 { 109 #ifdef _WIN32 110 using win32 = std::integral_constant<bool, true>; 111 #ifdef UNICODE 112 using unicode = std::integral_constant<bool, true>; 113 #else 114 using unicode = std::integral_constant<bool, false>; 115 #endif 116 #else 117 using win32 = std::integral_constant<bool, false>; 118 using unicode = std::integral_constant<bool, true>; 119 #endif 120 #ifdef __SIZEOF_INT128__ 121 using has_int128 = std::integral_constant<bool, true>; 122 using int128_type = __int128_t; 123 using uint128_type = __uint128_t; int128_maxcompile_info124 static constexpr int128_type int128_max() { return (~static_cast<uint128_type>(0)) >> 1; } uint128_maxcompile_info125 static constexpr uint128_type uint128_max() { return ~(static_cast<uint128_type>(0)); } 126 #else 127 using has_int128 = std::integral_constant<bool, false>; 128 using int128_type = INT128_DUMMY; 129 using uint128_type = UINT128_DUMMY; int128_maxcompile_info130 static constexpr int128_type int128_max() { return int128_type(); } uint128_maxcompile_info131 static constexpr uint128_type uint128_max() { return uint128_type(); } 132 #endif 133 #ifdef __clang__ 134 using type = std::integral_constant<ci_compiler, ci_compiler::CLANG>; 135 using version = std::integral_constant<int, (__clang_major__) * 100 + (__clang_minor__)>; 136 #elif defined(__GNUC__) 137 using type = std::integral_constant<ci_compiler, ci_compiler::GCC>; 138 using version = std::integral_constant<int, (__GNUC__) * 100 + (__GNUC_MINOR__)>; 139 #elif defined(_MSC_VER) 140 using type = std::integral_constant<ci_compiler, ci_compiler::MSC>; 141 using version = std::integral_constant<int, _MSC_VER>; 142 #else 143 using type = std::integral_constant<ci_compiler, ci_compiler::UNKNOWN>; 144 using version = std::integral_constant<int, 0>; 145 #endif 146 #ifdef __unix__ 147 using is_unix = std::integral_constant<bool, true>; 148 #else 149 using is_unix = std::integral_constant<bool, false>; 150 #endif 151 #if defined(__linux__) 152 using os = std::integral_constant<ci_os, ci_os::LINUX>; 153 #elif defined(__FreeBSD__) 154 using os = std::integral_constant<ci_os, ci_os::FREEBSD>; 155 #elif defined(__OpenBSD__) 156 using os = std::integral_constant<ci_os, ci_os::OPENBSD>; 157 #elif defined(__EMSCRIPTEN__) 158 using os = std::integral_constant<ci_os, ci_os::EMSCRIPTEN>; 159 #elif defined(_WIN32) 160 using os = std::integral_constant<ci_os, ci_os::WINDOWS>; 161 #elif defined(__APPLE__) 162 using os = std::integral_constant<ci_os, ci_os::MACOSX>; 163 #else 164 using os = std::integral_constant<ci_os, ci_os::UNKNOWN>; 165 #endif 166 #if defined(__x86_64__) || defined (_M_X64) || defined(__aarch64__) || defined(__mips64) || defined(_M_AMD64) || defined(_M_ARM64) 167 using m64 = std::integral_constant<bool, true>; 168 #else 169 using m64 = std::integral_constant<bool, false>; 170 #endif 171 #if defined(__x86_64__) || defined(__i386__) 172 using arch = std::integral_constant<ci_arch, ci_arch::X86>; 173 #elif defined(__arm__) || defined(__ARMEL__) || defined(__aarch64__) || defined(_M_ARM) 174 using arch = std::integral_constant<ci_arch, ci_arch::ARM>; 175 #elif defined(__MIPSEL__) || defined(__mips_isa_rev) || defined(__mips64) 176 using arch = std::integral_constant<ci_arch, ci_arch::MIPS>; 177 #else 178 using arch = std::integral_constant<ci_arch, ci_arch::UNKNOWN>; 179 #endif 180 #if defined(__MINGW32__) 181 using mingw = std::integral_constant<bool, true>; 182 #else 183 using mingw = std::integral_constant<bool, false>; 184 #endif 185 }; 186 187 } // namespace plib 188 189 using INT128 = plib::compile_info::int128_type; 190 using UINT128 = plib::compile_info::uint128_type; 191 192 namespace plib 193 { 194 195 template<typename T> struct is_integral : public std::is_integral<T> { }; 196 template<typename T> struct is_signed : public std::is_signed<T> { }; 197 template<typename T> struct is_unsigned : public std::is_unsigned<T> { }; 198 template<typename T> struct numeric_limits : public std::numeric_limits<T> { }; 199 200 // 128 bit support at least on GCC is not fully supported 201 202 template<> struct is_integral<UINT128> { static constexpr bool value = true; }; 203 template<> struct is_integral<INT128> { static constexpr bool value = true; }; 204 205 template<> struct is_signed<UINT128> { static constexpr bool value = false; }; 206 template<> struct is_signed<INT128> { static constexpr bool value = true; }; 207 208 template<> struct is_unsigned<UINT128> { static constexpr bool value = true; }; 209 template<> struct is_unsigned<INT128> { static constexpr bool value = false; }; 210 211 template<> struct numeric_limits<UINT128> 212 { 213 static constexpr UINT128 max() noexcept 214 { 215 return compile_info::uint128_max(); 216 } 217 }; 218 template<> struct numeric_limits<INT128> 219 { 220 static constexpr INT128 max() noexcept 221 { 222 return compile_info::int128_max(); 223 } 224 }; 225 226 template<typename T> struct is_floating_point : public std::is_floating_point<T> { }; 227 228 template< class T > 229 struct is_arithmetic : std::integral_constant<bool, 230 plib::is_integral<T>::value || plib::is_floating_point<T>::value> {}; 231 232 #if PUSE_FLOAT128 233 template<> struct is_floating_point<FLOAT128> { static constexpr bool value = true; }; 234 template<> struct numeric_limits<FLOAT128> 235 { 236 static constexpr FLOAT128 max() noexcept 237 { 238 return FLT128_MAX; 239 } 240 static constexpr FLOAT128 lowest() noexcept 241 { 242 return -FLT128_MAX; 243 } 244 }; 245 #endif 246 247 template<unsigned bits> 248 struct size_for_bits 249 { 250 static_assert(bits <= 64 || (bits <= 128 && compile_info::has_int128::value), "not supported"); 251 enum { value = 252 bits <= 8 ? 1 : 253 bits <= 16 ? 2 : 254 bits <= 32 ? 4 : 255 bits <= 64 ? 8 : 256 16 257 }; 258 }; 259 260 template<unsigned N> struct least_type_for_size; 261 template<> struct least_type_for_size<1> { using type = uint_least8_t; }; 262 template<> struct least_type_for_size<2> { using type = uint_least16_t; }; 263 template<> struct least_type_for_size<4> { using type = uint_least32_t; }; 264 template<> struct least_type_for_size<8> { using type = uint_least64_t; }; 265 template<> struct least_type_for_size<16> { using type = UINT128; }; 266 267 // This is different to the standard library. Mappings provided in stdint 268 // are not always fastest. 269 template<unsigned N> struct fast_type_for_size; 270 template<> struct fast_type_for_size<1> { using type = uint32_t; }; 271 template<> struct fast_type_for_size<2> { using type = uint32_t; }; 272 template<> struct fast_type_for_size<4> { using type = uint32_t; }; 273 template<> struct fast_type_for_size<8> { using type = uint_fast64_t; }; 274 template<> struct fast_type_for_size<16> { using type = UINT128; }; 275 276 template<unsigned bits> 277 struct least_type_for_bits 278 { 279 static_assert(bits <= 64 || (bits <= 128 && compile_info::has_int128::value), "not supported"); 280 using type = typename least_type_for_size<size_for_bits<bits>::value>::type; 281 }; 282 283 template<unsigned bits> 284 struct fast_type_for_bits 285 { 286 static_assert(bits <= 64 || (bits <= 128 && compile_info::has_int128::value), "not supported"); 287 using type = typename fast_type_for_size<size_for_bits<bits>::value>::type; 288 }; 289 290 /// \brief mark arguments as not used for compiler 291 /// 292 /// @tparam Ts unsused parameters 293 /// 294 template<typename... Ts> 295 inline void unused_var(Ts&&...) noexcept {} // NOLINT(readability-named-parameter) 296 297 /// \brief copy type S to type D byte by byte 298 /// 299 /// The purpose of this copy function is to suppress compiler warnings. 300 /// Use at your own risk. This is dangerous. 301 /// 302 /// \param s Source object 303 /// \param d Destination object 304 /// \tparam S Type of source object 305 /// \tparam D Type of destination object 306 template <typename S, typename D> 307 void reinterpret_copy(S &s, D &d) 308 { 309 static_assert(sizeof(D) >= sizeof(S), "size mismatch"); 310 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 311 auto *dp = reinterpret_cast<std::uint8_t *>(&d); 312 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 313 const auto *sp = reinterpret_cast<std::uint8_t *>(&s); 314 std::copy(sp, sp + sizeof(S), dp); 315 } 316 317 318 } // namespace plib 319 320 //============================================================ 321 // Define a "has member" trait. 322 //============================================================ 323 324 #define PDEFINE_HAS_MEMBER(name, member) \ 325 template <typename T> class name \ 326 { \ 327 template <typename U> static long test(decltype(&U:: member)); \ 328 template <typename U> static char test(...); \ 329 public: \ 330 static constexpr const bool value = sizeof(test<T>(nullptr)) == sizeof(long); \ 331 } 332 333 #endif // PTYPES_H_ 334