File indexing completed on 2025-01-18 09:54:46
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #ifndef CPP_TYPE_TRAITS_HPP
0014 #define CPP_TYPE_TRAITS_HPP
0015
0016 #include <tuple>
0017 #include <utility>
0018 #include <type_traits>
0019 #include <meta/meta.hpp>
0020
0021 namespace concepts
0022 {
0023 template<typename T>
0024 using remove_cvref_t =
0025 typename std::remove_cv<
0026 typename std::remove_reference<T>::type>::type;
0027
0028
0029 namespace detail
0030 {
0031 template<typename From, typename To>
0032 using is_convertible = std::is_convertible<meta::_t<std::add_rvalue_reference<From>>, To>;
0033
0034 template<bool>
0035 struct if_else_
0036 {
0037 template<typename, typename U>
0038 using invoke = U;
0039 };
0040 template<>
0041 struct if_else_<true>
0042 {
0043 template<typename T, typename>
0044 using invoke = T;
0045 };
0046 template<bool B, typename T, typename U>
0047 using if_else_t = meta::invoke<if_else_<B>, T, U>;
0048
0049 template<bool>
0050 struct if_
0051 {};
0052 template<>
0053 struct if_<true>
0054 {
0055 template<typename T>
0056 using invoke = T;
0057 };
0058 template<bool B, typename T = void>
0059 using if_t = meta::invoke<if_<B>, T>;
0060
0061 template<typename From, typename To>
0062 struct _copy_cv_
0063 {
0064 using type = To;
0065 };
0066 template<typename From, typename To>
0067 struct _copy_cv_<From const, To>
0068 {
0069 using type = To const;
0070 };
0071 template<typename From, typename To>
0072 struct _copy_cv_<From volatile, To>
0073 {
0074 using type = To volatile;
0075 };
0076 template<typename From, typename To>
0077 struct _copy_cv_<From const volatile, To>
0078 {
0079 using type = To const volatile;
0080 };
0081 template<typename From, typename To>
0082 using _copy_cv = meta::_t<_copy_cv_<From, To>>;
0083
0084
0085 template<typename T, typename U, typename = void>
0086 struct _builtin_common;
0087
0088 template<typename T, typename U>
0089 using _builtin_common_t = meta::_t<_builtin_common<T, U>>;
0090
0091 template<typename T, typename U>
0092 using _cond_res = decltype(true ? std::declval<T>() : std::declval<U>());
0093
0094 template<typename T, typename U, typename R = _builtin_common_t<T &, U &>>
0095 using _rref_res =
0096 if_else_t<std::is_reference<R>::value, meta::_t<std::remove_reference<R>> &&, R>;
0097
0098 template<typename T, typename U>
0099 using _lref_res = _cond_res<_copy_cv<T, U> &, _copy_cv<U, T> &>;
0100
0101 template<typename T>
0102 struct as_cref_
0103 {
0104 using type = T const &;
0105 };
0106 template<typename T>
0107 struct as_cref_<T &>
0108 {
0109 using type = T const &;
0110 };
0111 template<typename T>
0112 struct as_cref_<T &&>
0113 {
0114 using type = T const &;
0115 };
0116 template<>
0117 struct as_cref_<void>
0118 {
0119 using type = void;
0120 };
0121 template<>
0122 struct as_cref_<void const>
0123 {
0124 using type = void const;
0125 };
0126
0127 template<typename T>
0128 using as_cref_t = typename as_cref_<T>::type;
0129
0130 template<typename T>
0131 using decay_t = typename std::decay<T>::type;
0132
0133 #if !defined(__GNUC__) || defined(__clang__)
0134 template<typename T, typename U, typename = void>
0135 struct _builtin_common_3
0136 {};
0137 template<typename T, typename U>
0138 struct _builtin_common_3<T, U, meta::void_<_cond_res<as_cref_t<T>, as_cref_t<U>>>>
0139 : std::decay<_cond_res<as_cref_t<T>, as_cref_t<U>>>
0140 {};
0141 template<typename T, typename U, typename = void>
0142 struct _builtin_common_2
0143 : _builtin_common_3<T, U>
0144 {};
0145 template<typename T, typename U>
0146 struct _builtin_common_2<T, U, meta::void_<_cond_res<T, U>>>
0147 : std::decay<_cond_res<T, U>>
0148 {};
0149 template<typename T, typename U, typename >
0150 struct _builtin_common
0151 : _builtin_common_2<T, U>
0152 {};
0153 template<typename T, typename U>
0154 struct _builtin_common<T &&, U &&, if_t<
0155 is_convertible<T &&, _rref_res<T, U>>::value &&
0156 is_convertible<U &&, _rref_res<T, U>>::value>>
0157 {
0158 using type = _rref_res<T, U>;
0159 };
0160 template<typename T, typename U>
0161 struct _builtin_common<T &, U &>
0162 : meta::defer<_lref_res, T, U>
0163 {};
0164 template<typename T, typename U>
0165 struct _builtin_common<T &, U &&, if_t<
0166 is_convertible<U &&, _builtin_common_t<T &, U const &>>::value>>
0167 : _builtin_common<T &, U const &>
0168 {};
0169 template<typename T, typename U>
0170 struct _builtin_common<T &&, U &>
0171 : _builtin_common<U &, T &&>
0172 {};
0173 #else
0174 template<typename T, typename U, typename = void>
0175 struct _builtin_common_3
0176 {};
0177 template<typename T, typename U>
0178 struct _builtin_common_3<T, U, meta::void_<_cond_res<as_cref_t<T>, as_cref_t<U>>>>
0179 : std::decay<_cond_res<as_cref_t<T>, as_cref_t<U>>>
0180 {};
0181 template<typename T, typename U, typename = void>
0182 struct _builtin_common_2
0183 : _builtin_common_3<T, U>
0184 {};
0185 template<typename T, typename U>
0186 struct _builtin_common_2<T, U, meta::void_<_cond_res<T, U>>>
0187 : std::decay<_cond_res<T, U>>
0188 {};
0189 template<typename T, typename U, typename >
0190 struct _builtin_common
0191 : _builtin_common_2<T, U>
0192 {};
0193 template<typename T, typename U, typename = void>
0194 struct _builtin_common_rr
0195 : _builtin_common_2<T &&, U &&>
0196 {};
0197 template<typename T, typename U>
0198 struct _builtin_common_rr<T, U, if_t<
0199 is_convertible<T &&, _rref_res<T, U>>::value &&
0200 is_convertible<U &&, _rref_res<T, U>>::value>>
0201 {
0202 using type = _rref_res<T, U>;
0203 };
0204 template<typename T, typename U>
0205 struct _builtin_common<T &&, U &&>
0206 : _builtin_common_rr<T, U>
0207 {};
0208 template<typename T, typename U>
0209 struct _builtin_common<T &, U &>
0210 : meta::defer<_lref_res, T, U>
0211 {};
0212 template<typename T, typename U, typename = void>
0213 struct _builtin_common_lr
0214 : _builtin_common_2<T &, T &&>
0215 {};
0216 template<typename T, typename U>
0217 struct _builtin_common_lr<T, U, if_t<
0218 is_convertible<U &&, _builtin_common_t<T &, U const &>>::value>>
0219 : _builtin_common<T &, U const &>
0220 {};
0221 template<typename T, typename U>
0222 struct _builtin_common<T &, U &&>
0223 : _builtin_common_lr<T, U>
0224 {};
0225 template<typename T, typename U>
0226 struct _builtin_common<T &&, U &>
0227 : _builtin_common<U &, T &&>
0228 {};
0229 #endif
0230 }
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240 template<typename ...Ts>
0241 struct common_type
0242 {};
0243
0244 template<typename T>
0245 struct common_type<T>
0246 : std::decay<T>
0247 {};
0248
0249 template<typename T, typename U>
0250 struct common_type<T, U>
0251 : detail::if_else_t<
0252 (META_IS_SAME(detail::decay_t<T>, T) &&
0253 META_IS_SAME(detail::decay_t<U>, U) ),
0254 meta::defer<detail::_builtin_common_t, T, U>,
0255 common_type<detail::decay_t<T>, detail::decay_t<U>>>
0256 {};
0257
0258 template<typename... Ts>
0259 using common_type_t = typename common_type<Ts...>::type;
0260
0261 template<typename T, typename U, typename... Vs>
0262 struct common_type<T, U, Vs...>
0263 : meta::lazy::fold<meta::list<U, Vs...>, T, meta::quote<common_type_t>>
0264 {};
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274 template<
0275 typename T,
0276 typename U,
0277 template<typename> class TQual,
0278 template<typename> class UQual>
0279 struct basic_common_reference
0280 {};
0281
0282
0283 namespace detail
0284 {
0285 using _rref =
0286 meta::quote_trait<std::add_rvalue_reference>;
0287 using _lref =
0288 meta::quote_trait<std::add_lvalue_reference>;
0289
0290 template<typename>
0291 struct _xref
0292 {
0293 template<typename T>
0294 using invoke = T;
0295 };
0296 template<typename T>
0297 struct _xref<T &&>
0298 {
0299 template<typename U>
0300 using invoke =
0301 meta::_t<std::add_rvalue_reference<meta::invoke<_xref<T>, U>>>;
0302 };
0303 template<typename T>
0304 struct _xref<T &>
0305 {
0306 template<typename U>
0307 using invoke =
0308 meta::_t<std::add_lvalue_reference<meta::invoke<_xref<T>, U>>>;
0309 };
0310 template<typename T>
0311 struct _xref<T const>
0312 {
0313 template<typename U>
0314 using invoke = U const;
0315 };
0316 template<typename T>
0317 struct _xref<T volatile>
0318 {
0319 template<typename U>
0320 using invoke = U volatile;
0321 };
0322 template<typename T>
0323 struct _xref<T const volatile>
0324 {
0325 template<typename U>
0326 using invoke = U const volatile;
0327 };
0328
0329 template<typename T, typename U>
0330 using _basic_common_reference =
0331 basic_common_reference<
0332 remove_cvref_t<T>,
0333 remove_cvref_t<U>,
0334 _xref<T>::template invoke,
0335 _xref<U>::template invoke>;
0336
0337 template<typename T, typename U, typename = void>
0338 struct _common_reference2
0339 : if_else_t<
0340 meta::is_trait<_basic_common_reference<T, U>>::value,
0341 _basic_common_reference<T, U>,
0342 common_type<T, U>>
0343 {};
0344
0345 template<typename T, typename U>
0346 struct _common_reference2<T, U, if_t<std::is_reference<_builtin_common_t<T, U>>::value>>
0347 : _builtin_common<T, U>
0348 {};
0349 }
0350
0351
0352
0353
0354 template<typename ...Ts>
0355 struct common_reference
0356 {};
0357
0358 template<typename T>
0359 struct common_reference<T>
0360 {
0361 using type = T;
0362 };
0363
0364 template<typename T, typename U>
0365 struct common_reference<T, U>
0366 : detail::_common_reference2<T, U>
0367 {};
0368
0369 template<typename... Ts>
0370 using common_reference_t = typename common_reference<Ts...>::type;
0371
0372 template<typename T, typename U, typename... Vs>
0373 struct common_reference<T, U, Vs...>
0374 : meta::lazy::fold<meta::list<U, Vs...>, T, meta::quote<common_reference_t>>
0375 {};
0376
0377 }
0378
0379 #endif