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