xtensor
Loading...
Searching...
No Matches
xbuffer_adaptor.hpp
1/***************************************************************************
2 * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht *
3 * Copyright (c) QuantStack *
4 * *
5 * Distributed under the terms of the BSD 3-Clause License. *
6 * *
7 * The full license is in the file LICENSE, distributed with this software. *
8 ****************************************************************************/
9
10#ifndef XTENSOR_BUFFER_ADAPTOR_HPP
11#define XTENSOR_BUFFER_ADAPTOR_HPP
12
13#include <algorithm>
14#include <functional>
15#include <iterator>
16#include <memory>
17#include <stdexcept>
18
19#include <xtl/xclosure.hpp>
20
21#include "xstorage.hpp"
22#include "xtensor_config.hpp"
23
24namespace xt
25{
26
28 {
29 };
30
32
34 {
35 };
36
37 template <class CP, class O = no_ownership, class A = std::allocator<std::remove_pointer_t<std::remove_reference_t<CP>>>>
38 class xbuffer_adaptor;
39
40 /********************
41 * buffer_storage_t *
42 ********************/
43
44 namespace detail
45 {
46 template <class CP, class A>
47 class xbuffer_storage
48 {
49 public:
50
51 using self_type = xbuffer_storage<CP, A>;
52 using allocator_type = A;
53 using destructor_type = allocator_type;
54 using allocator_traits = std::allocator_traits<allocator_type>;
55 using value_type = typename allocator_traits::value_type;
56 using reference = std::conditional_t<
57 std::is_const<std::remove_pointer_t<std::remove_reference_t<CP>>>::value,
58 const value_type&,
59 value_type&>;
60 using const_reference = const value_type&;
61 using pointer = std::conditional_t<
62 std::is_const<std::remove_pointer_t<std::remove_reference_t<CP>>>::value,
63 typename allocator_traits::const_pointer,
64 typename allocator_traits::pointer>;
65 using const_pointer = typename allocator_traits::const_pointer;
66 using size_type = typename allocator_traits::size_type;
67 using difference_type = typename allocator_traits::difference_type;
68
69 xbuffer_storage();
70
71 template <class P>
72 xbuffer_storage(P&& data, size_type size, const allocator_type& alloc = allocator_type());
73
74 size_type size() const noexcept;
75 void resize(size_type size);
76
77 pointer data() noexcept;
78 const_pointer data() const noexcept;
79
80 void swap(self_type& rhs) noexcept;
81
83 void reset_data(P&& data, size_type size) noexcept;
84
85 private:
86
87 pointer p_data;
88 size_type m_size;
89 };
90
92 class xbuffer_smart_pointer
93 {
94 public:
95
96 using self_type = xbuffer_storage<CP, D>;
97 using destructor_type = D;
98 using value_type = std::remove_const_t<std::remove_pointer_t<std::remove_reference_t<CP>>>;
99 using allocator_type = std::allocator<value_type>;
100 using allocator_traits = std::allocator_traits<allocator_type>;
101 using reference = std::conditional_t<
102 std::is_const<std::remove_pointer_t<std::remove_reference_t<CP>>>::value,
103 const value_type&,
104 value_type&>;
105 using const_reference = const value_type&;
106 using pointer = std::conditional_t<
107 std::is_const<std::remove_pointer_t<std::remove_reference_t<CP>>>::value,
108 typename allocator_traits::const_pointer,
109 typename allocator_traits::pointer>;
110 using const_pointer = typename allocator_traits::const_pointer;
111 using size_type = typename allocator_traits::size_type;
112 using difference_type = typename allocator_traits::difference_type;
113
114 xbuffer_smart_pointer();
115
116 template <class P, class DT>
117 xbuffer_smart_pointer(P&& data_ptr, size_type size, DT&& destruct);
118
119 size_type size() const noexcept;
120 void resize(size_type size);
121
122 pointer data() noexcept;
123 const_pointer data() const noexcept;
124
125 void swap(self_type& rhs) noexcept;
126
128 void reset_data(P&& data, size_type size, DT&& destruct) noexcept;
129
130 private:
131
132 pointer p_data;
133 size_type m_size;
134 destructor_type m_destruct;
135 };
136
138 class xbuffer_owner_storage
139 {
140 public:
141
142 using self_type = xbuffer_owner_storage<CP, A>;
143 using allocator_type = A;
144 using destructor_type = allocator_type;
145 using allocator_traits = std::allocator_traits<allocator_type>;
146 using value_type = typename allocator_traits::value_type;
147 using reference = std::conditional_t<
148 std::is_const<std::remove_pointer_t<std::remove_reference_t<CP>>>::value,
149 const value_type&,
150 value_type&>;
151 using const_reference = const value_type&;
152 using pointer = std::conditional_t<
153 std::is_const<std::remove_pointer_t<std::remove_reference_t<CP>>>::value,
154 typename allocator_traits::const_pointer,
155 typename allocator_traits::pointer>;
156 using const_pointer = typename allocator_traits::const_pointer;
157 using size_type = typename allocator_traits::size_type;
158 using difference_type = typename allocator_traits::difference_type;
159
160 xbuffer_owner_storage() = default;
161
162 template <class P>
163 xbuffer_owner_storage(P&& data, size_type size, const allocator_type& alloc = allocator_type());
164
165 ~xbuffer_owner_storage();
166
167 xbuffer_owner_storage(const self_type&) = delete;
168 self_type& operator=(const self_type&);
169
170 xbuffer_owner_storage(self_type&&);
171 self_type& operator=(self_type&&);
172
173 size_type size() const noexcept;
174 void resize(size_type size);
175
176 pointer data() noexcept;
177 const_pointer data() const noexcept;
178
179 allocator_type get_allocator() const noexcept;
180
181 void swap(self_type& rhs) noexcept;
182
184 void reset_data(P&& data, size_type size, const allocator_type& alloc = allocator_type()) noexcept;
185
186 private:
187
188 xtl::xclosure_wrapper<CP> m_data;
189 size_type m_size;
190 bool m_moved_from;
191 allocator_type m_allocator;
192 };
193
194 // Workaround for MSVC2015: using void_t results in some
195 // template instantiation caching that leads to wrong
196 // type deduction later in xfunction.
197 template <class T>
198 struct msvc2015_void
199 {
200 using type = void;
201 };
202
203 template <class T>
204 using msvc2015_void_t = typename msvc2015_void<T>::type;
205
206 template <class E, class = void>
207 struct is_lambda_type : std::false_type
208 {
209 };
210
211 // check if operator() is available
212 template <class E>
213 struct is_lambda_type<E, msvc2015_void_t<decltype(&E::operator())>> : std::true_type
214 {
215 };
216
217 template <class T>
218 struct self_type
219 {
220 using type = T;
221 };
222
223 template <class CP, class A, class O>
224 struct get_buffer_storage
225 {
226 using type = xtl::mpl::eval_if_t<
227 is_lambda_type<A>,
228 self_type<xbuffer_smart_pointer<CP, A>>,
229 self_type<xbuffer_storage<CP, A>>>;
230 };
231
232 template <class CP, class A>
233 struct get_buffer_storage<CP, A, acquire_ownership>
234 {
235 using type = xbuffer_owner_storage<CP, A>;
236 };
237
238 template <class CP, class T>
239 struct get_buffer_storage<CP, std::shared_ptr<T>, no_ownership>
240 {
241 using type = xbuffer_smart_pointer<CP, std::shared_ptr<T>>;
242 };
243
244 template <class CP, class T>
245 struct get_buffer_storage<CP, std::unique_ptr<T>, no_ownership>
246 {
247 using type = xbuffer_smart_pointer<CP, std::unique_ptr<T>>;
248 };
249
250 template <class CP, class A, class O>
251 using buffer_storage_t = typename get_buffer_storage<CP, A, O>::type;
252 }
253
254 /************************
255 * xbuffer_adaptor_base *
256 ************************/
257
258 template <class D>
260
261 template <class D>
263 {
264 public:
265
267 using derived_type = D;
269 using value_type = typename inner_types::value_type;
270 using reference = typename inner_types::reference;
271 using const_reference = typename inner_types::const_reference;
272 using pointer = typename inner_types::pointer;
273 using const_pointer = typename inner_types::const_pointer;
274 using size_type = typename inner_types::size_type;
275 using difference_type = typename inner_types::difference_type;
276 using iterator = typename inner_types::iterator;
277 using const_iterator = typename inner_types::const_iterator;
278 using reverse_iterator = typename inner_types::reverse_iterator;
279 using const_reverse_iterator = typename inner_types::const_reverse_iterator;
280 using index_type = typename inner_types::index_type;
281
282 bool empty() const noexcept;
283
284 reference operator[](size_type i);
285 const_reference operator[](size_type i) const;
286
287 reference front();
288 const_reference front() const;
289
290 reference back();
291 const_reference back() const;
292
293 iterator begin() noexcept;
294 iterator end() noexcept;
295
296 const_iterator begin() const noexcept;
297 const_iterator end() const noexcept;
298 const_iterator cbegin() const noexcept;
299 const_iterator cend() const noexcept;
300
301 reverse_iterator rbegin() noexcept;
302 reverse_iterator rend() noexcept;
303
304 const_reverse_iterator rbegin() const noexcept;
305 const_reverse_iterator rend() const noexcept;
306 const_reverse_iterator crbegin() const noexcept;
307 const_reverse_iterator crend() const noexcept;
308
309 derived_type& derived_cast() noexcept;
310 const derived_type& derived_cast() const noexcept;
311
312 protected:
313
314 xbuffer_adaptor_base() = default;
315 ~xbuffer_adaptor_base() = default;
316
317 xbuffer_adaptor_base(const self_type&) = default;
318 self_type& operator=(const self_type&) = default;
319
320 xbuffer_adaptor_base(self_type&&) = default;
321 self_type& operator=(self_type&&) = default;
322 };
323
324 template <class D>
326
327 template <class D>
329
330 template <class D>
332
333 template <class D>
335
336 template <class D>
337 bool operator>(const xbuffer_adaptor_base<D>& lhs, const xbuffer_adaptor_base<D>& rhs);
338
339 template <class D>
340 bool operator>=(const xbuffer_adaptor_base<D>& lhs, const xbuffer_adaptor_base<D>& rhs);
341
342 /*******************
343 * xbuffer_adaptor *
344 *******************/
345
346 template <class CP, class O, class A>
348 {
349 using base_type = detail::buffer_storage_t<CP, A, O>;
350 using value_type = typename base_type::value_type;
351 using reference = typename base_type::reference;
352 using const_reference = typename base_type::const_reference;
353 using pointer = typename base_type::pointer;
354 using const_pointer = typename base_type::const_pointer;
355 using size_type = typename base_type::size_type;
356 using difference_type = typename base_type::difference_type;
357 using iterator = pointer;
358 using const_iterator = const_pointer;
359 using reverse_iterator = std::reverse_iterator<iterator>;
360 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
361 using index_type = size_type;
362 };
363
364 template <class CP, class O, class A>
365 class xbuffer_adaptor : private detail::buffer_storage_t<CP, A, O>,
366 public xbuffer_adaptor_base<xbuffer_adaptor<CP, O, A>>
367 {
368 public:
369
371 using base_type = detail::buffer_storage_t<CP, A, O>;
373 using allocator_type = typename base_type::allocator_type;
374 using destructor_type = typename base_type::destructor_type;
375 using value_type = typename buffer_base_type::value_type;
376 using reference = typename buffer_base_type::reference;
377 using const_reference = typename buffer_base_type::const_reference;
378 using pointer = typename buffer_base_type::pointer;
379 using const_pointer = typename buffer_base_type::const_pointer;
380 using size_type = typename buffer_base_type::size_type;
381 using difference_type = typename buffer_base_type::difference_type;
382 using iterator = typename buffer_base_type::iterator;
383 using const_iterator = typename buffer_base_type::const_iterator;
384 using reverse_iterator = typename buffer_base_type::reverse_iterator;
385 using const_reverse_iterator = typename buffer_base_type::const_reverse_iterator;
387
388 xbuffer_adaptor() = default;
389
390 using base_type::base_type;
391
392 ~xbuffer_adaptor() = default;
393
394 xbuffer_adaptor(const self_type&) = default;
395 self_type& operator=(const self_type&) = default;
396
397 xbuffer_adaptor(self_type&&) = default;
398 xbuffer_adaptor& operator=(self_type&&) = default;
399
400 self_type& operator=(temporary_type&&);
401
402 using base_type::data;
403 using base_type::reset_data;
404 using base_type::resize;
405 using base_type::size;
406 using base_type::swap;
407 };
408
409 template <class CP, class O, class A>
411
412 /*********************
413 * xiterator_adaptor *
414 *********************/
415
416 template <class I, class CI>
417 class xiterator_adaptor;
418
419 template <class I, class CI>
421 {
422 using traits = std::iterator_traits<I>;
423 using const_traits = std::iterator_traits<CI>;
424
425 using value_type = std::common_type_t<typename traits::value_type, typename const_traits::value_type>;
426 using reference = typename traits::reference;
427 using const_reference = typename const_traits::reference;
428 using pointer = typename traits::pointer;
429 using const_pointer = typename const_traits::pointer;
430 using difference_type = std::common_type_t<typename traits::difference_type, typename const_traits::difference_type>;
431 using size_type = std::make_unsigned_t<difference_type>;
432
433 using iterator = I;
434 using const_iterator = CI;
435 using reverse_iterator = std::reverse_iterator<iterator>;
436 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
437 using index_type = difference_type;
438 };
439
440 template <class I, class CI>
441 class xiterator_adaptor : public xbuffer_adaptor_base<xiterator_adaptor<I, CI>>
442 {
443 public:
444
447 using value_type = typename base_type::value_type;
448 using allocator_type = std::allocator<value_type>;
449 using size_type = typename base_type::size_type;
450 using iterator = typename base_type::iterator;
451 using const_iterator = typename base_type::const_iterator;
453
454 xiterator_adaptor() = default;
455 xiterator_adaptor(I it, CI cit, size_type size);
456
457 ~xiterator_adaptor() = default;
458
459 xiterator_adaptor(const self_type&) = default;
460 xiterator_adaptor& operator=(const self_type&) = default;
461
462 xiterator_adaptor(self_type&&) = default;
463 xiterator_adaptor& operator=(self_type&&) = default;
464
465 xiterator_adaptor& operator=(const temporary_type& rhs);
467
468 size_type size() const noexcept;
469 void resize(size_type size);
470
471 iterator data() noexcept;
472 const_iterator data() const noexcept;
473
474 void swap(self_type& rhs) noexcept;
475
476 private:
477
478 I m_it;
479 CI m_cit;
480 size_type m_size;
481 };
482
483 template <class I, class CI>
485
486 template <class I, class CI>
490
491 /***************************
492 * xiterator_owner_adaptor *
493 ***************************/
494
495 template <class C, class IG>
497
498 template <class C, class IG>
500 {
501 using iterator = typename IG::iterator;
502 using const_iterator = typename IG::const_iterator;
503 using reverse_iterator = std::reverse_iterator<iterator>;
504 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
505
506 using traits = std::iterator_traits<iterator>;
507 using const_traits = std::iterator_traits<const_iterator>;
508
509 using value_type = std::common_type_t<typename traits::value_type, typename const_traits::value_type>;
510 using reference = typename traits::reference;
511 using const_reference = typename const_traits::reference;
512 using pointer = typename traits::pointer;
513 using const_pointer = typename const_traits::pointer;
514 using difference_type = std::common_type_t<typename traits::difference_type, typename const_traits::difference_type>;
515 using size_type = std::make_unsigned_t<difference_type>;
516 using index_type = difference_type;
517 };
518
519 template <class C, class IG>
520 class xiterator_owner_adaptor : public xbuffer_adaptor_base<xiterator_owner_adaptor<C, IG>>
521 {
522 public:
523
526 using value_type = typename base_type::value_type;
527 using allocator_type = std::allocator<value_type>;
528 using size_type = typename base_type::size_type;
529 using iterator = typename base_type::iterator;
530 using const_iterator = typename base_type::const_iterator;
532
534
535 ~xiterator_owner_adaptor() = default;
536
538 xiterator_owner_adaptor& operator=(const self_type&);
539
542
543 xiterator_owner_adaptor& operator=(const temporary_type& rhs);
545
546 size_type size() const noexcept;
547 void resize(size_type size);
548
549 iterator data() noexcept;
550 const_iterator data() const noexcept;
551
552 void swap(self_type& rhs) noexcept;
553
554 private:
555
556 void init_iterators();
557
558 C m_container;
559 iterator m_it;
560 const_iterator m_cit;
561 size_type m_size;
562 };
563
564 template <class C, class IG>
566
567 template <class C, class IG>
569 : is_contiguous_container<typename IG::iterator>
570 {
571 };
572
573 /**************************
574 * make_xiterator_adaptor *
575 **************************/
576
577 template <class C, class IG>
578 auto make_xiterator_adaptor(C&& container, IG iterator_getter);
579
580 /************************************
581 * temporary_container metafunction *
582 ************************************/
583
584 template <class C>
586 {
587 using type = C;
588 };
589
590 template <class CP, class O, class A>
592 {
593 using type = typename xbuffer_adaptor<CP, O, A>::temporary_type;
594 };
595
596 template <class I, class CI>
598 {
599 using type = typename xiterator_adaptor<I, CI>::temporary_type;
600 };
601
602 template <class C, class IG>
607
608 template <class C>
609 using temporary_container_t = typename temporary_container<C>::type;
610
611 /**********************************
612 * xbuffer_storage implementation *
613 **********************************/
614
615 namespace detail
616 {
617 template <class CP, class A>
618 inline xbuffer_storage<CP, A>::xbuffer_storage()
619 : p_data(nullptr)
620 , m_size(0)
621 {
622 }
623
624 template <class CP, class A>
625 template <class P>
626 inline xbuffer_storage<CP, A>::xbuffer_storage(P&& data, size_type size, const allocator_type&)
627 : p_data(std::forward<P>(data))
628 , m_size(size)
629 {
630 }
631
632 template <class CP, class A>
633 inline auto xbuffer_storage<CP, A>::size() const noexcept -> size_type
634 {
635 return m_size;
636 }
637
638 template <class CP, class A>
639 inline void xbuffer_storage<CP, A>::resize(size_type size)
640 {
641 if (size != m_size)
642 {
643 XTENSOR_THROW(std::runtime_error, "xbuffer_storage not resizable");
644 }
645 }
646
647 template <class CP, class A>
648 inline auto xbuffer_storage<CP, A>::data() noexcept -> pointer
649 {
650 return p_data;
651 }
652
653 template <class CP, class A>
654 inline auto xbuffer_storage<CP, A>::data() const noexcept -> const_pointer
655 {
656 return p_data;
657 }
658
659 template <class CP, class A>
660 inline void xbuffer_storage<CP, A>::swap(self_type& rhs) noexcept
661 {
662 using std::swap;
663 swap(p_data, rhs.p_data);
664 swap(m_size, rhs.m_size);
665 }
666
667 template <class CP, class A>
668 template <class P>
669 inline void xbuffer_storage<CP, A>::reset_data(P&& data, size_type size) noexcept
670 {
671 p_data = std::forward<P>(data);
672 m_size = size;
673 }
674 }
675
676 /****************************************
677 * xbuffer_owner_storage implementation *
678 ****************************************/
679
680 namespace detail
681 {
682 template <class CP, class A>
683 template <class P>
684 inline xbuffer_owner_storage<CP, A>::xbuffer_owner_storage(P&& data, size_type size, const allocator_type& alloc)
685 : m_data(std::forward<P>(data))
686 , m_size(size)
687 , m_moved_from(false)
688 , m_allocator(alloc)
689 {
690 }
691
692 template <class CP, class A>
693 inline xbuffer_owner_storage<CP, A>::~xbuffer_owner_storage()
694 {
695 if (!m_moved_from)
696 {
697 safe_destroy_deallocate(m_allocator, m_data.get(), m_size);
698 m_size = 0;
699 }
700 }
701
702 template <class CP, class A>
703 inline auto xbuffer_owner_storage<CP, A>::operator=(const self_type& rhs) -> self_type&
704 {
705 using std::swap;
706 if (this != &rhs)
707 {
708 allocator_type al = std::allocator_traits<allocator_type>::select_on_container_copy_construction(
709 rhs.get_allocator()
710 );
711 pointer tmp = safe_init_allocate(al, rhs.m_size);
712 if (xtrivially_default_constructible<value_type>::value)
713 {
714 std::uninitialized_copy(rhs.m_data.get(), rhs.m_data.get() + rhs.m_size, tmp);
715 }
716 else
717 {
718 std::copy(rhs.m_data.get(), rhs.m_data.get() + rhs.m_size, tmp);
719 }
720 swap(m_data.get(), tmp);
721 swap(m_allocator, al);
722 safe_destroy_deallocate(al, tmp, m_size);
723 m_size = rhs.m_size;
724 }
725 return *this;
726 }
727
728 template <class CP, class A>
729 inline xbuffer_owner_storage<CP, A>::xbuffer_owner_storage(self_type&& rhs)
730 : m_data(std::move(rhs.m_data))
731 , m_size(std::move(rhs.m_size))
732 , m_moved_from(std::move(rhs.m_moved_from))
733 , m_allocator(std::move(rhs.m_allocator))
734 {
735 rhs.m_moved_from = true;
736 rhs.m_size = 0;
737 }
738
739 template <class CP, class A>
740 inline auto xbuffer_owner_storage<CP, A>::operator=(self_type&& rhs) -> self_type&
741 {
742 swap(rhs);
743 return *this;
744 }
745
746 template <class CP, class A>
747 inline auto xbuffer_owner_storage<CP, A>::size() const noexcept -> size_type
748 {
749 return m_size;
750 }
751
752 template <class CP, class A>
753 void xbuffer_owner_storage<CP, A>::resize(size_type size)
754 {
755 using std::swap;
756 if (size != m_size)
757 {
758 pointer tmp = safe_init_allocate(m_allocator, size);
759 swap(m_data.get(), tmp);
760 swap(m_size, size);
761 safe_destroy_deallocate(m_allocator, tmp, size);
762 }
763 }
764
765 template <class CP, class A>
766 inline auto xbuffer_owner_storage<CP, A>::data() noexcept -> pointer
767 {
768 return m_data.get();
769 }
770
771 template <class CP, class A>
772 inline auto xbuffer_owner_storage<CP, A>::data() const noexcept -> const_pointer
773 {
774 return m_data.get();
775 }
776
777 template <class CP, class A>
778 inline auto xbuffer_owner_storage<CP, A>::get_allocator() const noexcept -> allocator_type
779 {
780 return allocator_type(m_allocator);
781 }
782
783 template <class CP, class A>
784 inline void xbuffer_owner_storage<CP, A>::swap(self_type& rhs) noexcept
785 {
786 using std::swap;
787 swap(m_data, rhs.m_data);
788 swap(m_size, rhs.m_size);
789 swap(m_allocator, rhs.m_allocator);
790 }
791
792 template <class CP, class A>
793 template <class P>
794 inline void
795 xbuffer_owner_storage<CP, A>::reset_data(P&& data, size_type size, const allocator_type& alloc) noexcept
796 {
797 xbuffer_owner_storage<CP, A> tmp(std::forward<P>(data), size, alloc);
798 this->swap(tmp);
799 }
800 }
801
802 /****************************************
803 * xbuffer_smart_pointer implementation *
804 ****************************************/
805
806 namespace detail
807 {
808 template <class CP, class D>
809 template <class P, class DT>
810 xbuffer_smart_pointer<CP, D>::xbuffer_smart_pointer(P&& data_ptr, size_type size, DT&& destruct)
811 : p_data(data_ptr)
812 , m_size(size)
813 , m_destruct(std::forward<DT>(destruct))
814 {
815 }
816
817 template <class CP, class D>
818 auto xbuffer_smart_pointer<CP, D>::size() const noexcept -> size_type
819 {
820 return m_size;
821 }
822
823 template <class CP, class D>
824 void xbuffer_smart_pointer<CP, D>::resize(size_type size)
825 {
826 if (m_size != size)
827 {
828 XTENSOR_THROW(std::runtime_error, "xbuffer_storage not resizeable");
829 }
830 }
831
832 template <class CP, class D>
833 auto xbuffer_smart_pointer<CP, D>::data() noexcept -> pointer
834 {
835 return p_data;
836 }
837
838 template <class CP, class D>
839 auto xbuffer_smart_pointer<CP, D>::data() const noexcept -> const_pointer
840 {
841 return p_data;
842 }
843
844 template <class CP, class D>
845 void xbuffer_smart_pointer<CP, D>::swap(self_type& rhs) noexcept
846 {
847 using std::swap;
848 swap(p_data, rhs.p_data);
849 swap(m_size, rhs.m_size);
850 swap(m_destruct, rhs.m_destruct);
851 }
852
853 template <class CP, class D>
854 template <class P, class DT>
855 void xbuffer_smart_pointer<CP, D>::reset_data(P&& data, size_type size, DT&& destruct) noexcept
856 {
857 p_data = std::forward<P>(data);
858 m_size = size;
859 m_destruct = destruct;
860 }
861 }
862
863 /***************************************
864 * xbuffer_adaptor_base implementation *
865 ***************************************/
866
867 template <class D>
868 inline bool xbuffer_adaptor_base<D>::empty() const noexcept
869 {
870 return derived_cast().size() == size_type(0);
871 }
872
873 template <class D>
874 inline auto xbuffer_adaptor_base<D>::operator[](size_type i) -> reference
875 {
876 return derived_cast().data()[static_cast<index_type>(i)];
877 }
878
879 template <class D>
880 inline auto xbuffer_adaptor_base<D>::operator[](size_type i) const -> const_reference
881 {
882 return derived_cast().data()[static_cast<index_type>(i)];
883 }
884
885 template <class D>
886 inline auto xbuffer_adaptor_base<D>::front() -> reference
887 {
888 return this->operator[](0);
889 }
890
891 template <class D>
892 inline auto xbuffer_adaptor_base<D>::front() const -> const_reference
893 {
894 return this->operator[](0);
895 }
896
897 template <class D>
898 inline auto xbuffer_adaptor_base<D>::back() -> reference
899 {
900 return this->operator[](derived_cast().size() - 1);
901 }
902
903 template <class D>
904 inline auto xbuffer_adaptor_base<D>::back() const -> const_reference
905 {
906 return this->operator[](derived_cast().size() - 1);
907 }
908
909 template <class D>
910 inline auto xbuffer_adaptor_base<D>::begin() noexcept -> iterator
911 {
912 return derived_cast().data();
913 }
914
915 template <class D>
916 inline auto xbuffer_adaptor_base<D>::end() noexcept -> iterator
917 {
918 return derived_cast().data() + static_cast<index_type>(derived_cast().size());
919 }
920
921 template <class D>
922 inline auto xbuffer_adaptor_base<D>::begin() const noexcept -> const_iterator
923 {
924 return derived_cast().data();
925 }
926
927 template <class D>
928 inline auto xbuffer_adaptor_base<D>::end() const noexcept -> const_iterator
929 {
930 return derived_cast().data() + static_cast<index_type>(derived_cast().size());
931 }
932
933 template <class D>
934 inline auto xbuffer_adaptor_base<D>::cbegin() const noexcept -> const_iterator
935 {
936 return begin();
937 }
938
939 template <class D>
940 inline auto xbuffer_adaptor_base<D>::cend() const noexcept -> const_iterator
941 {
942 return end();
943 }
944
945 template <class D>
946 inline auto xbuffer_adaptor_base<D>::rbegin() noexcept -> reverse_iterator
947 {
948 return reverse_iterator(end());
949 }
950
951 template <class D>
952 inline auto xbuffer_adaptor_base<D>::rend() noexcept -> reverse_iterator
953 {
954 return reverse_iterator(begin());
955 }
956
957 template <class D>
958 inline auto xbuffer_adaptor_base<D>::rbegin() const noexcept -> const_reverse_iterator
959 {
960 return const_reverse_iterator(end());
961 }
962
963 template <class D>
964 inline auto xbuffer_adaptor_base<D>::rend() const noexcept -> const_reverse_iterator
965 {
966 return const_reverse_iterator(begin());
967 }
968
969 template <class D>
970 inline auto xbuffer_adaptor_base<D>::crbegin() const noexcept -> const_reverse_iterator
971 {
972 return rbegin();
973 }
974
975 template <class D>
976 inline auto xbuffer_adaptor_base<D>::crend() const noexcept -> const_reverse_iterator
977 {
978 return rend();
979 }
980
981 template <class D>
982 inline auto xbuffer_adaptor_base<D>::derived_cast() noexcept -> derived_type&
983 {
984 return *static_cast<derived_type*>(this);
985 }
986
987 template <class D>
988 inline auto xbuffer_adaptor_base<D>::derived_cast() const noexcept -> const derived_type&
989 {
990 return *static_cast<const derived_type*>(this);
991 }
992
993 template <class D>
994 inline bool operator==(const xbuffer_adaptor_base<D>& lhs, const xbuffer_adaptor_base<D>& rhs)
995 {
996 return lhs.derived_cast().size() == rhs.derived_cast().size()
997 && std::equal(lhs.begin(), lhs.end(), rhs.begin());
998 }
999
1000 template <class D>
1001 inline bool operator!=(const xbuffer_adaptor_base<D>& lhs, const xbuffer_adaptor_base<D>& rhs)
1002 {
1003 return !(lhs == rhs);
1004 }
1005
1006 template <class D>
1007 inline bool operator<(const xbuffer_adaptor_base<D>& lhs, const xbuffer_adaptor_base<D>& rhs)
1008 {
1009 return std::lexicographical_compare(
1010 lhs.begin(),
1011 lhs.end(),
1012 rhs.begin(),
1013 rhs.end(),
1014 std::less<typename D::value_type>()
1015 );
1016 }
1017
1018 template <class D>
1019 inline bool operator<=(const xbuffer_adaptor_base<D>& lhs, const xbuffer_adaptor_base<D>& rhs)
1020 {
1021 return std::lexicographical_compare(
1022 lhs.begin(),
1023 lhs.end(),
1024 rhs.begin(),
1025 rhs.end(),
1026 std::less_equal<typename D::value_type>()
1027 );
1028 }
1029
1030 template <class D>
1031 inline bool operator>(const xbuffer_adaptor_base<D>& lhs, const xbuffer_adaptor_base<D>& rhs)
1032 {
1033 return std::lexicographical_compare(
1034 lhs.begin(),
1035 lhs.end(),
1036 rhs.begin(),
1037 rhs.end(),
1038 std::greater<typename D::value_type>()
1039 );
1040 }
1041
1042 template <class D>
1043 inline bool operator>=(const xbuffer_adaptor_base<D>& lhs, const xbuffer_adaptor_base<D>& rhs)
1044 {
1045 return std::lexicographical_compare(
1046 lhs.begin(),
1047 lhs.end(),
1048 rhs.begin(),
1049 rhs.end(),
1050 std::greater_equal<typename D::value_type>()
1051 );
1052 }
1053
1054 /**********************************
1055 * xbuffer_adaptor implementation *
1056 **********************************/
1057
1058 template <class CP, class O, class A>
1059 inline auto xbuffer_adaptor<CP, O, A>::operator=(temporary_type&& tmp) -> self_type&
1060 {
1061 base_type::resize(tmp.size());
1062 std::copy(tmp.cbegin(), tmp.cend(), this->begin());
1063 return *this;
1064 }
1065
1066 template <class CP, class O, class A>
1067 inline void swap(xbuffer_adaptor<CP, O, A>& lhs, xbuffer_adaptor<CP, O, A>& rhs) noexcept
1068 {
1069 lhs.swap(rhs);
1070 }
1071
1072 /************************************
1073 * xiterator_adaptor implementation *
1074 ************************************/
1075
1076 template <class I, class CI>
1077 inline xiterator_adaptor<I, CI>::xiterator_adaptor(I it, CI cit, size_type size)
1078 : m_it(it)
1079 , m_cit(cit)
1080 , m_size(size)
1081 {
1082 }
1083
1084 template <class I, class CI>
1085 inline auto xiterator_adaptor<I, CI>::operator=(const temporary_type& rhs) -> self_type&
1086 {
1087 resize(rhs.size());
1088 std::copy(rhs.cbegin(), rhs.cend(), m_it);
1089 return *this;
1090 }
1091
1092 template <class I, class CI>
1093 inline auto xiterator_adaptor<I, CI>::operator=(temporary_type&& rhs) -> self_type&
1094 {
1095 return (*this = rhs);
1096 }
1097
1098 template <class I, class CI>
1099 inline auto xiterator_adaptor<I, CI>::size() const noexcept -> size_type
1100 {
1101 return m_size;
1102 }
1103
1104 template <class I, class CI>
1105 inline void xiterator_adaptor<I, CI>::resize(size_type size)
1106 {
1107 if (m_size != size)
1108 {
1109 XTENSOR_THROW(std::runtime_error, "xiterator_adaptor not resizeable");
1110 }
1111 }
1112
1113 template <class I, class CI>
1114 inline auto xiterator_adaptor<I, CI>::data() noexcept -> iterator
1115 {
1116 return m_it;
1117 }
1118
1119 template <class I, class CI>
1120 inline auto xiterator_adaptor<I, CI>::data() const noexcept -> const_iterator
1121 {
1122 return m_cit;
1123 }
1124
1125 template <class I, class CI>
1126 inline void xiterator_adaptor<I, CI>::swap(self_type& rhs) noexcept
1127 {
1128 using std::swap;
1129 swap(m_it, rhs.m_it);
1130 swap(m_cit, rhs.m_cit);
1131 swap(m_size, rhs.m_size);
1132 }
1133
1134 template <class I, class CI>
1135 inline void swap(xiterator_adaptor<I, CI>& lhs, xiterator_adaptor<I, CI>& rhs) noexcept
1136 {
1137 lhs.swap(rhs);
1138 }
1139
1140 /******************************************
1141 * xiterator_owner_adaptor implementation *
1142 ******************************************/
1143
1144 template <class C, class IG>
1145 inline xiterator_owner_adaptor<C, IG>::xiterator_owner_adaptor(C&& c)
1146 : m_container(std::move(c))
1147 {
1148 init_iterators();
1149 }
1150
1151 template <class C, class IG>
1152 inline xiterator_owner_adaptor<C, IG>::xiterator_owner_adaptor(const self_type& rhs)
1153 : m_container(rhs.m_container)
1154 {
1155 init_iterators();
1156 }
1157
1158 template <class C, class IG>
1159 inline xiterator_owner_adaptor<C, IG>& xiterator_owner_adaptor<C, IG>::operator=(const self_type& rhs)
1160 {
1161 m_container = rhs.m_container;
1162 init_iterators();
1163 }
1164
1165 template <class C, class IG>
1166 inline xiterator_owner_adaptor<C, IG>::xiterator_owner_adaptor(self_type&& rhs)
1167 : m_container(std::move(rhs.m_container))
1168 {
1169 init_iterators();
1170 }
1171
1172 template <class C, class IG>
1173 inline xiterator_owner_adaptor<C, IG>& xiterator_owner_adaptor<C, IG>::operator=(self_type&& rhs)
1174 {
1175 m_container = std::move(rhs.m_container);
1176 init_iterators();
1177 }
1178
1179 template <class C, class IG>
1180 inline xiterator_owner_adaptor<C, IG>& xiterator_owner_adaptor<C, IG>::operator=(const temporary_type& rhs)
1181 {
1182 resize(rhs.size());
1183 std::copy(rhs.cbegin(), rhs.cend(), m_it);
1184 return *this;
1185 }
1186
1187 template <class C, class IG>
1188 inline xiterator_owner_adaptor<C, IG>& xiterator_owner_adaptor<C, IG>::operator=(temporary_type&& rhs)
1189 {
1190 return (*this = rhs);
1191 }
1192
1193 template <class C, class IG>
1194 inline auto xiterator_owner_adaptor<C, IG>::size() const noexcept -> size_type
1195 {
1196 return m_size;
1197 }
1198
1199 template <class C, class IG>
1200 inline void xiterator_owner_adaptor<C, IG>::resize(size_type size)
1201 {
1202 if (m_size != size)
1203 {
1204 XTENSOR_THROW(std::runtime_error, "xiterator_owner_adaptor not resizeable");
1205 }
1206 }
1207
1208 template <class C, class IG>
1209 inline auto xiterator_owner_adaptor<C, IG>::data() noexcept -> iterator
1210 {
1211 return m_it;
1212 }
1213
1214 template <class C, class IG>
1215 inline auto xiterator_owner_adaptor<C, IG>::data() const noexcept -> const_iterator
1216 {
1217 return m_cit;
1218 }
1219
1220 template <class C, class IG>
1221 inline void xiterator_owner_adaptor<C, IG>::swap(self_type& rhs) noexcept
1222 {
1223 using std::swap;
1224 swap(m_container, rhs.m_container);
1225 init_iterators();
1226 rhs.init_iterators();
1227 }
1228
1229 template <class C, class IG>
1230 inline void xiterator_owner_adaptor<C, IG>::init_iterators()
1231 {
1232 m_it = IG::begin(m_container);
1233 m_cit = IG::cbegin(m_container);
1234 m_size = IG::size(m_container);
1235 }
1236
1237 template <class C, class IG>
1238 inline void swap(xiterator_owner_adaptor<C, IG>& lhs, xiterator_owner_adaptor<C, IG>& rhs) noexcept
1239 {
1240 lhs.swap(rhs);
1241 }
1242
1243 /*****************************************
1244 * make_xiterator_adaptor implementation *
1245 *****************************************/
1246
1247 namespace detail
1248 {
1249 template <class C, class IG, bool = std::is_lvalue_reference<C>::value>
1250 struct xiterator_adaptor_builder
1251 {
1252 using iterator = decltype(IG::begin(std::declval<C>()));
1253 using const_iterator = decltype(IG::cbegin(std::declval<C>()));
1254 using type = xiterator_adaptor<iterator, const_iterator>;
1255
1256 inline static type build(C& c)
1257 {
1258 return type(IG::begin(c), IG::cbegin(c), IG::size(c));
1259 }
1260 };
1261
1262 template <class C, class IG>
1263 struct xiterator_adaptor_builder<C, IG, false>
1264 {
1265 using type = xiterator_owner_adaptor<C, IG>;
1266
1267 inline static type build(C&& c)
1268 {
1269 return type(std::move(c));
1270 }
1271 };
1272 }
1273
1274 template <class C, class IG>
1275 inline auto make_xiterator_adaptor(C&& container, IG)
1276 {
1277 using builder_type = detail::xiterator_adaptor_builder<C, IG>;
1278 return builder_type::build(std::forward<C>(container));
1279 }
1280}
1281
1282#endif
standard mathematical functions for xexpressions
bool operator==(const xaxis_iterator< CT > &lhs, const xaxis_iterator< CT > &rhs)
Checks equality of the iterators.
bool operator!=(const xaxis_iterator< CT > &lhs, const xaxis_iterator< CT > &rhs)
Checks inequality of the iterators.
xarray< T, L > empty(const S &shape)
Create a xcontainer (xarray, xtensor or xtensor_fixed) with uninitialized values of with value_type T...
Definition xbuilder.hpp:89