xtensor
Loading...
Searching...
No Matches
xsemantic.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_SEMANTIC_HPP
11#define XTENSOR_SEMANTIC_HPP
12
13#include <functional>
14#include <utility>
15
16#include "xassign.hpp"
17#include "xexpression_traits.hpp"
18
19namespace xt
20{
21 namespace detail
22 {
23 template <class D>
24 struct is_sharable
25 {
26 static constexpr bool value = true;
27 };
28
29 template <class ET, class S, layout_type L, bool SH, class Tag>
30 struct is_sharable<xfixed_container<ET, S, L, SH, Tag>>
31 {
32 static constexpr bool value = SH;
33 };
34
35 template <class ET, class S, layout_type L, bool SH, class Tag>
36 struct is_sharable<xfixed_adaptor<ET, S, L, SH, Tag>>
37 {
38 static constexpr bool value = SH;
39 };
40 }
41
42 template <class D>
43 using select_expression_base_t = std::
44 conditional_t<detail::is_sharable<D>::value, xsharable_expression<D>, xexpression<D>>;
45
56 template <class D>
57 class xsemantic_base : public select_expression_base_t<D>
58 {
59 public:
60
62 using derived_type = typename base_type::derived_type;
63
64 using temporary_type = typename xcontainer_inner_types<D>::temporary_type;
65
66 template <class E>
67 disable_xexpression<E, derived_type&> operator+=(const E&);
68
69 template <class E>
70 disable_xexpression<E, derived_type&> operator-=(const E&);
71
72 template <class E>
73 disable_xexpression<E, derived_type&> operator*=(const E&);
74
75 template <class E>
76 disable_xexpression<E, derived_type&> operator/=(const E&);
77
78 template <class E>
79 disable_xexpression<E, derived_type&> operator%=(const E&);
80
81 template <class E>
82 disable_xexpression<E, derived_type&> operator&=(const E&);
83
84 template <class E>
85 disable_xexpression<E, derived_type&> operator|=(const E&);
86
87 template <class E>
88 disable_xexpression<E, derived_type&> operator^=(const E&);
89
90 template <class E>
91 derived_type& operator+=(const xexpression<E>&);
92
93 template <class E>
94 derived_type& operator-=(const xexpression<E>&);
95
96 template <class E>
97 derived_type& operator*=(const xexpression<E>&);
98
99 template <class E>
100 derived_type& operator/=(const xexpression<E>&);
101
102 template <class E>
103 derived_type& operator%=(const xexpression<E>&);
104
105 template <class E>
106 derived_type& operator&=(const xexpression<E>&);
107
108 template <class E>
109 derived_type& operator|=(const xexpression<E>&);
110
111 template <class E>
112 derived_type& operator^=(const xexpression<E>&);
113
114 template <class E>
115 derived_type& assign(const xexpression<E>&);
116
117 template <class E>
118 derived_type& plus_assign(const xexpression<E>&);
119
120 template <class E>
121 derived_type& minus_assign(const xexpression<E>&);
122
123 template <class E>
124 derived_type& multiplies_assign(const xexpression<E>&);
125
126 template <class E>
127 derived_type& divides_assign(const xexpression<E>&);
128
129 template <class E>
130 derived_type& modulus_assign(const xexpression<E>&);
131
132 template <class E>
133 derived_type& bit_and_assign(const xexpression<E>&);
134
135 template <class E>
136 derived_type& bit_or_assign(const xexpression<E>&);
137
138 template <class E>
139 derived_type& bit_xor_assign(const xexpression<E>&);
140
141 protected:
142
143 xsemantic_base() = default;
144 ~xsemantic_base() = default;
145
146 xsemantic_base(const xsemantic_base&) = default;
147 xsemantic_base& operator=(const xsemantic_base&) = default;
148
149 xsemantic_base(xsemantic_base&&) = default;
150 xsemantic_base& operator=(xsemantic_base&&) = default;
151
152 template <class E>
153 derived_type& operator=(const xexpression<E>&);
154 };
155
156 template <class E>
158
159 template <class E, class R = void>
160 using enable_assignable = typename std::enable_if<is_assignable<E>::value, R>::type;
161
162 template <class E, class R = void>
163 using disable_assignable = typename std::enable_if<!is_assignable<E>::value, R>::type;
164
176 template <class D>
178 {
179 public:
180
182 using derived_type = D;
183 using temporary_type = typename base_type::temporary_type;
184
185 derived_type& assign_temporary(temporary_type&&);
186
187 template <class E>
188 derived_type& assign_xexpression(const xexpression<E>& e);
189
190 template <class E>
191 derived_type& computed_assign(const xexpression<E>& e);
192
193 template <class E, class F>
194 derived_type& scalar_computed_assign(const E& e, F&& f);
195
196 protected:
197
198 xcontainer_semantic() = default;
199 ~xcontainer_semantic() = default;
200
202 xcontainer_semantic& operator=(const xcontainer_semantic&) = default;
203
205 xcontainer_semantic& operator=(xcontainer_semantic&&) = default;
206
207 template <class E>
208 derived_type& operator=(const xexpression<E>&);
209 };
210
211 template <class E>
213
214 template <class E, class R = void>
215 using enable_xcontainer_semantics = typename std::enable_if<has_container_semantics<E>::value, R>::type;
216
217 template <class E, class R = void>
218 using disable_xcontainer_semantics = typename std::enable_if<!has_container_semantics<E>::value, R>::type;
219
220
221 template <class D>
222 class xview_semantic;
223
224 template <class E>
226 E,
227 std::enable_if_t<!has_memory_address<E>::value && is_crtp_base_of<xview_semantic, E>::value>>
228 {
229 static bool check_overlap(const E& expr, const memory_range& dst_range)
230 {
231 if (expr.size() == 0)
232 {
233 return false;
234 }
235 else
236 {
237 using ChildE = std::decay_t<decltype(expr.expression())>;
239 }
240 }
241 };
242
253 template <class D>
255 {
256 public:
257
259 using derived_type = D;
260 using temporary_type = typename base_type::temporary_type;
261
262 derived_type& assign_temporary(temporary_type&&);
263
264 template <class E>
265 derived_type& assign_xexpression(const xexpression<E>& e);
266
267 template <class E>
268 derived_type& computed_assign(const xexpression<E>& e);
269
270 template <class E, class F>
271 derived_type& scalar_computed_assign(const E& e, F&& f);
272
273 protected:
274
275 xview_semantic() = default;
276 ~xview_semantic() = default;
277
278 xview_semantic(const xview_semantic&) = default;
279 xview_semantic& operator=(const xview_semantic&) = default;
280
281 xview_semantic(xview_semantic&&) = default;
282 xview_semantic& operator=(xview_semantic&&) = default;
283
284 template <class E>
285 derived_type& operator=(const xexpression<E>&);
286 };
287
288 template <class E>
290
291 template <class E, class R = void>
292 using enable_xview_semantics = typename std::enable_if<has_view_semantics<E>::value, R>::type;
293
294 template <class E, class R = void>
295 using disable_xview_semantics = typename std::enable_if<!has_view_semantics<E>::value, R>::type;
296
297 /*********************************
298 * xsemantic_base implementation *
299 *********************************/
300
310 template <class D>
311 template <class E>
313 {
314 return this->derived_cast().scalar_computed_assign(e, std::plus<>());
315 }
316
322 template <class D>
323 template <class E>
325 {
326 return this->derived_cast().scalar_computed_assign(e, std::minus<>());
327 }
328
334 template <class D>
335 template <class E>
337 {
338 return this->derived_cast().scalar_computed_assign(e, std::multiplies<>());
339 }
340
346 template <class D>
347 template <class E>
349 {
350 return this->derived_cast().scalar_computed_assign(e, std::divides<>());
351 }
352
358 template <class D>
359 template <class E>
361 {
362 return this->derived_cast().scalar_computed_assign(e, std::modulus<>());
363 }
364
370 template <class D>
371 template <class E>
373 {
374 return this->derived_cast().scalar_computed_assign(e, std::bit_and<>());
375 }
376
382 template <class D>
383 template <class E>
385 {
386 return this->derived_cast().scalar_computed_assign(e, std::bit_or<>());
387 }
388
394 template <class D>
395 template <class E>
397 {
398 return this->derived_cast().scalar_computed_assign(e, std::bit_xor<>());
399 }
400
406 template <class D>
407 template <class E>
408 inline auto xsemantic_base<D>::operator+=(const xexpression<E>& e) -> derived_type&
409 {
410 return this->derived_cast() = this->derived_cast() + e.derived_cast();
411 }
412
418 template <class D>
419 template <class E>
420 inline auto xsemantic_base<D>::operator-=(const xexpression<E>& e) -> derived_type&
421 {
422 return this->derived_cast() = this->derived_cast() - e.derived_cast();
423 }
424
430 template <class D>
431 template <class E>
432 inline auto xsemantic_base<D>::operator*=(const xexpression<E>& e) -> derived_type&
433 {
434 return this->derived_cast() = this->derived_cast() * e.derived_cast();
435 }
436
442 template <class D>
443 template <class E>
444 inline auto xsemantic_base<D>::operator/=(const xexpression<E>& e) -> derived_type&
445 {
446 return this->derived_cast() = this->derived_cast() / e.derived_cast();
447 }
448
454 template <class D>
455 template <class E>
456 inline auto xsemantic_base<D>::operator%=(const xexpression<E>& e) -> derived_type&
457 {
458 return this->derived_cast() = this->derived_cast() % e.derived_cast();
459 }
460
466 template <class D>
467 template <class E>
468 inline auto xsemantic_base<D>::operator&=(const xexpression<E>& e) -> derived_type&
469 {
470 return this->derived_cast() = this->derived_cast() & e.derived_cast();
471 }
472
478 template <class D>
479 template <class E>
480 inline auto xsemantic_base<D>::operator|=(const xexpression<E>& e) -> derived_type&
481 {
482 return this->derived_cast() = this->derived_cast() | e.derived_cast();
483 }
484
490 template <class D>
491 template <class E>
492 inline auto xsemantic_base<D>::operator^=(const xexpression<E>& e) -> derived_type&
493 {
494 return this->derived_cast() = this->derived_cast() ^ e.derived_cast();
495 }
496
498
509 template <class D>
510 template <class E>
511 inline auto xsemantic_base<D>::assign(const xexpression<E>& e) -> derived_type&
512 {
513 return this->derived_cast().assign_xexpression(e);
514 }
515
522 template <class D>
523 template <class E>
524 inline auto xsemantic_base<D>::plus_assign(const xexpression<E>& e) -> derived_type&
525 {
526 return this->derived_cast().computed_assign(this->derived_cast() + e.derived_cast());
527 }
528
535 template <class D>
536 template <class E>
537 inline auto xsemantic_base<D>::minus_assign(const xexpression<E>& e) -> derived_type&
538 {
539 return this->derived_cast().computed_assign(this->derived_cast() - e.derived_cast());
540 }
541
548 template <class D>
549 template <class E>
550 inline auto xsemantic_base<D>::multiplies_assign(const xexpression<E>& e) -> derived_type&
551 {
552 return this->derived_cast().computed_assign(this->derived_cast() * e.derived_cast());
553 }
554
561 template <class D>
562 template <class E>
563 inline auto xsemantic_base<D>::divides_assign(const xexpression<E>& e) -> derived_type&
564 {
565 return this->derived_cast().computed_assign(this->derived_cast() / e.derived_cast());
566 }
567
574 template <class D>
575 template <class E>
576 inline auto xsemantic_base<D>::modulus_assign(const xexpression<E>& e) -> derived_type&
577 {
578 return this->derived_cast().computed_assign(this->derived_cast() % e.derived_cast());
579 }
580
587 template <class D>
588 template <class E>
589 inline auto xsemantic_base<D>::bit_and_assign(const xexpression<E>& e) -> derived_type&
590 {
591 return this->derived_cast().computed_assign(this->derived_cast() & e.derived_cast());
592 }
593
600 template <class D>
601 template <class E>
602 inline auto xsemantic_base<D>::bit_or_assign(const xexpression<E>& e) -> derived_type&
603 {
604 return this->derived_cast().computed_assign(this->derived_cast() | e.derived_cast());
605 }
606
613 template <class D>
614 template <class E>
615 inline auto xsemantic_base<D>::bit_xor_assign(const xexpression<E>& e) -> derived_type&
616 {
617 return this->derived_cast().computed_assign(this->derived_cast() ^ e.derived_cast());
618 }
619
620 template <class D>
621 template <class E>
622 inline auto xsemantic_base<D>::operator=(const xexpression<E>& e) -> derived_type&
623 {
624#ifdef XTENSOR_FORCE_TEMPORARY_MEMORY_IN_ASSIGNMENTS
626 return this->derived_cast().assign_temporary(std::move(tmp));
627#else
628 auto&& this_derived = this->derived_cast();
629 auto memory_checker = make_overlapping_memory_checker(this_derived);
630 if (memory_checker.check_overlap(e.derived_cast()))
631 {
633 return this_derived.assign_temporary(std::move(tmp));
634 }
635 else
636 {
637 return this->assign(e);
638 }
639#endif
640 }
641
642 /**************************************
643 * xcontainer_semantic implementation *
644 **************************************/
645
651 template <class D>
653 {
654 return (this->derived_cast() = std::move(tmp));
655 }
656
657 template <class D>
658 template <class E>
659 inline auto xcontainer_semantic<D>::assign_xexpression(const xexpression<E>& e) -> derived_type&
660 {
661 xt::assign_xexpression(*this, e);
662 return this->derived_cast();
663 }
664
665 template <class D>
666 template <class E>
667 inline auto xcontainer_semantic<D>::computed_assign(const xexpression<E>& e) -> derived_type&
668 {
669 xt::computed_assign(*this, e);
670 return this->derived_cast();
671 }
672
673 template <class D>
674 template <class E, class F>
675 inline auto xcontainer_semantic<D>::scalar_computed_assign(const E& e, F&& f) -> derived_type&
676 {
677 xt::scalar_computed_assign(*this, e, std::forward<F>(f));
678 return this->derived_cast();
679 }
680
681 template <class D>
682 template <class E>
683 inline auto xcontainer_semantic<D>::operator=(const xexpression<E>& e) -> derived_type&
684 {
685 return base_type::operator=(e);
686 }
687
688 /*********************************
689 * xview_semantic implementation *
690 *********************************/
691
697 template <class D>
698 inline auto xview_semantic<D>::assign_temporary(temporary_type&& tmp) -> derived_type&
699 {
700 this->derived_cast().assign_temporary_impl(std::move(tmp));
701 return this->derived_cast();
702 }
703
704 namespace detail
705 {
706 template <class F>
707 bool get_rhs_triviality(const F&)
708 {
709 return true;
710 }
711
712 template <class F, class R, class... CT>
713 bool get_rhs_triviality(const xfunction<F, R, CT...>& rhs)
714 {
715 using index_type = xindex_type_t<typename xfunction<F, R, CT...>::shape_type>;
716 using size_type = typename index_type::size_type;
717 size_type size = rhs.dimension();
718 index_type shape = uninitialized_shape<index_type>(size);
719 bool trivial_broadcast = rhs.broadcast_shape(shape, true);
720 return trivial_broadcast;
721 }
722 }
723
724 template <class D>
725 template <class E>
726 inline auto xview_semantic<D>::assign_xexpression(const xexpression<E>& e) -> derived_type&
727 {
728 xt::assert_compatible_shape(*this, e);
729 xt::assign_data(*this, e, detail::get_rhs_triviality(e.derived_cast()));
730 return this->derived_cast();
731 }
732
733 template <class D>
734 template <class E>
735 inline auto xview_semantic<D>::computed_assign(const xexpression<E>& e) -> derived_type&
736 {
737 xt::assert_compatible_shape(*this, e);
738 xt::assign_data(*this, e, detail::get_rhs_triviality(e.derived_cast()));
739 return this->derived_cast();
740 }
741
742 namespace xview_semantic_detail
743 {
744 template <class D>
745 auto get_begin(D&& lhs, std::true_type)
746 {
747 return lhs.linear_begin();
748 }
749
750 template <class D>
751 auto get_begin(D&& lhs, std::false_type)
752 {
753 return lhs.begin();
754 }
755 }
756
757 template <class D>
758 template <class E, class F>
759 inline auto xview_semantic<D>::scalar_computed_assign(const E& e, F&& f) -> derived_type&
760 {
761 D& d = this->derived_cast();
762
763 using size_type = typename D::size_type;
764 auto dst = xview_semantic_detail::get_begin(d, std::integral_constant<bool, D::contiguous_layout>());
765 for (size_type i = d.size(); i > 0; --i)
766 {
767 *dst = f(*dst, e);
768 ++dst;
769 }
770 return this->derived_cast();
771 }
772
773 template <class D>
774 template <class E>
775 inline auto xview_semantic<D>::operator=(const xexpression<E>& rhs) -> derived_type&
776 {
777 bool cond = (rhs.derived_cast().shape().size() == this->derived_cast().dimension())
778 && std::equal(
779 this->derived_cast().shape().begin(),
780 this->derived_cast().shape().end(),
781 rhs.derived_cast().shape().begin()
782 );
783
784 if (!cond)
785 {
786 base_type::operator=(broadcast(rhs.derived_cast(), this->derived_cast().shape()));
787 }
788 else
789 {
790 base_type::operator=(rhs);
791 }
792 return this->derived_cast();
793 }
794}
795
796#endif
Implementation of the xsemantic_base interface for dense multidimensional containers.
derived_type & assign_temporary(temporary_type &&)
Assigns the temporary tmp to *this.
Base interface for assignable xexpressions.
Definition xsemantic.hpp:58
Implementation of the xsemantic_base interface for multidimensional views.
derived_type & assign_temporary(temporary_type &&)
Assigns the temporary tmp to *this.
standard mathematical functions for xexpressions
auto broadcast(E &&e, const S &s)
Returns an xexpression broadcasting the given expression to a specified shape.