duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

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_ */