Skip to content

Commit 1412daa

Browse files
authored
Merge pull request #2521 from tdegeus/pointer
Adding `reset_data` to `xbuffer_adaptor` and `reset_buffer` to `*adaptor` to replace the pointer without any reallocation.
2 parents 7c5078b + d3722b3 commit 1412daa

File tree

5 files changed

+131
-15
lines changed

5 files changed

+131
-15
lines changed

docs/source/external-structures.rst

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,34 @@ A requirement for the user-specified containers is to provide a minimal ``std::v
4343
provides the aforementioned interface. In fact, the container could even be backed by a
4444
file on the disk, a database or a binary message.
4545

46+
Adapting a pointer
47+
------------------
48+
49+
Suppose that you want to use the *xtensor* machinery on a small contiguous subset of a large tensor.
50+
You can, of course, use :ref:`Views`, but for efficiency you can also use pointers to the right bit of memory.
51+
Consider an example of an ``[M, 2, 2]`` tensor ``A``,
52+
for which you want to operate on ``A[i, :, :]`` for different ``i``.
53+
In this case the most efficient *xtensor* has to offer is:
54+
55+
.. code-block:: cpp
56+
57+
int main()
58+
{
59+
size_t M = 3;
60+
size_t nd = 2;
61+
size_t size = nd * nd;
62+
xt::xarray<int> A = xt::arange<int>(M * size).reshape({M, nd, nd});
63+
auto b = xt::adapt(&A.flat(0), std::array<size_t, 2>{nd, nd});
64+
65+
for (size_t i = 0; i < M; ++i) {
66+
b.reset_buffer(&A.flat(i * size), size);
67+
}
68+
return 0;
69+
}
70+
71+
where ``xt::adapt`` first creates an ``xt::xtensor_adaptor`` on the memory of ``A[0, :, :]``.
72+
Then, inside the loop, we only replace the pointer to the relevant ``A[i, 0, 0]``.
73+
4674
Structures that embed shape and strides
4775
---------------------------------------
4876

include/xtensor/xarray.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,9 @@ namespace xt
252252
template <class E>
253253
xarray_adaptor& operator=(const xexpression<E>& e);
254254

255+
template <class P, class S>
256+
void reset_buffer(P&& pointer, S&& size);
257+
255258
private:
256259

257260
container_closure_type m_storage;
@@ -616,6 +619,13 @@ namespace xt
616619
{
617620
return m_storage;
618621
}
622+
623+
template <class EC, layout_type L, class SC, class Tag>
624+
template <class P, class S>
625+
inline void xarray_adaptor<EC, L, SC, Tag>::reset_buffer(P&& pointer, S&& size)
626+
{
627+
return m_storage.reset_data(std::forward<P>(pointer), std::forward<S>(size));
628+
}
619629
}
620630

621631
#endif

include/xtensor/xbuffer_adaptor.hpp

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ namespace xt
7777

7878
void swap(self_type& rhs) noexcept;
7979

80+
template <class P>
81+
void reset_data(P&& data, size_type size) noexcept;
82+
8083
private:
8184

8285
pointer p_data;
@@ -117,6 +120,9 @@ namespace xt
117120

118121
void swap(self_type& rhs) noexcept;
119122

123+
template <class P, class DT>
124+
void reset_data(P&& data, size_type size, DT&& destruct) noexcept;
125+
120126
private:
121127

122128
pointer p_data;
@@ -168,6 +174,9 @@ namespace xt
168174

169175
void swap(self_type& rhs) noexcept;
170176

177+
template <class P>
178+
void reset_data(P&& data, size_type size, const allocator_type& alloc = allocator_type()) noexcept;
179+
171180
private:
172181

173182
xtl::xclosure_wrapper<CP> m_data;
@@ -177,7 +186,7 @@ namespace xt
177186
};
178187

179188
// Workaround for MSVC2015: using void_t results in some
180-
// template instantiation caching that leads to wrong
189+
// template instantiation caching that leads to wrong
181190
// type deduction later in xfunction.
182191
template <class T>
183192
struct msvc2015_void
@@ -393,6 +402,7 @@ namespace xt
393402
using base_type::resize;
394403
using base_type::data;
395404
using base_type::swap;
405+
using base_type::reset_data;
396406
};
397407

