Skip to content

Commit 0f6f58a

Browse files
authored
Merge pull request #2488 from tdegeus/operator
Adding `xt::missing` to `operator()`
2 parents 751f3ae + 9d5adc3 commit 0f6f58a

File tree

5 files changed

+102
-7
lines changed

5 files changed

+102
-7
lines changed

docs/source/indices.rst

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,16 @@ To this end the following operators are at your disposal:
5252
Returns a (constant) reference to the element,
5353
specified by an *array index* given by a number of unsigned integers.
5454

55-
.. note::
56-
57-
If the number of indices is less that the dimension of the array,
55+
* If the number of indices is less that the dimension of the array,
5856
the indices are pre-padded with zeros until the dimension is matched
5957
(example: ``a(2) == a(0, 2) == 2``).
6058

59+
* If the number of indices is greater than the dimension of the array,
60+
the first ``#indices - dimension`` indices are ignored.
61+
62+
* To post-pad an arbitrary number of zeros use ``xt::missing``
63+
(example ``a(2, xt::missing) == a(2, 0) == 8``.
64+
6165
``at(args...)``
6266
^^^^^^^^^^^^^^^
6367

include/xtensor/xcontainer.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@ namespace xt
438438
{
439439
XTENSOR_TRY(check_index(shape(), args...));
440440
XTENSOR_CHECK_DIMENSION(shape(), args...);
441-
size_type index = xt::data_offset<size_type>(strides(), static_cast<std::ptrdiff_t>(args)...);
441+
size_type index = xt::data_offset<size_type>(strides(), args...);
442442
return storage()[index];
443443
}
444444

@@ -454,7 +454,7 @@ namespace xt
454454
{
455455
XTENSOR_TRY(check_index(shape(), args...));
456456
XTENSOR_CHECK_DIMENSION(shape(), args...);
457-
size_type index = xt::data_offset<size_type>(strides(), static_cast<std::ptrdiff_t>(args)...);
457+
size_type index = xt::data_offset<size_type>(strides(), args...);
458458
return storage()[index];
459459
}
460460

include/xtensor/xexception.hpp

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,36 @@
1414
#include <sstream>
1515
#include <stdexcept>
1616
#include <string>
17+
#include <iostream>
1718

1819
#include "xtensor_config.hpp"
20+
#include <xtl/xsequence.hpp>
21+
#include <xtl/xspan_impl.hpp>
1922

2023
namespace xt
2124
{
25+
struct missing_type {};
26+
namespace {
27+
missing_type missing;
28+
}
29+
30+
namespace detail
31+
{
32+
template <class... Args>
33+
struct last_type_is_missing_impl
34+
: std::is_same<missing_type, xtl::mpl::back_t<xtl::mpl::vector<Args...>>>
35+
{
36+
};
37+
38+
template <>
39+
struct last_type_is_missing_impl<>
40+
: std::false_type
41+
{
42+
};
43+
44+
template <class... Args>
45+
constexpr bool last_type_is_missing = last_type_is_missing_impl<Args...>::value;
46+
}
2247

2348
/*******************
2449
* broadcast_error *
@@ -147,6 +172,11 @@ namespace xt
147172
{
148173
}
149174

175+
template <class S, std::size_t dim>
176+
inline void check_index_impl(const S&, missing_type)
177+
{
178+
}
179+
150180
template <class S, std::size_t dim, class T, class... Args>
151181
inline void check_index_impl(const S& shape, T arg, Args... args)
152182
{
@@ -165,6 +195,11 @@ namespace xt
165195
{
166196
}
167197

198+
template <class S>
199+
inline void check_index(const S&, missing_type)
200+
{
201+
}
202+
168203
template <class S, class Arg, class... Args>
169204
inline void check_index(const S& shape, Arg arg, Args... args)
170205
{
@@ -178,6 +213,11 @@ namespace xt
178213
// Too many arguments: drop the first
179214
check_index(shape, args...);
180215
}
216+
else if (detail::last_type_is_missing<Args...>)
217+
{
218+
// Too few arguments & last argument xt::missing: postfix index with zeros
219+
detail::check_index_impl<S, 0>(shape, arg, args...);
220+
}
181221
else
182222
{
183223
// Too few arguments: ignore the beginning of the shape
@@ -194,7 +234,7 @@ namespace xt
194234
auto dst = static_cast<size_type>(last - first);
195235
It efirst = last - static_cast<std::ptrdiff_t>((std::min)(shape.size(), dst));
196236
std::size_t axis = 0;
197-
237+
198238
while (efirst != last)
199239
{
200240
if (*efirst >= value_type(shape[axis]) && shape[axis] != 1)

include/xtensor/xstrides.hpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,17 +169,25 @@ namespace xt
169169

170170
namespace detail
171171
{
172+
172173
template <std::size_t dim, class S>
173174
inline auto raw_data_offset(const S&) noexcept
174175
{
175176
using strides_value_type = std::decay_t<decltype(std::declval<S>()[0])>;
176177
return strides_value_type(0);
177178
}
178179

180+
template <std::size_t dim, class S>
181+
inline auto raw_data_offset(const S&, missing_type) noexcept
182+
{
183+
using strides_value_type = std::decay_t<decltype(std::declval<S>()[0])>;
184+
return strides_value_type(0);
185+
}
186+
179187
template <std::size_t dim, class S, class Arg, class... Args>
180188
inline auto raw_data_offset(const S& strides, Arg arg, Args... args) noexcept
181189
{
182-
return arg * strides[dim] + raw_data_offset<dim + 1>(strides, args...);
190+
return static_cast<std::ptrdiff_t>(arg) * strides[dim] + raw_data_offset<dim + 1>(strides, args...);
183191
}
184192

185193
template <layout_type L, std::ptrdiff_t static_dim>
@@ -270,11 +278,17 @@ namespace xt
270278
// Too many arguments: drop the first
271279
return data_offset<offset_type, S>(strides, args...);
272280
}
281+
else if (detail::last_type_is_missing<Args...>)
282+
{
283+
// Too few arguments & last argument xt::missing: postfix index with zeros
284+
return static_cast<offset_type>(detail::raw_data_offset<0>(strides, arg, args...));
285+
}
273286
else
274287
{
275288
// Too few arguments: right to left scalar product
276289
auto view = strides.cend() - nargs;
277290
return static_cast<offset_type>(detail::raw_data_offset<0>(view, arg, args...));
291+
278292
}
279293
}
280294

test/test_xtensor.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,43 @@ namespace xt
167167
}
168168
}
169169

170+
TEST(xtensor, missign)
171+
{
172+
xt::xtensor<int, 2> a
173+
{{0, 1, 2},
174+
{3, 4, 5},
175+
{6, 7, 8}};
176+
177+
EXPECT_EQ(a(0), 0);
178+
EXPECT_EQ(a(1), 1);
179+
EXPECT_EQ(a(2), 2);
180+
EXPECT_EQ(a(0, 0), 0);
181+
EXPECT_EQ(a(1, 0), 3);
182+
EXPECT_EQ(a(2, 0), 6);
183+
EXPECT_EQ(a(xt::missing), 0);
184+
EXPECT_EQ(a(0, xt::missing), 0);
185+
EXPECT_EQ(a(1, xt::missing), 3);
186+
EXPECT_EQ(a(2, xt::missing), 6);
187+
EXPECT_EQ(a(0, 0), 0);
188+
EXPECT_EQ(a(0, 1), 1);
189+
EXPECT_EQ(a(0, 2), 2);
190+
EXPECT_EQ(a(1, 0), 3);
191+
EXPECT_EQ(a(1, 1), 4);
192+
EXPECT_EQ(a(1, 2), 5);
193+
EXPECT_EQ(a(2, 0), 6);
194+
EXPECT_EQ(a(2, 1), 7);
195+
EXPECT_EQ(a(2, 2), 8);
196+
EXPECT_EQ(a(9, 9, 9, 0, 0), 0);
197+
EXPECT_EQ(a(9, 9, 9, 0, 1), 1);
198+
EXPECT_EQ(a(9, 9, 9, 0, 2), 2);
199+
EXPECT_EQ(a(9, 9, 9, 1, 0), 3);
200+
EXPECT_EQ(a(9, 9, 9, 1, 1), 4);
201+
EXPECT_EQ(a(9, 9, 9, 1, 2), 5);
202+
EXPECT_EQ(a(9, 9, 9, 2, 0), 6);
203+
EXPECT_EQ(a(9, 9, 9, 2, 1), 7);
204+
EXPECT_EQ(a(9, 9, 9, 2, 2), 8);
205+
}
206+
170207
TEST(xtensor, resize)
171208
{
172209
xtensor_dynamic a;

0 commit comments

Comments
 (0)