view.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. /*
  2. @file
  3. Defines experimental views.
  4. @copyright Louis Dionne 2013-2016
  5. Distributed under the Boost Software License, Version 1.0.
  6. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  7. */
  8. #ifndef BOOST_HANA_EXPERIMENTAL_VIEW_HPP
  9. #define BOOST_HANA_EXPERIMENTAL_VIEW_HPP
  10. #include <boost/hana/and.hpp>
  11. #include <boost/hana/at.hpp>
  12. #include <boost/hana/bool.hpp>
  13. #include <boost/hana/detail/decay.hpp>
  14. #include <boost/hana/fold_left.hpp>
  15. #include <boost/hana/functional/compose.hpp>
  16. #include <boost/hana/fwd/ap.hpp>
  17. #include <boost/hana/fwd/concat.hpp>
  18. #include <boost/hana/fwd/drop_front.hpp>
  19. #include <boost/hana/fwd/empty.hpp>
  20. #include <boost/hana/fwd/equal.hpp>
  21. #include <boost/hana/fwd/flatten.hpp>
  22. #include <boost/hana/fwd/is_empty.hpp>
  23. #include <boost/hana/fwd/less.hpp>
  24. #include <boost/hana/fwd/lift.hpp>
  25. #include <boost/hana/fwd/transform.hpp>
  26. #include <boost/hana/integral_constant.hpp>
  27. #include <boost/hana/length.hpp>
  28. #include <boost/hana/lexicographical_compare.hpp>
  29. #include <boost/hana/range.hpp>
  30. #include <boost/hana/tuple.hpp>
  31. #include <boost/hana/unpack.hpp>
  32. #include <cstddef>
  33. #include <type_traits>
  34. #include <utility>
  35. // Pros of views
  36. // - No temporary container created between algorithms
  37. // - Lazy, so only the minimum is required
  38. //
  39. // Cons of views
  40. // - Reference semantics mean possibility for dangling references
  41. // - Lose the ability to move from temporary containers
  42. // - When fetching the members of a view multiple times, no caching is done.
  43. // So for example, `t = transform(xs, f); at_c<0>(t); at_c<0>(t)` will
  44. // compute `f(at_c<0>(xs))` twice.
  45. // - push_back creates a joint_view and a single_view. The single_view holds
  46. // the value as a member. When doing multiple push_backs, we end up with a
  47. // joint_view<xxx, joint_view<single_view<T>, joint_view<single_view<T>, ....>>>
  48. // which contains a reference to `xxx` and all the `T`s by value. Such a
  49. // "view" is not cheap to copy, which is inconsistent with the usual
  50. // expectations about views.
  51. BOOST_HANA_NAMESPACE_BEGIN
  52. namespace experimental {
  53. struct view_tag;
  54. namespace detail {
  55. template <typename Sequence>
  56. struct is_view {
  57. static constexpr bool value = false;
  58. };
  59. template <typename Sequence>
  60. using view_storage = typename std::conditional<
  61. detail::is_view<Sequence>::value, Sequence, Sequence&
  62. >::type;
  63. }
  64. //////////////////////////////////////////////////////////////////////////
  65. // sliced_view
  66. //////////////////////////////////////////////////////////////////////////
  67. template <typename Sequence, std::size_t ...indices>
  68. struct sliced_view_t {
  69. detail::view_storage<Sequence> sequence_;
  70. using hana_tag = view_tag;
  71. };
  72. template <typename Sequence, typename Indices>
  73. constexpr auto sliced(Sequence& sequence, Indices const& indices) {
  74. return hana::unpack(indices, [&](auto ...i) {
  75. return sliced_view_t<Sequence, decltype(i)::value...>{sequence};
  76. });
  77. }
  78. namespace detail {
  79. template <typename Sequence, std::size_t ...i>
  80. struct is_view<sliced_view_t<Sequence, i...>> {
  81. static constexpr bool value = true;
  82. };
  83. }
  84. //////////////////////////////////////////////////////////////////////////
  85. // transformed_view
  86. //////////////////////////////////////////////////////////////////////////
  87. template <typename Sequence, typename F>
  88. struct transformed_view_t {
  89. detail::view_storage<Sequence> sequence_;
  90. F f_;
  91. using hana_tag = view_tag;
  92. };
  93. template <typename Sequence, typename F>
  94. constexpr transformed_view_t<Sequence, typename std::decay<F>::type>
  95. transformed(Sequence& sequence, F&& f) {
  96. return {sequence, static_cast<F&&>(f)};
  97. }
  98. namespace detail {
  99. template <typename Sequence, typename F>
  100. struct is_view<transformed_view_t<Sequence, F>> {
  101. static constexpr bool value = true;
  102. };
  103. }
  104. //////////////////////////////////////////////////////////////////////////
  105. // filtered_view
  106. //////////////////////////////////////////////////////////////////////////
  107. #if 0
  108. template <typename Sequence, typename Pred>
  109. using filtered_view_t = sliced_view_t<Sequence, detail::filtered_indices<...>>;
  110. template <typename Sequence, typename Pred>
  111. constexpr filtered_view_t<Sequence, Pred> filtered(Sequence& sequence, Pred&& pred) {
  112. return {sequence};
  113. }
  114. #endif
  115. //////////////////////////////////////////////////////////////////////////
  116. // joined_view
  117. //////////////////////////////////////////////////////////////////////////
  118. template <typename Sequence1, typename Sequence2>
  119. struct joined_view_t {
  120. detail::view_storage<Sequence1> sequence1_;
  121. detail::view_storage<Sequence2> sequence2_;
  122. using hana_tag = view_tag;
  123. };
  124. struct make_joined_view_t {
  125. template <typename Sequence1, typename Sequence2>
  126. constexpr joined_view_t<Sequence1, Sequence2> operator()(Sequence1& s1, Sequence2& s2) const {
  127. return {s1, s2};
  128. }
  129. };
  130. constexpr make_joined_view_t joined{};
  131. namespace detail {
  132. template <typename Sequence1, typename Sequence2>
  133. struct is_view<joined_view_t<Sequence1, Sequence2>> {
  134. static constexpr bool value = true;
  135. };
  136. }
  137. //////////////////////////////////////////////////////////////////////////
  138. // single_view
  139. //////////////////////////////////////////////////////////////////////////
  140. template <typename T>
  141. struct single_view_t {
  142. T value_;
  143. using hana_tag = view_tag;
  144. };
  145. template <typename T>
  146. constexpr single_view_t<typename hana::detail::decay<T>::type> single_view(T&& t) {
  147. return {static_cast<T&&>(t)};
  148. }
  149. namespace detail {
  150. template <typename T>
  151. struct is_view<single_view_t<T>> {
  152. static constexpr bool value = true;
  153. };
  154. }
  155. //////////////////////////////////////////////////////////////////////////
  156. // empty_view
  157. //////////////////////////////////////////////////////////////////////////
  158. struct empty_view_t {
  159. using hana_tag = view_tag;
  160. };
  161. constexpr empty_view_t empty_view() {
  162. return {};
  163. }
  164. namespace detail {
  165. template <>
  166. struct is_view<empty_view_t> {
  167. static constexpr bool value = true;
  168. };
  169. }
  170. } // end namespace experimental
  171. //////////////////////////////////////////////////////////////////////////
  172. // Foldable
  173. //////////////////////////////////////////////////////////////////////////
  174. template <>
  175. struct unpack_impl<experimental::view_tag> {
  176. // sliced_view
  177. template <typename Sequence, std::size_t ...i, typename F>
  178. static constexpr decltype(auto)
  179. apply(experimental::sliced_view_t<Sequence, i...> view, F&& f) {
  180. return static_cast<F&&>(f)(hana::at_c<i>(view.sequence_)...);
  181. }
  182. // transformed_view
  183. template <typename Sequence, typename F, typename G>
  184. static constexpr decltype(auto)
  185. apply(experimental::transformed_view_t<Sequence, F> view, G&& g) {
  186. return hana::unpack(view.sequence_, hana::on(static_cast<G&&>(g), view.f_));
  187. }
  188. // joined_view
  189. template <typename View, typename F, std::size_t ...i1, std::size_t ...i2>
  190. static constexpr decltype(auto)
  191. unpack_joined(View view, F&& f, std::index_sequence<i1...>,
  192. std::index_sequence<i2...>)
  193. {
  194. return static_cast<F&&>(f)(hana::at_c<i1>(view.sequence1_)...,
  195. hana::at_c<i2>(view.sequence2_)...);
  196. }
  197. template <typename S1, typename S2, typename F>
  198. static constexpr decltype(auto)
  199. apply(experimental::joined_view_t<S1, S2> view, F&& f) {
  200. constexpr auto N1 = decltype(hana::length(view.sequence1_))::value;
  201. constexpr auto N2 = decltype(hana::length(view.sequence2_))::value;
  202. return unpack_joined(view, static_cast<F&&>(f),
  203. std::make_index_sequence<N1>{},
  204. std::make_index_sequence<N2>{});
  205. }
  206. // single_view
  207. template <typename T, typename F>
  208. static constexpr decltype(auto) apply(experimental::single_view_t<T> view, F&& f) {
  209. return static_cast<F&&>(f)(view.value_);
  210. }
  211. // empty_view
  212. template <typename F>
  213. static constexpr decltype(auto) apply(experimental::empty_view_t, F&& f) {
  214. return static_cast<F&&>(f)();
  215. }
  216. };
  217. //////////////////////////////////////////////////////////////////////////
  218. // Iterable
  219. //////////////////////////////////////////////////////////////////////////
  220. template <>
  221. struct at_impl<experimental::view_tag> {
  222. // sliced_view
  223. template <typename Sequence, std::size_t ...i, typename N>
  224. static constexpr decltype(auto)
  225. apply(experimental::sliced_view_t<Sequence, i...> view, N const&) {
  226. constexpr std::size_t indices[] = {i...};
  227. constexpr std::size_t n = indices[N::value];
  228. return hana::at_c<n>(view.sequence_);
  229. }
  230. // transformed_view
  231. template <typename Sequence, typename F, typename N>
  232. static constexpr decltype(auto)
  233. apply(experimental::transformed_view_t<Sequence, F> view, N const& n) {
  234. return view.f_(hana::at(view.sequence_, n));
  235. }
  236. // joined_view
  237. template <std::size_t Left, typename View, typename N>
  238. static constexpr decltype(auto) at_joined_view(View view, N const&, hana::true_) {
  239. return hana::at_c<N::value>(view.sequence1_);
  240. }
  241. template <std::size_t Left, typename View, typename N>
  242. static constexpr decltype(auto) at_joined_view(View view, N const&, hana::false_) {
  243. return hana::at_c<N::value - Left>(view.sequence2_);
  244. }
  245. template <typename S1, typename S2, typename N>
  246. static constexpr decltype(auto)
  247. apply(experimental::joined_view_t<S1, S2> view, N const& n) {
  248. constexpr auto Left = decltype(hana::length(view.sequence1_))::value;
  249. return at_joined_view<Left>(view, n, hana::bool_c<(N::value < Left)>);
  250. }
  251. // single_view
  252. template <typename T, typename N>
  253. static constexpr decltype(auto) apply(experimental::single_view_t<T> view, N const&) {
  254. static_assert(N::value == 0,
  255. "trying to fetch an out-of-bounds element in a hana::single_view");
  256. return view.value_;
  257. }
  258. // empty_view
  259. template <typename N>
  260. static constexpr decltype(auto) apply(experimental::empty_view_t, N const&) = delete;
  261. };
  262. template <>
  263. struct length_impl<experimental::view_tag> {
  264. // sliced_view
  265. template <typename Sequence, std::size_t ...i>
  266. static constexpr auto
  267. apply(experimental::sliced_view_t<Sequence, i...>) {
  268. return hana::size_c<sizeof...(i)>;
  269. }
  270. // transformed_view
  271. template <typename Sequence, typename F>
  272. static constexpr auto apply(experimental::transformed_view_t<Sequence, F> view) {
  273. return hana::length(view.sequence_);
  274. }
  275. // joined_view
  276. template <typename S1, typename S2>
  277. static constexpr auto apply(experimental::joined_view_t<S1, S2> view) {
  278. return hana::size_c<
  279. decltype(hana::length(view.sequence1_))::value +
  280. decltype(hana::length(view.sequence2_))::value
  281. >;
  282. }
  283. // single_view
  284. template <typename T>
  285. static constexpr auto apply(experimental::single_view_t<T>) {
  286. return hana::size_c<1>;
  287. }
  288. // empty_view
  289. static constexpr auto apply(experimental::empty_view_t) {
  290. return hana::size_c<0>;
  291. }
  292. };
  293. template <>
  294. struct is_empty_impl<experimental::view_tag> {
  295. // sliced_view
  296. template <typename Sequence, std::size_t ...i>
  297. static constexpr auto
  298. apply(experimental::sliced_view_t<Sequence, i...>) {
  299. return hana::bool_c<sizeof...(i) == 0>;
  300. }
  301. // transformed_view
  302. template <typename Sequence, typename F>
  303. static constexpr auto apply(experimental::transformed_view_t<Sequence, F> view) {
  304. return hana::is_empty(view.sequence_);
  305. }
  306. // joined_view
  307. template <typename S1, typename S2>
  308. static constexpr auto apply(experimental::joined_view_t<S1, S2> view) {
  309. return hana::and_(hana::is_empty(view.sequence1_),
  310. hana::is_empty(view.sequence2_));
  311. }
  312. // single_view
  313. template <typename T>
  314. static constexpr auto apply(experimental::single_view_t<T>) {
  315. return hana::false_c;
  316. }
  317. // empty_view
  318. static constexpr auto apply(experimental::empty_view_t) {
  319. return hana::true_c;
  320. }
  321. };
  322. template <>
  323. struct drop_front_impl<experimental::view_tag> {
  324. template <typename View, typename N>
  325. static constexpr auto apply(View view, N const&) {
  326. constexpr auto n = N::value;
  327. constexpr auto Length = decltype(hana::length(view))::value;
  328. return experimental::sliced(view, hana::range_c<std::size_t, n, Length>);
  329. }
  330. };
  331. //////////////////////////////////////////////////////////////////////////
  332. // Functor
  333. //////////////////////////////////////////////////////////////////////////
  334. template <>
  335. struct transform_impl<experimental::view_tag> {
  336. template <typename Sequence, typename F, typename G>
  337. static constexpr auto
  338. apply(experimental::transformed_view_t<Sequence, F> view, G&& g) {
  339. return experimental::transformed(view.sequence_,
  340. hana::compose(static_cast<G&&>(g), view.f_));
  341. }
  342. template <typename View, typename F>
  343. static constexpr auto apply(View view, F&& f) {
  344. return experimental::transformed(view, static_cast<F&&>(f));
  345. }
  346. };
  347. //////////////////////////////////////////////////////////////////////////
  348. // Applicative
  349. //////////////////////////////////////////////////////////////////////////
  350. template <>
  351. struct lift_impl<experimental::view_tag> {
  352. template <typename T>
  353. static constexpr auto apply(T&& t) {
  354. return experimental::single_view(static_cast<T&&>(t));
  355. }
  356. };
  357. template <>
  358. struct ap_impl<experimental::view_tag> {
  359. template <typename F, typename X>
  360. static constexpr auto apply(F&& f, X&& x) {
  361. // TODO: Implement cleverly; we most likely need a cartesian_product
  362. // view or something like that.
  363. return hana::ap(hana::to_tuple(f), hana::to_tuple(x));
  364. }
  365. };
  366. //////////////////////////////////////////////////////////////////////////
  367. // Monad
  368. //////////////////////////////////////////////////////////////////////////
  369. template <>
  370. struct flatten_impl<experimental::view_tag> {
  371. template <typename View>
  372. static constexpr auto apply(View view) {
  373. // TODO: Implement a flattened_view instead
  374. return hana::fold_left(view, experimental::empty_view(),
  375. experimental::joined);
  376. }
  377. };
  378. //////////////////////////////////////////////////////////////////////////
  379. // MonadPlus
  380. //////////////////////////////////////////////////////////////////////////
  381. template <>
  382. struct concat_impl<experimental::view_tag> {
  383. template <typename View1, typename View2>
  384. static constexpr auto apply(View1 view1, View2 view2) {
  385. return experimental::joined(view1, view2);
  386. }
  387. };
  388. template <>
  389. struct empty_impl<experimental::view_tag> {
  390. static constexpr auto apply() {
  391. return experimental::empty_view();
  392. }
  393. };
  394. //////////////////////////////////////////////////////////////////////////
  395. // Comparable
  396. //////////////////////////////////////////////////////////////////////////
  397. template <>
  398. struct equal_impl<experimental::view_tag, experimental::view_tag> {
  399. template <typename View1, typename View2>
  400. static constexpr auto apply(View1 v1, View2 v2) {
  401. // TODO: Use a lexicographical comparison algorithm.
  402. return hana::equal(hana::to_tuple(v1), hana::to_tuple(v2));
  403. }
  404. };
  405. template <typename S>
  406. struct equal_impl<experimental::view_tag, S, hana::when<hana::Sequence<S>::value>> {
  407. template <typename View1, typename Seq>
  408. static constexpr auto apply(View1 v1, Seq const& s) {
  409. // TODO: Use a lexicographical comparison algorithm.
  410. return hana::equal(hana::to_tuple(v1), hana::to_tuple(s));
  411. }
  412. };
  413. template <typename S>
  414. struct equal_impl<S, experimental::view_tag, hana::when<hana::Sequence<S>::value>> {
  415. template <typename Seq, typename View2>
  416. static constexpr auto apply(Seq const& s, View2 v2) {
  417. // TODO: Use a lexicographical comparison algorithm.
  418. return hana::equal(hana::to_tuple(s), hana::to_tuple(v2));
  419. }
  420. };
  421. //////////////////////////////////////////////////////////////////////////
  422. // Orderable
  423. //////////////////////////////////////////////////////////////////////////
  424. template <>
  425. struct less_impl<experimental::view_tag, experimental::view_tag> {
  426. template <typename View1, typename View2>
  427. static constexpr auto apply(View1 v1, View2 v2) {
  428. return hana::lexicographical_compare(v1, v2);
  429. }
  430. };
  431. template <typename S>
  432. struct less_impl<experimental::view_tag, S, hana::when<hana::Sequence<S>::value>> {
  433. template <typename View1, typename Seq>
  434. static constexpr auto apply(View1 v1, Seq const& s) {
  435. return hana::lexicographical_compare(v1, s);
  436. }
  437. };
  438. template <typename S>
  439. struct less_impl<S, experimental::view_tag, hana::when<hana::Sequence<S>::value>> {
  440. template <typename Seq, typename View2>
  441. static constexpr auto apply(Seq const& s, View2 v2) {
  442. return hana::lexicographical_compare(s, v2);
  443. }
  444. };
  445. BOOST_HANA_NAMESPACE_END
  446. #endif // !BOOST_HANA_EXPERIMENTAL_VIEW_HPP