398408
template <class CP, class O, class A>
@@ -421,7 +431,7 @@ namespace xt
421431
using difference_type = std::common_type_t<typename traits::difference_type,
422432
typename const_traits::difference_type>;
423433
using size_type = std::make_unsigned_t<difference_type>;
424-
434+
425435
using iterator = I;
426436
using const_iterator = CI;
427437
using reverse_iterator = std::reverse_iterator<iterator>;
@@ -440,7 +450,7 @@ namespace xt
440450
using allocator_type = std::allocator<value_type>;
441451
using size_type = typename base_type::size_type;
442452
using iterator = typename base_type::iterator;
443-
using const_iterator = typename base_type::const_iterator;
453+
using const_iterator = typename base_type::const_iterator;
444454
using temporary_type = uvector<value_type, allocator_type>;
445455

446456
xiterator_adaptor() = default;
@@ -459,12 +469,12 @@ namespace xt
459469

460470
size_type size() const noexcept;
461471
void resize(size_type size);
462-
472+
463473
iterator data() noexcept;
464474
const_iterator data() const noexcept;
465475

466476
void swap(self_type& rhs) noexcept;
467-
477+
468478
private:
469479

470480
I m_it;
@@ -523,7 +533,7 @@ namespace xt
523533
using allocator_type = std::allocator<value_type>;
524534
using size_type = typename base_type::size_type;
525535
using iterator = typename base_type::iterator;
526-
using const_iterator = typename base_type::const_iterator;
536+
using const_iterator = typename base_type::const_iterator;
527537
using temporary_type = uvector<value_type, allocator_type>;
528538

529539
xiterator_owner_adaptor(C&& c);
@@ -541,7 +551,7 @@ namespace xt
541551

542552
size_type size() const noexcept;
543553
void resize(size_type size);
544-
554+
545555
iterator data() noexcept;
546556
const_iterator data() const noexcept;
547557

@@ -658,6 +668,14 @@ namespace xt
658668
swap(p_data, rhs.p_data);
659669
swap(m_size, rhs.m_size);
660670
}
671+
672+
template <class CP, class A>
673+
template <class P>
674+
inline void xbuffer_storage<CP, A>::reset_data(P&& data, size_type size) noexcept
675+
{
676+
p_data = std::forward<P>(data);
677+
m_size = size;
678+
}
661679
}
662680

663681
/****************************************
@@ -767,6 +785,14 @@ namespace xt
767785
swap(m_size, rhs.m_size);
768786
swap(m_allocator, rhs.m_allocator);
769787
}
788+
789+
template <class CP, class A>
790+
template <class P>
791+
inline void xbuffer_owner_storage<CP, A>::reset_data(P&& data, size_type size, const allocator_type& alloc) noexcept
792+
{
793+
xbuffer_owner_storage<CP, A> tmp(std::forward<P>(data), size, alloc);
794+
this->swap(tmp);
795+
}
770796
}
771797

772798
/****************************************
@@ -793,7 +819,7 @@ namespace xt
793819
{
794820
if (m_size != size)
795821
{
796-
XTENSOR_THROW(std::runtime_error, "xbuffer_storage not resizable");
822+
XTENSOR_THROW(std::runtime_error, "xbuffer_storage not resizeable");
797823
}
798824
}
799825

@@ -816,6 +842,15 @@ namespace xt
816842
swap(m_size, rhs.m_size);
817843
swap(m_destruct, rhs.m_destruct);
818844
}
845+
846+
template <class CP, class D>
847+
template <class P, class DT>
848+
void xbuffer_smart_pointer<CP, D>::reset_data(P&& data, size_type size, DT&& destruct) noexcept
849+
{
850+
p_data = std::forward<P>(data);
851+
m_size = size;
852+
m_destruct = destruct;
853+
}
819854
}
820855

821856
/***************************************
@@ -1020,7 +1055,7 @@ namespace xt
10201055
/************************************
10211056
* xiterator_adaptor implementation *
10221057
************************************/
1023-
1058+
10241059
template <class I, class CI>
10251060
inline xiterator_adaptor<I, CI>::xiterator_adaptor(I it, CI cit, size_type size)
10261061
: m_it(it), m_cit(cit), m_size(size)
@@ -1040,7 +1075,7 @@ namespace xt
10401075
{
10411076
return (*this = rhs);
10421077
}
1043-
1078+
10441079
template <class I, class CI>
10451080
inline auto xiterator_adaptor<I, CI>::size() const noexcept -> size_type
10461081
{
@@ -1052,7 +1087,7 @@ namespace xt
10521087
{
10531088
if (m_size != size)
10541089
{
1055-
XTENSOR_THROW(std::runtime_error, "xiterator_adaptor not resizable");
1090+
XTENSOR_THROW(std::runtime_error, "xiterator_adaptor not resizeable");
10561091
}
10571092
}
10581093

@@ -1076,7 +1111,7 @@ namespace xt
10761111
swap(m_cit, rhs.m_cit);
10771112
swap(m_size, rhs.m_size);
10781113
}
1079-
1114+
10801115
template <class I, class CI>
10811116
inline void swap(xiterator_adaptor<I, CI>& lhs,
10821117
xiterator_adaptor<I, CI>& rhs) noexcept
@@ -1087,7 +1122,7 @@ namespace xt
10871122
/******************************************
10881123
* xiterator_owner_adaptor implementation *
10891124
******************************************/
1090-
1125+
10911126
template <class C, class IG>
10921127
inline xiterator_owner_adaptor<C, IG>::xiterator_owner_adaptor(C&& c)
10931128
: m_container(std::move(c))
@@ -1148,10 +1183,10 @@ namespace xt
11481183
{
11491184
if (m_size != size)
11501185
{
1151-
XTENSOR_THROW(std::runtime_error, "xiterator_owner_adaptor not resizable");
1186+
XTENSOR_THROW(std::runtime_error, "xiterator_owner_adaptor not resizeable");
11521187
}
11531188
}
1154-
1189+
11551190
template <class C, class IG>
11561191
inline auto xiterator_owner_adaptor<C, IG>:: data() noexcept -> iterator
11571192
{

include/xtensor/xtensor.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,9 @@ namespace xt
247247
template <class E>
248248
xtensor_adaptor& operator=(const xexpression<E>& e);
249249

250+
template <class P, class S>
251+
void reset_buffer(P&& pointer, S&& size);
252+
250253
private:
251254

252255
container_closure_type m_storage;
@@ -685,6 +688,13 @@ namespace xt
685688
return m_storage;
686689
}
687690

