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