asgn
 
Loading...
Searching...
No Matches
tagged.hpp
1#ifndef tagged_hpp_
2#define tagged_hpp_
3
4#include <concepts>
5#include <tuple>
6#include <ostream>
7#include <vector>
8#include <variant>
9
10namespace tagged {
11
14
15 // TAG
16
17 namespace impl {
18 template< typename T>
19 struct tag_traits;
20 }
21
27 template< typename T>
28 concept tag = impl::tag_traits<T>::is_tag;
29
35 template< typename T>
36 concept selector_tag = impl::tag_traits<T>::is_selector;
37
42 template< tag T>
43 using selector = typename impl::tag_traits<T>::selector;
44
46 template< typename T1, typename T2>
47 concept same_selector = std::same_as< selector<T1>, selector<T2>>;
48
49 struct tag_base {};
50
51 namespace impl {
52 template< typename T>
53 requires T::is_tag
54 struct tag_traits<T>
55 {
56 static constexpr bool is_tag = true;
57 static constexpr bool is_direct = false;
58 using core = typename T::core;
59 static constexpr bool is_selector = T::is_selector;
60 using selector = typename T::selector;
61 template<selector_tag T2>
62 using retag = typename T::template retag<T2>;
63 };
64
65 template< typename T>
66 requires std::derived_from<T, tag_base>
67 struct tag_traits<T>
68 {
69 static constexpr bool is_tag = true;
70 static constexpr bool is_direct = true;
71 using core = T;
72 static constexpr bool is_selector = true;
73 using selector = T;
74 template<selector_tag T2>
75 using retag = T2;
76 };
77 };
78
79 template< tag T>
80 using core = typename impl::tag_traits<T>::core;
81
82 template< typename T1, typename T2>
83 concept same_tag = std::same_as< core<T1>, core<T2>>;
84
85 template< selector_tag T2, tag T>
86 using retag = typename impl::tag_traits<T>::template retag<T2>;
87
88 template< tag T, std::size_t b, std::size_t e>
89 struct sr_tag {
90 static constexpr bool is_tag = true;
91 static constexpr bool is_direct = false;
92 using core = sr_tag< T, b, e>;
93 static constexpr bool is_selector = false;
94 using selector = T;
95 template<selector_tag T2>
96 using retag = sr_tag< T2, b, e>;
97
98 static constexpr bool is_static = true;
99 static constexpr std::size_t begin = b;
100 static constexpr std::size_t end = e;
101 };
102
103 template< typename T>
104 concept static_tag = tag<T> && T::is_static;
105
106 template< typename T>
107 concept non_static_tag = tag<T> && (!static_tag<T>);
108
109 // CARRIER
110
111 template< tag T>
112 using index_carrier_type = std::size_t;
114
116 template< tag ... TL>
117 class index_class;
118
119 template< tag ... TL>
120 class iterator_class;
121
122 template< tag ... TL>
123 class range_class;
124
125 template< typename E, tag ... TL>
126 class tensor_view;
128
130 namespace impl {
131 struct range_base {};
132 }
133
134 template< typename T>
135 concept is_range = std::derived_from< T, impl::range_base>;
136
137 namespace impl {
138 struct index_base {};
139
140 template< tag T, tag ... TL>
141 struct element_traits;
142
143 template< tag T>
144 struct element_traits< T> : std::false_type {};
145
146 template< tag T, tag T2, tag ... TL>
147 requires same_selector<T, T2>
148 struct element_traits< T, T2, TL ...> : std::true_type {};
149
150 template< tag T, tag T2, tag ... TL>
151 requires (!same_selector<T, T2>)
152 struct element_traits< T, T2, TL ...> : element_traits< T, TL ...> {};
153
154 template< typename T, typename ... TL>
155 concept one_of = element_traits< T, TL...>::value;
156
157 template< tag T, tag ... TL>
158 struct position_traits;
159
160 template< tag T, tag T2, tag ... TL>
161 requires same_selector<T, T2>
162 struct position_traits< T, T2, TL ...>
163 : std::integral_constant< std::size_t, 0>
164 {};
165
166 template< tag T, tag T2, tag ... TL>
167 requires (!same_selector<T, T2>)
168 struct position_traits< T, T2, TL ...>
169 : std::integral_constant< std::size_t, position_traits< T, TL ...>::value + 1>
170 {};
171
172 template< typename T, typename ... TL>
173 inline constexpr std::size_t position_of = position_traits< T, TL...>::value;
174 }
176
181 template< typename ... TL>
182 struct tag_list {};
183
185 namespace impl {
186 template< typename TA, typename TB>
187 struct concat_traits;
188
189 template< tag TA, tag TB>
190 struct concat_traits< TA, TB> {
191 using type = tag_list< TA, TB>;
192 };
193
194 template< tag TA, tag ... LB>
195 struct concat_traits< TA, tag_list< LB ...>> {
196 using type = tag_list< TA, LB ...>;
197 };
198
199 template< typename TA, typename TB>
200 using concat_list = typename concat_traits< TA, TB>::type;
201
202 template< typename LA, typename LB>
203 struct subtract_traits;
204
205 template< tag ... TLA>
206 struct subtract_traits< tag_list<TLA...>, tag_list<>> {
207 using type = tag_list<TLA...>;
208 };
209
210 template< tag TA, tag ... TLA, tag TB>
211 requires same_selector< TA, TB>
212 struct subtract_traits< tag_list<TA, TLA...>, tag_list<TB>>
213 {
214 using type = tag_list<TLA ...>;
215 };
216
217 template< tag TA, tag ... TLA, tag TB>
218 requires (!same_selector< TA, TB>)
219 struct subtract_traits< tag_list<TA, TLA...>, tag_list<TB>>
220 {
221 private:
222 using removed_a = typename subtract_traits< tag_list<TLA ...>, tag_list<TB>>::type;
223 public:
224 using type = concat_list< TA, removed_a>;
225 };
226
227 template< tag ... TLA, tag TB, tag ... TLB>
228 struct subtract_traits< tag_list<TLA...>, tag_list<TB, TLB...>>
229 {
230 private:
231 using removed_a = typename subtract_traits<tag_list<TLA...>, tag_list<TB>>::type;
232 public:
233 using type = typename subtract_traits<removed_a, tag_list<TLB ...>>::type;
234 };
235
236 template< selector_tag T, tag ... TL>
237 struct pick_traits;
238
239 template< selector_tag T, tag T0, tag ... TL>
240 requires same_selector<T, T0>
241 struct pick_traits< T, T0, TL ...>
242 {
243 using type = T0;
244 };
245
246 template< selector_tag T, tag T0, tag ... TL>
247 requires (!same_selector<T, T0>)
248 struct pick_traits< T, T0, TL ...>
249 : pick_traits< T, TL ...>
250 {};
251
252 template< std::size_t I, tag ... TL>
253 struct pick_index_traits;
254
255 template< tag T0, tag ... TL>
256 struct pick_index_traits< 0, T0, TL ...>
257 {
258 using type = T0;
259 };
260
261 template< std::size_t I, tag T0, tag ... TL>
262 struct pick_index_traits< I, T0, TL ...>
263 : pick_index_traits< I-1, TL ...>
264 {};
265
266 template< typename A, typename B>
267 struct same_list_traits;
268
269 template< tag ... AL, tag ... BL>
270 requires (sizeof...(AL) == sizeof...(BL))
271 struct same_list_traits< tag_list<AL...>, tag_list<BL...>>
272 {
273 static constexpr bool value = (same_selector<AL, BL> && ...);
274 };
275
276 template< typename A, typename B>
277 concept same_selector_list = same_list_traits< A, B>::value;
278
279 template< typename A, typename B>
280 struct subset_traits;
281
282 template< tag ... AL, tag ... BL>
283 struct subset_traits< tag_list<AL...>, tag_list<BL...>>
284 {
285 static constexpr bool value = (one_of<AL, BL...> && ...);
286 };
287
288 template< typename A, typename B>
289 concept subset_selector = subset_traits< A, B>::value;
290 }
291
292 template< typename T, typename ... TL>
293 requires impl::one_of<T, TL...>
294 using pick = typename impl::pick_traits< T, TL...>::type;
295
296 template< std::size_t I, typename ... TL>
297 requires (I < sizeof...(TL))
298 using pick_index = typename impl::pick_index_traits< I, TL...>::type;
300
307 template< tag T>
308 class index_class< T> : public impl::index_base {
309 public:
310 index_class() noexcept
311 : i_(0)
312 {}
313 constexpr explicit index_class(index_carrier_type< T> v) noexcept
314 : i_(v)
315 {}
316 template< tag T2>
317 index_class< T2> retag() const
318 {
319 return index_class< T2>(i_);
320 }
321 index_carrier_type<T> value() const noexcept
322 {
323 return i_;
324 }
325 template< std::size_t I>
326 requires (I == 0)
327 auto&& get() const noexcept
328 {
329 return std::get< I>(i_);
330 }
331 template< same_selector<T> T2>
332 auto&& get() const noexcept
333 {
334 return *this;
335 }
336 private:
337 index_carrier_type< T> i_;
338 };
339
341 template< tag T>
342 std::ostream& operator<<(std::ostream& o, index_class<T> v)
343 {
344 o << v.value();
345 return o;
346 }
348
350 template< tag T>
351 class iterator_class< T> {
352 public:
353 iterator_class() noexcept
354 : v_(0)
355 {}
356 explicit iterator_class(index_carrier_type< T> v) noexcept
357 : v_(v)
358 {}
359 index_class< T> operator*() const noexcept
360 {
361 return index_class< T>(v_);
362 }
363 bool operator==(const iterator_class<T>& b) const noexcept
364 {
365 return v_ == b.v_;
366 }
367 bool operator!=(const iterator_class<T>& b) const noexcept
368 {
369 return v_ != b.v_;
370 }
371 iterator_class<T>& operator++() noexcept
372 {
373 ++v_;
374 return *this;
375 }
376 iterator_class<T> operator++(int) noexcept
377 {
378 auto tmp = *this;
379 operator++();
380 return tmp;
381 }
382 private:
383 index_carrier_type< T> v_;
384 };
386
397 template< non_static_tag T>
398 class range_class< T> : public impl::range_base {
399 public:
400 using selector = tagged::selector<T>;
401
402 range_class() noexcept
403 : b_(0), e_(0)
404 {}
405 explicit range_class(index_carrier_type< T> e) noexcept
406 : b_(0), e_(e)
407 {}
408 range_class(index_carrier_type< T> b, index_carrier_type< T> e) noexcept
409 : b_(b), e_(e)
410 {}
411 range_class(const range_class<T>& b) = default;
412 range_class<T>& operator=(const range_class<T>& b) = default;
413 range_class(range_class<T>&& b) noexcept
414 : b_(b.b_), e_(b.e_)
415 {
416 b.b_ = 0;
417 b.e_ = 0;
418 }
419 range_class<T>& operator=(range_class<T>&& b) noexcept
420 {
421 b_ = b.b_;
422 e_ = b.e_;
423 b.b_ = 0;
424 b.e_ = 0;
425 return *this;
426 }
427 template< tag ... TL2>
428 requires (sizeof...(TL2) >= 1)
429 explicit range_class(const range_class< TL2...>& r) noexcept
430 : b_(r.template get<selector>().begin_value()), e_(r.template get<selector>().end_value())
431 {}
432 template<typename T2>
433 requires same_tag<T, T2>
434 bool operator==(const range_class<T2>& b) const
435 {
436 return b_ == b.begin_value() && e_ == b.end_value();
437 }
438 template<typename T2>
439 requires same_tag<T, T2>
440 bool operator!=(const range_class<T2>& b) const
441 {
442 return b_ != b.begin_value() || e_ != b.end_value();
443 }
444 template< tag T2>
445 range_class< T2> retag() const
446 {
447 return range_class< T2>(b_, e_);
448 }
449 index_carrier_type<T> flat(const index_class< selector>& i) const
450 {
451 return i.value() - b_;
452 }
453 index_carrier_type<T> size() const
454 {
455 return e_ - b_;
456 }
457 iterator_class<selector> begin() const noexcept
458 {
459 return iterator_class<selector>(b_);
460 }
461 iterator_class<selector> end() const noexcept
462 {
463 return iterator_class<selector>(e_);
464 }
465 index_carrier_type<T> begin_value() const noexcept
466 {
467 return b_;
468 }
469 index_carrier_type<T> end_value() const noexcept
470 {
471 return e_;
472 }
473 template< same_selector< T> T2>
474 auto&& get() const noexcept
475 {
476 return *this;
477 }
478 template< std::size_t I>
479 requires (I == 0)
480 auto&& get() const noexcept
481 {
482 return *this;
483 }
484 template< std::size_t I>
485 requires (I == 0)
486 using get_tag = T;
487 private:
488 index_carrier_type< T> b_, e_;
489 };
490
492 template< static_tag T>
493 class range_class< T> : public impl::range_base {
494 public:
496
497 constexpr range_class() noexcept
498 {}
499 constexpr explicit range_class(index_carrier_type< T> e)
500 {
501 if (0 != T::begin || e != T::end)
502 {
503 throw std::logic_error("WTF");
504 }
505 }
506 constexpr range_class(index_carrier_type< T> b, index_carrier_type< T> e)
507 {
508 if (b != T::begin || e != T::end)
509 {
510 throw std::logic_error("WTF");
511 }
512 }
513 template< tag ... TL2>
514 requires (sizeof...(TL2) >= 1)
515 explicit range_class(const range_class< TL2...>&) noexcept
516 requires pick<selector, TL2...>::is_static
517 {}
518 template<typename T2>
519 requires same_tag<T, T2>
520 constexpr bool operator==(const range_class<T2>&) const
521 {
522 return true;
523 }
524 template<typename T2>
525 requires same_tag<T, T2>
526 constexpr bool operator!=(const range_class<T2>&) const
527 {
528 return false;
529 }
530 template< static_tag T2>
531 static constexpr range_class< T2> retag()
532 {
533 return range_class< T2>();
534 }
535 static index_carrier_type<T> flat(const index_class< selector>& i)
536 {
537 return i.value() - T::begin;
538 }
539 static constexpr index_carrier_type<T> size()
540 {
541 return T::end - T::begin;
542 }
543 static iterator_class<selector> begin() noexcept
544 {
545 return iterator_class<selector>(T::begin);
546 }
547 static iterator_class<selector> end() noexcept
548 {
549 return iterator_class<selector>(T::end);
550 }
551 static constexpr index_carrier_type<T> begin_value() noexcept
552 {
553 return T::begin;
554 }
555 static constexpr index_carrier_type<T> end_value() noexcept
556 {
557 return T::end;
558 }
559 template< same_selector< T> T2>
560 static constexpr auto get() noexcept
561 {
562 return range_class<T>{};
563 }
564 template< std::size_t I>
565 requires (I == 0)
566 auto&& get() const noexcept
567 {
568 return *this;
569 }
570 template< std::size_t I>
571 requires (I == 0)
572 using get_tag = T;
573 };
575
583 template< tag ... TL>
584 class index_class : public impl::index_base {
585 public:
586 index_class() noexcept
587 : i_(index_carrier_type< TL>(0) ...)
588 {}
589 constexpr index_class(index_carrier_type< TL> ... vl) noexcept
590 : i_(index_class< TL>(vl) ...)
591 {}
592 index_class(index_class< TL> ... vl) noexcept
593 : i_(vl ...)
594 {}
600 template< std::size_t I>
601 requires (I < sizeof...(TL))
602 auto&& get() const noexcept
603 {
604 return std::get< I>(i_);
605 }
606
611 template< impl::one_of< TL ...> T>
612 auto&& get() const noexcept
613 {
614 return std::get< index_class< T>>(i_);
615 }
616 private:
617 std::tuple< index_class< TL> ...> i_;
618 };
619
621 template<>
622 class index_class<> : public impl::index_base {
623 public:
624 constexpr index_class() noexcept
625 {}
626 };
628
637 template< tag ... TL1, tag ... TL2>
638 index_class< TL1 ..., TL2 ...> operator&(const index_class< TL1 ...>& ia, const index_class< TL2 ...>& ib)
639 {
640 return index_class< TL1 ..., TL2 ...>(ia.template get< TL1>() ..., ib.template get< TL2>() ...);
641 }
642
644 template< tag T1, tag ... TL2>
645 std::ostream& operator<<(std::ostream& o, index_class<T1, TL2 ...> v)
646 {
647 ((o << "[" << v.template get<T1>()), ..., (o << "," << v.template get<TL2>())), o << "]";
648 return o;
649 }
651
653 template< tag ... TL>
654 class iterator_class {
655 public:
656 iterator_class() noexcept
657 : rngp_(nullptr), it_(iterator_class< TL>(0) ...)
658 {}
659 iterator_class(const range_class< TL...>* rngp, iterator_class< selector<TL>> ... v) noexcept
660 : rngp_(rngp), it_(v ...)
661 {}
662 index_class< selector<TL> ...> operator*() const noexcept
663 {
664 return index_class< selector<TL> ...>(*std::get< iterator_class< selector< TL>>>(it_)...);
665 }
666 bool operator==(const iterator_class<TL ...>& b) const noexcept
667 {
668 return equal< sizeof...(TL)>(b);
669 }
670 bool operator!=(const iterator_class<TL ...>& b) const noexcept
671 {
672 return !equal< sizeof...(TL)>(b);
673 }
674 iterator_class<TL ...>& operator++() noexcept
675 {
676 increment< sizeof...(TL)>();
677 return *this;
678 }
679 iterator_class<TL ...> operator++(int) noexcept
680 {
681 auto tmp = *this;
682 operator++();
683 return tmp;
684 }
685 private:
686 template< std::size_t I>
687 bool equal(const iterator_class<TL ...>& b) const noexcept
688 {
689 if constexpr (I > 0)
690 {
691 if (std::get<I - 1>(it_) != std::get<I - 1>(b.it_))
692 return false;
693 return equal< I - 1>(b);
694 }
695 else
696 {
697 return true;
698 }
699 }
700
701 template< std::size_t I>
702 void increment() noexcept
703 {
704 auto&& iti = std::get<I - 1>(it_);
705 ++iti;
706 if constexpr (I > 1)
707 {
708 auto&& rngi = rng().template get<I - 1>();
709 if (iti != rngi.end())
710 return;
711 iti = rngi.begin();
712 increment< I - 1>();
713 }
714 }
715
716 const range_class< TL...>& rng() const
717 {
718 return *rngp_;
719 }
720 const range_class< TL...>* rngp_;
721 std::tuple< iterator_class< selector<TL>> ...> it_;
722 };
724
732 template< tag ... TL>
733 class range_class : public impl::range_base {
734 public:
735 range_class() noexcept
736 {}
737 range_class(const range_class< TL> & ... vl) noexcept requires (sizeof...(TL) > 0)
738 : i_(vl ...)
739 {}
741 template< tag ... TL2>
742 requires (sizeof...(TL2) >= sizeof...(TL))
743 explicit range_class(const range_class< TL2...> & r) noexcept
744 : i_(r.template get<selector<TL>>() ...)
745 {}
751 std::size_t size() const
752 {
753 return (1 * ... * get< TL>().size());
754 }
755
759 iterator_class<TL ...> begin() const noexcept
760 {
761 return iterator_class<TL ...>(this, get_begin< TL>() ...);
762 }
763
767 iterator_class<TL ...> end() const noexcept
768 {
769 return iterator_class<TL ...>(this, get_end< TL>() ...);
770 }
771
776 template< typename T>
777 requires impl::one_of< selector<T>, selector<TL> ...>
778 && non_static_tag< pick<selector<T>, TL ...>>
779 auto&& get() const noexcept
780 {
781 return std::get< range_class< pick<selector<T>, TL ...>>>(i_);
782 }
783
788 template< typename T>
789 requires impl::one_of< selector<T>, selector<TL> ...>
790 && static_tag< pick<selector<T>, TL ...>>
791 static constexpr auto get() noexcept
792 {
793 return range_class< pick<selector<T>, TL ...>>{};
794 }
795
800 template< std::size_t I>
801 auto&& get() const noexcept
802 {
803 return std::get< I>(i_);
804 }
805
806 template< std::size_t I>
807 using get_tag = std::tuple_element_t<I, std::tuple<TL ...>>;
809 private:
810 template< tag T>
811 auto get_begin() const noexcept
812 {
813 auto&& rngi = std::get< range_class< T>>(i_);
814 return rngi.begin();
815 }
816 template< tag T>
817 auto get_end() const noexcept
818 {
819 auto&& rngi = std::get< range_class< T>>(i_);
820 if constexpr (impl::position_of<T, TL ...> == 0)
821 return rngi.end();
822 else
823 return rngi.begin();
824 }
825 using i_type = std::tuple< range_class< TL> ...>;
826 i_type i_;
827 };
828
837 template< tag ... TL1, tag ... TL2>
838 range_class< TL1 ..., TL2 ...> operator&(const range_class< TL1 ...>& rnga, const range_class< TL2 ...>& rngb)
839 {
840 return range_class< TL1 ..., TL2 ...>(rnga.template get< TL1>() ..., rngb.template get< TL2>() ...);
841 }
842
844 namespace impl {
845 template< tag T>
846 struct size_traits
847 {
848 static constexpr std::size_t static_multiplier = 1;
849 static constexpr bool has_dynamic_multiplier = true;
850 template< typename T2>
851 static std::size_t dynamic_multiplier(T2&& r)
852 {
853 return r.template get<selector<T>>().size();
854 }
855 };
856
857 template< tag T>
858 requires T::is_static
859 struct size_traits<T>
860 {
861 static constexpr std::size_t static_multiplier = T::end - T::begin;
862 static constexpr bool has_dynamic_multiplier = false;
863 };
864
865 template< tag T>
866 class multiplier_class
867 {
868 public:
869 multiplier_class()
870 : value_(0)
871 {}
872 explicit multiplier_class(std::size_t v)
873 : value_(v)
874 {}
875 void assign_value(std::size_t v)
876 {
877 value_ = v;
878 }
879 std::size_t value() const
880 {
881 return value_;
882 }
883 private:
884 std::size_t value_;
885 };
886
887 template< tag T, std::size_t s>
888 struct sm_tag
889 {
890 static constexpr bool is_tag = true;
891 static constexpr bool is_direct = false;
892 using core = sm_tag< T, s>;
893 static constexpr bool is_selector = false;
894 using selector = T;
895 template<selector_tag T2>
896 using retag = sm_tag< T2, s>;
897
898 static constexpr bool has_static_multiplier = true;
899 static constexpr std::size_t static_multiplier = s;
900 };
901
902 template< tag T, std::size_t b, std::size_t e, std::size_t s>
903 struct srm_tag
904 {
905 static constexpr bool is_tag = true;
906 static constexpr bool is_direct = false;
907 using core = sm_tag< T, s>;
908 static constexpr bool is_selector = false;
909 using selector = T;
910 template<selector_tag T2>
911 using retag = sm_tag< T2, s>;
912
913 static constexpr bool is_static = true;
914 static constexpr std::size_t begin = b;
915 static constexpr std::size_t end = e;
916
917 static constexpr bool has_static_multiplier = true;
918 static constexpr std::size_t static_multiplier = s;
919 };
920
921 template< typename T>
922 concept has_static_multiplier = requires {
923 requires tag<T>;
924 {T::has_static_multiplier} -> std::convertible_to<bool>;
925 requires T::has_static_multiplier;
926 };
927
928 template< tag T, std::size_t s>
929 class multiplier_class<sm_tag<T, s>>
930 {
931 public:
932 multiplier_class()
933 {}
934 static constexpr std::size_t value()
935 {
936 return s;
937 }
938 };
939
940 template< tag ... TL>
941 struct multiplier_list_traits;
942
943 template<>
944 struct multiplier_list_traits<>
945 {
946 static constexpr std::size_t static_multiplier = 1;
947 using multiplier_tag_list = tag_list<>;
948 static constexpr bool has_dynamic_multiplier = false;
949 };
950
951 template< tag T0, tag ... TL>
952 requires (!multiplier_list_traits< TL ...>::has_dynamic_multiplier)
953 struct multiplier_list_traits< T0, TL ...>
954 {
955 private:
956 using head_traits = size_traits<T0>;
957 using tail_traits = multiplier_list_traits< TL ...>;
958 public:
959 static constexpr std::size_t static_multiplier = head_traits::static_multiplier * tail_traits::static_multiplier;
960 private:
961 using head_multiplier_tag = sm_tag<selector<T0>, tail_traits::static_multiplier>;
962 using tail_multiplier_tag_list = typename tail_traits::multiplier_tag_list;
963 public:
964 using multiplier_tag_list = concat_list< head_multiplier_tag, tail_multiplier_tag_list>;
965 static constexpr bool has_dynamic_multiplier = head_traits::has_dynamic_multiplier;
966 template< tag ... TL2, tag ... TL3>
967 static std::size_t fill_dynamic_multiplier(std::tuple< multiplier_class< TL2>...>&, const range_class<TL3 ...>& r)
968 requires has_dynamic_multiplier
969 {
970 return head_traits::dynamic_multiplier(r);
971 }
972 };
973
974 template< tag T0, tag ... TL>
975 requires multiplier_list_traits< TL ...>::has_dynamic_multiplier
976 struct multiplier_list_traits< T0, TL ...>
977 {
978 private:
979 using head_traits = size_traits<T0>;
980 using tail_traits = multiplier_list_traits< TL ...>;
981 public:
982 static constexpr std::size_t static_multiplier = head_traits::static_multiplier * tail_traits::static_multiplier;
983 private:
984 using head_multiplier_tag = selector<T0>;
985 using tail_multiplier_tag_list = typename tail_traits::multiplier_tag_list;
986 public:
987 using multiplier_tag_list = concat_list< head_multiplier_tag, tail_multiplier_tag_list>;
988 static constexpr bool has_dynamic_multiplier = true;
989 template< tag ... TL2, tag ... TL3>
990 static std::size_t fill_dynamic_multiplier(std::tuple< multiplier_class< TL2>...>& m, const range_class<TL3 ...>& r)
991 {
992 std::size_t dm = tail_traits::fill_dynamic_multiplier(m, r);
993 std::get< multiplier_class<head_multiplier_tag>>(m).assign_value(tail_traits::static_multiplier * dm);
994 if constexpr (head_traits::has_dynamic_multiplier)
995 {
996 dm *= head_traits::dynamic_multiplier(r);
997 }
998 return dm;
999 }
1000 };
1001
1002 template< tag ... TL>
1003 class multiplier_list_class
1004 {
1005 public:
1006 multiplier_list_class()
1007 {}
1008 template< tag ... TL3>
1009 requires (sizeof...(TL3) == sizeof...(TL))
1010 explicit multiplier_list_class(const range_class<TL3 ...>& r)
1011 {
1012 using traits = multiplier_list_traits<pick<selector<TL>, TL3...> ...>;
1013 if constexpr (traits::has_dynamic_multiplier)
1014 {
1015 traits::fill_dynamic_multiplier(m_, r);
1016 }
1017 }
1018 template< tag ... TL3>
1019 requires (sizeof...(TL3) >= sizeof...(TL))
1020 explicit multiplier_list_class(const multiplier_list_class<TL3 ...>& r)
1021 : m_( r.template get<TL>() ...)
1022 {}
1023 template< tag ... TL3, tag ... TL2>
1024 requires same_selector_list<tag_list<TL3...>, tag_list<TL...>>
1025 && subset_selector< tag_list<TL2...>, tag_list<TL...>>
1026 std::size_t flat(const range_class<TL3 ...>& r, const index_class<TL2 ...>& i) const
1027 {
1028 return (0 + ... + flat_one<TL2>(r, i));
1029 }
1030 template< tag T2>
1031 auto&& get() const
1032 {
1033 return std::get< multiplier_class<pick<selector<T2>, TL...>>>(m_);
1034 }
1035 template< std::size_t I2>
1036 auto&& get() const
1037 {
1038 return std::get< I2>(m_);
1039 }
1040 private:
1041 std::tuple< multiplier_class< TL>...> m_;
1042
1043 template< tag T, tag ... TL3, tag ... TL2>
1044 std::size_t flat_one(const range_class<TL3 ...>& r, const index_class<TL2 ...>& i) const
1045 {
1046 auto&& ix = i.template get<selector<T>>();
1047 auto&& rx = r.template get<selector<T>>();
1048
1049 std::size_t mv = std::get< multiplier_class< pick<selector<T>, TL...>>>(m_).value();
1050 std::size_t fv = rx.flat(ix);
1051 return mv * fv;
1052 }
1053 };
1054
1055 template<typename L>
1056 struct multiplier_list_creator;
1057
1058 template<tag ... TL2>
1059 struct multiplier_list_creator< tag_list< TL2 ...>>
1060 {
1061 using type = multiplier_list_class< TL2 ...>;
1062 };
1063
1064 template< tag ... TL3>
1065 using multiplier_list = typename multiplier_list_creator< typename multiplier_list_traits< TL3...>::multiplier_tag_list>::type;
1066
1067 template< tag RT, tag MT>
1068 struct mixer_traits;
1069
1070 template< tag RT, tag MT>
1071 requires same_tag<RT, selector<MT>>
1072 struct mixer_traits<RT, MT>
1073 {
1074 using type = MT;
1075 };
1076
1077 template< tag RT, tag MT>
1078 requires same_tag<selector<RT>, MT>
1079 struct mixer_traits<RT, MT>
1080 {
1081 using type = RT;
1082 };
1083
1084 template< tag RT, tag MT>
1085 requires RT::is_static && MT::has_static_multiplier
1086 struct mixer_traits<RT, MT>
1087 {
1088 using type = srm_tag<selector<RT>, RT::begin, RT::end, MT::static_multiplier>;
1089 };
1090
1091 template< typename RC, typename MLC>
1092 struct mixer_list_traits;
1093
1094 template<>
1095 struct mixer_list_traits< range_class<>, multiplier_list_class<>>
1096 {
1097 using type = tag_list<>;
1098 };
1099
1100 template< tag RT, tag ... RL, tag MT, tag ... ML>
1101 requires (sizeof...(RL) == sizeof...(ML))
1102 struct mixer_list_traits< range_class< RT, RL...>, multiplier_list_class< MT, ML...>>
1103 {
1104 private:
1105 using head_traits = mixer_traits< RT, MT>;
1106 using tail_traits = mixer_list_traits< range_class< RL...>, multiplier_list_class< ML...>>;
1107 public:
1108 using type = concat_list< typename head_traits::type, typename tail_traits::type>;
1109 };
1110
1111 template< tag T>
1112 struct range_demixer_traits
1113 {
1114 using type = selector<T>;
1115 };
1116
1117 template< tag T>
1118 requires T::is_static
1119 struct range_demixer_traits<T>
1120 {
1121 using type = sr_tag<selector<T>, T::begin, T::end>;
1122 };
1123
1124 template< tag T>
1125 struct multiplier_demixer_traits
1126 {
1127 using type = selector<T>;
1128 };
1129
1130 template< tag T>
1131 requires T::has_static_multiplier
1132 struct multiplier_demixer_traits<T>
1133 {
1134 using type = sm_tag<selector<T>, T::static_multiplier>;
1135 };
1136 }
1137
1138 template< typename E, tag ... TL>
1139 class tensor_class;
1140
1141 template< typename E, tag ... TL>
1142 class tensor_view;
1143
1144 namespace impl {
1145 template< typename E, typename X>
1146 struct tensor_view_creator;
1147
1148 template< typename E, tag ... TL>
1149 struct tensor_view_creator< E, tag_list< TL...>>
1150 {
1151 using type = tensor_view< E, TL...>;
1152 };
1153 }
1155
1168 template< typename E, tag ... TL>
1170 private:
1171 using self_ = tensor_view< E, TL...>;
1173 public:
1175 template< tag ... TL3, tag ... TL2>
1176 explicit tensor_view(const range_class< TL3 ...>& rng, const impl::multiplier_list_class< TL2...>& mult, E* data)
1177 : rng_(rng),
1178 mult_(mult),
1179 arr_(data)
1180 {}
1181
1182 self_& operator=(const self_&) = delete;
1183 self_& operator=(self_&&) = delete;
1185
1190 const range_t& range() const
1191 {
1192 return rng_;
1193 }
1194
1205 template< tag ... TL2>
1207 requires (sizeof...(TL2) < sizeof...(TL))
1208 && impl::subset_selector< tag_list< TL2...>, tag_list< TL...>>
1209 {
1210 using result_list = typename impl::subtract_traits<tag_list< TL...>, tag_list< TL2...>>::type;
1211 using result_view = typename impl::tensor_view_creator< E, result_list>::type;
1212 return result_view(rng_, mult_, arr_ + mult_.flat(rng_, i));
1213 }
1214
1221 template< tag ... TL2>
1223 requires (sizeof...(TL2) == sizeof...(TL))
1224 && impl::subset_selector< tag_list< TL2...>, tag_list< TL...>>
1225 {
1226 return arr_[mult_.flat(rng_, i)];
1227 }
1228
1237 E* data() const
1238 requires (sizeof...(TL) == 1) && ((TL::has_static_multiplier) && ...) && ((TL::static_multiplier == 1) && ...)
1239 {
1240 return arr_;
1241 }
1242
1250 E* flat_data() const
1251 {
1252 return arr_;
1253 }
1254
1258 static constexpr std::size_t dimensions = sizeof...(TL);
1259
1265 template< tag T2>
1266 std::size_t dim_size() const
1267 {
1268 return rng_.template get< selector<T2>>().size();
1269 }
1270
1276 template< std::size_t I2>
1277 std::size_t dim_size() const
1278 {
1279 return rng_.template get< I2>().size();
1280 }
1281
1291 template< tag T2>
1292 requires impl::has_static_multiplier< pick< selector<T2>, TL...>>
1293 static constexpr std::size_t dim_multiplier()
1294 {
1295 return pick< selector<T2>, TL...>::static_multiplier;
1296 }
1297
1299 template< tag T2>
1300 requires (!impl::has_static_multiplier< pick< selector<T2>, TL...>>)
1301 std::size_t dim_multiplier() const
1302 {
1303 return mult_.template get< selector<T2>>().value();
1304 }
1306
1316 template< std::size_t I2>
1317 requires impl::has_static_multiplier< pick_index< I2, TL...>>
1318 static constexpr std::size_t dim_multiplier()
1319 {
1320 return pick_index< I2, TL...>::static_multiplier;
1321 }
1322
1324 template< std::size_t I2>
1325 requires (!impl::has_static_multiplier< pick_index< I2, TL...>>)
1326 std::size_t dim_multiplier() const
1327 {
1328 return mult_.template get< I2>().value();
1329 }
1331
1332 private:
1333 range_t rng_;
1334 impl::multiplier_list_class< typename impl::multiplier_demixer_traits< TL>::type ...> mult_;
1335 E* arr_;
1336 };
1337
1344 template< typename E, tag ... TL>
1345 using extract_tensor_view = typename impl::tensor_view_creator< E, typename impl::mixer_list_traits< range_class< TL...>, impl::multiplier_list< TL...>>::type>::type;
1346
1364 template< typename E, tag ... TL>
1365 class tensor_class {
1366 public:
1367 tensor_class() noexcept
1368 {}
1375 template< tag ... TL2>
1376 requires (sizeof...(TL2) == sizeof...(TL))
1378 : rng_(rng),
1379 mult_( rng),
1380 arr_(rng.size())
1381 {}
1382
1389 template< tag ... TL2>
1390 requires (sizeof...(TL2) == sizeof...(TL))
1391 tensor_class(const range_class< TL2 ...>& rng, const E& e) noexcept
1392 : rng_(rng),
1393 mult_(rng),
1394 arr_(rng.size(), e)
1395 {}
1396
1397 using view_type = extract_tensor_view< E, TL ...>;
1398 using const_view_type = extract_tensor_view< const E, TL ...>;
1399
1404 view_type view()
1405 {
1406 return view_type(rng_, mult_, arr_.data());
1407 }
1408
1413 const_view_type view() const
1414 {
1415 return const_view_type(rng_, mult_, arr_.data());
1416 }
1417
1428 template< tag ... TL2>
1430 requires (sizeof...(TL2) < sizeof...(TL))
1431 && impl::subset_selector< tag_list< TL2...>, tag_list< TL...>>
1432 {
1433 return view()[i];
1434 }
1435
1446 template< tag ... TL2>
1448 requires (sizeof...(TL2) < sizeof...(TL))
1449 && impl::subset_selector< tag_list< TL2...>, tag_list< TL...>>
1450 {
1451 return view()[i];
1452 }
1453
1458 const range_class< TL ...>& range() const
1459 {
1460 return rng_;
1461 }
1462
1469 template< tag ... TL2>
1471 requires (sizeof...(TL2) == sizeof...(TL))
1472 && impl::subset_selector< tag_list< TL2...>, tag_list< TL...>>
1473 {
1474 return arr_[mult_.flat(rng_, i)];
1475 }
1476
1483 template< tag ... TL2>
1484 const E& operator[](const index_class< TL2...>& i) const
1485 requires (sizeof...(TL2) == sizeof...(TL))
1486 && impl::subset_selector< tag_list< TL2...>, tag_list< TL...>>
1487 {
1488 return arr_[mult_.flat(rng_, i)];
1489 }
1490
1497 E* data()
1498 requires (sizeof...(TL) == 1)
1499 {
1500 return arr_.data();
1501 }
1502
1509 const E* data() const
1510 requires (sizeof...(TL) == 1)
1511 {
1512 return arr_.data();
1513 }
1514
1522 {
1523 return arr_.data();
1524 }
1525
1532 const E* flat_data() const
1533 {
1534 return arr_.data();
1535 }
1536 private:
1537 range_class< TL ...> rng_;
1538 impl::multiplier_list< TL ...> mult_;
1539 std::vector< E> arr_;
1540 };
1541
1543 namespace impl {
1544 template< typename P, typename C>
1545 struct permute;
1546
1547 template< typename ... SL, typename C>
1548 struct permute< tag_list< SL...>, C>
1549 {
1550 using type = typename C::template type< SL...>;
1551 };
1552
1553 template< typename P, typename C>
1554 using permute_t = typename permute< P, C>::type;
1555
1556 template< typename E, tag ... TL>
1557 struct permutator_tensor_class
1558 {
1559 template< typename ... SL>
1560 using type = tensor_class< E, pick<SL, TL...> ...>;
1561 };
1562
1563 template< tag ... TL>
1564 struct permutator_range_class
1565 {
1566 template< typename ... SL>
1567 using type = range_class< pick<SL, TL...> ...>;
1568 };
1569
1570 struct permutator_range
1571 {
1572 template< typename ... SL>
1573 struct type {
1574 template< tag ... TL>
1575 static auto permute_range(const range_class<TL...>& r)
1576 {
1577 using range = range_class< pick<SL, TL...> ...>;
1578 return range((r.template get<SL>() & ...));
1579 }
1580 };
1581 };
1582 }
1584
1592 template< typename P, typename E, tag ... TL>
1593 using permute_tensor_class = impl::permute_t< P, impl::permutator_tensor_class<E, TL...>>;
1594
1596 template< typename P, tag ... TL>
1597 using permute_range_class = impl::permute_t< P, impl::permutator_range_class<TL...>>;
1598
1599 template< typename P, tag ... TL>
1600 auto permute_range(const range_class<TL...>& r)
1601 {
1602 using permutator = impl::permute_t<P, impl::permutator_range>;
1603 return permutator::permute_range(r);
1604 }
1606
1607 // CO
1608
1610 namespace impl {
1611 template< selector_tag T>
1612 struct c {
1613 static constexpr bool is_tag = true;
1614 static constexpr bool is_direct = false;
1615 using core = c<T>;
1616 static constexpr bool is_selector = true;
1617 using selector = c<T>;
1618 template<selector_tag T2>
1619 using retag = T2;
1620 };
1621
1622 template< selector_tag T>
1623 struct co_traits {
1624 using co = c< T>;
1625 };
1626
1627 template< selector_tag T>
1628 struct co_traits< c<T>> {
1629 using co = T;
1630 };
1631 }
1633
1644 template< tag T>
1645 using co = retag< typename impl::co_traits<selector<T>>::co, T>;
1646
1648 namespace impl {
1649 template< typename X>
1650 struct co_list_traits;
1651
1652 template< tag ... TL>
1653 struct co_list_traits< tag_list<TL ...>> {
1654 using co_list = tag_list<co<TL>...>;
1655 };
1656 }
1658
1663 template< typename X>
1664 using co_list = typename impl::co_list_traits< X>::co_list;
1665
1672 template< tag T>
1673 inline constexpr range_class<co<T>> operator~(const range_class<T>& r)
1674 {
1675 return range_class<co<T>>(r.template retag<co<T>>());
1676 }
1677
1684 template< tag T>
1686 {
1687 return index_class<co<T>>(r.template retag<co<T>>());
1688 }
1689
1691
1692 template< typename E, tagged::tag STL0, tagged::tag DTL0>
1693 inline void permute_tensor(const tagged::tensor_view< const E, STL0>& svec, const tagged::tensor_view< E, DTL0>& dvec)
1694 {
1695 auto r0 = dvec.range().template get<DTL0>();
1696 for (auto i0 : r0)
1697 {
1698 dvec[i0] = svec[i0];
1699 }
1700 }
1701
1702 template< typename E, tagged::tag ... STL, tagged::tag DTL0, tagged::tag ... DTL>
1703 inline void permute_tensor(const tagged::tensor_view< const E, STL ...>& svec, const tagged::tensor_view< E, DTL0, DTL ...>& dvec)
1704 {
1705 auto r0 = dvec.range().template get<DTL0>();
1706 for (auto i0 : r0)
1707 {
1708 auto sslice = svec[i0];
1709 auto dslice = dvec[i0];
1710
1711 permute_tensor(sslice, dslice);
1712 }
1713 }
1714
1715 template< typename E, tagged::tag ... STL, tagged::tag ... DTL>
1716 requires (sizeof...(STL) == sizeof...(DTL))
1717 inline void permute_tensor(const tagged::tensor_class< E, STL ...>& svec, tagged::tensor_class< E, DTL ...>& dvec)
1718 {
1719 permute_tensor(svec.view(), dvec.view());
1720 }
1721
1722}
1723
1724#endif
A list of tagged indexes (a position in an N-dimensional space)
Definition tagged.hpp:584
auto && get() const noexcept
Retrieve individual tagged index by selector tag.
Definition tagged.hpp:612
auto && get() const noexcept
Retrieve individual tagged index by zero-based position.
Definition tagged.hpp:602
A list of tagged ranges (an N-dimensional box)
Definition tagged.hpp:733
iterator_class< TL ... > begin() const noexcept
Lexicographical iterator through the N-dimensional box.
Definition tagged.hpp:759
std::size_t size() const
Size (volume) of the range.
Definition tagged.hpp:751
auto && get() const noexcept
Retrieve individual range by selector tag.
Definition tagged.hpp:779
iterator_class< TL ... > end() const noexcept
Lexicographical iterator through the N-dimensional box.
Definition tagged.hpp:767
static constexpr auto get() noexcept
Retrieve individual range by selector tag.
Definition tagged.hpp:791
auto && get() const noexcept
Retrieve individual range by index.
Definition tagged.hpp:801
A tensor - a multi-dimensional tagged generalization of vector/matrix.
Definition tagged.hpp:1365
const E * flat_data() const
A const pointer to the beginning of the array containing the data.
Definition tagged.hpp:1532
auto operator[](const index_class< TL2 ... > &i) const
Extract an immutable reference to a sub-space of this tensor.
Definition tagged.hpp:1447
E & operator[](const index_class< TL2... > &i)
Access an element of this tensor.
Definition tagged.hpp:1470
const_view_type view() const
Return tensor_view acting as a const reference to the complete tensor_class.
Definition tagged.hpp:1413
E * data()
A pointer to the beginning of the array containing the data.
Definition tagged.hpp:1497
auto operator[](const index_class< TL2 ... > &i)
Extract a reference to a sub-space of this tensor.
Definition tagged.hpp:1429
const range_class< TL ... > & range() const
The range corresponding to this tensor.
Definition tagged.hpp:1458
const E & operator[](const index_class< TL2... > &i) const
Read an element of this tensor.
Definition tagged.hpp:1484
view_type view()
Return tensor_view acting as a reference to the complete tensor_class.
Definition tagged.hpp:1404
E * flat_data()
A pointer to the beginning of the array containing the data.
Definition tagged.hpp:1521
tensor_class(const range_class< TL2 ... > &rng, const E &e) noexcept
Initialize the tensor_class to a size defined by a range_class.
Definition tagged.hpp:1391
tensor_class(const range_class< TL2 ... > &rng)
Initialize the tensor_class to a size defined by a range_class.
Definition tagged.hpp:1377
const E * data() const
A const pointer to the beginning of the array containing the data.
Definition tagged.hpp:1509
A reference to a sub-space of a tensor.
Definition tagged.hpp:1169
auto operator[](const index_class< TL2 ... > &i) const
Extract a sub-space of this sub-space.
Definition tagged.hpp:1206
E * flat_data() const
A pointer to the element at the position defined by the lowermost index values of all dimensions of t...
Definition tagged.hpp:1250
const range_t & range() const
The range corresponding to the sub-space.
Definition tagged.hpp:1190
E & operator[](const index_class< TL2 ... > &i) const
Access an element of this sub-space.
Definition tagged.hpp:1222
E * data() const
A pointer to the beginning of the array containing the sub-space data.
Definition tagged.hpp:1237
static constexpr std::size_t dim_multiplier()
Return the multiplier associated with the dimension specified by a tag.
Definition tagged.hpp:1293
static constexpr std::size_t dimensions
Definition tagged.hpp:1258
static constexpr std::size_t dim_multiplier()
Return the multiplier associated with the dimension specified by an index.
Definition tagged.hpp:1318
std::size_t dim_size() const
Return the sub-space size in a dimension specified by a tag.
Definition tagged.hpp:1266
A bare tag used to select a dimension.
Definition tagged.hpp:36
Any tag used to specify a dimension.
Definition tagged.hpp:28
typename impl::tag_traits< T >::selector selector
Extract selector tag from any tag.
Definition tagged.hpp:43
typename impl::co_list_traits< X >::co_list co_list
Co-tag every element of a tag_list.
Definition tagged.hpp:1664
typename impl::tensor_view_creator< E, typename impl::mixer_list_traits< range_class< TL... >, impl::multiplier_list< TL... > >::type >::type extract_tensor_view
The type of a tensor_view acting as a reference to the complete tensor_class with the given tag list.
Definition tagged.hpp:1345
index_class< TL1 ..., TL2 ... > operator&(const index_class< TL1 ... > &ia, const index_class< TL2 ... > &ib)
Concatenate two (multi-dimensional) indexes together.
Definition tagged.hpp:638
retag< typename impl::co_traits< selector< T > >::co, T > co
Provide a co-tag for a given tag.
Definition tagged.hpp:1645
impl::permute_t< P, impl::permutator_tensor_class< E, TL... > > permute_tensor_class
Provide a tensor_class for the selected dimensions with layout specified by a tagged::tag_list.
Definition tagged.hpp:1593
constexpr range_class< co< T > > operator~(const range_class< T > &r)
Return a co-tagged range with the same extent.
Definition tagged.hpp:1673
A wrapped list of tags.
Definition tagged.hpp:182