@@ -17,18 +17,53 @@ namespace xt
1717
1818template <class UndefinedView > struct index_mapper ;
1919
20+ /* *
21+ * @class index_mapper
22+ * @brief A helper class for mapping indices between views and their underlying containers.
23+ *
24+ * The `index_mapper` class provides functionality to convert indices from a view's coordinate system
25+ * to the corresponding indices in the underlying container. This is particularly useful for views
26+ * that contain integral slices (fixed indices), as these slices reduce the dimensionality of the view.
27+ *
28+ * @tparam UndefinedView The primary template parameter, specialized for `xt::xview` types.
29+ *
30+ * @note This class is specialized for `xt::xview<UnderlyingContainer, Slices...>` types only.
31+ * Other view types will trigger a compilation error.
32+ *
33+ * @example
34+ * @code
35+ * xt::xarray<double> a = xt::arange(24).reshape({2, 3, 4});
36+ * auto view1 = xt::view(a, 1, xt::all(), xt::all()); // Fixed first dimension
37+ * index_mapper<decltype(view1)> mapper;
38+ *
39+ * // Map view indices (i,j) to container indices (1,i,j)
40+ * double val = mapper.map(a, view1, 0, 0); // Returns a(1, 0, 0)
41+ * double val2 = mapper.map(a, view1, 1, 2); // Returns a(1, 1, 2)
42+ * @endcode
43+ */
2044template <class UnderlyingContainer , class ... Slices>
2145class index_mapper < xt::xview<UnderlyingContainer, Slices...> >
2246{
23- static constexpr size_t n_slices = sizeof ...(Slices);
24- static constexpr size_t n_free = ((!std::is_integral_v<Slices>) + ... );
47+ static constexpr size_t n_slices = sizeof ...(Slices); // /< @brief Total number of slices in the view
48+ static constexpr size_t n_free = ((!std::is_integral_v<Slices>) + ... ); // /< @brief Number of free (non-integral) slices
2549public:
26- using view_type = xt::xview<UnderlyingContainer, Slices...>;
50+ using view_type = xt::xview<UnderlyingContainer, Slices...>; // /< @brief The view type this mapper works with
2751
28- using value_type = typename xt::xview<UnderlyingContainer, Slices...>::value_type;
52+ using value_type = typename xt::xview<UnderlyingContainer, Slices...>::value_type; // /< @brief Value type of the underlying container
2953private:
54+ // / @brief Helper type alias for the I-th slice type
3055 template <size_t I> using ith_slice_type = std::tuple_element_t <I, std::tuple<Slices...> >;
3156
57+ /* *
58+ * @brief Helper metafunction to generate an index sequence excluding newaxis slices.
59+ *
60+ * This recursive template builds an `std::index_sequence` containing indices of slices
61+ * that are not `xt::newaxis`. Newaxis slices increase dimensionality but don't correspond
62+ * to actual dimensions in the underlying container.
63+ *
64+ * @tparam first Current slice index being processed.
65+ * @tparam indices... Accumulated indices of non-newaxis slices.
66+ */
3267 template <size_t first, size_t ... indices>
3368 struct indices_sequence_helper
3469 {
@@ -37,33 +72,99 @@ class index_mapper< xt::xview<UnderlyingContainer, Slices...> >
3772
3873 using Type = std::conditional_t < xt::detail::is_newaxis< ith_slice_type<first> >::value , new_axis_type, not_new_axis_type>;
3974 };
40-
41- // closing the recurence
75+ // / @brief Base case: recursion termination
4276 template <size_t ... indices>
4377 struct indices_sequence_helper <n_slices, indices...>
4478 {
4579 using Type = std::index_sequence<indices...>;
4680 };
4781
48- using indices_sequence = indices_sequence_helper<0 >::Type;
49-
50- static constexpr size_t n_all_indices = indices_sequence::size();
51-
82+ using indices_sequence = indices_sequence_helper<0 >::Type; // /< @brief Index sequence of non-newaxis slices
83+
84+ /* *
85+ * @brief Maps an index for a specific slice to the corresponding index in the underlying container.
86+ *
87+ * For integral slices (fixed indices), returns the fixed index value.
88+ * For non-integral slices (like `xt::all()`), applies the slice transformation to the index.
89+ *
90+ * @tparam I The slice index to map.
91+ * @tparam Index Type of the index (must be integral).
92+ * @param view The view object containing slice information.
93+ * @param i The index within the slice to map.
94+ * @return size_t The mapped index in the underlying container.
95+ *
96+ * @throws Assertion failure if `i != 0` for integral slices.
97+ * @throws Assertion failure if `i >= slice.size()` for non-integral slices.
98+ */
5299 template <size_t I, std::integral Index>
53100 size_t map_ith_index (const view_type& view, const Index i) const ;
54101
102+ /* *
103+ * @brief Maps all indices and accesses the container.
104+ *
105+ * @tparam Is Index sequence for parameter pack expansion.
106+ * @param container The underlying container to access.
107+ * @param view The view providing slice information.
108+ * @param indices Array of indices for all slices.
109+ * @return value_type The value at the mapped location in the container.
110+ */
55111 template <size_t ... Is>
56- value_type map_all_indices (const UnderlyingContainer& container, const view_type& view, std::index_sequence<Is...>, const std::array<size_t , n_all_indices>& indices) const
57- requires(sizeof ...(Is) == n_all_indices);
58-
112+ value_type map_all_indices (const UnderlyingContainer& container, const view_type& view, std::index_sequence<Is...>, const std::array<size_t , n_slices>& indices) const ;
113+
114+ /* *
115+ * @brief Maps all indices and accesses the container with bounds checking.
116+ *
117+ * Same as `map_all_indices` but uses `container.at()` which performs bounds checking.
118+ *
119+ * @tparam Is Index sequence for parameter pack expansion.
120+ * @param container The underlying container to access.
121+ * @param view The view providing slice information.
122+ * @param indices Array of indices for all slices.
123+ * @return value_type The value at the mapped location in the container.
124+ *
125+ * @throws std::out_of_range if any index is out of bounds.
126+ */
59127 template <size_t ... Is>
60- value_type map_at_all_indices (const UnderlyingContainer& container, const view_type& view, std::index_sequence<Is...>, const std::array<size_t , n_all_indices>& indices) const
61- requires(sizeof ...(Is) == n_all_indices);
128+ value_type map_at_all_indices (const UnderlyingContainer& container, const view_type& view, std::index_sequence<Is...>, const std::array<size_t , n_slices>& indices) const ;
62129public:
130+ /* *
131+ * @brief Maps view indices to container indices and returns the value.
132+ *
133+ * Converts the provided indices (for the free dimensions of the view) to
134+ * the corresponding indices in the underlying container and returns the value.
135+ *
136+ * @tparam Indices Types of the indices (must be integral).
137+ * @param container The underlying container to access.
138+ * @param view The view providing slice information.
139+ * @param indices The indices for the free dimensions of the view.
140+ * @return value_type The value at the mapped location in the container.
141+ *
142+ * @note The number of provided indices must equal `n_free` (number of non-integral slices).
143+ *
144+ * @example
145+ * @code
146+ * // For view(a, 1, all(), all()):
147+ * // n_free = 2 (two all() slices)
148+ * mapper.map(a, view, i, j); // Maps to a(1, i, j)
149+ * @endcode
150+ */
63151 template <std::integral... Indices>
64152 value_type map (const UnderlyingContainer& container, const view_type& view, const Indices... indices) const
65153 requires(sizeof ...(Indices) == n_free);
66-
154+
155+ /* *
156+ * @brief Maps view indices to container indices with bounds checking.
157+ *
158+ * Same as `map()` but uses bounds-checked access via `container.at()`.
159+ *
160+ * @tparam Indices Types of the indices (must be integral).
161+ * @param container The underlying container to access.
162+ * @param view The view providing slice information.
163+ * @param indices The indices for the free dimensions of the view.
164+ * @return value_type The value at the mapped location in the container.
165+ *
166+ * @throws std::out_of_range if any mapped index is out of bounds.
167+ */
67168 template <std::integral... Indices>
68169 value_type map_at (const UnderlyingContainer& container, const view_type& view, const Indices... indices) const
69170 requires(sizeof ...(Indices) == n_free);
@@ -85,7 +186,7 @@ auto index_mapper< xt::xview<UnderlyingContainer, Slices...> >::map(
85186 std::array<size_t , sizeof ...(indices)> args{ size_t (indices)...};
86187
87188 auto it = std::cbegin (args);
88- std::array<size_t , n_all_indices > args_full{ (std::is_integral_v<Slices> ? size_t (0 ) : *it++)... };
189+ std::array<size_t , n_slices > args_full{ (std::is_integral_v<Slices> ? size_t (0 ) : *it++)... };
89190
90191 return map_all_indices (container, view, indices_sequence{}, args_full);
91192}
@@ -100,21 +201,19 @@ auto index_mapper< xt::xview<UnderlyingContainer, Slices...> >::map_at(
100201 std::array<size_t , sizeof ...(indices)> args{ size_t (indices)...};
101202
102203 auto it = std::cbegin (args);
103- std::array<size_t , n_all_indices > args_full{ (std::is_integral_v<Slices> ? size_t (0 ) : *it++)... };
204+ std::array<size_t , n_slices > args_full{ (std::is_integral_v<Slices> ? size_t (0 ) : *it++)... };
104205
105206 return map_at_all_indices (container, view, indices_sequence{}, args_full);
106207}
107208
108209template <class UnderlyingContainer , class ... Slices> template <size_t ... Is>
109- auto index_mapper< xt::xview<UnderlyingContainer, Slices...> >::map_all_indices(const UnderlyingContainer& container, const view_type& view, std::index_sequence<Is...>, const std::array<size_t , n_all_indices>& indices) const -> value_type
110- requires (sizeof ...(Is) == n_all_indices)
210+ auto index_mapper< xt::xview<UnderlyingContainer, Slices...> >::map_all_indices(const UnderlyingContainer& container, const view_type& view, std::index_sequence<Is...>, const std::array<size_t , n_slices>& indices) const -> value_type
111211{
112212 return container (map_ith_index<Is>(view, indices[Is])...);
113213}
114214
115215template <class UnderlyingContainer , class ... Slices> template <size_t ... Is>
116- auto index_mapper< xt::xview<UnderlyingContainer, Slices...> >::map_at_all_indices(const UnderlyingContainer& container, const view_type& view, std::index_sequence<Is...>, const std::array<size_t , n_all_indices>& indices) const -> value_type
117- requires (sizeof ...(Is) == n_all_indices)
216+ auto index_mapper< xt::xview<UnderlyingContainer, Slices...> >::map_at_all_indices(const UnderlyingContainer& container, const view_type& view, std::index_sequence<Is...>, const std::array<size_t , n_slices>& indices) const -> value_type
118217{
119218 return container.at (map_ith_index<Is>(view, indices[Is])...);
120219}
0 commit comments