• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*!
2 @file
3 Adapts `std::array` for use with Hana.
4 
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)
8  */
9 
10 #ifndef BOOST_HANA_EXT_STD_ARRAY_HPP
11 #define BOOST_HANA_EXT_STD_ARRAY_HPP
12 
13 #include <boost/hana/bool.hpp>
14 #include <boost/hana/config.hpp>
15 #include <boost/hana/detail/algorithm.hpp>
16 #include <boost/hana/fwd/at.hpp>
17 #include <boost/hana/fwd/core/tag_of.hpp>
18 #include <boost/hana/fwd/drop_front.hpp>
19 #include <boost/hana/fwd/equal.hpp>
20 #include <boost/hana/fwd/is_empty.hpp>
21 #include <boost/hana/fwd/length.hpp>
22 #include <boost/hana/fwd/less.hpp>
23 #include <boost/hana/integral_constant.hpp>
24 
25 #include <array>
26 #include <cstddef>
27 #include <type_traits>
28 #include <utility>
29 
30 
31 #ifdef BOOST_HANA_DOXYGEN_INVOKED
32 namespace std {
33     //! @ingroup group-ext-std
34     //! Adaptation of `std::array` for Hana.
35     //!
36     //!
37     //!
38     //! Modeled concepts
39     //! ----------------
40     //! 1. `Comparable`\n
41     //! `std::array`s are compared as per `std::equal`, except that two arrays
42     //! with different sizes compare unequal instead of triggering an error
43     //! and the result of the comparison is `constexpr` if both arrays are
44     //! `constexpr`.
45     //! @include example/ext/std/array/comparable.cpp
46     //!
47     //! 2. `Orderable`\n
48     //! `std::array`s are ordered with the usual lexicographical ordering,
49     //! except that two arrays with different size can be ordered instead
50     //! of triggering an error and the result of the comparison is `constexpr`
51     //! if both arrays are `constexpr`.
52     //! @include example/ext/std/array/orderable.cpp
53     //!
54     //! 3. `Foldable`\n
55     //! Folding an array from the left is equivalent to calling
56     //! `std::accumulate` on it, except it can be `constexpr`.
57     //! @include example/ext/std/array/foldable.cpp
58     //!
59     //! 4. `Iterable`\n
60     //! Iterating over a `std::array` is equivalent to iterating over it with
61     //! a normal `for` loop.
62     //! @include example/ext/std/array/iterable.cpp
63     template <typename T, std::size_t N>
64     struct array { };
65 }
66 #endif
67 
68 
69 BOOST_HANA_NAMESPACE_BEGIN
70     namespace ext { namespace std { struct array_tag; }}
71 
72     template <typename T, std::size_t N>
73     struct tag_of<std::array<T, N>> {
74         using type = ext::std::array_tag;
75     };
76 
77     //////////////////////////////////////////////////////////////////////////
78     // Foldable
79     //////////////////////////////////////////////////////////////////////////
80     template <>
81     struct length_impl<ext::std::array_tag> {
82         template <typename Xs>
applylength_impl83         static constexpr auto apply(Xs const&) {
84             return hana::size_c<std::tuple_size<Xs>::type::value>;
85         }
86     };
87 
88     //////////////////////////////////////////////////////////////////////////
89     // Iterable
90     //////////////////////////////////////////////////////////////////////////
91     template <>
92     struct at_impl<ext::std::array_tag> {
93         template <typename Xs, typename N>
applyat_impl94         static constexpr decltype(auto) apply(Xs&& xs, N const&) {
95             constexpr std::size_t n = N::value;
96             return std::get<n>(static_cast<Xs&&>(xs));
97         }
98     };
99 
100     template <>
101     struct drop_front_impl<ext::std::array_tag> {
102         template <std::size_t n, typename Xs, std::size_t ...i>
drop_front_helperdrop_front_impl103         static constexpr auto drop_front_helper(Xs&& xs, std::index_sequence<i...>) {
104             using T = typename std::remove_reference<Xs>::type::value_type;
105             return std::array<T, sizeof...(i)>{{static_cast<Xs&&>(xs)[n + i]...}};
106         }
107 
108         template <typename Xs, typename N>
applydrop_front_impl109         static constexpr auto apply(Xs&& xs, N const&) {
110             constexpr std::size_t n = N::value;
111             constexpr std::size_t len = std::tuple_size<
112                 typename std::remove_cv<
113                     typename std::remove_reference<Xs>::type
114                 >::type
115             >::value;
116             return drop_front_helper<n>(static_cast<Xs&&>(xs),
117                     std::make_index_sequence<(n < len ? len - n : 0)>{});
118         }
119     };
120 
121     template <>
122     struct is_empty_impl<ext::std::array_tag> {
123         template <typename T, std::size_t N>
applyis_empty_impl124         static constexpr auto apply(std::array<T, N> const&) {
125             return hana::bool_c<N == 0>;
126         }
127     };
128 
129     //////////////////////////////////////////////////////////////////////////
130     // Comparable
131     //////////////////////////////////////////////////////////////////////////
132     template <>
133     struct equal_impl<ext::std::array_tag, ext::std::array_tag> {
134         template <typename T, std::size_t n, typename U>
applyequal_impl135         static constexpr bool apply(std::array<T, n> const& xs, std::array<U, n> const& ys)
136         { return detail::equal(&xs[0], &xs[0] + n, &ys[0], &ys[0] + n); }
137 
138         template <typename T, typename U>
applyequal_impl139         static constexpr auto apply(std::array<T, 0> const&, std::array<U, 0> const&)
140         { return hana::true_c; }
141 
142         template <typename T, std::size_t n, typename U, std::size_t m>
applyequal_impl143         static constexpr auto apply(std::array<T, n> const&, std::array<U, m> const&)
144         { return hana::false_c; }
145     };
146 
147     //////////////////////////////////////////////////////////////////////////
148     // Orderable
149     //////////////////////////////////////////////////////////////////////////
150     template <>
151     struct less_impl<ext::std::array_tag, ext::std::array_tag> {
152         template <typename T, std::size_t n, typename U, std::size_t m>
applyless_impl153         static constexpr auto apply(std::array<T, n> const& xs, std::array<U, m> const& ys) {
154             // This logic is more complex than it needs to be because we can't
155             // use `.begin()` and `.end()`, which are not constexpr in C++14,
156             // and because `&arr[0]` is UB when the array is empty.
157             if (xs.empty()) {
158                 return !ys.empty();
159             } else {
160                 if (ys.empty()) {
161                     return false;
162                 } else {
163                     return detail::lexicographical_compare(&xs[0], &xs[0] + n,
164                                                            &ys[0], &ys[0] + m);
165                 }
166             }
167         }
168     };
169 BOOST_HANA_NAMESPACE_END
170 
171 #endif // !BOOST_HANA_EXT_STD_ARRAY_HPP
172