33// https://www.boost.org/LICENSE_1_0.txt
44
55// #pragma once
6- #ifndef BOOST_MULTI_DETAIL_EXTENTS_HPP
7- #define BOOST_MULTI_DETAIL_EXTENTS_HPP
6+ #ifndef BOOST_MULTI_DETAIL_OUTER_HPP
7+ #define BOOST_MULTI_DETAIL_OUTER_HPP
88
99#include " boost/multi/detail/index_range.hpp" // IWYU pragma: export // for index_extension, extension_t, tuple, intersection, range, operator!=, operator==
1010#include " boost/multi/detail/interfaces.hpp"
@@ -77,26 +77,93 @@ template<class T, class... Ts> struct tuple_tail<std::tuple<T, Ts...>> {
7777template <class Tuple > using tuple_type_t = typename tuple_tail<Tuple>::type;
7878} // end namespace stdx
7979
80- // namespace detail {
81- // template<typename... Ts>
82- // struct TailTuple {};
80+ template <class ... Exts>
81+ class outer_t ;
8382
84- // template<typename Head, typename... Tail>
85- // struct TailTuple<Head, Tail...> : TailTuple<Tail...> {
86- // using TailType = TailTuple<Tail...>;
87- // };
83+ template <class Outer >
84+ class outer_elements_t ; // lazy random-access range over the flattened coordinate tuples (defined below)
8885
89- // // Base case for the empty pack
90- // template<>
91- // struct TailTuple<> {};
86+ template <>
87+ class outer_t <> : public std::tuple<> { // base case: zero-dimensional extents
88+ public:
89+ static constexpr dimensionality_type dimensionality = 0 ;
9290
93- // } // end namespace detail
91+ using index = multi::index;
92+ using indices_type = std::tuple<>;
93+ using element = std::tuple<>;
9494
95- template <class ... Exts>
96- class extents_t ;
95+ outer_t () = default ;
96+
97+ constexpr auto num_elements () const noexcept -> multi::ssize_t { return 1 ; } // NOLINT(readability-convert-member-functions-to-static)
98+
99+ constexpr auto from_linear (index /* n*/ ) const noexcept -> indices_type { return {}; } // NOLINT(readability-convert-member-functions-to-static)
100+ constexpr auto sizes () const noexcept -> std::tuple<> { return {}; } // NOLINT(readability-convert-member-functions-to-static)
101+
102+ friend constexpr auto operator ==(outer_t const & /* self*/ , outer_t const & /* other*/ ) noexcept -> bool { return true ; }
103+ friend constexpr auto operator !=(outer_t const & /* self*/ , outer_t const & /* other*/ ) noexcept -> bool { return false ; }
104+ };
105+
106+ // A lazy, random-access, sized range over the flattened coordinate tuples of an `outer_t`:
107+ // `outer.elements()[n] == outer.from_linear(n)`. This is what makes `outer` behave like an
108+ // array of (coordinate) tuples -- the cartesian product materialized lazily, element by element.
109+ template <class Outer >
110+ class outer_elements_t {
111+ Outer outer_;
112+
113+ public:
114+ using value_type = typename Outer::indices_type;
115+ using size_type = multi::ssize_t ;
116+ using difference_type = std::ptrdiff_t ;
117+
118+ explicit constexpr outer_elements_t (Outer outer) : outer_{std::move (outer)} {}
119+
120+ constexpr auto size () const -> size_type { return outer_.num_elements (); }
121+ constexpr auto operator [](difference_type n) const -> value_type { return outer_.from_linear (static_cast <typename Outer::index>(n)); }
122+
123+ class iterator {
124+ Outer outer_;
125+ std::ptrdiff_t n_ = 0 ;
126+
127+ public:
128+ using value_type = typename Outer::indices_type;
129+ using reference = value_type; // proxy: dereference yields a fresh coordinate tuple by value
130+ using pointer = void ;
131+ using difference_type = std::ptrdiff_t ;
132+ using iterator_category = std::random_access_iterator_tag;
133+
134+ iterator () = default ;
135+ constexpr iterator (Outer outer, difference_type n) : outer_{std::move (outer)}, n_{n} {}
136+
137+ constexpr auto operator *() const -> value_type { return outer_.from_linear (static_cast <typename Outer::index>(n_)); }
138+ constexpr auto operator [](difference_type d) const -> value_type { return *(*this + d); }
139+
140+ constexpr auto operator ++() -> iterator& { ++n_; return *this ; }
141+ constexpr auto operator --() -> iterator& { --n_; return *this ; }
142+ constexpr auto operator ++(int ) -> iterator { auto ret = *this ; ++n_; return ret; } // NOLINT(cert-dcl21-cpp)
143+ constexpr auto operator --(int ) -> iterator { auto ret = *this ; --n_; return ret; } // NOLINT(cert-dcl21-cpp)
144+
145+ constexpr auto operator +=(difference_type d) -> iterator& { n_ += d; return *this ; }
146+ constexpr auto operator -=(difference_type d) -> iterator& { n_ -= d; return *this ; }
147+
148+ friend constexpr auto operator +(iterator it, difference_type d) -> iterator { it += d; return it; }
149+ friend constexpr auto operator +(difference_type d, iterator it) -> iterator { it += d; return it; }
150+ friend constexpr auto operator -(iterator it, difference_type d) -> iterator { it -= d; return it; }
151+ friend constexpr auto operator -(iterator const & lhs, iterator const & rhs) -> difference_type { return lhs.n_ - rhs.n_ ; }
152+
153+ friend constexpr auto operator ==(iterator const & lhs, iterator const & rhs) -> bool { return lhs.n_ == rhs.n_ ; }
154+ friend constexpr auto operator !=(iterator const & lhs, iterator const & rhs) -> bool { return lhs.n_ != rhs.n_ ; }
155+ friend constexpr auto operator < (iterator const & lhs, iterator const & rhs) -> bool { return lhs.n_ < rhs.n_ ; }
156+ friend constexpr auto operator > (iterator const & lhs, iterator const & rhs) -> bool { return lhs.n_ > rhs.n_ ; }
157+ friend constexpr auto operator <=(iterator const & lhs, iterator const & rhs) -> bool { return lhs.n_ <= rhs.n_ ; }
158+ friend constexpr auto operator >=(iterator const & lhs, iterator const & rhs) -> bool { return lhs.n_ >= rhs.n_ ; }
159+ };
160+
161+ constexpr auto begin () const -> iterator { return iterator{outer_, 0 }; }
162+ constexpr auto end () const -> iterator { return iterator{outer_, size ()}; }
163+ };
97164
98165template <class Ext , class ... Exts>
99- class extents_t <Ext, Exts...> : public std::tuple<Ext, Exts...> { // TODO(correaa) use libcuda++ in the future https://github.com/boostorg/math/blob/develop/include/boost/math/tools/cstdint.hpp
166+ class outer_t <Ext, Exts...> : public std::tuple<Ext, Exts...> { // TODO(correaa) use libcuda++ in the future https://github.com/boostorg/math/blob/develop/include/boost/math/tools/cstdint.hpp
100167 using base_ = std::tuple<Ext, Exts...>;
101168
102169 public:
@@ -111,9 +178,9 @@ class extents_t<Ext, Exts...> : public std::tuple<Ext, Exts...> { // TODO(corre
111178 using size_type = typename extension_type::size_type;
112179 using index = typename extension_type::index;
113180
114- extents_t () = default ;
181+ outer_t () = default ;
115182 // using std::tuple<Exts...>::tuple;
116- explicit extents_t (Ext ext, Exts... xs) : std::tuple<Ext, Exts...>{std::move (ext), std::move (xs)...} {}
183+ explicit outer_t (Ext ext, Exts... xs) : std::tuple<Ext, Exts...>{std::move (ext), std::move (xs)...} {}
117184
118185 auto extension () const -> extension_type {
119186 using std::get;
@@ -126,15 +193,45 @@ class extents_t<Ext, Exts...> : public std::tuple<Ext, Exts...> { // TODO(corre
126193
127194 auto size () const -> size_type { return extension ().size (); }
128195
129- using sub_type = extents_t <>;
196+ auto num_elements () const { return size () * sub ().num_elements (); }
197+
198+ using sub_type = outer_t <Exts...>;
199+
200+ constexpr auto sub () const -> sub_type {
201+ return std::apply (
202+ [](auto ... xs) noexcept -> sub_type { return sub_type (xs...); },
203+ stdx::tail (static_cast <std::tuple<Ext, Exts...> const &>(*this ))
204+ );
205+ }
206+
207+ // the coordinate type produced when fully indexing: a tuple of `dimensionality + 1` indices
208+ using indices_type = decltype (std::tuple_cat(std::declval<std::tuple<index>>(), std::declval<typename sub_type::indices_type>()));
209+
210+ // row-major decomposition of a linear index `n` into the full coordinate tuple
211+ constexpr auto from_linear (index n) const -> indices_type {
212+ auto const sub_num = sub ().num_elements ();
213+ return std::tuple_cat (
214+ std::make_tuple (static_cast <index>(extension ().first () + (n / sub_num))),
215+ sub ().from_linear (static_cast <index>(n % sub_num))
216+ );
217+ }
218+
219+ // the structured factors of the cartesian product (the D extensions, as a tuple)
220+ constexpr auto extensions () const -> element { return static_cast <base_ const &>(*this ); }
221+
222+ // the per-dimension sizes
223+ constexpr auto sizes () const { return std::tuple_cat (std::make_tuple (size ()), sub ().sizes ()); }
224+
225+ // lazy random-access array of the `num_elements()` coordinate tuples (cartesian product, flattened)
226+ constexpr auto elements () const -> outer_elements_t<outer_t> { return outer_elements_t <outer_t >{*this }; }
130227
131228 class iterator : public detail ::forward_iterator_facade<iterator> {
132- friend class extents_t ;
229+ friend class outer_t ;
133230
134231 typename extension_type::iterator idx_;
135- extents_t <Exts...> rest_;
232+ outer_t <Exts...> rest_;
136233
137- constexpr explicit iterator (typename extension_type::iterator idx, extents_t <Exts...> rest)
234+ constexpr explicit iterator (typename extension_type::iterator idx, outer_t <Exts...> rest)
138235 : idx_{idx}, rest_{std::move (rest)} {}
139236
140237 public:
@@ -204,28 +301,28 @@ class extents_t<Ext, Exts...> : public std::tuple<Ext, Exts...> { // TODO(corre
204301 constexpr auto begin () const noexcept {
205302 return iterator{
206303 stdx::head (static_cast <std::tuple<Ext, Exts...> const &>(*this )).begin (),
207- std::apply ([](auto ... xs) noexcept -> auto { return extents_t <Exts...>(xs...); }, stdx::tail (static_cast <std::tuple<Ext, Exts...> const &>(*this )))
304+ std::apply ([](auto ... xs) noexcept -> auto { return outer_t <Exts...>(xs...); }, stdx::tail (static_cast <std::tuple<Ext, Exts...> const &>(*this )))
208305 };
209306 }
210307
211308 template <std::size_t I>
212- friend auto get (extents_t const & self) {
309+ friend auto get (outer_t const & self) {
213310 using std::get;
214311 return get<I>(static_cast <std::tuple<Ext, Exts...> const &>(self));
215312 }
216313};
217314
218- template <class ... Exts> extents_t (Exts...) -> extents_t <decltype(multi::extension_t (std::declval<Exts>()))...>;
315+ template <class ... Exts> outer_t (Exts...) -> outer_t <decltype(multi::extension_t (std::declval<Exts>()))...>;
219316
220317} // end namespace boost::multi
221318
222319template <class ... Exts>
223- struct std ::tuple_size<::boost::multi::extents_t <Exts...>> { // NOLINT(cert-dcl58-cpp) structured binding
320+ struct std ::tuple_size<::boost::multi::outer_t <Exts...>> { // NOLINT(cert-dcl58-cpp) structured binding
224321 static constexpr std::size_t value = sizeof ...(Exts);
225322};
226323
227324template <std::size_t I, class ... Exts>
228- struct std ::tuple_element<I, ::boost::multi::extents_t <Exts...>> { // NOLINT(cert-dcl58-cpp) structured binding
325+ struct std ::tuple_element<I, ::boost::multi::outer_t <Exts...>> { // NOLINT(cert-dcl58-cpp) structured binding
229326 using type = std::tuple_element_t <I, std::tuple<Exts...>>;
230327};
231328
@@ -2134,4 +2231,4 @@ struct std::tuple_element<I, ::boost::multi::extents_t<Exts...>> { // NOLINT(ce
21342231
21352232#undef BOOST_MULTI_HD
21362233
2137- #endif // BOOST_MULTI_DETAIL_EXTENTS_HPP
2234+ #endif // BOOST_MULTI_DETAIL_OUTER_HPP
0 commit comments