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.
 
 
 
 

779 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. template<typename Tp>
  355. using is_swappable = std::is_swappable<Tp>;
  356. template<typename T, typename U>
  357. using is_swappable_with = std::is_swappable_with<T, U>;
  358. #endif
  359. // != std:: on CommonReference
  360. template<class T, class U>
  361. _utlConcept SwappableWith =
  362. is_swappable_with<T, T>::type::value &&
  363. is_swappable_with<U, U>::type::value &&
  364. is_swappable_with<T, U>::type::value &&
  365. is_swappable_with<U, T>::type::value;
  366. // std::CommonReference<
  367. // const std::remove_reference_t<T>&,
  368. // const std::remove_reference_t<U>&
  369. // >;
  370. // != std:: we use is_swappable_with now is_swappable
  371. template<class T>
  372. _utlConcept Swappable = is_swappable_with<T, T>::type::value;
  373. //! @}
  374. /*!
  375. * Destructible
  376. */
  377. template <class T>
  378. _utlConcept Destructible = std::is_nothrow_destructible<T>::value;
  379. /*!
  380. * Constructible
  381. */
  382. template <class T, class... Args>
  383. _utlConcept Constructible =
  384. Destructible<T> && std::is_constructible<T, Args...>::value;
  385. /*!
  386. * DefaultConstructible
  387. */
  388. template <class T>
  389. _utlConcept DefaultConstructible = Constructible<T>;
  390. /*!
  391. * MoveConstructible
  392. * \note
  393. * Another approach would be std::is_move_constructible<T>::value;
  394. */
  395. template<class T>
  396. _utlConcept MoveConstructible =
  397. Constructible<T, T> && ConvertibleTo<T, T>;
  398. /*!
  399. * CopyConstructible
  400. */
  401. template <class T>
  402. _utlConcept CopyConstructible =
  403. MoveConstructible<T> &&
  404. Constructible<T, _ref_t<T>> && ConvertibleTo<_ref_t<T>, T> &&
  405. Constructible<T, const _ref_t<T>> && ConvertibleTo<const _ref_t<T>, T> &&
  406. Constructible<T, const T> && ConvertibleTo<const T, T>;
  407. /*!
  408. * Movable
  409. */
  410. template <class T>
  411. _utlConcept Movable =
  412. std::is_object<T>::value &&
  413. MoveConstructible<T> &&
  414. Assignable<_ref_t<T>, T> &&
  415. Swappable<T>;
  416. /*!
  417. * Copyable
  418. */
  419. template <class T>
  420. _utlConcept Copyable =
  421. CopyConstructible<T> &&
  422. Movable<T> &&
  423. Assignable<_ref_t<T>, const _ref_t<T>>;
  424. /*!
  425. * Boolean
  426. */
  427. #if CXX_CONCEPTS
  428. template <class B>
  429. _utlConcept Boolean =
  430. Movable<remove_cvref_t<B>> &&
  431. requires(const std::remove_reference_t<B>& b1,
  432. const std::remove_reference_t<B>& b2, const bool a) {
  433. requires ConvertibleTo<const std::remove_reference_t<B>&, bool>;
  434. !b1; requires ConvertibleTo<decltype(!b1), bool>;
  435. b1 && a; requires Same<decltype(b1 && a), bool>;
  436. b1 || a; requires Same<decltype(b1 || a), bool>;
  437. b1 && b2; requires Same<decltype(b1 && b2), bool>;
  438. a && b2; requires Same<decltype(a && b2), bool>;
  439. b1 || b2; requires Same<decltype(b1 || b2), bool>;
  440. a || b2; requires Same<decltype(a || b2), bool>;
  441. b1 == b2; requires ConvertibleTo<decltype(b1 == b2), bool>;
  442. b1 == a; requires ConvertibleTo<decltype(b1 == a), bool>;
  443. a == b2; requires ConvertibleTo<decltype(a == b2), bool>;
  444. b1 != b2; requires ConvertibleTo<decltype(b1 != b2), bool>;
  445. b1 != a; requires ConvertibleTo<decltype(b1 != a), bool>;
  446. a != b2; requires ConvertibleTo<decltype(a != b2), bool>;
  447. };
  448. #else
  449. namespace details {
  450. // template <typename B> using try_op_not_ = decltype(!std::declval<cref_<B>>());
  451. // template <typename B> using try_op_eq_ = decltype(std::declval<cref_<B>>() == std::declval<cref_<B>>());
  452. // template <typename B> using try_op_neq_ = decltype(std::declval<cref_<B>>() != std::declval<cref_<B>>());
  453. // template <typename B> using try_op_and_ = decltype(std::declval<cref_<B>>() && std::declval<cref_<B>>());
  454. // template <typename B> using try_op_or_ = decltype(std::declval<cref_<B>>() || std::declval<cref_<B>>());
  455. //
  456. // template <typename B>
  457. // struct is_boolean__ {
  458. // using type = meta::and_ <
  459. // meta::is_detected<B, try_op_not_>,
  460. // meta::is_detected<B, try_op_eq_>,
  461. // meta::is_detected<B, try_op_neq_>,
  462. // meta::is_detected<B, try_op_and_>,
  463. // meta::is_detected<B, try_op_or_>
  464. // >;
  465. // };
  466. template <typename B, typename = void>
  467. struct is_boolean_ {
  468. using type = meta::false_;
  469. };
  470. template <typename B>
  471. struct is_boolean_ <B, meta::void_t<
  472. meta::use_if_same_t<bool, decltype(!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. meta::use_if_same_t<bool, decltype(std::declval<cref_<B>>() && std::declval<cref_<B>>())>,
  476. meta::use_if_same_t<bool, decltype(std::declval<cref_<B>>() || std::declval<cref_<B>>())>
  477. >> {
  478. using type = meta::true_;
  479. };
  480. template <typename B>
  481. using is_boolean_t = meta::eval <
  482. is_boolean_<B>
  483. >;
  484. }
  485. template <class B>
  486. _utlConcept Boolean =
  487. Movable<remove_cvref_t<B>> &&
  488. //ConvertibleTo<const std::remove_reference_t<B>&, bool> &&
  489. ConvertibleTo<const _ref_t<B>, bool> &&
  490. Same<meta::true_, details::is_boolean_t<B>>;
  491. #endif
  492. namespace details {
  493. template <typename T, typename U, typename = void>
  494. struct is_weakly_equality_comparable_with_ {
  495. using type = meta::false_;
  496. };
  497. template <typename T, typename U>
  498. struct is_weakly_equality_comparable_with_<T, U, meta::void_t<
  499. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() == std::declval<cref_<U>>())>,
  500. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() != std::declval<cref_<U>>())>,
  501. meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() == std::declval<cref_<T>>())>,
  502. meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() != std::declval<cref_<T>>())>
  503. >> {
  504. using type = meta::true_;
  505. };
  506. template <typename T, typename U>
  507. using is_weakly_equality_comparable_with_t = meta::eval<
  508. is_weakly_equality_comparable_with_ <T, U>
  509. >;
  510. }
  511. template <class T, class U>
  512. _utlConcept WeaklyEqualityComparableWith =
  513. #if CXX_CONCEPTS
  514. requires(const std::remove_reference_t<T>& t,
  515. const std::remove_reference_t<U>& u) {
  516. t == u; requires Boolean<decltype(t == u)>;
  517. t != u; requires Boolean<decltype(t != u)>;
  518. u == t; requires Boolean<decltype(u == t)>;
  519. u != t; requires Boolean<decltype(u != t)>;
  520. };
  521. #else
  522. Same<meta::true_, details::is_weakly_equality_comparable_with_t<T, U>>;
  523. #endif
  524. template <class T>
  525. _utlConcept EqualityComparable = WeaklyEqualityComparableWith<T, T>;
  526. template <class T, class U>
  527. _utlConcept EqualityComparableWith =
  528. EqualityComparable<T> &&
  529. EqualityComparable<U> &&
  530. // CommonReference<
  531. // const std::remove_reference_t<T>&,
  532. // const std::remove_reference_t<U>&> &&
  533. // EqualityComparable<
  534. // common_reference_t<
  535. // const std::remove_reference_t<T>&,
  536. // const std::remove_reference_t<U>&>> &&
  537. WeaklyEqualityComparableWith<T, U>;
  538. #if CXX_CONCEPTS
  539. template <class T>
  540. _utlConcept StrictTotallyOrdered =
  541. EqualityComparable<T> &&
  542. requires(const std::remove_reference_t<T>& a,
  543. const std::remove_reference_t<T>& b) {
  544. a < b; requires Boolean<decltype(a < b)>;
  545. a > b; requires Boolean<decltype(a > b)>;
  546. a <= b; requires Boolean<decltype(a <= b)>;
  547. a >= b; requires Boolean<decltype(a >= b)>;
  548. };
  549. #else
  550. namespace details {
  551. template <typename T, typename = void>
  552. struct is_strict_totally_ordered_ {
  553. using type = meta::false_;
  554. };
  555. template <typename T>
  556. struct is_strict_totally_ordered_ <T, meta::void_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. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() <= std::declval<cref_<T>>())>,
  560. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() >= std::declval<cref_<T>>())>
  561. >> {
  562. using type = meta::true_;
  563. };
  564. template <typename T>
  565. using is_strict_totally_ordered_t = meta::eval <
  566. is_strict_totally_ordered_<T>
  567. >;
  568. }
  569. template <class T>
  570. _utlConcept StrictTotallyOrdered =
  571. EqualityComparable<T> &&
  572. Same <meta::true_, details::is_strict_totally_ordered_t<T>>;
  573. #endif
  574. #if CXX_CONCEPTS
  575. template <class T, class U>
  576. _utlConcept StrictTotallyOrderedWith =
  577. StrictTotallyOrdered<T> &&
  578. StrictTotallyOrdered<U> &&
  579. // CommonReference<
  580. // const std::remove_reference_t<T>&,
  581. // const std::remove_reference_t<U>&
  582. // > &&
  583. // StrictTotallyOrdered<
  584. // common_reference_t<
  585. // const std::remove_reference_t<T>&,
  586. // const std::remove_reference_t<U>&
  587. // >
  588. // > &&
  589. EqualityComparableWith<T, U> &&
  590. requires(const std::remove_reference_t<T>& t,
  591. const std::remove_reference_t<U>& u) {
  592. t < u; requires Boolean<decltype(t < u)>;
  593. t > u; requires Boolean<decltype(t > u)>;
  594. t <= u; requires Boolean<decltype(t <= u)>;
  595. t >= u; requires Boolean<decltype(t >= u)>;
  596. u < t; requires Boolean<decltype(u < t)>;
  597. u > t; requires Boolean<decltype(u > t)>;
  598. u <= t; requires Boolean<decltype(u <= t)>;
  599. u >= t; requires Boolean<decltype(u >= t)>;
  600. };
  601. #else
  602. namespace details {
  603. template <typename T, typename U, typename = void>
  604. struct is_strict_totally_ordered_with_ {
  605. using type = meta::false_;
  606. };
  607. template <typename T, typename U>
  608. struct is_strict_totally_ordered_with_ <T, U, meta::void_t <
  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_<T>>() <= std::declval<cref_<U>>())>,
  612. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() >= std::declval<cref_<U>>())>,
  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. meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() <= std::declval<cref_<T>>())>,
  616. meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() >= std::declval<cref_<T>>())>
  617. >> {
  618. using type = meta::true_;
  619. };
  620. template <typename T, typename U>
  621. using is_strict_totally_ordered_with_t = meta::eval <
  622. is_strict_totally_ordered_with_<T, U>
  623. >;
  624. }
  625. template <class T, class U>
  626. _utlConcept StrictTotallyOrderedWith =
  627. StrictTotallyOrdered<T> &&
  628. StrictTotallyOrdered<U> &&
  629. EqualityComparableWith<T, U> &&
  630. Same <meta::true_, details::is_strict_totally_ordered_with_t<T, U>>;
  631. #endif
  632. /*!
  633. * Semiregular
  634. */
  635. template <class T>
  636. _utlConcept Semiregular = Copyable<T> && DefaultConstructible<T>;
  637. /*!
  638. * Regular
  639. */
  640. template <class T>
  641. _utlConcept Regular = Semiregular<T> && EqualityComparable<T>;
  642. /*!
  643. * Scalar
  644. */
  645. template<class T>
  646. _utlConcept Scalar =
  647. std::is_scalar<T>::value && Regular<T>;
  648. /*!
  649. * Arithmetic
  650. */
  651. template<class T>
  652. _utlConcept Arithmetic =
  653. std::is_arithmetic<T>::value && Scalar<T> && StrictTotallyOrdered<T>;
  654. /*!
  655. * FloatingPoint
  656. */
  657. template<class T>
  658. _utlConcept FloatingPoint =
  659. std::is_floating_point<T>::value && Arithmetic<T>;
  660. /*!
  661. * Invocable
  662. */
  663. template <class F, class... Args>
  664. _utlConcept Invocable = is_invocable<F, Args...>::value;
  665. // requires(F&& f, Args&&... args) {
  666. // invoke(std::forward<F>(f), std::forward<Args>(args)...);
  667. // };
  668. template< class F, class... Args >
  669. _utlConcept RegularInvocable = Invocable<F, Args...>;
  670. template < class F, class... Args >
  671. _utlConcept Predicate =
  672. RegularInvocable<F, Args...> &&
  673. Boolean<invoke_result_t<F, Args...>>;
  674. template <class R, class T, class U>
  675. _utlConcept Relation =
  676. Predicate<R, T, T> && Predicate<R, U, U> &&
  677. Predicate<R, T, U> && Predicate<R, U, T>;
  678. template < class R, class T, class U >
  679. _utlConcept StrictWeakOrder = Relation<R, T, U>;
  680. }
  681. //! @}
  682. #endif /* __utl_concepts_stl_h__ */