Skip to content

Commit f818520

Browse files
author
Alexandre Hoffmann
committed
added comments
1 parent 66dd786 commit f818520

File tree

1 file changed

+121
-22
lines changed

1 file changed

+121
-22
lines changed

include/xtensor/views/index_mapper.hpp

Lines changed: 121 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,53 @@ namespace xt
1717

1818
template<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+
*/
2044
template<class UnderlyingContainer, class... Slices>
2145
class 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
2549
public:
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
2953
private:
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;
62129
public:
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

108209
template<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

115215
template<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

Comments
 (0)