3 Defines experimental views.
5 @copyright Louis Dionne 2013-2017
6 Distributed under the Boost Software License, Version 1.0.
7 (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
10 #ifndef BOOST_HANA_EXPERIMENTAL_VIEW_HPP
11 #define BOOST_HANA_EXPERIMENTAL_VIEW_HPP
13 #include <boost/hana/and.hpp>
14 #include <boost/hana/at.hpp>
15 #include <boost/hana/bool.hpp>
16 #include <boost/hana/detail/decay.hpp>
17 #include <boost/hana/fold_left.hpp>
18 #include <boost/hana/functional/compose.hpp>
19 #include <boost/hana/functional/on.hpp>
20 #include <boost/hana/fwd/ap.hpp>
21 #include <boost/hana/fwd/concat.hpp>
22 #include <boost/hana/fwd/drop_front.hpp>
23 #include <boost/hana/fwd/empty.hpp>
24 #include <boost/hana/fwd/equal.hpp>
25 #include <boost/hana/fwd/flatten.hpp>
26 #include <boost/hana/fwd/is_empty.hpp>
27 #include <boost/hana/fwd/less.hpp>
28 #include <boost/hana/fwd/lift.hpp>
29 #include <boost/hana/fwd/transform.hpp>
30 #include <boost/hana/integral_constant.hpp>
31 #include <boost/hana/length.hpp>
32 #include <boost/hana/lexicographical_compare.hpp>
33 #include <boost/hana/range.hpp>
34 #include <boost/hana/tuple.hpp>
35 #include <boost/hana/unpack.hpp>
38 #include <type_traits>
43 // - No temporary container created between algorithms
44 // - Lazy, so only the minimum is required
47 // - Reference semantics mean possibility for dangling references
48 // - Lose the ability to move from temporary containers
49 // - When fetching the members of a view multiple times, no caching is done.
50 // So for example, `t = transform(xs, f); at_c<0>(t); at_c<0>(t)` will
51 // compute `f(at_c<0>(xs))` twice.
52 // - push_back creates a joint_view and a single_view. The single_view holds
53 // the value as a member. When doing multiple push_backs, we end up with a
54 // joint_view<xxx, joint_view<single_view<T>, joint_view<single_view<T>, ....>>>
55 // which contains a reference to `xxx` and all the `T`s by value. Such a
56 // "view" is not cheap to copy, which is inconsistent with the usual
57 // expectations about views.
59 BOOST_HANA_NAMESPACE_BEGIN
61 namespace experimental {
65 template <typename Sequence>
67 static constexpr bool value = false;
70 template <typename Sequence>
71 using view_storage = typename std::conditional<
72 detail::is_view<Sequence>::value, Sequence, Sequence&
76 //////////////////////////////////////////////////////////////////////////
78 //////////////////////////////////////////////////////////////////////////
79 template <typename Sequence, std::size_t ...indices>
80 struct sliced_view_t {
81 detail::view_storage<Sequence> sequence_;
82 using hana_tag = view_tag;
85 template <typename Sequence, typename Indices>
86 constexpr auto sliced(Sequence& sequence, Indices const& indices) {
87 return hana::unpack(indices, [&](auto ...i) {
88 return sliced_view_t<Sequence, decltype(i)::value...>{sequence};
93 template <typename Sequence, std::size_t ...i>
94 struct is_view<sliced_view_t<Sequence, i...>> {
95 static constexpr bool value = true;
99 //////////////////////////////////////////////////////////////////////////
101 //////////////////////////////////////////////////////////////////////////
102 template <typename Sequence, typename F>
103 struct transformed_view_t {
104 detail::view_storage<Sequence> sequence_;
106 using hana_tag = view_tag;
109 template <typename Sequence, typename F>
110 constexpr transformed_view_t<Sequence, typename hana::detail::decay<F>::type>
111 transformed(Sequence& sequence, F&& f) {
112 return {sequence, static_cast<F&&>(f)};
116 template <typename Sequence, typename F>
117 struct is_view<transformed_view_t<Sequence, F>> {
118 static constexpr bool value = true;
122 //////////////////////////////////////////////////////////////////////////
124 //////////////////////////////////////////////////////////////////////////
126 template <typename Sequence, typename Pred>
127 using filtered_view_t = sliced_view_t<Sequence, detail::filtered_indices<...>>;
129 template <typename Sequence, typename Pred>
130 constexpr filtered_view_t<Sequence, Pred> filtered(Sequence& sequence, Pred&& pred) {
135 //////////////////////////////////////////////////////////////////////////
137 //////////////////////////////////////////////////////////////////////////
138 template <typename Sequence1, typename Sequence2>
139 struct joined_view_t {
140 detail::view_storage<Sequence1> sequence1_;
141 detail::view_storage<Sequence2> sequence2_;
142 using hana_tag = view_tag;
145 struct make_joined_view_t {
146 template <typename Sequence1, typename Sequence2>
147 constexpr joined_view_t<Sequence1, Sequence2> operator()(Sequence1& s1, Sequence2& s2) const {
151 constexpr make_joined_view_t joined{};
154 template <typename Sequence1, typename Sequence2>
155 struct is_view<joined_view_t<Sequence1, Sequence2>> {
156 static constexpr bool value = true;
160 //////////////////////////////////////////////////////////////////////////
162 //////////////////////////////////////////////////////////////////////////
163 template <typename T>
164 struct single_view_t {
166 using hana_tag = view_tag;
169 template <typename T>
170 constexpr single_view_t<typename hana::detail::decay<T>::type> single_view(T&& t) {
171 return {static_cast<T&&>(t)};
175 template <typename T>
176 struct is_view<single_view_t<T>> {
177 static constexpr bool value = true;
181 //////////////////////////////////////////////////////////////////////////
183 //////////////////////////////////////////////////////////////////////////
184 struct empty_view_t {
185 using hana_tag = view_tag;
188 constexpr empty_view_t empty_view() {
194 struct is_view<empty_view_t> {
195 static constexpr bool value = true;
198 } // end namespace experimental
200 //////////////////////////////////////////////////////////////////////////
202 //////////////////////////////////////////////////////////////////////////
204 struct unpack_impl<experimental::view_tag> {
206 template <typename Sequence, std::size_t ...i, typename F>
207 static constexpr decltype(auto)
208 apply(experimental::sliced_view_t<Sequence, i...> view, F&& f) {
209 (void)view; // Remove spurious unused variable warning with GCC
210 return static_cast<F&&>(f)(hana::at_c<i>(view.sequence_)...);
214 template <typename Sequence, typename F, typename G>
215 static constexpr decltype(auto)
216 apply(experimental::transformed_view_t<Sequence, F> view, G&& g) {
217 return hana::unpack(view.sequence_, hana::on(static_cast<G&&>(g), view.f_));
221 template <typename View, typename F, std::size_t ...i1, std::size_t ...i2>
222 static constexpr decltype(auto)
223 unpack_joined(View view, F&& f, std::index_sequence<i1...>,
224 std::index_sequence<i2...>)
226 (void)view; // Remove spurious unused variable warning with GCC
227 return static_cast<F&&>(f)(hana::at_c<i1>(view.sequence1_)...,
228 hana::at_c<i2>(view.sequence2_)...);
231 template <typename S1, typename S2, typename F>
232 static constexpr decltype(auto)
233 apply(experimental::joined_view_t<S1, S2> view, F&& f) {
234 constexpr auto N1 = decltype(hana::length(view.sequence1_))::value;
235 constexpr auto N2 = decltype(hana::length(view.sequence2_))::value;
236 return unpack_joined(view, static_cast<F&&>(f),
237 std::make_index_sequence<N1>{},
238 std::make_index_sequence<N2>{});
242 template <typename T, typename F>
243 static constexpr decltype(auto) apply(experimental::single_view_t<T> view, F&& f) {
244 return static_cast<F&&>(f)(view.value_);
248 template <typename F>
249 static constexpr decltype(auto) apply(experimental::empty_view_t, F&& f) {
250 return static_cast<F&&>(f)();
254 //////////////////////////////////////////////////////////////////////////
256 //////////////////////////////////////////////////////////////////////////
258 struct at_impl<experimental::view_tag> {
260 template <typename Sequence, std::size_t ...i, typename N>
261 static constexpr decltype(auto)
262 apply(experimental::sliced_view_t<Sequence, i...> view, N const&) {
263 constexpr std::size_t indices[] = {i...};
264 constexpr std::size_t n = indices[N::value];
265 return hana::at_c<n>(view.sequence_);
269 template <typename Sequence, typename F, typename N>
270 static constexpr decltype(auto)
271 apply(experimental::transformed_view_t<Sequence, F> view, N const& n) {
272 return view.f_(hana::at(view.sequence_, n));
276 template <std::size_t Left, typename View, typename N>
277 static constexpr decltype(auto) at_joined_view(View view, N const&, hana::true_) {
278 return hana::at_c<N::value>(view.sequence1_);
281 template <std::size_t Left, typename View, typename N>
282 static constexpr decltype(auto) at_joined_view(View view, N const&, hana::false_) {
283 return hana::at_c<N::value - Left>(view.sequence2_);
286 template <typename S1, typename S2, typename N>
287 static constexpr decltype(auto)
288 apply(experimental::joined_view_t<S1, S2> view, N const& n) {
289 constexpr auto Left = decltype(hana::length(view.sequence1_))::value;
290 return at_joined_view<Left>(view, n, hana::bool_c<(N::value < Left)>);
294 template <typename T, typename N>
295 static constexpr decltype(auto) apply(experimental::single_view_t<T> view, N const&) {
296 static_assert(N::value == 0,
297 "trying to fetch an out-of-bounds element in a hana::single_view");
302 template <typename N>
303 static constexpr decltype(auto) apply(experimental::empty_view_t, N const&) = delete;
307 struct length_impl<experimental::view_tag> {
309 template <typename Sequence, std::size_t ...i>
310 static constexpr auto
311 apply(experimental::sliced_view_t<Sequence, i...>) {
312 return hana::size_c<sizeof...(i)>;
316 template <typename Sequence, typename F>
317 static constexpr auto apply(experimental::transformed_view_t<Sequence, F> view) {
318 return hana::length(view.sequence_);
322 template <typename S1, typename S2>
323 static constexpr auto apply(experimental::joined_view_t<S1, S2> view) {
325 decltype(hana::length(view.sequence1_))::value +
326 decltype(hana::length(view.sequence2_))::value
331 template <typename T>
332 static constexpr auto apply(experimental::single_view_t<T>) {
333 return hana::size_c<1>;
337 static constexpr auto apply(experimental::empty_view_t) {
338 return hana::size_c<0>;
343 struct is_empty_impl<experimental::view_tag> {
345 template <typename Sequence, std::size_t ...i>
346 static constexpr auto
347 apply(experimental::sliced_view_t<Sequence, i...>) {
348 return hana::bool_c<sizeof...(i) == 0>;
352 template <typename Sequence, typename F>
353 static constexpr auto apply(experimental::transformed_view_t<Sequence, F> view) {
354 return hana::is_empty(view.sequence_);
358 template <typename S1, typename S2>
359 static constexpr auto apply(experimental::joined_view_t<S1, S2> view) {
360 return hana::and_(hana::is_empty(view.sequence1_),
361 hana::is_empty(view.sequence2_));
365 template <typename T>
366 static constexpr auto apply(experimental::single_view_t<T>) {
367 return hana::false_c;
371 static constexpr auto apply(experimental::empty_view_t) {
377 struct drop_front_impl<experimental::view_tag> {
378 template <typename View, typename N>
379 static constexpr auto apply(View view, N const&) {
380 constexpr auto n = N::value;
381 constexpr auto Length = decltype(hana::length(view))::value;
382 return experimental::sliced(view, hana::range_c<std::size_t, n, Length>);
386 //////////////////////////////////////////////////////////////////////////
388 //////////////////////////////////////////////////////////////////////////
390 struct transform_impl<experimental::view_tag> {
391 template <typename Sequence, typename F, typename G>
392 static constexpr auto
393 apply(experimental::transformed_view_t<Sequence, F> view, G&& g) {
394 return experimental::transformed(view.sequence_,
395 hana::compose(static_cast<G&&>(g), view.f_));
398 template <typename View, typename F>
399 static constexpr auto apply(View view, F&& f) {
400 return experimental::transformed(view, static_cast<F&&>(f));
404 //////////////////////////////////////////////////////////////////////////
406 //////////////////////////////////////////////////////////////////////////
408 struct lift_impl<experimental::view_tag> {
409 template <typename T>
410 static constexpr auto apply(T&& t) {
411 return experimental::single_view(static_cast<T&&>(t));
416 struct ap_impl<experimental::view_tag> {
417 template <typename F, typename X>
418 static constexpr auto apply(F&& f, X&& x) {
419 // TODO: Implement cleverly; we most likely need a cartesian_product
420 // view or something like that.
421 return hana::ap(hana::to_tuple(f), hana::to_tuple(x));
425 //////////////////////////////////////////////////////////////////////////
427 //////////////////////////////////////////////////////////////////////////
429 struct flatten_impl<experimental::view_tag> {
430 template <typename View>
431 static constexpr auto apply(View view) {
432 // TODO: Implement a flattened_view instead
433 return hana::fold_left(view, experimental::empty_view(),
434 experimental::joined);
438 //////////////////////////////////////////////////////////////////////////
440 //////////////////////////////////////////////////////////////////////////
442 struct concat_impl<experimental::view_tag> {
443 template <typename View1, typename View2>
444 static constexpr auto apply(View1 view1, View2 view2) {
445 return experimental::joined(view1, view2);
450 struct empty_impl<experimental::view_tag> {
451 static constexpr auto apply() {
452 return experimental::empty_view();
456 //////////////////////////////////////////////////////////////////////////
458 //////////////////////////////////////////////////////////////////////////
460 struct equal_impl<experimental::view_tag, experimental::view_tag> {
461 template <typename View1, typename View2>
462 static constexpr auto apply(View1 v1, View2 v2) {
463 // TODO: Use a lexicographical comparison algorithm.
464 return hana::equal(hana::to_tuple(v1), hana::to_tuple(v2));
468 template <typename S>
469 struct equal_impl<experimental::view_tag, S, hana::when<hana::Sequence<S>::value>> {
470 template <typename View1, typename Seq>
471 static constexpr auto apply(View1 v1, Seq const& s) {
472 // TODO: Use a lexicographical comparison algorithm.
473 return hana::equal(hana::to_tuple(v1), hana::to_tuple(s));
477 template <typename S>
478 struct equal_impl<S, experimental::view_tag, hana::when<hana::Sequence<S>::value>> {
479 template <typename Seq, typename View2>
480 static constexpr auto apply(Seq const& s, View2 v2) {
481 // TODO: Use a lexicographical comparison algorithm.
482 return hana::equal(hana::to_tuple(s), hana::to_tuple(v2));
486 //////////////////////////////////////////////////////////////////////////
488 //////////////////////////////////////////////////////////////////////////
490 struct less_impl<experimental::view_tag, experimental::view_tag> {
491 template <typename View1, typename View2>
492 static constexpr auto apply(View1 v1, View2 v2) {
493 return hana::lexicographical_compare(v1, v2);
497 template <typename S>
498 struct less_impl<experimental::view_tag, S, hana::when<hana::Sequence<S>::value>> {
499 template <typename View1, typename Seq>
500 static constexpr auto apply(View1 v1, Seq const& s) {
501 return hana::lexicographical_compare(v1, s);
505 template <typename S>
506 struct less_impl<S, experimental::view_tag, hana::when<hana::Sequence<S>::value>> {
507 template <typename Seq, typename View2>
508 static constexpr auto apply(Seq const& s, View2 v2) {
509 return hana::lexicographical_compare(s, v2);
513 BOOST_HANA_NAMESPACE_END
515 #endif // !BOOST_HANA_EXPERIMENTAL_VIEW_HPP