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