3 Defines experimental views.
5 @copyright Louis Dionne 2013-2016
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/fwd/ap.hpp>
20 #include <boost/hana/fwd/concat.hpp>
21 #include <boost/hana/fwd/drop_front.hpp>
22 #include <boost/hana/fwd/empty.hpp>
23 #include <boost/hana/fwd/equal.hpp>
24 #include <boost/hana/fwd/flatten.hpp>
25 #include <boost/hana/fwd/is_empty.hpp>
26 #include <boost/hana/fwd/less.hpp>
27 #include <boost/hana/fwd/lift.hpp>
28 #include <boost/hana/fwd/transform.hpp>
29 #include <boost/hana/integral_constant.hpp>
30 #include <boost/hana/length.hpp>
31 #include <boost/hana/lexicographical_compare.hpp>
32 #include <boost/hana/range.hpp>
33 #include <boost/hana/tuple.hpp>
34 #include <boost/hana/unpack.hpp>
37 #include <type_traits>
42 // - No temporary container created between algorithms
43 // - Lazy, so only the minimum is required
46 // - Reference semantics mean possibility for dangling references
47 // - Lose the ability to move from temporary containers
48 // - When fetching the members of a view multiple times, no caching is done.
49 // So for example, `t = transform(xs, f); at_c<0>(t); at_c<0>(t)` will
50 // compute `f(at_c<0>(xs))` twice.
51 // - push_back creates a joint_view and a single_view. The single_view holds
52 // the value as a member. When doing multiple push_backs, we end up with a
53 // joint_view<xxx, joint_view<single_view<T>, joint_view<single_view<T>, ....>>>
54 // which contains a reference to `xxx` and all the `T`s by value. Such a
55 // "view" is not cheap to copy, which is inconsistent with the usual
56 // expectations about views.
58 BOOST_HANA_NAMESPACE_BEGIN
60 namespace experimental {
64 template <typename Sequence>
66 static constexpr bool value = false;
69 template <typename Sequence>
70 using view_storage = typename std::conditional<
71 detail::is_view<Sequence>::value, Sequence, Sequence&
75 //////////////////////////////////////////////////////////////////////////
77 //////////////////////////////////////////////////////////////////////////
78 template <typename Sequence, std::size_t ...indices>
79 struct sliced_view_t {
80 detail::view_storage<Sequence> sequence_;
81 using hana_tag = view_tag;
84 template <typename Sequence, typename Indices>
85 constexpr auto sliced(Sequence& sequence, Indices const& indices) {
86 return hana::unpack(indices, [&](auto ...i) {
87 return sliced_view_t<Sequence, decltype(i)::value...>{sequence};
92 template <typename Sequence, std::size_t ...i>
93 struct is_view<sliced_view_t<Sequence, i...>> {
94 static constexpr bool value = true;
98 //////////////////////////////////////////////////////////////////////////
100 //////////////////////////////////////////////////////////////////////////
101 template <typename Sequence, typename F>
102 struct transformed_view_t {
103 detail::view_storage<Sequence> sequence_;
105 using hana_tag = view_tag;
108 template <typename Sequence, typename F>
109 constexpr transformed_view_t<Sequence, typename hana::detail::decay<F>::type>
110 transformed(Sequence& sequence, F&& f) {
111 return {sequence, static_cast<F&&>(f)};
115 template <typename Sequence, typename F>
116 struct is_view<transformed_view_t<Sequence, F>> {
117 static constexpr bool value = true;
121 //////////////////////////////////////////////////////////////////////////
123 //////////////////////////////////////////////////////////////////////////
125 template <typename Sequence, typename Pred>
126 using filtered_view_t = sliced_view_t<Sequence, detail::filtered_indices<...>>;
128 template <typename Sequence, typename Pred>
129 constexpr filtered_view_t<Sequence, Pred> filtered(Sequence& sequence, Pred&& pred) {
134 //////////////////////////////////////////////////////////////////////////
136 //////////////////////////////////////////////////////////////////////////
137 template <typename Sequence1, typename Sequence2>
138 struct joined_view_t {
139 detail::view_storage<Sequence1> sequence1_;
140 detail::view_storage<Sequence2> sequence2_;
141 using hana_tag = view_tag;
144 struct make_joined_view_t {
145 template <typename Sequence1, typename Sequence2>
146 constexpr joined_view_t<Sequence1, Sequence2> operator()(Sequence1& s1, Sequence2& s2) const {
150 constexpr make_joined_view_t joined{};
153 template <typename Sequence1, typename Sequence2>
154 struct is_view<joined_view_t<Sequence1, Sequence2>> {
155 static constexpr bool value = true;
159 //////////////////////////////////////////////////////////////////////////
161 //////////////////////////////////////////////////////////////////////////
162 template <typename T>
163 struct single_view_t {
165 using hana_tag = view_tag;
168 template <typename T>
169 constexpr single_view_t<typename hana::detail::decay<T>::type> single_view(T&& t) {
170 return {static_cast<T&&>(t)};
174 template <typename T>
175 struct is_view<single_view_t<T>> {
176 static constexpr bool value = true;
180 //////////////////////////////////////////////////////////////////////////
182 //////////////////////////////////////////////////////////////////////////
183 struct empty_view_t {
184 using hana_tag = view_tag;
187 constexpr empty_view_t empty_view() {
193 struct is_view<empty_view_t> {
194 static constexpr bool value = true;
197 } // end namespace experimental
199 //////////////////////////////////////////////////////////////////////////
201 //////////////////////////////////////////////////////////////////////////
203 struct unpack_impl<experimental::view_tag> {
205 template <typename Sequence, std::size_t ...i, typename F>
206 static constexpr decltype(auto)
207 apply(experimental::sliced_view_t<Sequence, i...> view, F&& f) {
208 (void)view; // Remove spurious unused variable warning with GCC
209 return static_cast<F&&>(f)(hana::at_c<i>(view.sequence_)...);
213 template <typename Sequence, typename F, typename G>
214 static constexpr decltype(auto)
215 apply(experimental::transformed_view_t<Sequence, F> view, G&& g) {
216 return hana::unpack(view.sequence_, hana::on(static_cast<G&&>(g), view.f_));
220 template <typename View, typename F, std::size_t ...i1, std::size_t ...i2>
221 static constexpr decltype(auto)
222 unpack_joined(View view, F&& f, std::index_sequence<i1...>,
223 std::index_sequence<i2...>)
225 (void)view; // Remove spurious unused variable warning with GCC
226 return static_cast<F&&>(f)(hana::at_c<i1>(view.sequence1_)...,
227 hana::at_c<i2>(view.sequence2_)...);
230 template <typename S1, typename S2, typename F>
231 static constexpr decltype(auto)
232 apply(experimental::joined_view_t<S1, S2> view, F&& f) {
233 constexpr auto N1 = decltype(hana::length(view.sequence1_))::value;
234 constexpr auto N2 = decltype(hana::length(view.sequence2_))::value;
235 return unpack_joined(view, static_cast<F&&>(f),
236 std::make_index_sequence<N1>{},
237 std::make_index_sequence<N2>{});
241 template <typename T, typename F>
242 static constexpr decltype(auto) apply(experimental::single_view_t<T> view, F&& f) {
243 return static_cast<F&&>(f)(view.value_);
247 template <typename F>
248 static constexpr decltype(auto) apply(experimental::empty_view_t, F&& f) {
249 return static_cast<F&&>(f)();
253 //////////////////////////////////////////////////////////////////////////
255 //////////////////////////////////////////////////////////////////////////
257 struct at_impl<experimental::view_tag> {
259 template <typename Sequence, std::size_t ...i, typename N>
260 static constexpr decltype(auto)
261 apply(experimental::sliced_view_t<Sequence, i...> view, N const&) {
262 constexpr std::size_t indices[] = {i...};
263 constexpr std::size_t n = indices[N::value];
264 return hana::at_c<n>(view.sequence_);
268 template <typename Sequence, typename F, typename N>
269 static constexpr decltype(auto)
270 apply(experimental::transformed_view_t<Sequence, F> view, N const& n) {
271 return view.f_(hana::at(view.sequence_, n));
275 template <std::size_t Left, typename View, typename N>
276 static constexpr decltype(auto) at_joined_view(View view, N const&, hana::true_) {
277 return hana::at_c<N::value>(view.sequence1_);
280 template <std::size_t Left, typename View, typename N>
281 static constexpr decltype(auto) at_joined_view(View view, N const&, hana::false_) {
282 return hana::at_c<N::value - Left>(view.sequence2_);
285 template <typename S1, typename S2, typename N>
286 static constexpr decltype(auto)
287 apply(experimental::joined_view_t<S1, S2> view, N const& n) {
288 constexpr auto Left = decltype(hana::length(view.sequence1_))::value;
289 return at_joined_view<Left>(view, n, hana::bool_c<(N::value < Left)>);
293 template <typename T, typename N>
294 static constexpr decltype(auto) apply(experimental::single_view_t<T> view, N const&) {
295 static_assert(N::value == 0,
296 "trying to fetch an out-of-bounds element in a hana::single_view");
301 template <typename N>
302 static constexpr decltype(auto) apply(experimental::empty_view_t, N const&) = delete;
306 struct length_impl<experimental::view_tag> {
308 template <typename Sequence, std::size_t ...i>
309 static constexpr auto
310 apply(experimental::sliced_view_t<Sequence, i...>) {
311 return hana::size_c<sizeof...(i)>;
315 template <typename Sequence, typename F>
316 static constexpr auto apply(experimental::transformed_view_t<Sequence, F> view) {
317 return hana::length(view.sequence_);
321 template <typename S1, typename S2>
322 static constexpr auto apply(experimental::joined_view_t<S1, S2> view) {
324 decltype(hana::length(view.sequence1_))::value +
325 decltype(hana::length(view.sequence2_))::value
330 template <typename T>
331 static constexpr auto apply(experimental::single_view_t<T>) {
332 return hana::size_c<1>;
336 static constexpr auto apply(experimental::empty_view_t) {
337 return hana::size_c<0>;
342 struct is_empty_impl<experimental::view_tag> {
344 template <typename Sequence, std::size_t ...i>
345 static constexpr auto
346 apply(experimental::sliced_view_t<Sequence, i...>) {
347 return hana::bool_c<sizeof...(i) == 0>;
351 template <typename Sequence, typename F>
352 static constexpr auto apply(experimental::transformed_view_t<Sequence, F> view) {
353 return hana::is_empty(view.sequence_);
357 template <typename S1, typename S2>
358 static constexpr auto apply(experimental::joined_view_t<S1, S2> view) {
359 return hana::and_(hana::is_empty(view.sequence1_),
360 hana::is_empty(view.sequence2_));
364 template <typename T>
365 static constexpr auto apply(experimental::single_view_t<T>) {
366 return hana::false_c;
370 static constexpr auto apply(experimental::empty_view_t) {
376 struct drop_front_impl<experimental::view_tag> {
377 template <typename View, typename N>
378 static constexpr auto apply(View view, N const&) {
379 constexpr auto n = N::value;
380 constexpr auto Length = decltype(hana::length(view))::value;
381 return experimental::sliced(view, hana::range_c<std::size_t, n, Length>);
385 //////////////////////////////////////////////////////////////////////////
387 //////////////////////////////////////////////////////////////////////////
389 struct transform_impl<experimental::view_tag> {
390 template <typename Sequence, typename F, typename G>
391 static constexpr auto
392 apply(experimental::transformed_view_t<Sequence, F> view, G&& g) {
393 return experimental::transformed(view.sequence_,
394 hana::compose(static_cast<G&&>(g), view.f_));
397 template <typename View, typename F>
398 static constexpr auto apply(View view, F&& f) {
399 return experimental::transformed(view, static_cast<F&&>(f));
403 //////////////////////////////////////////////////////////////////////////
405 //////////////////////////////////////////////////////////////////////////
407 struct lift_impl<experimental::view_tag> {
408 template <typename T>
409 static constexpr auto apply(T&& t) {
410 return experimental::single_view(static_cast<T&&>(t));
415 struct ap_impl<experimental::view_tag> {
416 template <typename F, typename X>
417 static constexpr auto apply(F&& f, X&& x) {
418 // TODO: Implement cleverly; we most likely need a cartesian_product
419 // view or something like that.
420 return hana::ap(hana::to_tuple(f), hana::to_tuple(x));
424 //////////////////////////////////////////////////////////////////////////
426 //////////////////////////////////////////////////////////////////////////
428 struct flatten_impl<experimental::view_tag> {
429 template <typename View>
430 static constexpr auto apply(View view) {
431 // TODO: Implement a flattened_view instead
432 return hana::fold_left(view, experimental::empty_view(),
433 experimental::joined);
437 //////////////////////////////////////////////////////////////////////////
439 //////////////////////////////////////////////////////////////////////////
441 struct concat_impl<experimental::view_tag> {
442 template <typename View1, typename View2>
443 static constexpr auto apply(View1 view1, View2 view2) {
444 return experimental::joined(view1, view2);
449 struct empty_impl<experimental::view_tag> {
450 static constexpr auto apply() {
451 return experimental::empty_view();
455 //////////////////////////////////////////////////////////////////////////
457 //////////////////////////////////////////////////////////////////////////
459 struct equal_impl<experimental::view_tag, experimental::view_tag> {
460 template <typename View1, typename View2>
461 static constexpr auto apply(View1 v1, View2 v2) {
462 // TODO: Use a lexicographical comparison algorithm.
463 return hana::equal(hana::to_tuple(v1), hana::to_tuple(v2));
467 template <typename S>
468 struct equal_impl<experimental::view_tag, S, hana::when<hana::Sequence<S>::value>> {
469 template <typename View1, typename Seq>
470 static constexpr auto apply(View1 v1, Seq const& s) {
471 // TODO: Use a lexicographical comparison algorithm.
472 return hana::equal(hana::to_tuple(v1), hana::to_tuple(s));
476 template <typename S>
477 struct equal_impl<S, experimental::view_tag, hana::when<hana::Sequence<S>::value>> {
478 template <typename Seq, typename View2>
479 static constexpr auto apply(Seq const& s, View2 v2) {
480 // TODO: Use a lexicographical comparison algorithm.
481 return hana::equal(hana::to_tuple(s), hana::to_tuple(v2));
485 //////////////////////////////////////////////////////////////////////////
487 //////////////////////////////////////////////////////////////////////////
489 struct less_impl<experimental::view_tag, experimental::view_tag> {
490 template <typename View1, typename View2>
491 static constexpr auto apply(View1 v1, View2 v2) {
492 return hana::lexicographical_compare(v1, v2);
496 template <typename S>
497 struct less_impl<experimental::view_tag, S, hana::when<hana::Sequence<S>::value>> {
498 template <typename View1, typename Seq>
499 static constexpr auto apply(View1 v1, Seq const& s) {
500 return hana::lexicographical_compare(v1, s);
504 template <typename S>
505 struct less_impl<S, experimental::view_tag, hana::when<hana::Sequence<S>::value>> {
506 template <typename Seq, typename View2>
507 static constexpr auto apply(Seq const& s, View2 v2) {
508 return hana::lexicographical_compare(s, v2);
512 BOOST_HANA_NAMESPACE_END
514 #endif // !BOOST_HANA_EXPERIMENTAL_VIEW_HPP