base.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. // Copyright Louis Dionne 2013-2017
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  4. #ifndef BOOST_HANA_TEST_LAWS_BASE_HPP
  5. #define BOOST_HANA_TEST_LAWS_BASE_HPP
  6. #include <boost/hana/and.hpp>
  7. #include <boost/hana/bool.hpp>
  8. #include <boost/hana/core/when.hpp>
  9. #include <boost/hana/detail/wrong.hpp>
  10. #include <boost/hana/equal.hpp>
  11. #include <boost/hana/eval_if.hpp>
  12. #include <boost/hana/for_each.hpp>
  13. #include <boost/hana/functional/compose.hpp>
  14. #include <boost/hana/functional/infix.hpp>
  15. #include <boost/hana/functional/partial.hpp>
  16. #include <boost/hana/fwd/concept/integral_constant.hpp>
  17. #include <boost/hana/fwd/core/to.hpp>
  18. #include <boost/hana/fwd/less.hpp>
  19. #include <boost/hana/not.hpp>
  20. #include <boost/hana/or.hpp>
  21. #include <boost/hana/tuple.hpp>
  22. #include <support/tracked.hpp>
  23. #include <type_traits>
  24. #include <utility>
  25. namespace boost { namespace hana {
  26. //////////////////////////////////////////////////////////////////////////
  27. // Misc
  28. //////////////////////////////////////////////////////////////////////////
  29. namespace test {
  30. struct laws;
  31. template <int i>
  32. struct for_each_n_t {
  33. static_assert(i > 0, "can't use for_each_n with i < 0");
  34. template <typename Xs, typename F>
  35. constexpr auto operator()(Xs const& xs, F const& f) const {
  36. hana::for_each(xs,
  37. hana::compose(
  38. hana::partial(for_each_n_t<i - 1>{}, xs),
  39. hana::partial(hana::partial, f)
  40. )
  41. );
  42. }
  43. };
  44. template <>
  45. struct for_each_n_t<1> {
  46. template <typename Xs, typename F>
  47. constexpr auto operator()(Xs const& xs, F const& f) const {
  48. hana::for_each(xs, f);
  49. }
  50. };
  51. template <int i>
  52. constexpr for_each_n_t<i> for_each_n{};
  53. auto foreach = hana::for_each;
  54. constexpr auto foreach3 = for_each_n<3>;
  55. constexpr auto foreach2 = for_each_n<2>;
  56. struct implies_t {
  57. template <typename P, typename Q>
  58. constexpr decltype(auto) operator()(P&& p, Q&& q) const {
  59. return hana::or_(hana::not_(static_cast<P&&>(p)),
  60. static_cast<Q&&>(q));
  61. }
  62. };
  63. constexpr auto implies = hana::infix(implies_t{});
  64. struct iff_t {
  65. template <typename P, typename Q>
  66. constexpr decltype(auto) operator()(P&& p, Q&& q) const {
  67. return hana::and_(implies(p, q), implies(q, p));
  68. }
  69. };
  70. constexpr auto iff = hana::infix(iff_t{});
  71. template <typename Cond, typename F>
  72. constexpr decltype(auto) only_when_(Cond cond, F f) {
  73. return hana::eval_if(cond, f, [](auto){ });
  74. }
  75. // A type with a constructor that must not be instantiated.
  76. // This is to make sure we don't instantiate something else than
  77. // the copy-constructor of the elements inside a container when we
  78. // copy the container.
  79. struct trap_construct {
  80. trap_construct() = default;
  81. trap_construct(trap_construct const&) = default;
  82. #ifndef BOOST_HANA_WORKAROUND_MSVC_MULTIPLECTOR_106654
  83. trap_construct(trap_construct&) = default;
  84. #endif
  85. trap_construct(trap_construct&&) = default;
  86. template <typename X>
  87. trap_construct(X&&) {
  88. static_assert(detail::wrong<X>{},
  89. "this constructor must not be instantiated");
  90. }
  91. };
  92. // A move-only type. Useful for testing containers.
  93. struct move_only {
  94. move_only() = default;
  95. move_only(move_only const&) = delete;
  96. move_only(move_only&&) = default;
  97. };
  98. //////////////////////////////////////////////////////////////////////
  99. // InjectionResult
  100. //////////////////////////////////////////////////////////////////////
  101. struct InjectionResult { };
  102. template <int i, typename ...X>
  103. struct injection_result {
  104. using hana_tag = InjectionResult;
  105. static constexpr int injection_id = i;
  106. hana::tuple<X...> args;
  107. Tracked tracker;
  108. template <typename ...Y, typename = decltype(tuple<X...>{std::declval<Y>()...})>
  109. constexpr explicit injection_result(Y&& ...y)
  110. : args{static_cast<Y&&>(y)...}, tracker{i}
  111. { }
  112. };
  113. //! A monotonic injective function.
  114. //!
  115. //! This is used in the unit tests, where we often just need a function
  116. //! which preserves equality and order, but which also satisfies the
  117. //! following law for all `Injection`s `f` and `g`:
  118. //! @code
  119. //! f(x) == g(x) if and only if f === g
  120. //! @endcode
  121. //! where `===` means _was created by the same call to `injection`_.
  122. //! This allows creating several such functions in the unit tests while
  123. //! conserving precious information such as the fact that
  124. //! `f(g(x)) != g(f(x))`.
  125. template <int i>
  126. struct _injection {
  127. template <typename ...X>
  128. constexpr auto operator()(X&& ...x) const {
  129. return injection_result<i,
  130. typename std::decay<X>::type...
  131. >{static_cast<X&&>(x)...};
  132. }
  133. };
  134. } // end namespace test
  135. template <>
  136. struct equal_impl<test::InjectionResult, test::InjectionResult> {
  137. template <typename X, typename Y>
  138. static constexpr auto apply(X x, Y y) {
  139. return hana::and_(
  140. hana::bool_c<X::injection_id == Y::injection_id>,
  141. hana::equal(x.args, y.args)
  142. );
  143. }
  144. };
  145. template <>
  146. struct less_impl<test::InjectionResult, test::InjectionResult> {
  147. template <typename X, typename Y>
  148. static constexpr auto apply(X x, Y y) {
  149. static_assert(X::injection_id == Y::injection_id,
  150. "can't order the result of two different injections");
  151. return hana::less(x.args, y.args);
  152. }
  153. };
  154. //////////////////////////////////////////////////////////////////////////
  155. // Integer
  156. //////////////////////////////////////////////////////////////////////////
  157. namespace test {
  158. enum class Policy : int {
  159. // One of those is mandatory
  160. Constant = 1 << 0
  161. , Constexpr = 1 << 1
  162. , Runtime = 1 << 2
  163. // Those are optional
  164. , Tracked = 1 << 3
  165. , Comparable = 1 << 4
  166. , Orderable = 1 << 5
  167. };
  168. constexpr bool operator&&(Policy a, Policy b) {
  169. return static_cast<int>(a) && static_cast<int>(b);
  170. }
  171. constexpr bool operator&&(Policy a, bool b) {
  172. return static_cast<int>(a) && b;
  173. }
  174. constexpr bool operator&&(bool a, Policy b) {
  175. return a && static_cast<int>(b);
  176. }
  177. constexpr bool operator||(Policy a, Policy b) {
  178. return static_cast<int>(a) || static_cast<int>(b);
  179. }
  180. constexpr bool operator||(Policy a, bool b) {
  181. return static_cast<int>(a) || b;
  182. }
  183. constexpr bool operator||(bool a, Policy b) {
  184. return a || static_cast<int>(b);
  185. }
  186. constexpr bool operator!(Policy a) {
  187. return !static_cast<int>(a);
  188. }
  189. constexpr Policy operator|(Policy a, Policy b) {
  190. return static_cast<Policy>(static_cast<int>(a) | static_cast<int>(b));
  191. }
  192. constexpr Policy operator&(Policy a, Policy b) {
  193. return static_cast<Policy>(static_cast<int>(a) & static_cast<int>(b));
  194. }
  195. template <Policy policy, typename = void>
  196. struct Integer { };
  197. template <Policy policy>
  198. struct Integer<policy, std::enable_if_t<!!(policy & Policy::Constant)>> {
  199. using value_type = int;
  200. };
  201. template <int i, Policy policy, typename = void>
  202. struct integer {
  203. static_assert(
  204. !!(policy & (Policy::Constant | Policy::Constexpr | Policy::Runtime))
  205. , "You must choose at least one of Constant, Constexpr and Runtime.");
  206. static constexpr int value = i;
  207. constexpr operator int() const { return value; }
  208. using hana_tag = Integer<policy>;
  209. Tracked tracker{i};
  210. };
  211. template <int i, Policy policy>
  212. struct integer <i, policy, std::enable_if_t<!!(policy & Policy::Constexpr)>> {
  213. static constexpr int value = i;
  214. constexpr operator int() const { return value; }
  215. using hana_tag = Integer<policy>;
  216. };
  217. template <int i>
  218. struct eq : integer<i, Policy::Comparable | Policy::Runtime> { };
  219. template <int i>
  220. struct ct_eq : integer<i, Policy::Comparable | Policy::Constant> { };
  221. template <int i>
  222. struct cx_eq : integer<i, Policy::Comparable | Policy::Constexpr> { };
  223. template <int i>
  224. struct ord : integer<i, Policy::Orderable | Policy::Runtime> { };
  225. template <int i>
  226. struct ct_ord : integer<i, Policy::Orderable | Policy::Constant> { };
  227. template <int i>
  228. struct cx_ord : integer<i, Policy::Orderable | Policy::Constexpr> { };
  229. template <int i>
  230. struct _constant
  231. : integer<i, Policy::Constant | Policy::Comparable | Policy::Orderable>
  232. { };
  233. }
  234. //////////////////////////////////////////////////////////////////////////
  235. // Model of Constant/IntegralConstant
  236. //////////////////////////////////////////////////////////////////////////
  237. template <test::Policy policy>
  238. struct IntegralConstant<test::Integer<policy>> {
  239. static constexpr bool value = static_cast<bool>(policy & test::Policy::Constant);
  240. };
  241. template <test::Policy policy, typename C>
  242. struct to_impl<test::Integer<policy>, C, when<
  243. (policy & test::Policy::Constant) &&
  244. hana::IntegralConstant<C>::value
  245. >>
  246. : embedding<is_embedded<typename C::value_type, int>::value>
  247. {
  248. template <typename N>
  249. static constexpr auto apply(N const&) {
  250. return test::integer<N::value, policy>{};
  251. }
  252. };
  253. //////////////////////////////////////////////////////////////////////////
  254. // Model of Comparable
  255. //////////////////////////////////////////////////////////////////////////
  256. template <test::Policy p1, test::Policy p2>
  257. struct equal_impl<test::Integer<p1>, test::Integer<p2>, when<
  258. // both Comparable or Orderable
  259. (p1 & (test::Policy::Comparable | test::Policy::Orderable)) &&
  260. (p2 & (test::Policy::Comparable | test::Policy::Orderable)) &&
  261. // one Constexpr and the other Constant, or both Constexpr
  262. (((p1 & test::Policy::Constant) && (p2 & test::Policy::Constexpr)) ||
  263. ((p1 & test::Policy::Constexpr) && (p2 & test::Policy::Constant)) ||
  264. ((p1 & test::Policy::Constexpr) && (p2 & test::Policy::Constexpr)))
  265. >> {
  266. template <typename X, typename Y>
  267. static constexpr bool apply(X const&, Y const&)
  268. { return X::value == Y::value; }
  269. };
  270. template <test::Policy p1, test::Policy p2>
  271. struct equal_impl<test::Integer<p1>, test::Integer<p2>, when<
  272. // both Comparable or Orderable
  273. (p1 & (test::Policy::Comparable | test::Policy::Orderable)) &&
  274. (p2 & (test::Policy::Comparable | test::Policy::Orderable)) &&
  275. // either one is Runtime
  276. ((p1 & test::Policy::Runtime) || (p2 & test::Policy::Runtime))
  277. >> {
  278. template <typename X, typename Y>
  279. static bool apply(X const&, Y const&)
  280. { return X::value == Y::value; }
  281. };
  282. //////////////////////////////////////////////////////////////////////////
  283. // Model of Orderable
  284. //////////////////////////////////////////////////////////////////////////
  285. template <test::Policy p1, test::Policy p2>
  286. struct less_impl<test::Integer<p1>, test::Integer<p2>, when<
  287. // both Orderable
  288. (p1 & test::Policy::Orderable) && (p2 & test::Policy::Orderable) &&
  289. // one Constexpr and the other Constant, or both Constexpr
  290. (((p1 & test::Policy::Constant) && (p2 & test::Policy::Constexpr)) ||
  291. ((p1 & test::Policy::Constexpr) && (p2 & test::Policy::Constant)) ||
  292. ((p1 & test::Policy::Constexpr) && (p2 & test::Policy::Constexpr)))
  293. >> {
  294. template <typename X, typename Y>
  295. static constexpr bool apply(X const&, Y const&)
  296. { return X::value < Y::value; }
  297. };
  298. template <test::Policy p1, test::Policy p2>
  299. struct less_impl<test::Integer<p1>, test::Integer<p2>, when<
  300. // both Orderable
  301. (p1 & test::Policy::Orderable) && (p2 & test::Policy::Orderable) &&
  302. // either one is Runtime
  303. ((p1 & test::Policy::Runtime) || (p2 & test::Policy::Runtime))
  304. >> {
  305. template <typename X, typename Y>
  306. static bool apply(X const&, Y const&)
  307. { return X::value < Y::value; }
  308. };
  309. }} // end namespace boost::hana
  310. #endif // !BOOST_HANA_TEST_LAWS_BASE_HPP