1 //=================================================================================================
2 /*!
3 //  \file blaze/math/expressions/DVecScalarDivExpr.h
4 //  \brief Header file for the dense vector/scalar division expression
5 //
6 //  Copyright (C) 2012-2020 Klaus Iglberger - All Rights Reserved
7 //
8 //  This file is part of the Blaze library. You can redistribute it and/or modify it under
9 //  the terms of the New (Revised) BSD License. Redistribution and use in source and binary
10 //  forms, with or without modification, are permitted provided that the following conditions
11 //  are met:
12 //
13 //  1. Redistributions of source code must retain the above copyright notice, this list of
14 //     conditions and the following disclaimer.
15 //  2. Redistributions in binary form must reproduce the above copyright notice, this list
16 //     of conditions and the following disclaimer in the documentation and/or other materials
17 //     provided with the distribution.
18 //  3. Neither the names of the Blaze development group nor the names of its contributors
19 //     may be used to endorse or promote products derived from this software without specific
20 //     prior written permission.
21 //
22 //  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
23 //  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 //  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25 //  SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 //  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27 //  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 //  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 //  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 //  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31 //  DAMAGE.
32 */
33 //=================================================================================================
34 
35 #ifndef _BLAZE_MATH_EXPRESSIONS_DVECSCALARDIVEXPR_H_
36 #define _BLAZE_MATH_EXPRESSIONS_DVECSCALARDIVEXPR_H_
37 
38 
39 //*************************************************************************************************
40 // Includes
41 //*************************************************************************************************
42 
43 #include <iterator>
44 #include <utility>
45 #include <blaze/math/Aliases.h>
46 #include <blaze/math/constraints/DenseVector.h>
47 #include <blaze/math/constraints/RequiresEvaluation.h>
48 #include <blaze/math/constraints/Scalar.h>
49 #include <blaze/math/constraints/TransposeFlag.h>
50 #include <blaze/math/Exception.h>
51 #include <blaze/math/expressions/Computation.h>
52 #include <blaze/math/expressions/DenseVector.h>
53 #include <blaze/math/expressions/Forward.h>
54 #include <blaze/math/expressions/VecScalarDivExpr.h>
55 #include <blaze/math/shims/Invert.h>
56 #include <blaze/math/shims/Serial.h>
57 #include <blaze/math/SIMD.h>
58 #include <blaze/math/traits/DivTrait.h>
59 #include <blaze/math/traits/MultTrait.h>
60 #include <blaze/math/typetraits/HasSIMDDiv.h>
61 #include <blaze/math/typetraits/IsAligned.h>
62 #include <blaze/math/typetraits/IsComputation.h>
63 #include <blaze/math/typetraits/IsExpression.h>
64 #include <blaze/math/typetraits/IsInvertible.h>
65 #include <blaze/math/typetraits/IsPadded.h>
66 #include <blaze/math/typetraits/IsScalar.h>
67 #include <blaze/math/typetraits/IsTemporary.h>
68 #include <blaze/math/typetraits/RequiresEvaluation.h>
69 #include <blaze/math/typetraits/UnderlyingBuiltin.h>
70 #include <blaze/math/typetraits/UnderlyingElement.h>
71 #include <blaze/system/HostDevice.h>
72 #include <blaze/system/Inline.h>
73 #include <blaze/system/MacroDisable.h>
74 #include <blaze/system/Thresholds.h>
75 #include <blaze/util/Assert.h>
76 #include <blaze/util/constraints/FloatingPoint.h>
77 #include <blaze/util/constraints/SameType.h>
78 #include <blaze/util/EnableIf.h>
79 #include <blaze/util/FunctionTrace.h>
80 #include <blaze/util/mpl/If.h>
81 #include <blaze/util/Types.h>
82 #include <blaze/util/typetraits/IsBuiltin.h>
83 #include <blaze/util/typetraits/IsFloatingPoint.h>
84 #include <blaze/util/typetraits/IsNumeric.h>
85 
86 
87 namespace blaze {
88 
89 //=================================================================================================
90 //
91 //  CLASS DVECSCALARDIVEXPR
92 //
93 //=================================================================================================
94 
95 //*************************************************************************************************
96 /*!\brief Expression object for divisions of a dense vector by a scalar.
97 // \ingroup dense_vector_expression
98 //
99 // The DVecScalarDivExpr class represents the compile time expression for divisions of dense
100 // vectors by scalar values.
101 */
102 template< typename VT  // Type of the left-hand side dense vector
103         , typename ST  // Type of the right-hand side scalar value
104         , bool TF >    // Transpose flag
105 class DVecScalarDivExpr
106    : public VecScalarDivExpr< DenseVector< DVecScalarDivExpr<VT,ST,TF>, TF > >
107    , private Computation
108 {
109  private:
110    //**Type definitions****************************************************************************
111    using RT = ResultType_t<VT>;     //!< Result type of the dense vector expression.
112    using RN = ReturnType_t<VT>;     //!< Return type of the dense vector expression.
113    using ET = ElementType_t<VT>;    //!< Element type of the dense vector expression.
114    using CT = CompositeType_t<VT>;  //!< Composite type of the dense vector expression.
115    //**********************************************************************************************
116 
117    //**Return type evaluation**********************************************************************
118    //! Compilation switch for the selection of the subscript operator return type.
119    /*! The \a returnExpr compile time constant expression is a compilation switch for the
120        selection of the \a ReturnType. If the vector operand returns a temporary vector
121        or matrix, \a returnExpr will be set to \a false and the subscript operator will
122        return it's result by value. Otherwise \a returnExpr will be set to \a true and
123        the subscript operator may return it's result as an expression. */
124    static constexpr bool returnExpr = !IsTemporary_v<RN>;
125 
126    //! Expression return type for the subscript operator.
127    using ExprReturnType = decltype( std::declval<RN>() / std::declval<ST>() );
128    //**********************************************************************************************
129 
130    //**Serial evaluation strategy******************************************************************
131    //! Compilation switch for the serial evaluation strategy of the division expression.
132    /*! The \a useAssign compile time constant expression represents a compilation switch for
133        the serial evaluation strategy of the division expression. In case the given dense
134        vector expression of type \a VT is a computation expression and requires an intermediate
135        evaluation, \a useAssign will be set to 1 and the division expression will be evaluated
136        via the \a assign function family. Otherwise \a useAssign will be set to 0 and the
137        expression will be evaluated via the subscript operator. */
138    static constexpr bool useAssign = IsComputation_v<VT> && RequiresEvaluation_v<VT>;
139 
140    /*! \cond BLAZE_INTERNAL */
141    //! Helper variable template for the explicit application of the SFINAE principle.
142    template< typename VT2 >
143    static constexpr bool UseAssign_v = useAssign;
144    /*! \endcond */
145    //**********************************************************************************************
146 
147    //**Parallel evaluation strategy****************************************************************
148    /*! \cond BLAZE_INTERNAL */
149    //! Helper variable template for the explicit application of the SFINAE principle.
150    /*! This variable template is a helper for the selection of the parallel evaluation strategy.
151        In case either the target vector or the dense vector operand is not SMP assignable and the
152        vector operand is a computation expression that requires an intermediate evaluation, the
153        variable is set to 1 and the expression specific evaluation strategy is selected. Otherwise
154        the variable is set to 0 and the default strategy is chosen. */
155    template< typename VT2 >
156    static constexpr bool UseSMPAssign_v =
157       ( ( !VT2::smpAssignable || !VT::smpAssignable ) && useAssign );
158    /*! \endcond */
159    //**********************************************************************************************
160 
161  public:
162    //**Type definitions****************************************************************************
163    //! Type of this DVecScalarDivExpr instance.
164    using This = DVecScalarDivExpr<VT,ST,TF>;
165 
166    //! Base type of this DVecScalarDivExpr instance.
167    using BaseType = VecScalarDivExpr< DenseVector<This,TF> >;
168 
169    using ResultType    = DivTrait_t<RT,ST>;            //!< Result type for expression template evaluations.
170    using TransposeType = TransposeType_t<ResultType>;  //!< Transpose type for expression template evaluations.
171    using ElementType   = ElementType_t<ResultType>;    //!< Resulting element type.
172 
173    //! Return type for expression template evaluations.
174    using ReturnType = const If_t< returnExpr, ExprReturnType, ElementType >;
175 
176    //! Data type for composite expression templates.
177    using CompositeType = If_t< useAssign, const ResultType, const DVecScalarDivExpr& >;
178 
179    //! Composite type of the left-hand side dense vector expression.
180    using LeftOperand = If_t< IsExpression_v<VT>, const VT, const VT& >;
181 
182    //! Composite type of the right-hand side scalar value.
183    using RightOperand = ST;
184    //**********************************************************************************************
185 
186    //**ConstIterator class definition**************************************************************
187    /*!\brief Iterator over the elements of the dense vector.
188    */
189    class ConstIterator
190    {
191     public:
192       //**Type definitions*************************************************************************
193       using IteratorCategory = std::random_access_iterator_tag;  //!< The iterator category.
194       using ValueType        = ElementType;                      //!< Type of the underlying elements.
195       using PointerType      = ElementType*;                     //!< Pointer return type.
196       using ReferenceType    = ElementType&;                     //!< Reference return type.
197       using DifferenceType   = ptrdiff_t;                        //!< Difference between two iterators.
198 
199       // STL iterator requirements
200       using iterator_category = IteratorCategory;  //!< The iterator category.
201       using value_type        = ValueType;         //!< Type of the underlying elements.
202       using pointer           = PointerType;       //!< Pointer return type.
203       using reference         = ReferenceType;     //!< Reference return type.
204       using difference_type   = DifferenceType;    //!< Difference between two iterators.
205 
206       //! ConstIterator type of the dense vector expression.
207       using IteratorType = ConstIterator_t<VT>;
208       //*******************************************************************************************
209 
210       //**Constructor******************************************************************************
211       /*!\brief Constructor for the ConstIterator class.
212       //
213       // \param iterator Iterator to the initial element.
214       // \param scalar Scalar of the division expression.
215       */
ConstIterator(IteratorType iterator,RightOperand scalar)216       inline ConstIterator( IteratorType iterator, RightOperand scalar )
217          : iterator_( iterator )  // Iterator to the current element
218          , scalar_  ( scalar   )  // Scalar of the division expression
219       {}
220       //*******************************************************************************************
221 
222       //**Addition assignment operator*************************************************************
223       /*!\brief Addition assignment operator.
224       //
225       // \param inc The increment of the iterator.
226       // \return The incremented iterator.
227       */
228       inline BLAZE_DEVICE_CALLABLE ConstIterator& operator+=( size_t inc ) {
229          iterator_ += inc;
230          return *this;
231       }
232       //*******************************************************************************************
233 
234       //**Subtraction assignment operator**********************************************************
235       /*!\brief Subtraction assignment operator.
236       //
237       // \param dec The decrement of the iterator.
238       // \return The decremented iterator.
239       */
240       inline BLAZE_DEVICE_CALLABLE ConstIterator& operator-=( size_t dec ) {
241          iterator_ -= dec;
242          return *this;
243       }
244       //*******************************************************************************************
245 
246       //**Prefix increment operator****************************************************************
247       /*!\brief Pre-increment operator.
248       //
249       // \return Reference to the incremented iterator.
250       */
251       inline BLAZE_DEVICE_CALLABLE ConstIterator& operator++() {
252          ++iterator_;
253          return *this;
254       }
255       //*******************************************************************************************
256 
257       //**Postfix increment operator***************************************************************
258       /*!\brief Post-increment operator.
259       //
260       // \return The previous position of the iterator.
261       */
262       inline BLAZE_DEVICE_CALLABLE const ConstIterator operator++( int ) {
263          return ConstIterator( iterator_++, scalar_ );
264       }
265       //*******************************************************************************************
266 
267       //**Prefix decrement operator****************************************************************
268       /*!\brief Pre-decrement operator.
269       //
270       // \return Reference to the decremented iterator.
271       */
272       inline BLAZE_DEVICE_CALLABLE ConstIterator& operator--() {
273          --iterator_;
274          return *this;
275       }
276       //*******************************************************************************************
277 
278       //**Postfix decrement operator***************************************************************
279       /*!\brief Post-decrement operator.
280       //
281       // \return The previous position of the iterator.
282       */
283       inline BLAZE_DEVICE_CALLABLE const ConstIterator operator--( int ) {
284          return ConstIterator( iterator_--, scalar_ );
285       }
286       //*******************************************************************************************
287 
288       //**Element access operator******************************************************************
289       /*!\brief Direct access to the element at the current iterator position.
290       //
291       // \return The resulting value.
292       */
293       inline ReturnType operator*() const {
294          return *iterator_ / scalar_;
295       }
296       //*******************************************************************************************
297 
298       //**Load function****************************************************************************
299       /*!\brief Access to the SIMD elements of the vector.
300       //
301       // \return The resulting SIMD element.
302       */
load()303       inline auto load() const noexcept {
304          return iterator_.load() / set( scalar_ );
305       }
306       //*******************************************************************************************
307 
308       //**Equality operator************************************************************************
309       /*!\brief Equality comparison between two ConstIterator objects.
310       //
311       // \param rhs The right-hand side iterator.
312       // \return \a true if the iterators refer to the same element, \a false if not.
313       */
314       inline bool operator==( const ConstIterator& rhs ) const {
315          return iterator_ == rhs.iterator_;
316       }
317       //*******************************************************************************************
318 
319       //**Inequality operator**********************************************************************
320       /*!\brief Inequality comparison between two ConstIterator objects.
321       //
322       // \param rhs The right-hand side iterator.
323       // \return \a true if the iterators don't refer to the same element, \a false if they do.
324       */
325       inline bool operator!=( const ConstIterator& rhs ) const {
326          return iterator_ != rhs.iterator_;
327       }
328       //*******************************************************************************************
329 
330       //**Less-than operator***********************************************************************
331       /*!\brief Less-than comparison between two ConstIterator objects.
332       //
333       // \param rhs The right-hand side iterator.
334       // \return \a true if the left-hand side iterator is smaller, \a false if not.
335       */
336       inline bool operator<( const ConstIterator& rhs ) const {
337          return iterator_ < rhs.iterator_;
338       }
339       //*******************************************************************************************
340 
341       //**Greater-than operator********************************************************************
342       /*!\brief Greater-than comparison between two ConstIterator objects.
343       //
344       // \param rhs The right-hand side iterator.
345       // \return \a true if the left-hand side iterator is greater, \a false if not.
346       */
347       inline bool operator>( const ConstIterator& rhs ) const {
348          return iterator_ > rhs.iterator_;
349       }
350       //*******************************************************************************************
351 
352       //**Less-or-equal-than operator**************************************************************
353       /*!\brief Less-than comparison between two ConstIterator objects.
354       //
355       // \param rhs The right-hand side iterator.
356       // \return \a true if the left-hand side iterator is smaller or equal, \a false if not.
357       */
358       inline bool operator<=( const ConstIterator& rhs ) const {
359          return iterator_ <= rhs.iterator_;
360       }
361       //*******************************************************************************************
362 
363       //**Greater-or-equal-than operator***********************************************************
364       /*!\brief Greater-than comparison between two ConstIterator objects.
365       //
366       // \param rhs The right-hand side iterator.
367       // \return \a true if the left-hand side iterator is greater or equal, \a false if not.
368       */
369       inline bool operator>=( const ConstIterator& rhs ) const {
370          return iterator_ >= rhs.iterator_;
371       }
372       //*******************************************************************************************
373 
374       //**Subtraction operator*********************************************************************
375       /*!\brief Calculating the number of elements between two iterators.
376       //
377       // \param rhs The right-hand side iterator.
378       // \return The number of elements between the two iterators.
379       */
380       inline DifferenceType operator-( const ConstIterator& rhs ) const {
381          return iterator_ - rhs.iterator_;
382       }
383       //*******************************************************************************************
384 
385       //**Addition operator************************************************************************
386       /*!\brief Addition between a ConstIterator and an integral value.
387       //
388       // \param it The iterator to be incremented.
389       // \param inc The number of elements the iterator is incremented.
390       // \return The incremented iterator.
391       */
392       friend inline const ConstIterator operator+( const ConstIterator& it, size_t inc ) {
393          return ConstIterator( it.iterator_ + inc, it.scalar_ );
394       }
395       //*******************************************************************************************
396 
397       //**Addition operator************************************************************************
398       /*!\brief Addition between an integral value and a ConstIterator.
399       //
400       // \param inc The number of elements the iterator is incremented.
401       // \param it The iterator to be incremented.
402       // \return The incremented iterator.
403       */
404       friend inline const ConstIterator operator+( size_t inc, const ConstIterator& it ) {
405          return ConstIterator( it.iterator_ + inc, it.scalar_ );
406       }
407       //*******************************************************************************************
408 
409       //**Subtraction operator*********************************************************************
410       /*!\brief Subtraction between a ConstIterator and an integral value.
411       //
412       // \param it The iterator to be decremented.
413       // \param dec The number of elements the iterator is decremented.
414       // \return The decremented iterator.
415       */
416       friend inline const ConstIterator operator-( const ConstIterator& it, size_t dec ) {
417          return ConstIterator( it.iterator_ - dec, it.scalar_ );
418       }
419       //*******************************************************************************************
420 
421     private:
422       //**Member variables*************************************************************************
423       IteratorType iterator_;  //!< Iterator to the current element.
424       RightOperand scalar_;    //!< Scalar of the division expression.
425       //*******************************************************************************************
426    };
427    //**********************************************************************************************
428 
429    //**Compilation flags***************************************************************************
430    //! Compilation switch for the expression template evaluation strategy.
431    static constexpr bool simdEnabled =
432       ( VT::simdEnabled && IsNumeric_v<ET> &&
433         ( HasSIMDDiv_v<ET,ST> || HasSIMDDiv_v<UnderlyingElement_t<ET>,ST> ) );
434 
435    //! Compilation switch for the expression template assignment strategy.
436    static constexpr bool smpAssignable = VT::smpAssignable;
437    //**********************************************************************************************
438 
439    //**SIMD properties*****************************************************************************
440    //! The number of elements packed within a single SIMD element.
441    static constexpr size_t SIMDSIZE = SIMDTrait<ElementType>::size;
442    //**********************************************************************************************
443 
444    //**Constructor*********************************************************************************
445    /*!\brief Constructor for the DVecScalarDivExpr class.
446    //
447    // \param vector The left-hand side dense vector of the division expression.
448    // \param scalar The right-hand side scalar of the division expression.
449    */
DVecScalarDivExpr(const VT & vector,ST scalar)450    inline DVecScalarDivExpr( const VT& vector, ST scalar ) noexcept
451       : vector_( vector )  // Left-hand side dense vector of the division expression
452       , scalar_( scalar )  // Right-hand side scalar of the division expression
453    {}
454    //**********************************************************************************************
455 
456    //**Subscript operator**************************************************************************
457    /*!\brief Subscript operator for the direct access to the vector elements.
458    //
459    // \param index Access index. The index has to be in the range \f$[0..N-1]\f$.
460    // \return The resulting value.
461    */
462    inline ReturnType operator[]( size_t index ) const {
463       BLAZE_INTERNAL_ASSERT( index < vector_.size(), "Invalid vector access index" );
464       return vector_[index] / scalar_;
465    }
466    //**********************************************************************************************
467 
468    //**At function*********************************************************************************
469    /*!\brief Checked access to the vector elements.
470    //
471    // \param index Access index. The index has to be in the range \f$[0..N-1]\f$.
472    // \return The resulting value.
473    // \exception std::out_of_range Invalid vector access index.
474    */
at(size_t index)475    inline ReturnType at( size_t index ) const {
476       if( index >= vector_.size() ) {
477          BLAZE_THROW_OUT_OF_RANGE( "Invalid vector access index" );
478       }
479       return (*this)[index];
480    }
481    //**********************************************************************************************
482 
483    //**Load function*******************************************************************************
484    /*!\brief Access to the SIMD elements of the vector.
485    //
486    // \param index Access index. The index has to be in the range \f$[0..N-1]\f$.
487    // \return Reference to the accessed values.
488    */
load(size_t index)489    BLAZE_ALWAYS_INLINE auto load( size_t index ) const noexcept {
490       BLAZE_INTERNAL_ASSERT( index < vector_.size() , "Invalid vector access index" );
491       BLAZE_INTERNAL_ASSERT( index % SIMDSIZE == 0UL, "Invalid vector access index" );
492       return vector_.load( index ) / set( scalar_ );
493    }
494    //**********************************************************************************************
495 
496    //**Begin function******************************************************************************
497    /*!\brief Returns an iterator to the first non-zero element of the dense vector.
498    //
499    // \return Iterator to the first non-zero element of the dense vector.
500    */
begin()501    inline ConstIterator begin() const {
502       return ConstIterator( vector_.begin(), scalar_ );
503    }
504    //**********************************************************************************************
505 
506    //**End function********************************************************************************
507    /*!\brief Returns an iterator just past the last non-zero element of the dense vector.
508    //
509    // \return Iterator just past the last non-zero element of the dense vector.
510    */
end()511    inline ConstIterator end() const {
512       return ConstIterator( vector_.end(), scalar_ );
513    }
514    //**********************************************************************************************
515 
516    //**Size function*******************************************************************************
517    /*!\brief Returns the current size/dimension of the vector.
518    //
519    // \return The size of the vector.
520    */
size()521    inline size_t size() const noexcept {
522       return vector_.size();
523    }
524    //**********************************************************************************************
525 
526    //**Left operand access*************************************************************************
527    /*!\brief Returns the left-hand side dense vector operand.
528    //
529    // \return The left-hand side dense vector operand.
530    */
leftOperand()531    inline LeftOperand leftOperand() const noexcept {
532       return vector_;
533    }
534    //**********************************************************************************************
535 
536    //**Right operand access************************************************************************
537    /*!\brief Returns the right-hand side scalar operand.
538    //
539    // \return The right-hand side scalar operand.
540    */
rightOperand()541    inline RightOperand rightOperand() const noexcept {
542       return scalar_;
543    }
544    //**********************************************************************************************
545 
546    //**********************************************************************************************
547    /*!\brief Returns whether the expression can alias with the given address \a alias.
548    //
549    // \param alias The alias to be checked.
550    // \return \a true in case the expression can alias, \a false otherwise.
551    */
552    template< typename T >
canAlias(const T * alias)553    inline bool canAlias( const T* alias ) const noexcept {
554       return IsExpression_v<VT> && vector_.canAlias( alias );
555    }
556    //**********************************************************************************************
557 
558    //**********************************************************************************************
559    /*!\brief Returns whether the expression is aliased with the given address \a alias.
560    //
561    // \param alias The alias to be checked.
562    // \return \a true in case an alias effect is detected, \a false otherwise.
563    */
564    template< typename T >
isAliased(const T * alias)565    inline bool isAliased( const T* alias ) const noexcept {
566       return vector_.isAliased( alias );
567    }
568    //**********************************************************************************************
569 
570    //**********************************************************************************************
571    /*!\brief Returns whether the operands of the expression are properly aligned in memory.
572    //
573    // \return \a true in case the operands are aligned, \a false if not.
574    */
isAligned()575    inline bool isAligned() const noexcept {
576       return vector_.isAligned();
577    }
578    //**********************************************************************************************
579 
580    //**********************************************************************************************
581    /*!\brief Returns whether the expression can be used in SMP assignments.
582    //
583    // \return \a true in case the expression can be used in SMP assignments, \a false if not.
584    */
canSMPAssign()585    inline bool canSMPAssign() const noexcept {
586       return vector_.canSMPAssign() || ( size() > SMP_DVECSCALARMULT_THRESHOLD );
587    }
588    //**********************************************************************************************
589 
590  private:
591    //**Member variables****************************************************************************
592    LeftOperand  vector_;  //!< Left-hand side dense vector of the division expression.
593    RightOperand scalar_;  //!< Right-hand side scalar of the division expression.
594    //**********************************************************************************************
595 
596    //**Assignment to dense vectors*****************************************************************
597    /*! \cond BLAZE_INTERNAL */
598    /*!\brief Assignment of a dense vector-scalar division to a dense vector.
599    // \ingroup dense_vector
600    //
601    // \param lhs The target left-hand side dense vector.
602    // \param rhs The right-hand side division expression to be assigned.
603    // \return void
604    //
605    // This function implements the performance optimized assignment of a dense vector-scalar
606    // division expression to a dense vector. Due to the explicit application of the SFINAE
607    // principle, this function can only be selected by the compiler in case the vector
608    // operand is a computation expression and requires an intermediate evaluation.
609    */
610    template< typename VT2 >  // Type of the target dense vector
611    friend inline auto assign( DenseVector<VT2,TF>& lhs, const DVecScalarDivExpr& rhs )
612       -> EnableIf_t< UseAssign_v<VT2> >
613    {
614       BLAZE_FUNCTION_TRACE;
615 
616       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
617 
618       assign( *lhs, rhs.vector_ );
619       assign( *lhs, (*lhs) / rhs.scalar_ );
620    }
621    /*! \endcond */
622    //**********************************************************************************************
623 
624    //**Assignment to sparse vectors****************************************************************
625    /*! \cond BLAZE_INTERNAL */
626    /*!\brief Assignment of a dense vector-scalar division to a sparse vector.
627    // \ingroup dense_vector
628    //
629    // \param lhs The target left-hand side sparse vector.
630    // \param rhs The right-hand side division expression to be assigned.
631    // \return void
632    //
633    // This function implements the performance optimized assignment of a dense vector-scalar
634    // division expression to a sparse vector. Due to the explicit application of the SFINAE
635    // principle, this function can only be selected by the compiler in case the vector
636    // operand is a computation expression and requires an intermediate evaluation.
637    */
638    template< typename VT2 >  // Type of the target sparse vector
639    friend inline auto assign( SparseVector<VT2,TF>& lhs, const DVecScalarDivExpr& rhs )
640       -> EnableIf_t< UseAssign_v<VT2> >
641    {
642       BLAZE_FUNCTION_TRACE;
643 
644       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
645 
646       assign( *lhs, rhs.vector_ );
647       (*lhs) /= rhs.scalar_;
648    }
649    /*! \endcond */
650    //**********************************************************************************************
651 
652    //**Addition assignment to dense vectors********************************************************
653    /*! \cond BLAZE_INTERNAL */
654    /*!\brief Addition assignment of a dense vector-scalar division to a dense vector.
655    // \ingroup dense_vector
656    //
657    // \param lhs The target left-hand side dense vector.
658    // \param rhs The right-hand side division expression to be added.
659    // \return void
660    //
661    // This function implements the performance optimized addition assignment of a dense vector-
662    // scalar division expression to a dense vector. Due to the explicit application of the
663    // SFINAE principle, this function can only be selected by the compiler in case the vector
664    // operand is a computation expression and requires an intermediate evaluation.
665    */
666    template< typename VT2 >  // Type of the target dense vector
667    friend inline auto addAssign( DenseVector<VT2,TF>& lhs, const DVecScalarDivExpr& rhs )
668       -> EnableIf_t< UseAssign_v<VT2> >
669    {
670       BLAZE_FUNCTION_TRACE;
671 
672       BLAZE_CONSTRAINT_MUST_BE_DENSE_VECTOR_TYPE( ResultType );
673       BLAZE_CONSTRAINT_MUST_BE_VECTOR_WITH_TRANSPOSE_FLAG( ResultType, TF );
674       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( ResultType );
675 
676       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
677 
678       const ResultType tmp( serial( rhs ) );
679       addAssign( *lhs, tmp );
680    }
681    /*! \endcond */
682    //**********************************************************************************************
683 
684    //**Addition assignment to sparse vectors*******************************************************
685    // No special implementation for the addition assignment to sparse vectors.
686    //**********************************************************************************************
687 
688    //**Subtraction assignment to dense vectors*****************************************************
689    /*! \cond BLAZE_INTERNAL */
690    /*!\brief Subtraction assignment of a dense vector-scalar division to a dense vector.
691    // \ingroup dense_vector
692    //
693    // \param lhs The target left-hand side dense vector.
694    // \param rhs The right-hand side division expression to be subtracted.
695    // \return void
696    //
697    // This function implements the performance optimized subtraction assignment of a dense vector-
698    // scalar division expression to a dense vector. Due to the explicit application of the SFINAE
699    // principle, this function can only be selected by the compiler in case the vector operand is
700    // a computation expression and requires an intermediate evaluation.
701    */
702    template< typename VT2 >  // Type of the target dense vector
703    friend inline auto subAssign( DenseVector<VT2,TF>& lhs, const DVecScalarDivExpr& rhs )
704       -> EnableIf_t< UseAssign_v<VT2> >
705    {
706       BLAZE_FUNCTION_TRACE;
707 
708       BLAZE_CONSTRAINT_MUST_BE_DENSE_VECTOR_TYPE( ResultType );
709       BLAZE_CONSTRAINT_MUST_BE_VECTOR_WITH_TRANSPOSE_FLAG( ResultType, TF );
710       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( ResultType );
711 
712       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
713 
714       const ResultType tmp( serial( rhs ) );
715       subAssign( *lhs, tmp );
716    }
717    /*! \endcond */
718    //**********************************************************************************************
719 
720    //**Subtraction assignment to sparse vectors****************************************************
721    // No special implementation for the subtraction assignment to sparse vectors.
722    //**********************************************************************************************
723 
724    //**Multiplication assignment to dense vectors**************************************************
725    /*! \cond BLAZE_INTERNAL */
726    /*!\brief Multiplication assignment of a dense vector-scalar division to a dense vector.
727    // \ingroup dense_vector
728    //
729    // \param lhs The target left-hand side dense vector.
730    // \param rhs The right-hand side division expression to be multiplied.
731    // \return void
732    //
733    // This function implements the performance optimized multiplication assignment of a dense
734    // vector-scalar division expression to a dense vector. Due to the explicit application
735    // of the SFINAE principle, this function can only be selected by the compiler in case the
736    // vector operand is a computation expression and requires an intermediate evaluation.
737    */
738    template< typename VT2 >  // Type of the target dense vector
739    friend inline auto multAssign( DenseVector<VT2,TF>& lhs, const DVecScalarDivExpr& rhs )
740       -> EnableIf_t< UseAssign_v<VT2> >
741    {
742       BLAZE_FUNCTION_TRACE;
743 
744       BLAZE_CONSTRAINT_MUST_BE_DENSE_VECTOR_TYPE( ResultType );
745       BLAZE_CONSTRAINT_MUST_BE_VECTOR_WITH_TRANSPOSE_FLAG( ResultType, TF );
746       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( ResultType );
747 
748       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
749 
750       const ResultType tmp( serial( rhs ) );
751       multAssign( *lhs, tmp );
752    }
753    /*! \endcond */
754    //**********************************************************************************************
755 
756    //**Multiplication assignment to sparse vectors*************************************************
757    // No special implementation for the multiplication assignment to sparse vectors.
758    //**********************************************************************************************
759 
760    //**Division assignment to dense vectors********************************************************
761    /*! \cond BLAZE_INTERNAL */
762    /*!\brief Division assignment of a dense vector-scalar division to a dense vector.
763    // \ingroup dense_vector
764    //
765    // \param lhs The target left-hand side dense vector.
766    // \param rhs The right-hand side division expression divisor.
767    // \return void
768    //
769    // This function implements the performance optimized division assignment of a dense vector-
770    // scalar division expression to a dense vector. Due to the explicit application of the SFINAE
771    // principle, this function can only be selected by the compiler in case the vector operand
772    // is a computation expression and requires an intermediate evaluation.
773    */
774    template< typename VT2 >  // Type of the target dense vector
775    friend inline auto divAssign( DenseVector<VT2,TF>& lhs, const DVecScalarDivExpr& rhs )
776       -> EnableIf_t< UseAssign_v<VT2> >
777    {
778       BLAZE_FUNCTION_TRACE;
779 
780       BLAZE_CONSTRAINT_MUST_BE_DENSE_VECTOR_TYPE( ResultType );
781       BLAZE_CONSTRAINT_MUST_BE_VECTOR_WITH_TRANSPOSE_FLAG( ResultType, TF );
782       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( ResultType );
783 
784       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
785 
786       const ResultType tmp( serial( rhs ) );
787       divAssign( *lhs, tmp );
788    }
789    /*! \endcond */
790    //**********************************************************************************************
791 
792    //**Division assignment to sparse vectors*******************************************************
793    // No special implementation for the division assignment to sparse vectors.
794    //**********************************************************************************************
795 
796    //**SMP assignment to dense vectors*************************************************************
797    /*! \cond BLAZE_INTERNAL */
798    /*!\brief SMP assignment of a dense vector-scalar division to a dense vector.
799    // \ingroup dense_vector
800    //
801    // \param lhs The target left-hand side dense vector.
802    // \param rhs The right-hand side division expression to be assigned.
803    // \return void
804    //
805    // This function implements the performance optimized SMP assignment of a dense vector-
806    // scalar division expression to a dense vector. Due to the explicit application of the
807    // SFINAE principle, this function can only be selected by the compiler in case the
808    // expression specific parallel evaluation strategy is selected.
809    */
810    template< typename VT2 >  // Type of the target dense vector
811    friend inline auto smpAssign( DenseVector<VT2,TF>& lhs, const DVecScalarDivExpr& rhs )
812       -> EnableIf_t< UseSMPAssign_v<VT2> >
813    {
814       BLAZE_FUNCTION_TRACE;
815 
816       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
817 
818       smpAssign( *lhs, rhs.vector_ );
819       smpAssign( *lhs, (*lhs) / rhs.scalar_ );
820    }
821    /*! \endcond */
822    //**********************************************************************************************
823 
824    //**SMP assignment to sparse vectors************************************************************
825    /*! \cond BLAZE_INTERNAL */
826    /*!\brief SMP assignment of a dense vector-scalar division to a sparse vector.
827    // \ingroup dense_vector
828    //
829    // \param lhs The target left-hand side sparse vector.
830    // \param rhs The right-hand side division expression to be assigned.
831    // \return void
832    //
833    // This function implements the performance optimized SMP assignment of a dense vector-
834    // scalar division expression to a sparse vector. Due to the explicit application of
835    // the SFINAE principle, this function can only be selected by the compiler in case the
836    // expression specific parallel evaluation strategy is selected.
837    */
838    template< typename VT2 >  // Type of the target sparse vector
839    friend inline auto smpAssign( SparseVector<VT2,TF>& lhs, const DVecScalarDivExpr& rhs )
840       -> EnableIf_t< UseSMPAssign_v<VT2> >
841    {
842       BLAZE_FUNCTION_TRACE;
843 
844       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
845 
846       smpAssign( *lhs, rhs.vector_ );
847       (*lhs) /= rhs.scalar_;
848    }
849    /*! \endcond */
850    //**********************************************************************************************
851 
852    //**SMP addition assignment to dense vectors****************************************************
853    /*! \cond BLAZE_INTERNAL */
854    /*!\brief SMP addition assignment of a dense vector-scalar division to a dense vector.
855    // \ingroup dense_vector
856    //
857    // \param lhs The target left-hand side dense vector.
858    // \param rhs The right-hand side division expression to be added.
859    // \return void
860    //
861    // This function implements the performance optimized SMP addition assignment of a dense
862    // vector-scalar division expression to a dense vector. Due to the explicit application
863    // of the SFINAE principle, this function can only be selected by the compiler in case
864    // the expression specific parallel evaluation strategy is selected.
865    */
866    template< typename VT2 >  // Type of the target dense vector
867    friend inline auto smpAddAssign( DenseVector<VT2,TF>& lhs, const DVecScalarDivExpr& rhs )
868       -> EnableIf_t< UseSMPAssign_v<VT2> >
869    {
870       BLAZE_FUNCTION_TRACE;
871 
872       BLAZE_CONSTRAINT_MUST_BE_DENSE_VECTOR_TYPE( ResultType );
873       BLAZE_CONSTRAINT_MUST_BE_VECTOR_WITH_TRANSPOSE_FLAG( ResultType, TF );
874       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( ResultType );
875 
876       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
877 
878       const ResultType tmp( rhs );
879       smpAddAssign( *lhs, tmp );
880    }
881    /*! \endcond */
882    //**********************************************************************************************
883 
884    //**SMP addition assignment to sparse vectors***************************************************
885    // No special implementation for the SMP addition assignment to sparse vectors.
886    //**********************************************************************************************
887 
888    //**SMP subtraction assignment to dense vectors*************************************************
889    /*! \cond BLAZE_INTERNAL */
890    /*!\brief SMP subtraction assignment of a dense vector-scalar division to a dense vector.
891    // \ingroup dense_vector
892    //
893    // \param lhs The target left-hand side dense vector.
894    // \param rhs The right-hand side division expression to be subtracted.
895    // \return void
896    //
897    // This function implements the performance optimized SMP subtraction assignment of a dense
898    // vector-scalar division expression to a dense vector. Due to the explicit application of
899    // the SFINAE principle, this function can only be selected by the compiler in case the
900    // expression specific parallel evaluation strategy is selected.
901    */
902    template< typename VT2 >  // Type of the target dense vector
903    friend inline auto smpSubAssign( DenseVector<VT2,TF>& lhs, const DVecScalarDivExpr& rhs )
904       -> EnableIf_t< UseSMPAssign_v<VT2> >
905    {
906       BLAZE_FUNCTION_TRACE;
907 
908       BLAZE_CONSTRAINT_MUST_BE_DENSE_VECTOR_TYPE( ResultType );
909       BLAZE_CONSTRAINT_MUST_BE_VECTOR_WITH_TRANSPOSE_FLAG( ResultType, TF );
910       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( ResultType );
911 
912       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
913 
914       const ResultType tmp( rhs );
915       smpSubAssign( *lhs, tmp );
916    }
917    /*! \endcond */
918    //**********************************************************************************************
919 
920    //**SMP subtraction assignment to sparse vectors************************************************
921    // No special implementation for the SMP subtraction assignment to sparse vectors.
922    //**********************************************************************************************
923 
924    //**SMP multiplication assignment to dense vectors**********************************************
925    /*! \cond BLAZE_INTERNAL */
926    /*!\brief SMP multiplication assignment of a dense vector-scalar division to a dense vector.
927    // \ingroup dense_vector
928    //
929    // \param lhs The target left-hand side dense vector.
930    // \param rhs The right-hand side division expression to be multiplied.
931    // \return void
932    //
933    // This function implements the performance optimized SMP multiplication assignment of a
934    // dense vector-scalar division expression to a dense vector. Due to the explicit application
935    // of the SFINAE principle, this function can only be selected by the compiler in case the
936    // expression specific parallel evaluation strategy is selected.
937    */
938    template< typename VT2 >  // Type of the target dense vector
939    friend inline auto smpMultAssign( DenseVector<VT2,TF>& lhs, const DVecScalarDivExpr& rhs )
940       -> EnableIf_t< UseSMPAssign_v<VT2> >
941    {
942       BLAZE_FUNCTION_TRACE;
943 
944       BLAZE_CONSTRAINT_MUST_BE_DENSE_VECTOR_TYPE( ResultType );
945       BLAZE_CONSTRAINT_MUST_BE_VECTOR_WITH_TRANSPOSE_FLAG( ResultType, TF );
946       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( ResultType );
947 
948       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
949 
950       const ResultType tmp( rhs );
951       smpMultAssign( *lhs, tmp );
952    }
953    /*! \endcond */
954    //**********************************************************************************************
955 
956    //**SMP multiplication assignment to sparse vectors*********************************************
957    // No special implementation for the SMP multiplication assignment to sparse vectors.
958    //**********************************************************************************************
959 
960    //**SMP division assignment to dense vectors****************************************************
961    /*! \cond BLAZE_INTERNAL */
962    /*!\brief SMP division assignment of a dense vector-scalar division to a dense vector.
963    // \ingroup dense_vector
964    //
965    // \param lhs The target left-hand side dense vector.
966    // \param rhs The right-hand side division expression divisor.
967    // \return void
968    //
969    // This function implements the performance optimized SMP division assignment of a dense
970    // vector-scalar division expression to a dense vector. Due to the explicit application of
971    // the SFINAE principle, this function can only be selected by the compiler in case the
972    // expression specific parallel evaluation strategy is selected.
973    */
974    template< typename VT2 >  // Type of the target dense vector
975    friend inline auto smpDivAssign( DenseVector<VT2,TF>& lhs, const DVecScalarDivExpr& rhs )
976       -> EnableIf_t< UseSMPAssign_v<VT2> >
977    {
978       BLAZE_FUNCTION_TRACE;
979 
980       BLAZE_CONSTRAINT_MUST_BE_DENSE_VECTOR_TYPE( ResultType );
981       BLAZE_CONSTRAINT_MUST_BE_VECTOR_WITH_TRANSPOSE_FLAG( ResultType, TF );
982       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( ResultType );
983 
984       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
985 
986       const ResultType tmp( rhs );
987       smpDivAssign( *lhs, tmp );
988    }
989    /*! \endcond */
990    //**********************************************************************************************
991 
992    //**SMP division assignment to sparse vectors***************************************************
993    // No special implementation for the SMP division assignment to sparse vectors.
994    //**********************************************************************************************
995 
996    //**Compile time checks*************************************************************************
997    /*! \cond BLAZE_INTERNAL */
998    BLAZE_CONSTRAINT_MUST_BE_DENSE_VECTOR_TYPE( VT );
999    BLAZE_CONSTRAINT_MUST_BE_VECTOR_WITH_TRANSPOSE_FLAG( VT, TF );
1000    BLAZE_CONSTRAINT_MUST_BE_SCALAR_TYPE( ST );
1001    BLAZE_CONSTRAINT_MUST_NOT_BE_FLOATING_POINT_TYPE( ST );
1002    BLAZE_CONSTRAINT_MUST_NOT_BE_FLOATING_POINT_TYPE( ElementType );
1003    BLAZE_CONSTRAINT_MUST_BE_SAME_TYPE( ST, RightOperand );
1004    /*! \endcond */
1005    //**********************************************************************************************
1006 };
1007 //*************************************************************************************************
1008 
1009 
1010 
1011 
1012 //=================================================================================================
1013 //
1014 //  GLOBAL BINARY ARITHMETIC OPERATORS
1015 //
1016 //=================================================================================================
1017 
1018 //*************************************************************************************************
1019 /*! \cond BLAZE_INTERNAL */
1020 /*!\brief Auxiliary helper struct for the dense vector/scalar division operator.
1021 // \ingroup dense_vector
1022 */
1023 template< typename VT    // Type of the left-hand side dense vector
1024         , typename ST >  // Type of the right-hand side scalar
1025 using DVecScalarDivExprHelper_t =
1026    If_t< IsFloatingPoint_v< UnderlyingBuiltin_t<VT> > ||
1027          IsFloatingPoint_v< UnderlyingBuiltin_t<ST> >
1028        , If_t< IsBuiltin_v<ST>
1029              , DivTrait_t< UnderlyingBuiltin_t<VT>, ST >
1030              , decltype( inv( std::declval<ST>() ) ) >
1031        , ST >;
1032 /*! \endcond */
1033 //*************************************************************************************************
1034 
1035 
1036 //*************************************************************************************************
1037 /*! \cond BLAZE_INTERNAL */
1038 /*!\brief Backend implementation of the division between a dense vector and a scalar value
1039 //        (\f$ \vec{a}=\vec{b}/s \f$).
1040 // \ingroup dense_vector
1041 //
1042 // \param vec The left-hand side dense vector for the division.
1043 // \param scalar The right-hand side scalar value for the division.
1044 // \return The scaled result vector.
1045 //
1046 // This function implements the default treatment of the dense vector/scalar division.
1047 */
1048 template< typename VT  // Type of the left-hand side sparse vector
1049         , bool TF      // Transpose flag of the left-hand side sparse vector
1050         , typename ST  // Type of the right-hand side scalar
1051         , EnableIf_t< !IsInvertible_v< DVecScalarDivExprHelper_t<VT,ST> > >* = nullptr >
decltype(auto)1052 inline decltype(auto) dvecscalardiv( const DenseVector<VT,TF>& vec, ST scalar )
1053 {
1054    BLAZE_FUNCTION_TRACE;
1055 
1056    using ScalarType = DVecScalarDivExprHelper_t<VT,ST>;
1057    using ReturnType = const DVecScalarDivExpr<VT,ScalarType,TF>;
1058 
1059    return ReturnType( *vec, scalar );
1060 }
1061 /*! \endcond */
1062 //*************************************************************************************************
1063 
1064 
1065 //*************************************************************************************************
1066 /*! \cond BLAZE_INTERNAL */
1067 /*!\brief Backend implementation of the division between a dense vector and a scalar value
1068 //        (\f$ \vec{a}=\vec{b}/s \f$).
1069 // \ingroup dense_vector
1070 //
1071 // \param vec The left-hand side dense vector for the division.
1072 // \param scalar The right-hand side scalar value for the division.
1073 // \return The scaled result vector.
1074 //
1075 // This function implements a performance optimized treatment of the dense vector/scalar division.
1076 */
1077 template< typename VT  // Type of the left-hand side sparse vector
1078         , bool TF      // Transpose flag of the left-hand side sparse vector
1079         , typename ST  // Type of the right-hand side scalar
1080         , EnableIf_t< IsInvertible_v< DVecScalarDivExprHelper_t<VT,ST> > >* = nullptr >
decltype(auto)1081 inline decltype(auto) dvecscalardiv( const DenseVector<VT,TF>& vec, ST scalar )
1082 {
1083    BLAZE_FUNCTION_TRACE;
1084 
1085    using ScalarType = DVecScalarDivExprHelper_t<VT,ST>;
1086    using ReturnType = const DVecScalarMultExpr<VT,ScalarType,TF>;
1087 
1088    return ReturnType( *vec, inv(scalar) );
1089 }
1090 /*! \endcond */
1091 //*************************************************************************************************
1092 
1093 
1094 //*************************************************************************************************
1095 /*!\brief Division operator for the divison of a dense vector by a scalar value
1096 //        (\f$ \vec{a}=\vec{b}/s \f$).
1097 // \ingroup dense_vector
1098 //
1099 // \param vec The left-hand side dense vector for the division.
1100 // \param scalar The right-hand side scalar value for the division.
1101 // \return The scaled result vector.
1102 //
1103 // This operator represents the division of a dense vector by a scalar value:
1104 
1105    \code
1106    blaze::DynamicVector<double> a, b;
1107    // ... Resizing and initialization
1108    b = a / 0.24;
1109    \endcode
1110 
1111 // The operator returns an expression representing a dense vector of the higher-order
1112 // element type of the involved data types \a VT::ElementType and \a ST. Both data types
1113 // \a VT::ElementType and \a ST have to be supported by the DivTrait class template.
1114 // Note that this operator only works for scalar values of built-in data type.
1115 //
1116 // \note A division by zero is only checked by an user assert.
1117 */
1118 template< typename VT  // Type of the left-hand side dense vector
1119         , typename ST  // Type of the right-hand side scalar
1120         , bool TF      // Transpose flag
1121         , EnableIf_t< IsScalar_v<ST> >* = nullptr >
1122 inline decltype(auto) operator/( const DenseVector<VT,TF>& vec, ST scalar )
1123 {
1124    BLAZE_FUNCTION_TRACE;
1125 
1126    BLAZE_USER_ASSERT( scalar != ST{}, "Division by zero detected" );
1127 
1128    return dvecscalardiv( *vec, scalar );
1129 }
1130 //*************************************************************************************************
1131 
1132 
1133 
1134 
1135 //=================================================================================================
1136 //
1137 //  ISALIGNED SPECIALIZATIONS
1138 //
1139 //=================================================================================================
1140 
1141 //*************************************************************************************************
1142 /*! \cond BLAZE_INTERNAL */
1143 template< typename VT, typename ST, bool TF >
1144 struct IsAligned< DVecScalarDivExpr<VT,ST,TF> >
1145    : public IsAligned<VT>
1146 {};
1147 /*! \endcond */
1148 //*************************************************************************************************
1149 
1150 
1151 
1152 
1153 //=================================================================================================
1154 //
1155 //  ISPADDED SPECIALIZATIONS
1156 //
1157 //=================================================================================================
1158 
1159 //*************************************************************************************************
1160 /*! \cond BLAZE_INTERNAL */
1161 template< typename VT, typename ST, bool TF >
1162 struct IsPadded< DVecScalarDivExpr<VT,ST,TF> >
1163    : public IsPadded<VT>
1164 {};
1165 /*! \endcond */
1166 //*************************************************************************************************
1167 
1168 } // namespace blaze
1169 
1170 #endif
1171