// This file is part of the uSTL library, an STL implementation. // // Copyright (c) 2005 by Mike Sharov // This file is free software, distributed under the MIT License. #pragma once #include "utypes.h" #if HAVE_CPP11 namespace ustl { //{{{ Helper templates and specs --------------------------------------- /// true or false templatized constant for metaprogramming template struct integral_constant { using value_type = T; using type = integral_constant; static constexpr const T value = v; constexpr operator value_type() const { return value; } constexpr T operator()() const { return value; } }; template constexpr const T integral_constant::value; using true_type = integral_constant; using false_type = integral_constant; /// Selects type = flag ? T : U template struct conditional { using type = T; }; template struct conditional { using type = U; }; template using conditional_t = typename conditional::type; /// Selects bool = flag ? T : U template struct t_if : public integral_constant {}; template struct t_if : public integral_constant {}; template struct enable_if { }; template struct enable_if { using type = T; }; template using enable_if_t = typename enable_if::type; #define UNARY_TRAIT_DEFB(name,condition) \ template struct name : public integral_constant {} #define UNARY_TRAIT_DEFN(name) \ template struct name : public false_type {} #define UNARY_TRAIT_TRUE(name,type) \ template <> struct name : public true_type {} //}}}------------------------------------------------------------------- //{{{ Type modifications template struct remove_const { using type = T; }; template struct remove_const { using type = T; }; template using remove_const_t = typename remove_const::type; template struct remove_volatile { using type = T; }; template struct remove_volatile{ using type = T; }; template using remove_volatile_t = typename remove_volatile::type; template struct remove_cv { using type = remove_volatile_t>; }; template using remove_cv_t = typename remove_cv::type; template struct add_const { using type = T const; }; template struct add_const { using type = T const; }; template using add_const_t = typename add_const::type; template constexpr add_const_t& as_const (T& v) { return v; } template void as_const(const T&&) = delete; template struct add_volatile { using type = T volatile; }; template struct add_volatile { using type = T volatile; }; template using add_volatile_t = typename add_volatile::type; template struct add_cv { using type = add_volatile_t>; }; template using add_cv_t = typename add_cv::type; template struct remove_reference { using type = T; }; template struct remove_reference { using type = T; }; template struct remove_reference { using type = T; }; template using remove_reference_t = typename remove_reference::type; template struct remove_pointer { using type = T; }; template struct remove_pointer { using type = T; }; template using remove_pointer_t = typename remove_pointer::type; template struct add_pointer { using type = T*; }; template struct add_pointer { using type = T*; }; template using add_pointer_t = typename add_pointer::type; template struct remove_extent { using type = T; }; template struct remove_extent { using type = T; }; template struct remove_extent { using type = T; }; template using remove_extent_t = typename remove_extent::type; template struct remove_all_extents { using type = T; }; template struct remove_all_extents { using type = typename remove_all_extents::type; }; template struct remove_all_extents { using type = typename remove_all_extents::type; }; template using remove_all_extents_t = typename remove_all_extents::type; template struct underlying_type { using type = __underlying_type(T); }; template using underlying_type_t = typename underlying_type::type; #if HAVE_CPP14 template using void_t = void; #endif template struct make_signed { using type = T; }; template <> struct make_signed { using type = signed char; }; template <> struct make_signed { using type = signed char; }; template <> struct make_signed { using type = signed short; }; template <> struct make_signed { using type = signed int; }; template <> struct make_signed { using type = signed long; }; #if HAVE_LONG_LONG template <> struct make_signed { using type = signed long long; }; #endif template using make_signed_t = typename make_signed::type; template struct make_unsigned { using type = T; }; template <> struct make_unsigned { using type = unsigned char; }; template <> struct make_unsigned { using type = unsigned char; }; template <> struct make_unsigned { using type = unsigned short; }; template <> struct make_unsigned { using type = unsigned int; }; template <> struct make_unsigned { using type = unsigned long; }; #if HAVE_LONG_LONG template <> struct make_unsigned { using type = unsigned long long; }; #endif template using make_unsigned_t = typename make_unsigned::type; //}}}------------------------------------------------------------------- //{{{ Primary type categories #if __clang__ // clang already has these __is_ helpers as builtins UNARY_TRAIT_DEFB (is_void, __is_void(remove_cv_t)); UNARY_TRAIT_DEFB (is_integral, __is_integral(remove_cv_t)); UNARY_TRAIT_DEFB (is_signed, __is_signed(remove_cv_t)); UNARY_TRAIT_DEFB (is_floating_point, __is_floating_point(remove_cv_t)); UNARY_TRAIT_DEFB (is_pointer, __is_pointer(remove_cv_t)); UNARY_TRAIT_DEFB (is_member_pointer, __is_member_pointer(remove_cv_t)); UNARY_TRAIT_DEFB (is_member_function_pointer, __is_member_function_pointer(remove_cv_t)); #else UNARY_TRAIT_DEFN (__is_void); UNARY_TRAIT_TRUE (__is_void, void); UNARY_TRAIT_DEFB (is_void, __is_void>::value); UNARY_TRAIT_DEFN (__is_integral); UNARY_TRAIT_TRUE (__is_integral, char); #if HAVE_THREE_CHAR_TYPES UNARY_TRAIT_TRUE (__is_integral, signed char); #endif UNARY_TRAIT_TRUE (__is_integral, short); UNARY_TRAIT_TRUE (__is_integral, int); UNARY_TRAIT_TRUE (__is_integral, long); UNARY_TRAIT_TRUE (__is_integral, unsigned char); UNARY_TRAIT_TRUE (__is_integral, unsigned short); UNARY_TRAIT_TRUE (__is_integral, unsigned int); UNARY_TRAIT_TRUE (__is_integral, unsigned long); #if HAVE_LONG_LONG UNARY_TRAIT_TRUE (__is_integral, long long); UNARY_TRAIT_TRUE (__is_integral, unsigned long long); #endif UNARY_TRAIT_TRUE (__is_integral, wchar_t); UNARY_TRAIT_TRUE (__is_integral, bool); UNARY_TRAIT_DEFB (is_integral, __is_integral>::value); UNARY_TRAIT_DEFN (__is_signed); UNARY_TRAIT_TRUE (__is_signed, char); UNARY_TRAIT_TRUE (__is_signed, wchar_t); UNARY_TRAIT_TRUE (__is_signed, short); UNARY_TRAIT_TRUE (__is_signed, int); UNARY_TRAIT_TRUE (__is_signed, long); UNARY_TRAIT_TRUE (__is_signed, long long); UNARY_TRAIT_DEFB (is_signed, __is_signed>::value); UNARY_TRAIT_DEFN (__is_floating_point); //UNARY_TRAIT_TRUE (__is_floating_point, float); //UNARY_TRAIT_TRUE (__is_floating_point, double); //UNARY_TRAIT_TRUE (__is_floating_point, long double); UNARY_TRAIT_DEFB (is_floating_point, __is_floating_point>::value); template struct __is_pointer : public false_type {}; template struct __is_pointer : public true_type {}; template struct is_pointer : public __is_pointer> {}; UNARY_TRAIT_DEFN (__is_member_pointer); template struct __is_member_pointer : public true_type {}; UNARY_TRAIT_DEFB (is_member_pointer, __is_member_pointer>::value); UNARY_TRAIT_DEFN (__is_member_function_pointer); template struct __is_member_function_pointer : public true_type {}; template struct __is_member_function_pointer : public true_type {}; template struct __is_member_function_pointer : public true_type {}; template struct __is_member_function_pointer : public true_type {}; UNARY_TRAIT_DEFB (is_member_function_pointer, __is_member_function_pointer>::value); #endif // __clang__ UNARY_TRAIT_DEFB (is_unsigned, !is_signed::value); UNARY_TRAIT_DEFB (is_member_object_pointer, is_member_pointer::value && !is_member_function_pointer::value); UNARY_TRAIT_DEFN (is_array); UNARY_TRAIT_DEFN (is_lvalue_reference); template struct is_lvalue_reference : public true_type {}; UNARY_TRAIT_DEFN (is_rvalue_reference); template struct is_rvalue_reference : public true_type {}; UNARY_TRAIT_DEFB (is_reference, is_lvalue_reference::value || is_rvalue_reference::value); template struct is_array : public true_type {}; template struct is_array : public true_type {}; UNARY_TRAIT_DEFB (is_union, __is_union(T)); UNARY_TRAIT_DEFB (is_class, __is_class(T)); UNARY_TRAIT_DEFB (is_enum, __is_enum(T)); UNARY_TRAIT_DEFN (is_function); template struct is_function : public true_type { }; template struct is_function : public true_type { }; template struct is_function : public true_type { }; template struct is_function : public true_type { }; template struct is_function : public true_type { }; template struct is_function : public true_type { }; template struct is_function : public true_type { }; template struct is_function : public true_type { }; template struct is_function : public true_type { }; template struct is_function : public true_type { }; template struct is_function : public true_type { }; template struct is_function : public true_type { }; template struct is_function : public true_type { }; template struct is_function : public true_type { }; template struct is_function : public true_type { }; template struct is_function : public true_type { }; template struct is_function : public true_type { }; template struct is_function : public true_type { }; template struct is_function : public true_type { }; template struct is_function : public true_type { }; template struct is_function : public true_type { }; template struct is_function : public true_type { }; template struct is_function : public true_type { }; template struct is_function : public true_type { }; UNARY_TRAIT_DEFB (is_object, !is_reference::value && !is_void::value && !is_function::value); UNARY_TRAIT_DEFB (__is_referenceable, is_reference::value || is_object::value); template struct __is_referenceable : public true_type {}; template struct __is_referenceable : public true_type {}; //}}}------------------------------------------------------------------- //{{{ Composite type categories UNARY_TRAIT_DEFB (is_arithmetic, is_integral::value || is_floating_point::value); UNARY_TRAIT_DEFB (is_fundamental, is_arithmetic::value || is_void::value); UNARY_TRAIT_DEFB (is_scalar, is_arithmetic::value || is_enum::value || is_pointer::value || is_member_pointer::value); UNARY_TRAIT_DEFB (is_compound, !is_fundamental::value); template ::value> struct __add_lvalue_reference { using type = T; }; template struct __add_lvalue_reference { using type = T&; }; template struct add_lvalue_reference : public __add_lvalue_reference {}; template using add_lvalue_reference_t = typename add_lvalue_reference::type; template ::value> struct __add_rvalue_reference { using type = T; }; template struct __add_rvalue_reference { using type = T&&; }; template struct add_rvalue_reference : public __add_rvalue_reference {}; template using add_rvalue_reference_t = typename add_rvalue_reference::type; /// Unusable default value for T. Use with decltype. template add_rvalue_reference_t declval (void) noexcept; //}}}------------------------------------------------------------------- //{{{ Type properties UNARY_TRAIT_DEFN (is_const); template struct is_const : public true_type {}; UNARY_TRAIT_DEFN (is_volatile); template struct is_volatile : public true_type {}; UNARY_TRAIT_DEFB (is_empty, __is_empty(T)); UNARY_TRAIT_DEFB (is_abstract, __is_abstract(T)); UNARY_TRAIT_DEFB (is_literal_type, __is_literal_type(T)); UNARY_TRAIT_DEFB (is_polymorphic, __is_polymorphic(T)); #if HAVE_CPP14 UNARY_TRAIT_DEFB (is_final, __is_final(T)); #endif UNARY_TRAIT_DEFB (is_standard_layout, __is_standard_layout(T)); UNARY_TRAIT_DEFB (is_pod, __is_pod(T) || is_scalar::value || (is_array::value && is_scalar>::value)); UNARY_TRAIT_DEFB (has_unique_object_representations, is_pod::value); UNARY_TRAIT_DEFB (is_trivial, is_pod::value || __is_trivial(T)); UNARY_TRAIT_DEFB (is_swappable, is_trivial::value); UNARY_TRAIT_DEFB (is_nothrow_swappable, is_trivial::value); UNARY_TRAIT_DEFB (has_trivial_copy, is_pod::value || __has_trivial_copy(T)); UNARY_TRAIT_DEFB (has_trivial_assign, is_pod::value || __has_trivial_assign(T)); UNARY_TRAIT_DEFB (has_trivial_constructor, is_pod::value || __has_trivial_constructor(T)); UNARY_TRAIT_DEFB (has_trivial_destructor, is_pod::value || __has_trivial_destructor(T)); UNARY_TRAIT_DEFB (has_virtual_destructor, __has_virtual_destructor(T)); UNARY_TRAIT_DEFB (has_nothrow_assign, __has_nothrow_assign(T)); UNARY_TRAIT_DEFB (has_nothrow_copy, __has_nothrow_copy(T)); UNARY_TRAIT_DEFB (has_nothrow_constructor, __has_nothrow_constructor(T)); template struct alignment_of : public integral_constant {}; template struct rank : public integral_constant {}; template struct rank : public integral_constant::value> {}; template struct rank : public integral_constant::value> {}; template struct extent { static constexpr const size_t value = 0; }; template struct extent { static constexpr const size_t value = I ? extent::value : 0; }; template struct extent { static constexpr const size_t value = I ? extent::value : N; }; template ::value, bool IsFunction = is_function::value> struct __decay; template struct __decay { using type = remove_cv_t; }; template struct __decay { using type = remove_extent_t*; }; template struct __decay { using type = add_pointer_t; }; template struct decay : public __decay> {}; template using decay_t = typename decay::type; template struct common_type; template struct common_type { using type = decay_t; }; template using common_type_t = typename common_type::type; template struct common_type { using type = decay_t() : declval())>; }; template struct common_type { using type = common_type_t, V...>; }; //}}}------------------------------------------------------------------- //{{{ Constructability and destructability // All these use the standard SFINAE technique struct __is_destructible { template ().~T())> static true_type test (int); template static false_type test (...); }; template struct is_destructible : public decltype(__is_destructible::test(0)) {}; struct __is_nothrow_destructible { template static integral_constant().~T())> test (int); template static false_type test (...); }; template struct is_nothrow_destructible : public decltype(__is_nothrow_destructible::test(0)) {}; struct __is_default_constructible { template static true_type test (int); template static false_type test (...); }; template struct is_default_constructible : public decltype(__is_default_constructible::test(0)) {}; struct __is_nothrow_default_constructible { template static integral_constant test (int); template static false_type test (...); }; template struct is_nothrow_default_constructible : public decltype(__is_nothrow_default_constructible::test(0)) {}; template struct is_constructible : public is_default_constructible {}; template struct is_nothrow_constructible : public is_nothrow_default_constructible {}; struct __is_copy_constructible { template ()))> static true_type test (int); template static false_type test (...); }; template struct is_copy_constructible : public decltype(__is_copy_constructible::test(0)) {}; struct __is_move_constructible { template ()))> static true_type test (int); template static false_type test (...); }; template struct is_move_constructible : public decltype(__is_move_constructible::test(0)) {}; #if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 9) || __GNUC__ >= 8 template struct is_assignable : public integral_constant {}; #else struct __is_assignable { template () = declval())> static true_type test (int); template static false_type test (...); }; template struct is_assignable : public decltype(__is_assignable::test(0)) {}; #endif template struct is_copy_assignable : public is_assignable {}; template struct is_move_assignable : public is_assignable {}; // TODO: later template struct is_nothrow_copy_constructible : public false_type {}; template struct is_nothrow_move_constructible : public false_type {}; template struct is_nothrow_assignable : public false_type {}; template struct is_nothrow_copy_assignable : public false_type {}; template struct is_nothrow_move_assignable : public false_type {}; #if __GNUC__ >= 5 UNARY_TRAIT_DEFB (is_trivially_copyable, __is_trivially_copyable(T)); template struct is_trivially_constructible : public integral_constant {}; template struct is_trivially_copy_constructible : public integral_constant::value && __is_trivially_constructible(T, const T&)> {}; template struct is_trivially_move_constructible : public integral_constant::value && __is_trivially_constructible(T, T&&)> {}; template struct is_trivially_assignable : public integral_constant {}; UNARY_TRAIT_DEFB (is_trivially_default_constructible, __is_trivially_constructible(T)); UNARY_TRAIT_DEFB (is_trivially_copy_assignable, __is_trivially_assignable(T,const T&)); UNARY_TRAIT_DEFB (is_trivially_move_assignable, __is_trivially_assignable(T,T&&)); #else UNARY_TRAIT_DEFB (is_trivially_copyable, __has_trivial_copy(T)); UNARY_TRAIT_DEFB (is_trivially_default_constructible, __has_trivial_constructor(T)); UNARY_TRAIT_DEFB (is_trivially_copy_assignable, __has_trivial_assign(T)); UNARY_TRAIT_DEFB (is_trivially_move_assignable, false); #endif UNARY_TRAIT_DEFB (is_trivially_destructible, __has_trivial_destructor(T)); UNARY_TRAIT_DEFB (has_trivial_copy_constructor, __has_trivial_copy(T)); UNARY_TRAIT_DEFB (has_trivial_copy_assign, __has_trivial_assign(T)); //}}}------------------------------------------------------------------- //{{{ Type relations template struct is_same : public false_type {}; template struct is_same : public true_type {}; #if __clang__ // clang has __is_convertible builtin template struct is_convertible : public integral_constant {}; #else template ::value || is_function::value || is_array::value> class __is_convertible : public integral_constant::value> {}; template class __is_convertible { template static void __test_aux(TT); template (declval()))> static true_type __test(int); template static false_type __test(...); public: using type = decltype(__test(0)); }; template struct is_convertible : public __is_convertible::type {}; #endif template struct is_swappable_with : public integral_constant::value && is_convertible::value> {}; template struct is_nothrow_swappable_with : public integral_constant::value && is_convertible::value> {}; /// Defines a has_member_function_name template where has_member_function_name::value is true when O::name exists /// Example: HAS_MEMBER_FUNCTION(read, void (O::*)(istream&)); has_member_function_read>::value == true #define HAS_MEMBER_FUNCTION(name, signature) \ template \ class __has_member_function_##name { \ template struct test_for_##name {};\ template static true_type found (test_for_##name*);\ template static false_type found (...);\ public: \ using type = decltype(found(nullptr)); \ }; \ template \ struct has_member_function_##name : public __has_member_function_##name::type {} /// Defines a has_static_member_variable template where has_static_member_variable_name::value is true when O::name exists /// Example: HAS_STATIC_MEMBER_VARIABLE(int, _val); has_static_member_variable__val::value == true #define HAS_STATIC_MEMBER_VARIABLE(varT,name) \ template \ class __has_static_member_variable_##name { \ template > V> struct test_for_##name {};\ template static true_type found (test_for_##name*);\ template static false_type found (...);\ public: \ using type = decltype(found(nullptr)); \ }; \ template \ struct has_static_member_variable_##name : public __has_static_member_variable_##name::type {} template struct is_base_of { static constexpr const bool value = __is_base_of(T,U); }; template struct is_base_of : public false_type {}; template struct is_base_of : public false_type {}; template struct aligned_storage { struct type { alignas(Grain) unsigned char _data[Size]; }; }; //}}}------------------------------------------------------------------- //{{{ Helper templates and specs #undef UNARY_TRAIT_DEFN #undef UNARY_TRAIT_DEFB #define POD_CLASS(T) namespace ustl { UNARY_TRAIT_TRUE(is_pod,T); } //}}} } // namespace ustl #endif // HAVE_CPP11