Micro template library A library for building device drivers
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

777 lines
25 KiB

  1. /*!
  2. * \file /utl/concepts/stl.h
  3. * \brief STL's Concepts
  4. *
  5. * Copyright (C) 2018 - 2019 Christos Choutouridis
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Lesser General Public License as
  9. * published by the Free Software Foundation, either version 3
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. *
  20. */
  21. #ifndef __utl_concepts_stl_h__
  22. #define __utl_concepts_stl_h__
  23. #include <utl/core/impl.h>
  24. #include <utl/meta/meta.h>
  25. #include <utl/utility/invoke.h>
  26. #include <utl/concepts/defines.h>
  27. /*!
  28. * \brief
  29. * STL's core language concepts
  30. *
  31. * We provide std concepts in case host's stl does not provide them yet.
  32. *
  33. * For more information \see https://en.cppreference.com/w/cpp/concepts
  34. */
  35. //! @{
  36. namespace utl {
  37. template <typename T>
  38. using remove_cvref_t = std::remove_cv_t< std::remove_reference_t<T> >;
  39. template <typename T>
  40. using cref_ = const std::remove_reference_t<T>&;
  41. template <typename T>
  42. using _ref_t = std::add_lvalue_reference_t<T>;
  43. template <typename _T1, typename _T2, typename _Ret =_T1>
  44. using use_if_same_t = meta::eval<
  45. meta::enable_if<
  46. meta::same_<_T1, _T2>::value, _Ret
  47. >
  48. >;
  49. /*!
  50. * Same
  51. */
  52. template <class T, class U>
  53. _utlConcept Same = meta::same_<T, U>::value;
  54. // template<class T>
  55. // _utlConcept Decayed = Same<T, std::decay_t<T>>;
  56. /*!
  57. * DerivedFrom
  58. */
  59. template <class Derived, class Base>
  60. _utlConcept DerivedFrom =
  61. std::is_base_of<Base, Derived>::value &&
  62. std::is_convertible<const volatile Derived*, const volatile Base*>::value;
  63. /*!
  64. * ConvertibleTo
  65. */
  66. template <class From, class To>
  67. #if CXX_CONCEPTS
  68. _utlConcept ConvertibleTo =
  69. std::is_convertible<From, To>::value &&
  70. requires(From (&f)()) {
  71. static_cast<To>(f());
  72. };
  73. #else
  74. _utlConcept ConvertibleTo = std::is_convertible<From, To>::value;
  75. #endif
  76. /*!
  77. * Common Reference
  78. */
  79. //! @{
  80. namespace common_impl {
  81. //! \see https://ericniebler.github.io/std/wg21/D0022.html
  82. // ========== common reference ===========
  83. template<class T, class U>
  84. using __cond_res =
  85. decltype(false ? std::declval<T(&)()>()() : std::declval<U(&)()>()());
  86. template<class From>
  87. struct __copy_cv_ {
  88. static_assert(!std::is_reference<From>::value);
  89. template<class To> using apply = To;
  90. };
  91. template<class From>
  92. struct __copy_cv_<const From> {
  93. template<class To> using apply = const To;
  94. };
  95. template<class From>
  96. struct __copy_cv_<volatile From> {
  97. template<class To> using apply = volatile To;
  98. };
  99. template<class From>
  100. struct __copy_cv_<const volatile From> {
  101. template<class To> using apply = const volatile To;
  102. };
  103. template<class From, class To>
  104. using __copy_cv = meta::invoke<__copy_cv_<From>, To>;
  105. // CREF [meta.trans.other]/2.1
  106. template<class T>
  107. using __cref = std::add_lvalue_reference_t<const std::remove_reference_t<T>>;
  108. // COMMON_REF [meta.trans.other]/2
  109. template<class T, class U, class = void>
  110. struct __common_ref_ {
  111. static_assert(std::is_reference<T>::value, "");
  112. static_assert(std::is_reference<U>::value, "");
  113. };
  114. template<class T, class U>
  115. using __common_ref = meta::eval<__common_ref_<T, U>>;
  116. // [meta.trans.other]/2.5
  117. template<class T, class U>
  118. using __lref_res = __cond_res<
  119. __copy_cv<T, U> &,
  120. __copy_cv<U, T> &
  121. >;
  122. // [meta.trans.other]/2.6
  123. template<class T, class U, class R = __common_ref<T&, U&>>
  124. using __rref_res = std::remove_reference_t<R>&&;
  125. template<class T, class U>
  126. struct __common_ref_<T&, U&,
  127. meta::void_t<__lref_res<T, U>,
  128. meta::when<std::is_reference<__lref_res<T, U>>::value>> > {
  129. using type = __lref_res<T, U>;
  130. };
  131. template<class T, class U>
  132. struct __common_ref_<T&&, U&&,
  133. meta::void_t<__common_ref<T&, U&>,
  134. meta::when<ConvertibleTo<T&&, __rref_res<T, U>>>,
  135. meta::when<ConvertibleTo<U&&, __rref_res<T, U>>>> > {
  136. using type = __rref_res<T, U>;
  137. };
  138. // [meta.trans.other]/2.7
  139. template<class T, class U>
  140. struct __common_ref_<T&&, U&,
  141. meta::void_t<__common_ref<const T&, U&>,
  142. meta::when<ConvertibleTo<T&&, __common_ref<const T&, U&>>>> > {
  143. using type = __common_ref<const T&, U&>;
  144. };
  145. // [meta.trans.other]/2.8
  146. template<class T, class U>
  147. struct __common_ref_<T&, U&&,
  148. meta::void_t<__common_ref<T&, const U&>,
  149. meta::when<ConvertibleTo<U&&, __common_ref<T&, const U&>>>> > {
  150. using type = __common_ref<T&, const U&>;
  151. };
  152. template<class>
  153. struct __xref {
  154. template<class U> using apply = U;
  155. };
  156. template<class T>
  157. struct __xref<const T> {
  158. template<class U> using apply = const U;
  159. };
  160. template<class T>
  161. struct __xref<volatile T> {
  162. template<class U> using apply = volatile U;
  163. };
  164. template<class T>
  165. struct __xref<const volatile T> {
  166. template<class U> using apply = const volatile U;
  167. };
  168. template<class T>
  169. struct __xref<T&> {
  170. template<class U> using apply =
  171. std::add_lvalue_reference_t<meta::invoke<__xref<T>, U>>;
  172. };
  173. template<class T>
  174. struct __xref<T&&> {
  175. template<class U> using apply =
  176. std::add_rvalue_reference_t<meta::invoke<__xref<T>, U>>;
  177. };
  178. template<class,
  179. class,
  180. template<class> class,
  181. template<class> class
  182. >
  183. struct basic_common_reference { };
  184. template<class T, class U>
  185. using __basic_common_reference_t = meta::eval<
  186. basic_common_reference<
  187. remove_cvref_t<T>,
  188. remove_cvref_t<U>,
  189. __xref<T>::template apply,
  190. __xref<U>::template apply
  191. >
  192. >;
  193. template<class...>
  194. struct common_reference {};
  195. template<class... Ts>
  196. using common_reference_t = meta::eval<
  197. common_reference<Ts...>
  198. >;
  199. // [meta.trans.other]/5.2
  200. template<class T>
  201. struct common_reference<T> {
  202. using type = T;
  203. };
  204. // [meta.trans.other]/5.3.4
  205. template<class T, class U, class...>
  206. struct __common_reference3
  207. : std::common_type<T, U> {};
  208. // [meta.trans.other]/5.3.3
  209. template<class T, class U>
  210. struct __common_reference3<T, U,
  211. meta::void_t<__cond_res<T, U>>> {
  212. using type = __cond_res<T, U>;
  213. };
  214. template<class T, class U, class...>
  215. struct __common_reference2
  216. : __common_reference3<T, U> {};
  217. // [meta.trans.other]/5.3.2
  218. template<class T, class U>
  219. struct __common_reference2<T, U,
  220. meta::void_t<__basic_common_reference_t<T, U>>> {
  221. using type = __basic_common_reference_t<T, U>;
  222. };
  223. template <class T, class U, class...>
  224. struct __common_reference
  225. : __common_reference2<T, U> { };
  226. template <class T, class U>
  227. struct __common_reference<T, U,
  228. meta::when<std::is_reference<T>::value && std::is_reference<U>::value>> {
  229. using type = __common_ref<T, U>;
  230. };
  231. template<class T, class U>
  232. struct common_reference<T, U> : __common_reference<T, U> { };
  233. // [meta.trans.other]/5.4
  234. template<class T, class U, class V, class... W>
  235. //requires requires { typename common_reference_t<T, U>; }
  236. struct common_reference<T, U, V, W...>
  237. : common_reference <
  238. common_reference_t<T, U>, V, W...
  239. > {};
  240. }
  241. template<typename...Ts>
  242. using common_reference = common_impl::common_reference<Ts...>;
  243. template<typename... Ts>
  244. using common_reference_t = meta::eval<
  245. common_reference<Ts...>
  246. >;
  247. //! @}
  248. //FIXME: CommonReference needs better implementation
  249. template <class T, class U>
  250. _utlConcept CommonReference =
  251. Same<common_reference_t<T, U>, common_reference_t<U, T>> &&
  252. ConvertibleTo<T, common_reference_t<T, U>> &&
  253. ConvertibleTo<U, common_reference_t<T, U>>;
  254. // != std::Common on CommonReference
  255. template <class T, class U>
  256. _utlConcept Common =
  257. #if CXX_CONCEPTS
  258. Same<std::common_type_t<T, U>, std::common_type_t<U, T>> &&
  259. requires {
  260. static_cast<std::common_type_t<T, U>>(std::declval<T>());
  261. static_cast<std::common_type_t<T, U>>(std::declval<U>());
  262. };
  263. // } &&
  264. // CommonReference<
  265. // std::add_lvalue_reference_t<const T>,
  266. // std::add_lvalue_reference_t<const U>> &&
  267. // CommonReference<
  268. // std::add_lvalue_reference_t<std::common_type_t<T, U>>,
  269. // std::common_reference_t<
  270. // std::add_lvalue_reference_t<const T>,
  271. // std::add_lvalue_reference_t<const U>
  272. // >
  273. // >;
  274. #else
  275. // meta::and_ <
  276. Same<std::common_type_t<T, U>, std::common_type_t<U, T>>; //>
  277. // meta::bool_<CommonReference<
  278. // std::add_lvalue_reference_t<const T>,
  279. // std::add_lvalue_reference_t<const U>
  280. // >>,
  281. // meta::bool_< CommonReference<
  282. // std::add_lvalue_reference_t<std::common_type_t<T, U>>,
  283. // common_reference_t<
  284. // std::add_lvalue_reference_t<const T>,
  285. // std::add_lvalue_reference_t<const U>
  286. // >
  287. // >>
  288. // >::value;
  289. #endif
  290. /*!
  291. * Integral
  292. */
  293. template <class T>
  294. _utlConcept Integral = std::is_integral<T>::value;
  295. /*!
  296. * Signed Integral
  297. */
  298. template <class T>
  299. _utlConcept SignedIntegral = Integral<T> && std::is_signed<T>::value;
  300. /*!
  301. * Unsigned Integral
  302. */
  303. template <class T>
  304. _utlConcept UnsignedIntegral = Integral<T> && !std::is_signed<T>::value;
  305. template <typename T>
  306. _utlConcept MoveAssignable = std::is_move_assignable<T>::value;
  307. template <typename T>
  308. _utlConcept CopyAssignable = std::is_copy_assignable<T>::value;
  309. /*!
  310. * Assignable
  311. * \note != std:: on CommonReference
  312. */
  313. template<class LHS, class RHS>
  314. _utlConcept Assignable =
  315. #if CXX_CONCEPTS
  316. std::is_lvalue_reference<LHS>::value &&
  317. // CommonReference<
  318. // const std::remove_reference_t<L>&,
  319. // const std::remove_reference_t<R>&> &&
  320. requires(LHS lhs, RHS&& rhs) {
  321. lhs = std::forward<RHS>(rhs);
  322. requires Same<
  323. decltype(lhs = std::forward<RHS>(rhs)), LHS
  324. >;
  325. };
  326. #else
  327. std::is_assignable<LHS, RHS>::value;
  328. #endif
  329. /*!
  330. * Swappable, SwappableWith
  331. */
  332. //! @{
  333. #if CXX_VER < CXX_VER_STD_17
  334. namespace swappable_with_impl {
  335. struct is_swappable_with_ {
  336. // can apply std::swap
  337. template<typename _Tp,
  338. typename _Up,
  339. typename
  340. = decltype(std::swap(std::declval<_Tp&>(), std::declval<_Up&>())),
  341. typename
  342. = decltype(std::swap(std::declval<_Up&>(), std::declval<_Tp&>()))>
  343. static meta::true_ check(int);
  344. // can not apply std::swap
  345. template<typename, typename> static meta::false_ check(...);
  346. };
  347. }
  348. template <typename _Tp, typename _Up>
  349. struct is_swappable_with
  350. : swappable_with_impl::is_swappable_with_ {
  351. using type = decltype(check<_Tp, _Up>(0));
  352. };
  353. #else
  354. using is_swappable = std::is_swappable;
  355. using is_swappable_with = std::is_swappable_with;
  356. #endif
  357. // != std:: on CommonReference
  358. template<class T, class U>
  359. _utlConcept SwappableWith =
  360. is_swappable_with<T, T>::type::value &&
  361. is_swappable_with<U, U>::type::value &&
  362. is_swappable_with<T, U>::type::value &&
  363. is_swappable_with<U, T>::type::value;
  364. // std::CommonReference<
  365. // const std::remove_reference_t<T>&,
  366. // const std::remove_reference_t<U>&
  367. // >;
  368. // != std:: we use is_swappable_with now is_swappable
  369. template<class T>
  370. _utlConcept Swappable = is_swappable_with<T, T>::type::value;
  371. //! @}
  372. /*!
  373. * Destructible
  374. */
  375. template <class T>
  376. _utlConcept Destructible = std::is_nothrow_destructible<T>::value;
  377. /*!
  378. * Constructible
  379. */
  380. template <class T, class... Args>
  381. _utlConcept Constructible =
  382. Destructible<T> && std::is_constructible<T, Args...>::value;
  383. /*!
  384. * DefaultConstructible
  385. */
  386. template <class T>
  387. _utlConcept DefaultConstructible = Constructible<T>;
  388. /*!
  389. * MoveConstructible
  390. * \note
  391. * Another approach would be std::is_move_constructible<T>::value;
  392. */
  393. template<class T>
  394. _utlConcept MoveConstructible =
  395. Constructible<T, T> && ConvertibleTo<T, T>;
  396. /*!
  397. * CopyConstructible
  398. */
  399. template <class T>
  400. _utlConcept CopyConstructible =
  401. MoveConstructible<T> &&
  402. Constructible<T, _ref_t<T>> && ConvertibleTo<_ref_t<T>, T> &&
  403. Constructible<T, const _ref_t<T>> && ConvertibleTo<const _ref_t<T>, T> &&
  404. Constructible<T, const T> && ConvertibleTo<const T, T>;
  405. /*!
  406. * Movable
  407. */
  408. template <class T>
  409. _utlConcept Movable =
  410. std::is_object<T>::value &&
  411. MoveConstructible<T> &&
  412. Assignable<_ref_t<T>, T> &&
  413. Swappable<T>;
  414. /*!
  415. * Copyable
  416. */
  417. template <class T>
  418. _utlConcept Copyable =
  419. CopyConstructible<T> &&
  420. Movable<T> &&
  421. Assignable<_ref_t<T>, const _ref_t<T>>;
  422. /*!
  423. * Boolean
  424. */
  425. #if CXX_CONCEPTS
  426. template <class B>
  427. _utlConcept Boolean =
  428. Movable<remove_cvref_t<B>> &&
  429. requires(const std::remove_reference_t<B>& b1,
  430. const std::remove_reference_t<B>& b2, const bool a) {
  431. requires ConvertibleTo<const std::remove_reference_t<B>&, bool>;
  432. !b1; requires ConvertibleTo<decltype(!b1), bool>;
  433. b1 && a; requires Same<decltype(b1 && a), bool>;
  434. b1 || a; requires Same<decltype(b1 || a), bool>;
  435. b1 && b2; requires Same<decltype(b1 && b2), bool>;
  436. a && b2; requires Same<decltype(a && b2), bool>;
  437. b1 || b2; requires Same<decltype(b1 || b2), bool>;
  438. a || b2; requires Same<decltype(a || b2), bool>;
  439. b1 == b2; requires ConvertibleTo<decltype(b1 == b2), bool>;
  440. b1 == a; requires ConvertibleTo<decltype(b1 == a), bool>;
  441. a == b2; requires ConvertibleTo<decltype(a == b2), bool>;
  442. b1 != b2; requires ConvertibleTo<decltype(b1 != b2), bool>;
  443. b1 != a; requires ConvertibleTo<decltype(b1 != a), bool>;
  444. a != b2; requires ConvertibleTo<decltype(a != b2), bool>;
  445. };
  446. #else
  447. namespace details {
  448. // template <typename B> using try_op_not_ = decltype(!std::declval<cref_<B>>());
  449. // template <typename B> using try_op_eq_ = decltype(std::declval<cref_<B>>() == std::declval<cref_<B>>());
  450. // template <typename B> using try_op_neq_ = decltype(std::declval<cref_<B>>() != std::declval<cref_<B>>());
  451. // template <typename B> using try_op_and_ = decltype(std::declval<cref_<B>>() && std::declval<cref_<B>>());
  452. // template <typename B> using try_op_or_ = decltype(std::declval<cref_<B>>() || std::declval<cref_<B>>());
  453. //
  454. // template <typename B>
  455. // struct is_boolean__ {
  456. // using type = meta::and_ <
  457. // meta::is_detected<B, try_op_not_>,
  458. // meta::is_detected<B, try_op_eq_>,
  459. // meta::is_detected<B, try_op_neq_>,
  460. // meta::is_detected<B, try_op_and_>,
  461. // meta::is_detected<B, try_op_or_>
  462. // >;
  463. // };
  464. template <typename B, typename = void>
  465. struct is_boolean_ {
  466. using type = meta::false_;
  467. };
  468. template <typename B>
  469. struct is_boolean_ <B, meta::void_t<
  470. meta::use_if_same_t<bool, decltype(!std::declval<cref_<B>>())>,
  471. meta::use_if_same_t<bool, decltype(std::declval<cref_<B>>() == std::declval<cref_<B>>())>,
  472. meta::use_if_same_t<bool, decltype(std::declval<cref_<B>>() != std::declval<cref_<B>>())>,
  473. meta::use_if_same_t<bool, decltype(std::declval<cref_<B>>() && std::declval<cref_<B>>())>,
  474. meta::use_if_same_t<bool, decltype(std::declval<cref_<B>>() || std::declval<cref_<B>>())>
  475. >> {
  476. using type = meta::true_;
  477. };
  478. template <typename B>
  479. using is_boolean_t = meta::eval <
  480. is_boolean_<B>
  481. >;
  482. }
  483. template <class B>
  484. _utlConcept Boolean =
  485. Movable<remove_cvref_t<B>> &&
  486. //ConvertibleTo<const std::remove_reference_t<B>&, bool> &&
  487. ConvertibleTo<const _ref_t<B>, bool> &&
  488. Same<meta::true_, details::is_boolean_t<B>>;
  489. #endif
  490. namespace details {
  491. template <typename T, typename U, typename = void>
  492. struct is_weakly_equality_comparable_with_ {
  493. using type = meta::false_;
  494. };
  495. template <typename T, typename U>
  496. struct is_weakly_equality_comparable_with_<T, U, meta::void_t<
  497. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() == std::declval<cref_<U>>())>,
  498. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() != std::declval<cref_<U>>())>,
  499. meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() == std::declval<cref_<T>>())>,
  500. meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() != std::declval<cref_<T>>())>
  501. >> {
  502. using type = meta::true_;
  503. };
  504. template <typename T, typename U>
  505. using is_weakly_equality_comparable_with_t = meta::eval<
  506. is_weakly_equality_comparable_with_ <T, U>
  507. >;
  508. }
  509. template <class T, class U>
  510. _utlConcept WeaklyEqualityComparableWith =
  511. #if CXX_CONCEPTS
  512. requires(const std::remove_reference_t<T>& t,
  513. const std::remove_reference_t<U>& u) {
  514. t == u; requires Boolean<decltype(t == u)>;
  515. t != u; requires Boolean<decltype(t != u)>;
  516. u == t; requires Boolean<decltype(u == t)>;
  517. u != t; requires Boolean<decltype(u != t)>;
  518. };
  519. #else
  520. Same<meta::true_, details::is_weakly_equality_comparable_with_t<T, U>>;
  521. #endif
  522. template <class T>
  523. _utlConcept EqualityComparable = WeaklyEqualityComparableWith<T, T>;
  524. template <class T, class U>
  525. _utlConcept EqualityComparableWith =
  526. EqualityComparable<T> &&
  527. EqualityComparable<U> &&
  528. // CommonReference<
  529. // const std::remove_reference_t<T>&,
  530. // const std::remove_reference_t<U>&> &&
  531. // EqualityComparable<
  532. // common_reference_t<
  533. // const std::remove_reference_t<T>&,
  534. // const std::remove_reference_t<U>&>> &&
  535. WeaklyEqualityComparableWith<T, U>;
  536. #if CXX_CONCEPTS
  537. template <class T>
  538. _utlConcept StrictTotallyOrdered =
  539. EqualityComparable<T> &&
  540. requires(const std::remove_reference_t<T>& a,
  541. const std::remove_reference_t<T>& b) {
  542. a < b; requires Boolean<decltype(a < b)>;
  543. a > b; requires Boolean<decltype(a > b)>;
  544. a <= b; requires Boolean<decltype(a <= b)>;
  545. a >= b; requires Boolean<decltype(a >= b)>;
  546. };
  547. #else
  548. namespace details {
  549. template <typename T, typename = void>
  550. struct is_strict_totally_ordered_ {
  551. using type = meta::false_;
  552. };
  553. template <typename T>
  554. struct is_strict_totally_ordered_ <T, meta::void_t <
  555. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() < std::declval<cref_<T>>())>,
  556. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() > std::declval<cref_<T>>())>,
  557. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() <= std::declval<cref_<T>>())>,
  558. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() >= std::declval<cref_<T>>())>
  559. >> {
  560. using type = meta::true_;
  561. };
  562. template <typename T>
  563. using is_strict_totally_ordered_t = meta::eval <
  564. is_strict_totally_ordered_<T>
  565. >;
  566. }
  567. template <class T>
  568. _utlConcept StrictTotallyOrdered =
  569. EqualityComparable<T> &&
  570. Same <meta::true_, details::is_strict_totally_ordered_t<T>>;
  571. #endif
  572. #if CXX_CONCEPTS
  573. template <class T, class U>
  574. _utlConcept StrictTotallyOrderedWith =
  575. StrictTotallyOrdered<T> &&
  576. StrictTotallyOrdered<U> &&
  577. // CommonReference<
  578. // const std::remove_reference_t<T>&,
  579. // const std::remove_reference_t<U>&
  580. // > &&
  581. // StrictTotallyOrdered<
  582. // common_reference_t<
  583. // const std::remove_reference_t<T>&,
  584. // const std::remove_reference_t<U>&
  585. // >
  586. // > &&
  587. EqualityComparableWith<T, U> &&
  588. requires(const std::remove_reference_t<T>& t,
  589. const std::remove_reference_t<U>& u) {
  590. t < u; requires Boolean<decltype(t < u)>;
  591. t > u; requires Boolean<decltype(t > u)>;
  592. t <= u; requires Boolean<decltype(t <= u)>;
  593. t >= u; requires Boolean<decltype(t >= u)>;
  594. u < t; requires Boolean<decltype(u < t)>;
  595. u > t; requires Boolean<decltype(u > t)>;
  596. u <= t; requires Boolean<decltype(u <= t)>;
  597. u >= t; requires Boolean<decltype(u >= t)>;
  598. };
  599. #else
  600. namespace details {
  601. template <typename T, typename U, typename = void>
  602. struct is_strict_totally_ordered_with_ {
  603. using type = meta::false_;
  604. };
  605. template <typename T, typename U>
  606. struct is_strict_totally_ordered_with_ <T, U, meta::void_t <
  607. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() < std::declval<cref_<U>>())>,
  608. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() > std::declval<cref_<U>>())>,
  609. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() <= std::declval<cref_<U>>())>,
  610. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() >= std::declval<cref_<U>>())>,
  611. meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() < std::declval<cref_<T>>())>,
  612. meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() > std::declval<cref_<T>>())>,
  613. meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() <= std::declval<cref_<T>>())>,
  614. meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() >= std::declval<cref_<T>>())>
  615. >> {
  616. using type = meta::true_;
  617. };
  618. template <typename T, typename U>
  619. using is_strict_totally_ordered_with_t = meta::eval <
  620. is_strict_totally_ordered_with_<T, U>
  621. >;
  622. }
  623. template <class T, class U>
  624. _utlConcept StrictTotallyOrderedWith =
  625. StrictTotallyOrdered<T> &&
  626. StrictTotallyOrdered<U> &&
  627. EqualityComparableWith<T, U> &&
  628. Same <meta::true_, details::is_strict_totally_ordered_with_t<T, U>>;
  629. #endif
  630. /*!
  631. * Semiregular
  632. */
  633. template <class T>
  634. _utlConcept Semiregular = Copyable<T> && DefaultConstructible<T>;
  635. /*!
  636. * Regular
  637. */
  638. template <class T>
  639. _utlConcept Regular = Semiregular<T> && EqualityComparable<T>;
  640. /*!
  641. * Scalar
  642. */
  643. template<class T>
  644. _utlConcept Scalar =
  645. std::is_scalar<T>::value && Regular<T>;
  646. /*!
  647. * Arithmetic
  648. */
  649. template<class T>
  650. _utlConcept Arithmetic =
  651. std::is_arithmetic<T>::value && Scalar<T> && StrictTotallyOrdered<T>;
  652. /*!
  653. * FloatingPoint
  654. */
  655. template<class T>
  656. _utlConcept FloatingPoint =
  657. std::is_floating_point<T>::value && Arithmetic<T>;
  658. /*!
  659. * Invocable
  660. */
  661. template <class F, class... Args>
  662. _utlConcept Invocable = is_invocable<F, Args...>::value;
  663. // requires(F&& f, Args&&... args) {
  664. // invoke(std::forward<F>(f), std::forward<Args>(args)...);
  665. // };
  666. template< class F, class... Args >
  667. _utlConcept RegularInvocable = Invocable<F, Args...>;
  668. template < class F, class... Args >
  669. _utlConcept Predicate =
  670. RegularInvocable<F, Args...> &&
  671. Boolean<invoke_result_t<F, Args...>>;
  672. template <class R, class T, class U>
  673. _utlConcept Relation =
  674. Predicate<R, T, T> && Predicate<R, U, U> &&
  675. Predicate<R, T, U> && Predicate<R, U, T>;
  676. template < class R, class T, class U >
  677. _utlConcept StrictWeakOrder = Relation<R, T, U>;
  678. }
  679. //! @}
  680. #endif /* __utl_concepts_stl_h__ */