691+
template <class EC, std::size_t N, layout_type L, class Tag>
692+
template <class P, class S>
693+
inline void xtensor_adaptor<EC, N, L, Tag>::reset_buffer(P&& pointer, S&& size)
694+
{
695+
return m_storage.reset_data(std::forward<P>(pointer), std::forward<S>(size));
696+
}
697+
688698
/*******************************
689699
* xtensor_view implementation *
690700
*******************************/

test/test_xadapt.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,23 @@ namespace xt
6161
delete[] data;
6262
}
6363

64+
TEST(xarray_adaptor, pointer_no_ownership_replace)
65+
{
66+
size_t size = 4;
67+
int* data = new int[3 * size];
68+
using shape_type = std::vector<vec_type::size_type>;
69+
shape_type s({2, 2});
70+
71+
auto a1 = adapt(data, size, no_ownership(), s);
72+
size_t st = static_cast<size_t>(a1.strides()[0]);
73+
74+
for (size_t i = 0; i < 3; ++i) {
75+
a1.reset_buffer(&data[i * size], size);
76+
a1(1, 0) = static_cast<int>(i);
77+
EXPECT_EQ(i, data[i * size + st]);
78+
}
79+
}
80+
6481
TEST(xarray_adaptor, pointer_acquire_ownership)
6582
{
6683
size_t size = 4;
@@ -211,6 +228,22 @@ namespace xt
211228
delete[] data;
212229
}
213230

231+
TEST(xtensor_adaptor, pointer_no_ownership_replace)
232+
{
233+
size_t size = 4;
234+
int* data = new int[3 * size];
235+
std::array<size_t, 2> shape = {2, 2};
236+
237+
auto a1 = adapt(data, size, no_ownership(), shape);
238+
size_t st = static_cast<size_t>(a1.strides()[0]);
239+
240+
for (size_t i = 0; i < 3; ++i) {
241+
a1.reset_buffer(&data[i * size], size);
242+
a1(1, 0) = static_cast<int>(i);
243+
EXPECT_EQ(i, data[i * size + st]);
244+
}
245+
}
246+
214247
TEST(xtensor_adaptor, pointer_const_no_ownership)
215248
{
216249
size_t size = 4;

0 commit comments

Comments
 (0)