1 // -*- C++ -*-
2 /** @file */
3 #pragma once
4
5 namespace arm_cmsis_dsp {
6
7 /** \addtogroup FUSION Abstract syntax tree for fusion
8 * \ingroup DSPPP
9 * @{
10 */
11
12 template<typename T> struct traits
13 {
14 typedef T Scalar;
15 #if defined(HAS_VECTOR)
16 typedef typename vector_traits<T>::vector Vector;
17 #endif
18 };
19
20 template<typename M>
21 struct Complexity
22 {
23 constexpr static int value = 0;
24 };
25
26 /*
27
28 An unregular datatype has different strides like MatrixView
29 and can only be assigned to a MatrixView using a 2D functions.
30 So all normal eval functions will reject unregular structures.
31
32 */
33 template<typename T>
34 struct HasMatrixIndexing
35 {
36 constexpr static bool value = false;
37 };
38
39 template<typename T>
40 struct HasStaticStride
41 {
42 constexpr static bool value = false;
43 };
44
45
46
47 template<typename T>
48 struct IsVector
49 {
50 constexpr static bool value = false;
51 };
52
53 template<typename T>
54 struct IsMatrix
55 {
56 constexpr static bool value = false;
57 };
58
59
60
61 template<typename T>
62 struct StaticLength
63 {
64 constexpr static vector_length_t value = 0;
65 };
66
67 template<typename T>
68 struct ElementType
69 {
70 typedef T type;
71 };
72
73
74 template<typename A,typename B>
75 using SameElementType=std::is_same<typename ElementType<A>::type,typename ElementType<B>::type>;
76
77 /**
78 * @brief Determines if vector datatype supports vector instruction
79 * on a current architecture
80 *
81 * @tparam DA Datatype
82 *
83 * @return True if has vector instructions
84 */
85 template<typename DA>
has_vector_inst()86 constexpr bool has_vector_inst() {return (vector_traits<typename ElementType<DA>::type>::has_vector);}
87
88 /**
89 * @brief Determines if datatype has predicated loop for current architecture
90 *
91 * @tparam DA Datatype
92 *
93 * @return True if has predicated loops
94 */
95 template<typename DA>
has_predicate_inst()96 constexpr bool has_predicate_inst() {return (vector_traits<typename ElementType<DA>::type>::has_predicate);}
97
98 /**
99 * @brief Determines if scalar datatype (not vector, vectorview, matrix, matrixview)
100 *
101 * @tparam DA { description }
102 *
103 * @return True if scalar, False otherwise.
104 */
105 template<typename DA>
is_scalar()106 constexpr bool is_scalar() {return (!IsVector<DA>::value &&
107 !HasMatrixIndexing<DA>::value);}
108
109 /**
110 * @brief Check if datatype can only be used as a matrix (no vector addressing)
111 *
112 * @tparam DA Datatype
113 *
114 * @return True if can only be used as a matrix (no vector indexing)
115 */
116 template<typename DA>
must_use_matrix_idx()117 constexpr bool must_use_matrix_idx() {return (!IsVector<DA>::value &&
118 HasMatrixIndexing<DA>::value);}
119 /**
120 * @brief Check if both datatype have vector indexing are
121 * same scalar datatype
122 *
123 * @tparam DA First datatype
124 * @tparam DB Second datatype
125 *
126 * @return True if both datatype have vectro indexing and same scalar type
127 */
128 template<typename DA,typename DB>
vector_idx_pair()129 constexpr bool vector_idx_pair() {return (IsVector<DA>::value &&
130 IsVector<DB>::value &&
131 SameElementType<DA,DB>::value);}
132
133 // By default scalar has no vector size so can't be used
134 // to infer a size at build time. They are considered as dynamic
135 // Otherwise, by default vectors are considered static
136 // except is there is a specialization of this template
137 // (and that is the case for dynamic vectors)
138 template<typename T>
139 struct IsDynamic
140 {
141 constexpr static bool value = is_scalar<T>();
142 };
143
144 /*
145
146 Vector only not including matrixes (which are also vectors)
147
148 */
149
150 /**
151 * @brief Check if has vector indexing
152 *
153 * @tparam DA Datatype
154 *
155 * @return True if dtatype supports vector indexing
156 */
157 template<typename DA>
is_only_vector()158 constexpr bool is_only_vector() {return (IsVector<DA>::value &&
159 !HasMatrixIndexing<DA>::value);}
160
161 /**
162 * @brief Check if datatypes have same scalar datatype and no vector indexing
163 *
164 * @tparam DA First datatype
165 * @tparam DB Second datatype
166 *
167 * @return True if datatypes have same scalar datatype and no vector indexing
168 */
169 template<typename DA,typename DB>
must_use_matrix_idx_pair()170 constexpr bool must_use_matrix_idx_pair() {return ((must_use_matrix_idx<DA>() || must_use_matrix_idx<DB>()) &&
171 SameElementType<DA,DB>::value);}
172
173
174 /*
175
176 Static length is 0 for scalar and Dynamic vectors
177 */
178
179 /**
180 * @brief Static length
181 *
182 * @tparam DA First datatype
183 * @tparam DB Second datatype
184 *
185 * @return Return the static length of the first datatype having
186 * a static length in the pair.
187 */
188 template<typename DA,typename DB>
static_length()189 constexpr vector_length_t static_length() {
190 return ((StaticLength<DA>::value==0) ? StaticLength<DB>::value : StaticLength<DA>::value);
191 }
192
193 /*
194
195 False only when DA and DB are static vector and with differet size
196 Anyother case is ok.
197
198 */
199
200 /**
201 * @brief Check compatibility of length
202 *
203 * @tparam DA First datatype
204 * @tparam DB Second datatype
205 *
206 * @return False only when DA and DA have different static lengths.
207 * All other cases are True.
208 */
209 template<typename DA,typename DB>
same_static_length()210 constexpr bool same_static_length()
211 {
212 return((StaticLength<DA>::value == 0) || /* Scalar or dynamic case */
213 (StaticLength<DB>::value == 0) || /* Scalar or dynamic case */
214 (StaticLength<DA>::value == StaticLength<DB>::value));
215 }
216 /*
217
218 Vector operators at instruction level
219
220 */
221 #include "fusion_ops.hpp"
222
223
224 /**
225 * @brief Expression template
226 *
227 * @tparam T Datatype representing the expression
228 *
229 */
230 template<typename T>
231 struct _Expr {
232
233 using Scalar = typename traits<T>::Scalar;
234 #if defined(HAS_VECTOR)
235 using Vector = typename traits<T>::Vector;
236 #endif
237
238 /**
239 * @brief Derived datatype
240 *
241 * @return Return the derived datatype
242 */
derivedarm_cmsis_dsp::_Expr243 T& derived() {return(static_cast<T&>(*this));}
244
245 /**
246 * @brief Derived datatype
247 *
248 * @return Return the derived datatype
249 */
derivedarm_cmsis_dsp::_Expr250 T const& derived() const {return(static_cast<T const&>(*this));}
251
252 /**
253 * @brief Vector indexing in the expression
254 *
255 * @param[in] i Index
256 *
257 * @return The result of the vector indexer
258 */
operator []arm_cmsis_dsp::_Expr259 Scalar const operator[](const index_t i) const {return(this->derived()[i]);}
260
261 /**
262 * @brief Matrix indexing
263 *
264 * @param[in] r Row index
265 * @param[in] c Column index
266 *
267 * @return Element at index
268 */
operator ()arm_cmsis_dsp::_Expr269 Scalar const operator()(const index_t r,const index_t c) const {return(this->derived()(r,c));}
270
271 #if defined(HAS_VECTOR)
272 /**
273 * @brief Vector operation at given index
274 *
275 * @param[in] i Vector index
276 *
277 * @return Evaluation of vector at the index
278 */
vector_oparm_cmsis_dsp::_Expr279 Vector const vector_op(const index_t i) const {return(this->derived().vector_op(i));}
280
281 /**
282 * @brief Vector operation at index with loop predicate
283 *
284 * @param[in] i Vector index
285 * @param[in] remaining Remaining elements in the loop
286 *
287 * @return Evaluation of vector at index with tail predication
288 */
vector_op_tailarm_cmsis_dsp::_Expr289 Vector const vector_op_tail(const index_t i,const vector_length_t remaining) const {return(this->derived().vector_op_tail(i,remaining));}
290
291 /**
292 * @brief Matrix operation at index
293 *
294 * @param[in] r row index
295 * @param[in] c column index
296 *
297 * @return Evaluation of matrix expression at index
298 */
matrix_oparm_cmsis_dsp::_Expr299 Vector const matrix_op(const index_t r,const index_t c) const {return(this->derived().matrix_op(r,c));}
300
301 /**
302 * @brief Matrix operation at index with tail predication
303 *
304 * @param[in] r row index
305 * @param[in] c column index
306 * @param[in] remaining Remaining elements in the loop
307 *
308 * @return Evaluation of matrix operation at index
309 */
matrix_op_tailarm_cmsis_dsp::_Expr310 Vector const matrix_op_tail(const index_t r,const index_t c,const vector_length_t remaining) const {return(this->derived().matrix_op_tail(r,c,remaining));}
311 #endif
312
313 /**
314 * @brief Length of result
315 *
316 * @return The vector length.
317 */
lengtharm_cmsis_dsp::_Expr318 vector_length_t length() const {return(this->derived().length());}
319
320 /**
321 * @brief Number of rows for result
322 *
323 * @return Number of rows
324 */
rowsarm_cmsis_dsp::_Expr325 vector_length_t rows() const {return(this->derived().rows());}
326
327 /**
328 * @brief Number of columns for result
329 *
330 * @return Number of columns
331 */
columnsarm_cmsis_dsp::_Expr332 vector_length_t columns() const {return(this->derived().columns());}
333
~_Exprarm_cmsis_dsp::_Expr334 virtual ~_Expr(){};
335
336 protected:
337 _Expr() = default;
338 _Expr(const _Expr&) = default;
339 _Expr(_Expr&&) = default;
340 _Expr& operator=(const _Expr& other) = delete;
341 _Expr& operator=(_Expr&& other) = delete;
342 };
343
344 /*****************
345 *
346 * BINARY AST
347 */
348
349 /**
350 * @brief Expression for binary operator
351 *
352 * @tparam LHS Left hand side datatype
353 * @tparam RHS Right hand side datatype
354 * @tparam DerivedOp Operator for the binary operation
355 *
356 */
357 template<typename LHS,typename RHS,typename DerivedOp>
358 struct _Binary: _Expr<_Binary<LHS,RHS,DerivedOp>>
359 {
360 using Scalar = typename traits<LHS>::Scalar;
361 #if defined(HAS_VECTOR)
362 using Vector = typename traits<LHS>::Vector;
363 #endif
_Binaryarm_cmsis_dsp::_Binary364 _Binary(const LHS &lhs,
365 const RHS &rhs,
366 const _BinaryOperator<Scalar,DerivedOp> &op):
367 lhs_(lhs),rhs_(rhs),op_(op){
368 }
369
370
_Binaryarm_cmsis_dsp::_Binary371 _Binary(const _Binary &other):
372 lhs_(other.lhs_),rhs_(other.rhs_),op_(other.op_){
373 }
374
375 _Binary& operator=(const _Binary& other) = delete;
376 _Binary& operator=(_Binary&& other) = delete;
377
_Binaryarm_cmsis_dsp::_Binary378 _Binary(_Binary &&other):
379 lhs_(std::move(other.lhs_)),rhs_(std::move(other.rhs_)),op_(std::move(other.op_))
380 {
381 }
382
383 template<typename R=RHS, typename L=LHS,
384 typename std::enable_if<IsVector<L>::value,bool>::type = true>
lengtharm_cmsis_dsp::_Binary385 vector_length_t length() const {
386 return(lhs_.length());
387 }
388
389 template<typename R=RHS, typename L=LHS,
390 typename std::enable_if<!IsVector<L>::value && IsVector<R>::value,bool>::type = true>
lengtharm_cmsis_dsp::_Binary391 vector_length_t length() const {
392 return(rhs_.length());
393 }
394
395 template<typename R=RHS, typename L=LHS,
396 typename std::enable_if<HasMatrixIndexing<L>::value,bool>::type = true>
rowsarm_cmsis_dsp::_Binary397 vector_length_t rows() const {
398 return(lhs_.rows());
399 }
400
401 template<typename R=RHS, typename L=LHS,
402 typename std::enable_if<!HasMatrixIndexing<L>::value && HasMatrixIndexing<R>::value,bool>::type = true>
rowsarm_cmsis_dsp::_Binary403 vector_length_t rows() const {
404 return(rhs_.rows());
405 }
406
407 template<typename R=RHS, typename L=LHS,
408 typename std::enable_if<HasMatrixIndexing<L>::value,bool>::type = true>
columnsarm_cmsis_dsp::_Binary409 vector_length_t columns() const {
410 return(lhs_.columns());
411 }
412
413 template<typename R=RHS, typename L=LHS,
414 typename std::enable_if<!HasMatrixIndexing<L>::value && HasMatrixIndexing<R>::value,bool>::type = true>
columnsarm_cmsis_dsp::_Binary415 vector_length_t columns() const {
416 return(rhs_.columns());
417 }
418
419
420
421 template<typename R=RHS, typename L=LHS,
422 typename std::enable_if<
423 IsVector<L>::value &&
424 IsVector<R>::value,bool>::type = true>
operator []arm_cmsis_dsp::_Binary425 Scalar const operator[](const index_t i) const {
426 return(op_(lhs_[i],rhs_[i]));
427 }
428
429 template<typename R=RHS, typename L=LHS,
430 typename std::enable_if<IsVector<L>::value &&
431 is_scalar<R>(),bool>::type = true>
432 Scalar const operator[](const index_t i) const {
433 return(op_(lhs_[i],rhs_));
434 }
435
436 template<typename R=RHS, typename L=LHS,
437 typename std::enable_if<is_scalar<L>() &&
438 IsVector<R>::value,bool>::type = true>
439 Scalar const operator[](const index_t i) const {
440 return(op_(lhs_,rhs_[i]));
441 }
442
443 template<typename R=RHS, typename L=LHS,
444 typename std::enable_if<HasMatrixIndexing<L>::value &&
445 HasMatrixIndexing<R>::value,bool>::type = true>
operator ()arm_cmsis_dsp::_Binary446 Scalar const operator()(const index_t r,const index_t c) const
447 {
448 return(op_(lhs_(r,c),rhs_(r,c)));
449 }
450
451 template<typename R=RHS, typename L=LHS,
452 typename std::enable_if<is_scalar<L>() &&
453 HasMatrixIndexing<R>::value,bool>::type = true>
454 Scalar const operator()(const index_t r,const index_t c) const
455 {
456 return(op_(lhs_,rhs_(r,c)));
457 }
458
459 template<typename R=RHS, typename L=LHS,
460 typename std::enable_if<HasMatrixIndexing<L>::value &&
461 is_scalar<R>(),bool>::type = true>
462 Scalar const operator()(const index_t r,const index_t c) const
463 {
464 return(op_(lhs_(r,c),rhs_));
465 }
466
467 #if defined(HAS_VECTOR)
468 /* V + V */
469 template<typename R=RHS, typename L=LHS,
470 typename std::enable_if<
471 IsVector<L>::value &&
472 IsVector<R>::value,bool>::type = true>
vector_oparm_cmsis_dsp::_Binary473 Vector const vector_op(const index_t i) const
474 {
475 return(op_(lhs_.vector_op(i),rhs_.vector_op(i)));
476 }
477
478 template<typename R=RHS, typename L=LHS,
479 typename std::enable_if<
480 has_predicate_inst<L>() &&
481 IsVector<L>::value &&
482 IsVector<R>::value,bool>::type = true>
483 Vector const vector_op_tail(const index_t i,const vector_length_t remaining) const
484 {
485 return(op_(lhs_.vector_op_tail(i,remaining),rhs_.vector_op_tail(i,remaining),inner::vctpq<Scalar>::mk(remaining)));
486 }
487
488 /* V + S */
489 template<typename R=RHS, typename L=LHS,
490 typename std::enable_if<
491 IsVector<L>::value &&
492 is_scalar<R>(),bool>::type = true>
493 Vector const vector_op(const index_t i) const
494 {
495 return(op_(lhs_.vector_op(i),rhs_));
496 }
497
498 template<typename R=RHS, typename L=LHS,
499 typename std::enable_if<
500 has_predicate_inst<L>() &&
501 IsVector<L>::value &&
502 is_scalar<R>(),bool>::type = true>
503 Vector const vector_op_tail(const index_t i,const vector_length_t remaining) const
504 {
505 return(op_(lhs_.vector_op_tail(i,remaining),rhs_,inner::vctpq<Scalar>::mk(remaining)));
506 }
507
508
509
510 /* S + V */
511 template<typename R=RHS, typename L=LHS,
512 typename std::enable_if<is_scalar<L>() &&
513 IsVector<R>::value,bool>::type = true>
514 Vector const vector_op(const index_t i) const
515 {
516 return(op_(lhs_,rhs_.vector_op(i)));
517 }
518
519 template<typename R=RHS, typename L=LHS,
520 typename std::enable_if<
521 has_predicate_inst<L>() &&
522 is_scalar<L>() &&
523 IsVector<R>::value,bool>::type = true>
524 Vector const vector_op_tail(const index_t i,const vector_length_t remaining) const
525 {
526 return(op_(lhs_,rhs_.vector_op_tail(i,remaining),inner::vctpq<Scalar>::mk(remaining)));
527 }
528
529
530 /*************
531 *
532 * For matrix
533 *
534 */
535
536 /* V + V */
537 template<typename R=RHS, typename L=LHS,
538 typename std::enable_if<HasMatrixIndexing<L>::value &&
539 HasMatrixIndexing<R>::value,bool>::type = true>
matrix_oparm_cmsis_dsp::_Binary540 Vector const matrix_op(const index_t r,const index_t c) const
541 {
542 return(op_(lhs_.matrix_op(r,c),rhs_.matrix_op(r,c)));
543 }
544
545 template<typename R=RHS, typename L=LHS,
546 typename std::enable_if<
547 has_predicate_inst<L>() &&
548 HasMatrixIndexing<L>::value &&
549 HasMatrixIndexing<R>::value,bool>::type = true>
550 Vector const matrix_op_tail(const index_t r,const index_t c,const vector_length_t remaining) const
551 {
552 return(op_(lhs_.matrix_op_tail(r,c,remaining),rhs_.matrix_op_tail(r,c,remaining),inner::vctpq<Scalar>::mk(remaining)));
553 }
554
555 /* V + S */
556 template<typename R=RHS, typename L=LHS,
557 typename std::enable_if<HasMatrixIndexing<L>::value &&
558 is_scalar<R>(),bool>::type = true>
559 Vector const matrix_op(const index_t r,const index_t c) const
560 {
561 return(op_(lhs_.matrix_op(r,c),rhs_));
562 }
563
564 template<typename R=RHS, typename L=LHS,
565 typename std::enable_if<has_predicate_inst<L>() &&
566 HasMatrixIndexing<L>::value &&
567 is_scalar<R>(),bool>::type = true>
568 Vector const matrix_op_tail(const index_t r,const index_t c,const vector_length_t remaining) const
569 {
570 return(op_(lhs_.matrix_op_tail(r,c,remaining),rhs_,inner::vctpq<Scalar>::mk(remaining)));
571 }
572
573
574
575 /* S + V */
576 template<typename R=RHS, typename L=LHS,
577 typename std::enable_if<is_scalar<L>() &&
578 HasMatrixIndexing<R>::value,bool>::type = true>
579 Vector const matrix_op(const index_t r,const index_t c) const
580 {
581 return(op_(lhs_,rhs_.matrix_op(r,c)));
582 }
583
584 template<typename R=RHS, typename L=LHS,
585 typename std::enable_if<has_predicate_inst<L>() &&
586 is_scalar<L>() &&
587 HasMatrixIndexing<R>::value,bool>::type = true>
588 Vector const matrix_op_tail(const index_t r,const index_t c,const vector_length_t remaining) const
589 {
590 return(op_(lhs_,rhs_.matrix_op_tail(r,c,remaining),inner::vctpq<Scalar>::mk(remaining)));
591 }
592
593
594 #endif
595 const LHS lhs_;
596 const RHS rhs_;
597 const _BinaryOperator<Scalar,DerivedOp> op_;
598 };
599
600 template<typename DerivedOp>
601 struct Complexity<_Expr<DerivedOp>>
602 {
603 constexpr static int value = Complexity<DerivedOp>::value;
604 };
605
606 template<typename DerivedOp>
607 struct ElementType<_Expr<DerivedOp>>
608 {
609 typedef typename ElementType<DerivedOp>::type type;
610 };
611
612 template<typename LHS,typename RHS,typename DerivedOp>
613 struct Complexity<_Binary<LHS,RHS,DerivedOp>>
614 {
615 constexpr static int lhsv = Complexity<LHS>::value;
616 constexpr static int rhsv = Complexity<RHS>::value;
617 constexpr static int value = lhsv + rhsv + 1;
618 };
619
620 template<typename LHS,typename RHS,typename DerivedOp>
621 struct ElementType<_Binary<LHS,RHS,DerivedOp>>
622 {
623 typedef typename ElementType<LHS>::type type;
624 };
625
626
627 template<typename DerivedOp>
628 struct IsVector<_Expr<DerivedOp>>
629 {
630 constexpr static bool value = IsVector<DerivedOp>::value;
631 };
632
633 template<typename DerivedOp>
634 struct HasMatrixIndexing<_Expr<DerivedOp>>
635 {
636 constexpr static bool value = HasMatrixIndexing<DerivedOp>::value;
637 };
638
639 template<typename LHS,typename RHS,typename DerivedOp>
640 struct IsVector<_Binary<LHS,RHS,DerivedOp>>
641 {
642 constexpr static bool value =
643 (IsVector<LHS>::value && IsVector<RHS>::value) ||
644 (IsVector<LHS>::value && is_scalar<RHS>()) ||
645 (is_scalar<LHS>() && IsVector<RHS>::value);
646 };
647
648 template<typename LHS,typename RHS,typename DerivedOp>
649 struct HasMatrixIndexing<_Binary<LHS,RHS,DerivedOp>>
650 {
651 constexpr static bool value =
652 (HasMatrixIndexing<LHS>::value && HasMatrixIndexing<RHS>::value) ||
653 (HasMatrixIndexing<LHS>::value && is_scalar<RHS>()) ||
654 (is_scalar<LHS>() && HasMatrixIndexing<RHS>::value);
655 };
656
657 template<typename DerivedOp>
658 struct IsDynamic<_Expr<DerivedOp>>
659 {
660 constexpr static bool value = IsDynamic<DerivedOp>::value;
661 };
662
663 template<typename LHS,typename RHS,typename DerivedOp>
664 struct IsDynamic<_Binary<LHS,RHS,DerivedOp>>
665 {
666 constexpr static bool value = IsDynamic<LHS>::value && IsDynamic<RHS>::value;
667 };
668
669 template<typename DerivedOp>
670 struct StaticLength<_Expr<DerivedOp>>
671 {
672 constexpr static vector_length_t value = StaticLength<DerivedOp>::value;
673 };
674
675 template<typename LHS,typename RHS,typename DerivedOp>
676 struct StaticLength<_Binary<LHS,RHS,DerivedOp>>
677 {
678 constexpr static vector_length_t value = static_length<LHS,RHS>();
679
680 };
681
682 template<typename DerivedOp>
683 struct traits<_Expr<DerivedOp>>
684 {
685 typedef typename traits<DerivedOp>::Scalar Scalar;
686 #if defined(HAS_VECTOR)
687 typedef typename traits<DerivedOp>::Vector Vector;
688 #endif
689 };
690
691 template<typename LHS,typename RHS,typename DerivedOp>
692 struct traits<_Binary<LHS,RHS,DerivedOp>>
693 {
694 typedef typename traits<LHS>::Scalar Scalar;
695 #if defined(HAS_VECTOR)
696 typedef typename traits<LHS>::Vector Vector;
697 #endif
698 };
699
700
701 /*****************
702 *
703 * UNARY AST
704 */
705
706 /**
707 * @brief Expression for unary operator
708 *
709 * @tparam LHS Left hand side datatype
710 * @tparam DerivedOp Operator for the binary operation
711 *
712 */
713 template<typename LHS,typename DerivedOp>
714 struct _Unary: _Expr<_Unary<LHS,DerivedOp>>
715 {
716 using Scalar = typename traits<LHS>::Scalar;
717 #if defined(HAS_VECTOR)
718 using Vector = typename traits<LHS>::Vector;
719 #endif
_Unaryarm_cmsis_dsp::_Unary720 _Unary(const LHS &lhs,
721 const _UnaryOperator<Scalar,DerivedOp> &op):
722 lhs_(lhs),op_(op){
723 }
724
_Unaryarm_cmsis_dsp::_Unary725 _Unary(const _Unary &other):
726 lhs_(other.lhs_),op_(other.op_){
727 }
728
_Unaryarm_cmsis_dsp::_Unary729 _Unary(LHS &&other):
730 lhs_(std::move(other.lhs_)),op_(std::move(other.op_)){
731 }
732
733 _Unary& operator=(const _Unary& other) = delete;
734 _Unary& operator=(_Unary&& other) = delete;
735
736
lengtharm_cmsis_dsp::_Unary737 vector_length_t length() const {
738 return(lhs_.length());
739 }
740
741 template<typename L=LHS,
742 typename std::enable_if<HasMatrixIndexing<L>::value,bool>::type = true>
rowsarm_cmsis_dsp::_Unary743 vector_length_t rows() const {
744 return(lhs_.rows());
745 }
746
747 template<typename L=LHS,
748 typename std::enable_if<HasMatrixIndexing<L>::value,bool>::type = true>
columnsarm_cmsis_dsp::_Unary749 vector_length_t columns() const {
750 return(lhs_.columns());
751 }
752
753 template<typename L=LHS,
754 typename std::enable_if<IsVector<L>::value ,bool>::type = true>
operator []arm_cmsis_dsp::_Unary755 Scalar const operator[](const index_t i) const {
756 return(op_(lhs_[i]));
757 }
758
759 template<typename L=LHS,
760 typename std::enable_if<HasMatrixIndexing<L>::value ,bool>::type = true>
operator ()arm_cmsis_dsp::_Unary761 Scalar const operator()(const index_t r,const index_t c) const
762 {
763 return(op_(lhs_(r,c)));
764 }
765
766
767 #if defined(HAS_VECTOR)
768 /* V */
769 template<typename L=LHS,
770 typename std::enable_if<
771 IsVector<L>::value ,bool>::type = true>
vector_oparm_cmsis_dsp::_Unary772 Vector const vector_op(const index_t i) const
773 {
774 return(op_(lhs_.vector_op(i)));
775 }
776
777 template<typename L=LHS,
778 typename std::enable_if<has_predicate_inst<L>() &&
779 IsVector<L>::value ,bool>::type = true>
780 Vector const vector_op_tail(const index_t i,const vector_length_t remaining) const
781 {
782 return(op_(lhs_.vector_op_tail(i,remaining),inner::vctpq<Scalar>::mk(remaining)));
783 }
784
785 /*
786
787 For Matrix
788
789 */
790
791 /* V */
792 template<typename L=LHS,
793 typename std::enable_if<HasMatrixIndexing<L>::value ,bool>::type = true>
matrix_oparm_cmsis_dsp::_Unary794 Vector const matrix_op(const index_t r,const index_t c) const
795 {
796 return(op_(lhs_.matrix_op(r,c)));
797 }
798
799 template<typename L=LHS,
800 typename std::enable_if<has_predicate_inst<L>() &&
801 HasMatrixIndexing<L>::value ,bool>::type = true>
802 Vector const matrix_op_tail(const index_t r,const index_t c,const vector_length_t remaining) const
803 {
804 return(op_(lhs_.matrix_op_tail(r,c,remaining),inner::vctpq<Scalar>::mk(remaining)));
805 }
806
807
808 #endif
809 const LHS lhs_;
810 const _UnaryOperator<Scalar,DerivedOp> op_;
811 };
812
813 template<typename LHS,typename DerivedOp>
814 struct Complexity<_Unary<LHS,DerivedOp>>
815 {
816 constexpr static int value = 1 + Complexity<LHS>::value;
817 };
818
819 template<typename LHS,typename DerivedOp>
820 struct ElementType<_Unary<LHS,DerivedOp>>
821 {
822 typedef typename ElementType<LHS>::type type;
823 };
824
825 template<typename LHS,typename DerivedOp>
826 struct IsVector<_Unary<LHS,DerivedOp>>
827 {
828 constexpr static bool value = IsVector<LHS>::value;
829 };
830
831 template<typename LHS,typename DerivedOp>
832 struct HasMatrixIndexing<_Unary<LHS,DerivedOp>>
833 {
834 constexpr static bool value = HasMatrixIndexing<LHS>::value;
835 };
836
837 template<typename LHS,typename DerivedOp>
838 struct IsDynamic<_Unary<LHS,DerivedOp>>
839 {
840 constexpr static bool value = IsDynamic<LHS>::value;
841 };
842
843 template<typename LHS,typename DerivedOp>
844 struct StaticLength<_Unary<LHS,DerivedOp>>
845 {
846 constexpr static vector_length_t value = StaticLength<LHS>::value;
847 };
848
849
850 template<typename LHS,typename DerivedOp>
851 struct traits<_Unary<LHS,DerivedOp>>
852 {
853 typedef typename traits<LHS>::Scalar Scalar;
854 #if defined(HAS_VECTOR)
855 typedef typename traits<LHS>::Vector Vector;
856 #endif
857 };
858
859
860
861
862 /*
863
864 Dot product
865
866 */
867
868 template<typename DA>
869 using DotResult = typename number_traits<typename traits<DA>::Scalar>::accumulator;
870
871
872
873 /**
874 * @brief Dot product
875 *
876 * @tparam VA Left hand side vector datatype
877 * @tparam VB Right hand side vector datatype
878 * @param a left hand side vector
879 * @param b right hand side vector
880 * @return The dot product
881 *
882 * The vector can be vector, vector views or expressions.
883 *
884 */
885 template<typename VA,typename VB,
886 typename std::enable_if<vector_idx_pair<VA,VB>() &&
887 is_only_vector<VA>() &&
888 is_only_vector<VB>() &&
889 (!IsDynamic<VA>::value || !IsDynamic<VB>::value),bool>::type = true>
dot(const VA & a,const VB & b)890 inline DotResult<VA> dot(const VA& a,
891 const VB& b)
892 {
893 constexpr vector_length_t l = static_length<VA,VB>();
894 return(_dot(a,b,l,CURRENT_ARCH));
895 }
896
897
898 template<typename VA,typename VB,
899 typename std::enable_if<vector_idx_pair<VA,VB>() &&
900 is_only_vector<VA>() &&
901 is_only_vector<VB>() &&
902 (IsDynamic<VA>::value && IsDynamic<VB>::value),bool>::type = true>
dot(const VA & a,const VB & b)903 inline DotResult<VA> dot(const VA& a,
904 const VB& b)
905 {
906 const vector_length_t l = a.length();
907
908 return(_dot(a,b,l,CURRENT_ARCH));
909 }
910
911
912
913
914 /**
915 * @brief Swap vectors
916 *
917 * @tparam VA Left hand side vector datatype
918 * @tparam VB Right hand side vector datatype
919 * @param a left hand side vector
920 * @param b right hand side vector
921 *
922 * The vector can be vector, vector views or expressions.
923 *
924 * The content of vector is swapped.
925 *
926 */
927 template<typename VA,typename VB,
928 typename std::enable_if<vector_idx_pair<VA,VB>() &&
929 (!IsDynamic<VA>::value || !IsDynamic<VB>::value),bool>::type = true>
swap(VA && a,VB && b)930 inline void swap(VA&& a,
931 VB&& b)
932 {
933 constexpr vector_length_t l = static_length<VA,VB>();
934
935 _swap(std::forward<VA>(a),std::forward<VB>(b),l,CURRENT_ARCH);
936 }
937
938
939 template<typename VA,typename VB,
940 typename std::enable_if<vector_idx_pair<VA,VB>() &&
941 (IsDynamic<VA>::value && IsDynamic<VB>::value),bool>::type = true>
swap(VA && a,VB && b)942 inline void swap(VA&& a,
943 VB&& b)
944 {
945 const vector_length_t l = a.length();
946
947 _swap(std::forward<VA>(a),std::forward<VB>(b),l,CURRENT_ARCH);
948 }
949
950 /*! @} */
951
952 }
953
954