types.hpp (18788B)
1 #ifndef _C4_TYPES_HPP_ 2 #define _C4_TYPES_HPP_ 3 4 #include <stdint.h> 5 #include <stddef.h> 6 #include <type_traits> 7 8 #if __cplusplus >= 201103L 9 #include <utility> // for integer_sequence and friends 10 #endif 11 12 #include "c4/preprocessor.hpp" 13 #include "c4/language.hpp" 14 15 /** @file types.hpp basic types, and utility macros and traits for types. 16 * @ingroup basic_headers */ 17 18 /** @defgroup types Type utilities */ 19 20 namespace c4 { 21 22 /** @defgroup intrinsic_types Intrinsic types 23 * @ingroup types 24 * @{ */ 25 26 using cbyte = const char; /**< a constant byte */ 27 using byte = char; /**< a mutable byte */ 28 29 using i8 = int8_t; 30 using i16 = int16_t; 31 using i32 = int32_t; 32 using i64 = int64_t; 33 using u8 = uint8_t; 34 using u16 = uint16_t; 35 using u32 = uint32_t; 36 using u64 = uint64_t; 37 38 using f32 = float; 39 using f64 = double; 40 41 using ssize_t = typename std::make_signed<size_t>::type; 42 43 /** @} */ 44 45 //-------------------------------------------------- 46 47 /** @defgroup utility_types Utility types 48 * @ingroup types 49 * @{ */ 50 51 // some tag types 52 53 #if !defined(__clang__) && defined(__GNUC__) 54 #pragma GCC diagnostic push 55 #if __GNUC__ >= 6 56 #pragma GCC diagnostic ignored "-Wunused-const-variable" 57 #endif 58 #endif 59 60 /** a tag type for initializing the containers with variadic arguments a la 61 * initializer_list, minus the initializer_list overload problems. 62 */ 63 struct aggregate_t {}; 64 /** @see aggregate_t */ 65 constexpr const aggregate_t aggregate{}; 66 67 /** a tag type for specifying the initial capacity of allocatable contiguous storage */ 68 struct with_capacity_t {}; 69 /** @see with_capacity_t */ 70 constexpr const with_capacity_t with_capacity{}; 71 72 /** a tag type for disambiguating template parameter packs in variadic template overloads */ 73 struct varargs_t {}; 74 /** @see with_capacity_t */ 75 constexpr const varargs_t varargs{}; 76 77 #if !defined(__clang__) && defined(__GNUC__) 78 #pragma GCC diagnostic pop 79 #endif 80 81 82 //-------------------------------------------------- 83 84 /** whether a value should be used in place of a const-reference in argument passing. */ 85 template<class T> 86 struct cref_uses_val 87 { 88 enum { value = ( 89 std::is_scalar<T>::value 90 || 91 ( 92 #if C4_CPP >= 20 93 (std::is_trivially_copyable<T>::value && std::is_standard_layout<T>::value) 94 #else 95 std::is_pod<T>::value 96 #endif 97 && 98 sizeof(T) <= sizeof(size_t))) }; 99 }; 100 /** utility macro to override the default behaviour for c4::fastcref<T> 101 @see fastcref */ 102 #define C4_CREF_USES_VAL(T) \ 103 template<> \ 104 struct cref_uses_val<T> \ 105 { \ 106 enum { value = true }; \ 107 }; 108 109 /** Whether to use pass-by-value or pass-by-const-reference in a function argument 110 * or return type. */ 111 template<class T> 112 using fastcref = typename std::conditional<c4::cref_uses_val<T>::value, T, T const&>::type; 113 114 //-------------------------------------------------- 115 116 /** Just what its name says. Useful sometimes as a default empty policy class. */ 117 struct EmptyStruct 118 { 119 template<class... T> EmptyStruct(T && ...){} 120 }; 121 122 /** Just what its name says. Useful sometimes as a default policy class to 123 * be inherited from. */ 124 struct EmptyStructVirtual 125 { 126 virtual ~EmptyStructVirtual() = default; 127 template<class... T> EmptyStructVirtual(T && ...){} 128 }; 129 130 131 /** */ 132 template<class T> 133 struct inheritfrom : public T {}; 134 135 //-------------------------------------------------- 136 // Utilities to make a class obey size restrictions (eg, min size or size multiple of). 137 // DirectX usually makes this restriction with uniform buffers. 138 // This is also useful for padding to prevent false-sharing. 139 140 /** how many bytes must be added to size such that the result is at least minsize? */ 141 C4_ALWAYS_INLINE constexpr size_t min_remainder(size_t size, size_t minsize) noexcept 142 { 143 return size < minsize ? minsize-size : 0; 144 } 145 146 /** how many bytes must be added to size such that the result is a multiple of multipleof? */ 147 C4_ALWAYS_INLINE constexpr size_t mult_remainder(size_t size, size_t multipleof) noexcept 148 { 149 return (((size % multipleof) != 0) ? (multipleof-(size % multipleof)) : 0); 150 } 151 152 /* force the following class to be tightly packed. */ 153 #pragma pack(push, 1) 154 /** pad a class with more bytes at the end. 155 * @see http://stackoverflow.com/questions/21092415/force-c-structure-to-pack-tightly */ 156 template<class T, size_t BytesToPadAtEnd> 157 struct Padded : public T 158 { 159 using T::T; 160 using T::operator=; 161 Padded(T const& val) : T(val) {} 162 Padded(T && val) : T(val) {} 163 char ___c4padspace___[BytesToPadAtEnd]; 164 }; 165 #pragma pack(pop) 166 /** When the padding argument is 0, we cannot declare the char[] array. */ 167 template<class T> 168 struct Padded<T, 0> : public T 169 { 170 using T::T; 171 using T::operator=; 172 Padded(T const& val) : T(val) {} 173 Padded(T && val) : T(val) {} 174 }; 175 176 /** make T have a size which is at least Min bytes */ 177 template<class T, size_t Min> 178 using MinSized = Padded<T, min_remainder(sizeof(T), Min)>; 179 180 /** make T have a size which is a multiple of Mult bytes */ 181 template<class T, size_t Mult> 182 using MultSized = Padded<T, mult_remainder(sizeof(T), Mult)>; 183 184 /** make T have a size which is simultaneously: 185 * -bigger or equal than Min 186 * -a multiple of Mult */ 187 template<class T, size_t Min, size_t Mult> 188 using MinMultSized = MultSized<MinSized<T, Min>, Mult>; 189 190 /** make T be suitable for use as a uniform buffer. (at least with DirectX). */ 191 template<class T> 192 using UbufSized = MinMultSized<T, 64, 16>; 193 194 195 //----------------------------------------------------------------------------- 196 197 #define C4_NO_COPY_CTOR(ty) ty(ty const&) = delete 198 #define C4_NO_MOVE_CTOR(ty) ty(ty &&) = delete 199 #define C4_NO_COPY_ASSIGN(ty) ty& operator=(ty const&) = delete 200 #define C4_NO_MOVE_ASSIGN(ty) ty& operator=(ty &&) = delete 201 #define C4_DEFAULT_COPY_CTOR(ty) ty(ty const&) noexcept = default 202 #define C4_DEFAULT_MOVE_CTOR(ty) ty(ty &&) noexcept = default 203 #define C4_DEFAULT_COPY_ASSIGN(ty) ty& operator=(ty const&) noexcept = default 204 #define C4_DEFAULT_MOVE_ASSIGN(ty) ty& operator=(ty &&) noexcept = default 205 206 #define C4_NO_COPY_OR_MOVE_CTOR(ty) \ 207 C4_NO_COPY_CTOR(ty); \ 208 C4_NO_MOVE_CTOR(ty) 209 210 #define C4_NO_COPY_OR_MOVE_ASSIGN(ty) \ 211 C4_NO_COPY_ASSIGN(ty); \ 212 C4_NO_MOVE_ASSIGN(ty) 213 214 #define C4_NO_COPY_OR_MOVE(ty) \ 215 C4_NO_COPY_OR_MOVE_CTOR(ty); \ 216 C4_NO_COPY_OR_MOVE_ASSIGN(ty) 217 218 #define C4_DEFAULT_COPY_AND_MOVE_CTOR(ty) \ 219 C4_DEFAULT_COPY_CTOR(ty); \ 220 C4_DEFAULT_MOVE_CTOR(ty) 221 222 #define C4_DEFAULT_COPY_AND_MOVE_ASSIGN(ty) \ 223 C4_DEFAULT_COPY_ASSIGN(ty); \ 224 C4_DEFAULT_MOVE_ASSIGN(ty) 225 226 #define C4_DEFAULT_COPY_AND_MOVE(ty) \ 227 C4_DEFAULT_COPY_AND_MOVE_CTOR(ty); \ 228 C4_DEFAULT_COPY_AND_MOVE_ASSIGN(ty) 229 230 /** @see https://en.cppreference.com/w/cpp/named_req/TriviallyCopyable */ 231 #define C4_MUST_BE_TRIVIAL_COPY(ty) \ 232 static_assert(std::is_trivially_copyable<ty>::value, #ty " must be trivially copyable") 233 234 /** @} */ 235 236 237 //----------------------------------------------------------------------------- 238 239 /** @defgroup traits_types Type traits utilities 240 * @ingroup types 241 * @{ */ 242 243 // http://stackoverflow.com/questions/10821380/is-t-an-instance-of-a-template-in-c 244 template<template<typename...> class X, typename T> struct is_instance_of_tpl : std::false_type {}; 245 template<template<typename...> class X, typename... Y> struct is_instance_of_tpl<X, X<Y...>> : std::true_type {}; 246 247 //----------------------------------------------------------------------------- 248 249 /** SFINAE. use this macro to enable a template function overload 250 based on a compile-time condition. 251 @code 252 // define an overload for a non-pod type 253 template<class T, C4_REQUIRE_T(std::is_pod<T>::value)> 254 void foo() { std::cout << "pod type\n"; } 255 256 // define an overload for a non-pod type 257 template<class T, C4_REQUIRE_T(!std::is_pod<T>::value)> 258 void foo() { std::cout << "nonpod type\n"; } 259 260 struct non_pod 261 { 262 non_pod() : name("asdfkjhasdkjh") {} 263 const char *name; 264 }; 265 266 int main() 267 { 268 foo<float>(); // prints "pod type" 269 foo<non_pod>(); // prints "nonpod type" 270 } 271 @endcode */ 272 #define C4_REQUIRE_T(cond) typename std::enable_if<cond, bool>::type* = nullptr 273 274 /** enable_if for a return type 275 * @see C4_REQUIRE_T */ 276 #define C4_REQUIRE_R(cond, type_) typename std::enable_if<cond, type_>::type 277 278 //----------------------------------------------------------------------------- 279 /** define a traits class reporting whether a type provides a member typedef */ 280 #define C4_DEFINE_HAS_TYPEDEF(member_typedef) \ 281 template<typename T> \ 282 struct has_##stype \ 283 { \ 284 private: \ 285 \ 286 typedef char yes; \ 287 typedef struct { char array[2]; } no; \ 288 \ 289 template<typename C> \ 290 static yes _test(typename C::member_typedef*); \ 291 \ 292 template<typename C> \ 293 static no _test(...); \ 294 \ 295 public: \ 296 \ 297 enum { value = (sizeof(_test<T>(0)) == sizeof(yes)) }; \ 298 \ 299 } 300 301 302 /** @} */ 303 304 305 //----------------------------------------------------------------------------- 306 307 308 /** @defgroup type_declarations Type declaration utilities 309 * @ingroup types 310 * @{ */ 311 312 #define _c4_DEFINE_ARRAY_TYPES_WITHOUT_ITERATOR(T, I) \ 313 \ 314 using size_type = I; \ 315 using ssize_type = typename std::make_signed<I>::type; \ 316 using difference_type = typename std::make_signed<I>::type; \ 317 \ 318 using value_type = T; \ 319 using pointer = T*; \ 320 using const_pointer = T const*; \ 321 using reference = T&; \ 322 using const_reference = T const& 323 324 #define _c4_DEFINE_TUPLE_ARRAY_TYPES_WITHOUT_ITERATOR(interior_types, I) \ 325 \ 326 using size_type = I; \ 327 using ssize_type = typename std::make_signed<I>::type; \ 328 using difference_type = typename std::make_signed<I>::type; \ 329 \ 330 template<I n> using value_type = typename std::tuple_element< n, std::tuple<interior_types...>>::type; \ 331 template<I n> using pointer = value_type<n>*; \ 332 template<I n> using const_pointer = value_type<n> const*; \ 333 template<I n> using reference = value_type<n>&; \ 334 template<I n> using const_reference = value_type<n> const& 335 336 337 #define _c4_DEFINE_ARRAY_TYPES(T, I) \ 338 \ 339 _c4_DEFINE_ARRAY_TYPES_WITHOUT_ITERATOR(T, I); \ 340 \ 341 using iterator = T*; \ 342 using const_iterator = T const*; \ 343 using reverse_iterator = std::reverse_iterator<T*>; \ 344 using const_reverse_iterator = std::reverse_iterator<T const*> 345 346 347 #define _c4_DEFINE_TUPLE_ARRAY_TYPES(interior_types, I) \ 348 \ 349 _c4_DEFINE_TUPLE_ARRAY_TYPES_WITHOUT_ITERATOR(interior_types, I); \ 350 \ 351 template<I n> using iterator = value_type<n>*; \ 352 template<I n> using const_iterator = value_type<n> const*; \ 353 template<I n> using reverse_iterator = std::reverse_iterator< value_type<n>*>; \ 354 template<I n> using const_reverse_iterator = std::reverse_iterator< value_type<n> const*> 355 356 357 358 /** @} */ 359 360 361 //----------------------------------------------------------------------------- 362 363 364 /** @defgroup compatility_utilities Backport implementation of some Modern C++ utilities 365 * @ingroup types 366 * @{ */ 367 368 //----------------------------------------------------------------------------- 369 // index_sequence and friends are available only for C++14 and later. 370 // A C++11 implementation is provided here. 371 // This implementation was copied over from clang. 372 // see http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 373 374 #if __cplusplus > 201103L 375 376 using std::integer_sequence; 377 using std::index_sequence; 378 using std::make_integer_sequence; 379 using std::make_index_sequence; 380 using std::index_sequence_for; 381 382 #else 383 384 /** C++11 implementation of integer sequence 385 * @see https://en.cppreference.com/w/cpp/utility/integer_sequence 386 * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ 387 template<class _Tp, _Tp... _Ip> 388 struct integer_sequence 389 { 390 static_assert(std::is_integral<_Tp>::value, 391 "std::integer_sequence can only be instantiated with an integral type" ); 392 using value_type = _Tp; 393 static constexpr size_t size() noexcept { return sizeof...(_Ip); } 394 }; 395 396 /** C++11 implementation of index sequence 397 * @see https://en.cppreference.com/w/cpp/utility/integer_sequence 398 * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ 399 template<size_t... _Ip> 400 using index_sequence = integer_sequence<size_t, _Ip...>; 401 402 /** @cond DONT_DOCUMENT_THIS */ 403 namespace __detail { 404 405 template<typename _Tp, size_t ..._Extra> 406 struct __repeat; 407 408 template<typename _Tp, _Tp ..._Np, size_t ..._Extra> 409 struct __repeat<integer_sequence<_Tp, _Np...>, _Extra...> 410 { 411 using type = integer_sequence<_Tp, 412 _Np..., 413 sizeof...(_Np) + _Np..., 414 2 * sizeof...(_Np) + _Np..., 415 3 * sizeof...(_Np) + _Np..., 416 4 * sizeof...(_Np) + _Np..., 417 5 * sizeof...(_Np) + _Np..., 418 6 * sizeof...(_Np) + _Np..., 419 7 * sizeof...(_Np) + _Np..., 420 _Extra...>; 421 }; 422 423 template<size_t _Np> struct __parity; 424 template<size_t _Np> struct __make : __parity<_Np % 8>::template __pmake<_Np> {}; 425 426 template<> struct __make<0> { using type = integer_sequence<size_t>; }; 427 template<> struct __make<1> { using type = integer_sequence<size_t, 0>; }; 428 template<> struct __make<2> { using type = integer_sequence<size_t, 0, 1>; }; 429 template<> struct __make<3> { using type = integer_sequence<size_t, 0, 1, 2>; }; 430 template<> struct __make<4> { using type = integer_sequence<size_t, 0, 1, 2, 3>; }; 431 template<> struct __make<5> { using type = integer_sequence<size_t, 0, 1, 2, 3, 4>; }; 432 template<> struct __make<6> { using type = integer_sequence<size_t, 0, 1, 2, 3, 4, 5>; }; 433 template<> struct __make<7> { using type = integer_sequence<size_t, 0, 1, 2, 3, 4, 5, 6>; }; 434 435 template<> struct __parity<0> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type> {}; }; 436 template<> struct __parity<1> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 1> {}; }; 437 template<> struct __parity<2> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 2, _Np - 1> {}; }; 438 template<> struct __parity<3> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 3, _Np - 2, _Np - 1> {}; }; 439 template<> struct __parity<4> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; }; 440 template<> struct __parity<5> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; }; 441 template<> struct __parity<6> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 6, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; }; 442 template<> struct __parity<7> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 7, _Np - 6, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; }; 443 444 template<typename _Tp, typename _Up> 445 struct __convert 446 { 447 template<typename> struct __result; 448 template<_Tp ..._Np> struct __result<integer_sequence<_Tp, _Np...>> 449 { 450 using type = integer_sequence<_Up, _Np...>; 451 }; 452 }; 453 454 template<typename _Tp> 455 struct __convert<_Tp, _Tp> 456 { 457 template<typename _Up> struct __result 458 { 459 using type = _Up; 460 }; 461 }; 462 463 template<typename _Tp, _Tp _Np> 464 using __make_integer_sequence_unchecked = typename __detail::__convert<size_t, _Tp>::template __result<typename __detail::__make<_Np>::type>::type; 465 466 template<class _Tp, _Tp _Ep> 467 struct __make_integer_sequence 468 { 469 static_assert(std::is_integral<_Tp>::value, 470 "std::make_integer_sequence can only be instantiated with an integral type" ); 471 static_assert(0 <= _Ep, "std::make_integer_sequence input shall not be negative"); 472 typedef __make_integer_sequence_unchecked<_Tp, _Ep> type; 473 }; 474 475 } // namespace __detail 476 /** @endcond */ 477 478 479 /** C++11 implementation of index sequence 480 * @see https://en.cppreference.com/w/cpp/utility/integer_sequence 481 * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ 482 template<class _Tp, _Tp _Np> 483 using make_integer_sequence = typename __detail::__make_integer_sequence<_Tp, _Np>::type; 484 485 /** C++11 implementation of index sequence 486 * @see https://en.cppreference.com/w/cpp/utility/integer_sequence 487 * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ 488 template<size_t _Np> 489 using make_index_sequence = make_integer_sequence<size_t, _Np>; 490 491 /** C++11 implementation of index sequence 492 * @see https://en.cppreference.com/w/cpp/utility/integer_sequence 493 * @see taken from clang: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?revision=211563&view=markup#l687 */ 494 template<class... _Tp> 495 using index_sequence_for = make_index_sequence<sizeof...(_Tp)>; 496 #endif 497 498 /** @} */ 499 500 501 } // namespace c4 502 503 #endif /* _C4_TYPES_HPP_ */