Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 10:25:47

0001 /*  This file is part of the Vc library. {{{
0002 Copyright © 2009-2015 Matthias Kretz <kretz@kde.org>
0003 
0004 Redistribution and use in source and binary forms, with or without
0005 modification, are permitted provided that the following conditions are met:
0006     * Redistributions of source code must retain the above copyright
0007       notice, this list of conditions and the following disclaimer.
0008     * Redistributions in binary form must reproduce the above copyright
0009       notice, this list of conditions and the following disclaimer in the
0010       documentation and/or other materials provided with the distribution.
0011     * Neither the names of contributing organizations nor the
0012       names of its contributors may be used to endorse or promote products
0013       derived from this software without specific prior written permission.
0014 
0015 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
0016 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
0017 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0018 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
0019 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
0020 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
0021 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0022 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0023 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0024 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0025 
0026 }}}*/
0027 
0028 #ifndef VC_COMMON_MEMORYBASE_H_
0029 #define VC_COMMON_MEMORYBASE_H_
0030 
0031 #include <assert.h>
0032 #include <type_traits>
0033 #include <iterator>
0034 #include "macros.h"
0035 
0036 namespace Vc_VERSIONED_NAMESPACE
0037 {
0038 namespace Common
0039 {
0040 
0041 #define Vc_MEM_OPERATOR_EQ(op) \
0042         template<typename T> \
0043         Vc_ALWAYS_INLINE enable_if_mutable<T, MemoryVector &> operator op##=(const T &x) { \
0044             const V v = value() op x; \
0045             v.store(&m_data[0], Flags()); \
0046             return *this; \
0047         }
0048 /*dox{{{*/
0049 /**
0050  * Helper class for the Memory::vector(size_t) class of functions.
0051  *
0052  * You will never need to directly make use of this class. It is an implementation detail of the
0053  * Memory API.
0054  *
0055  * \headerfile memorybase.h <Vc/Memory>
0056  *//*}}}*/
0057 template<typename _V, typename Flags> class MemoryVector/*{{{*/
0058 {
0059     typedef typename std::remove_cv<_V>::type V;
0060 
0061     template<typename T, typename R> using enable_if_mutable =
0062         typename std::enable_if<std::is_same<T, T>::value && !std::is_const<_V>::value, R>::type;
0063 
0064     using EntryType =
0065         typename std::conditional<std::is_const<_V>::value, const typename V::EntryType,
0066                                   typename V::EntryType>::type;
0067     typedef typename V::Mask Mask;
0068 
0069     EntryType m_data[V::Size];
0070 
0071 public:
0072         // It is important that neither initialization nor cleanup is done as MemoryVector aliases
0073         // other memory
0074         Vc_INTRINSIC MemoryVector() = default;
0075 
0076         // disable copies because this type is supposed to alias the data in a Memory object,
0077         // nothing else
0078         MemoryVector(const MemoryVector &) = delete;
0079         MemoryVector(MemoryVector &&) = delete;
0080         // Do not disable MemoryVector &operator=(const MemoryVector &) = delete; because it is
0081         // covered nicely by the operator= below.
0082 
0083         //! \internal
0084         Vc_ALWAYS_INLINE Vc_PURE V value() const { return V(&m_data[0], Flags()); }
0085 
0086         /**
0087          * Cast to \p V operator.
0088          *
0089          * This function allows to assign this object to any object of type \p V.
0090          */
0091         Vc_ALWAYS_INLINE Vc_PURE operator V() const { return value(); }
0092 
0093         template<typename T>
0094         Vc_ALWAYS_INLINE enable_if_mutable<T, MemoryVector &> operator=(const T &x) {
0095             V v;
0096             v = x;
0097             v.store(&m_data[0], Flags());
0098             return *this;
0099         }
0100 
0101         Vc_ALL_BINARY(Vc_MEM_OPERATOR_EQ);
0102         Vc_ALL_ARITHMETICS(Vc_MEM_OPERATOR_EQ);
0103 
0104     Vc_ALWAYS_INLINE EntryType &operator[](size_t i) { return m_data[i]; }
0105     Vc_ALWAYS_INLINE const EntryType &operator[](size_t i) const { return m_data[i]; }
0106 };
0107 
0108 template<typename _V, typename Flags> class MemoryVectorIterator
0109 {
0110     typedef typename std::remove_cv<_V>::type V;
0111 
0112     template<typename T, typename R> using enable_if_mutable =
0113         typename std::enable_if<std::is_same<T, T>::value && !std::is_const<_V>::value, R>::type;
0114 
0115     using iterator_traits = std::iterator_traits<MemoryVector<_V, Flags> *>;
0116 
0117     MemoryVector<_V, Flags> *d;
0118 public:
0119     typedef typename iterator_traits::difference_type difference_type;
0120     typedef typename iterator_traits::value_type value_type;
0121     typedef typename iterator_traits::pointer pointer;
0122     typedef typename iterator_traits::reference reference;
0123     typedef typename iterator_traits::iterator_category iterator_category;
0124 
0125     constexpr MemoryVectorIterator(MemoryVector<_V, Flags> *dd) : d(dd) {}
0126     constexpr MemoryVectorIterator(const MemoryVectorIterator &) = default;
0127     constexpr MemoryVectorIterator(MemoryVectorIterator &&) = default;
0128     Vc_ALWAYS_INLINE MemoryVectorIterator &operator=(const MemoryVectorIterator &) = default;
0129 
0130     Vc_ALWAYS_INLINE void *orderBy() const { return d; }
0131 
0132     Vc_ALWAYS_INLINE difference_type operator-(const MemoryVectorIterator &rhs) const { return d - rhs.d; }
0133     Vc_ALWAYS_INLINE reference operator[](size_t i) const { return d[i]; }
0134     Vc_ALWAYS_INLINE reference operator*() const { return *d; }
0135     Vc_ALWAYS_INLINE pointer operator->() const { return d; }
0136     Vc_ALWAYS_INLINE MemoryVectorIterator &operator++() { ++d; return *this; }
0137     Vc_ALWAYS_INLINE MemoryVectorIterator operator++(int) { MemoryVectorIterator r(*this); ++d; return r; }
0138     Vc_ALWAYS_INLINE MemoryVectorIterator &operator--() { --d; return *this; }
0139     Vc_ALWAYS_INLINE MemoryVectorIterator operator--(int) { MemoryVectorIterator r(*this); --d; return r; }
0140     Vc_ALWAYS_INLINE MemoryVectorIterator &operator+=(size_t n) { d += n; return *this; }
0141     Vc_ALWAYS_INLINE MemoryVectorIterator &operator-=(size_t n) { d -= n; return *this; }
0142     Vc_ALWAYS_INLINE MemoryVectorIterator operator+(size_t n) const { return MemoryVectorIterator(d + n); }
0143     Vc_ALWAYS_INLINE MemoryVectorIterator operator-(size_t n) const { return MemoryVectorIterator(d - n); }
0144 };
0145 
0146 template<typename V, typename FlagsL, typename FlagsR>
0147 Vc_ALWAYS_INLINE bool operator==(const MemoryVectorIterator<V, FlagsL> &l, const MemoryVectorIterator<V, FlagsR> &r)
0148 {
0149     return l.orderBy() == r.orderBy();
0150 }
0151 template<typename V, typename FlagsL, typename FlagsR>
0152 Vc_ALWAYS_INLINE bool operator!=(const MemoryVectorIterator<V, FlagsL> &l, const MemoryVectorIterator<V, FlagsR> &r)
0153 {
0154     return l.orderBy() != r.orderBy();
0155 }
0156 template<typename V, typename FlagsL, typename FlagsR>
0157 Vc_ALWAYS_INLINE bool operator>=(const MemoryVectorIterator<V, FlagsL> &l, const MemoryVectorIterator<V, FlagsR> &r)
0158 {
0159     return l.orderBy() >= r.orderBy();
0160 }
0161 template<typename V, typename FlagsL, typename FlagsR>
0162 Vc_ALWAYS_INLINE bool operator<=(const MemoryVectorIterator<V, FlagsL> &l, const MemoryVectorIterator<V, FlagsR> &r)
0163 {
0164     return l.orderBy() <= r.orderBy();
0165 }
0166 template<typename V, typename FlagsL, typename FlagsR>
0167 Vc_ALWAYS_INLINE bool operator> (const MemoryVectorIterator<V, FlagsL> &l, const MemoryVectorIterator<V, FlagsR> &r)
0168 {
0169     return l.orderBy() >  r.orderBy();
0170 }
0171 template<typename V, typename FlagsL, typename FlagsR>
0172 Vc_ALWAYS_INLINE bool operator< (const MemoryVectorIterator<V, FlagsL> &l, const MemoryVectorIterator<V, FlagsR> &r)
0173 {
0174     return l.orderBy() <  r.orderBy();
0175 }
0176 /*}}}*/
0177 #undef Vc_MEM_OPERATOR_EQ
0178 
0179 #define Vc_VPH_OPERATOR(op)                                                              \
0180     template <typename V1, typename Flags1, typename V2, typename Flags2>                \
0181     decltype(std::declval<V1>() op std::declval<V2>()) operator op(                      \
0182         const MemoryVector<V1, Flags1> &x, const MemoryVector<V2, Flags2> &y)            \
0183     {                                                                                    \
0184         return x.value() op y.value();                                                   \
0185     }
0186 Vc_ALL_ARITHMETICS(Vc_VPH_OPERATOR);
0187 Vc_ALL_BINARY     (Vc_VPH_OPERATOR);
0188 Vc_ALL_COMPARES   (Vc_VPH_OPERATOR);
0189 #undef Vc_VPH_OPERATOR
0190 
0191 template<typename V, typename Parent, typename Flags = Prefetch<>> class MemoryRange/*{{{*/
0192 {
0193     Parent *m_parent;
0194     size_t m_first;
0195     size_t m_last;
0196 
0197 public:
0198     MemoryRange(Parent *p, size_t firstIndex, size_t lastIndex)
0199         : m_parent(p), m_first(firstIndex), m_last(lastIndex)
0200     {}
0201 
0202     MemoryVectorIterator<V, Flags> begin() const { return &m_parent->vector(m_first   , Flags()); }
0203     MemoryVectorIterator<V, Flags> end() const   { return &m_parent->vector(m_last + 1, Flags()); }
0204 };/*}}}*/
0205 template<typename V, typename Parent, int Dimension, typename RowMemory> class MemoryDimensionBase;
0206 template<typename V, typename Parent, typename RowMemory> class MemoryDimensionBase<V, Parent, 1, RowMemory> // {{{1
0207 {
0208     private:
0209         Parent *p() { return static_cast<Parent *>(this); }
0210         const Parent *p() const { return static_cast<const Parent *>(this); }
0211     public:
0212         /**
0213          * The type of the scalar entries in the array.
0214          */
0215         typedef typename V::EntryType EntryType;
0216 
0217         /**
0218          * Returns a pointer to the start of the allocated memory.
0219          */
0220         Vc_ALWAYS_INLINE Vc_PURE       EntryType *entries()       { return &p()->m_mem[0]; }
0221         /// Const overload of the above function.
0222         Vc_ALWAYS_INLINE Vc_PURE const EntryType *entries() const { return &p()->m_mem[0]; }
0223 
0224         /**
0225          * Returns the \p i-th scalar value in the memory.
0226          */
0227         Vc_ALWAYS_INLINE Vc_PURE EntryType &scalar(size_t i) { return entries()[i]; }
0228         /// Const overload of the above function.
0229         Vc_ALWAYS_INLINE Vc_PURE const EntryType scalar(size_t i) const { return entries()[i]; }
0230 
0231 #ifdef DOXYGEN
0232         /**
0233          * Cast operator to the scalar type. This allows to use the object very much like a standard
0234          * C array.
0235          */
0236         Vc_ALWAYS_INLINE Vc_PURE operator       EntryType*()       { return entries(); }
0237         /// Const overload of the above function.
0238         Vc_ALWAYS_INLINE Vc_PURE operator const EntryType*() const { return entries(); }
0239 #else
0240         // The above conversion operator allows implicit conversion to bool. To prohibit this
0241         // conversion we use SFINAE to allow only conversion to EntryType* and void*.
0242         template <typename T,
0243                   typename std::enable_if<
0244                       std::is_same<typename std::remove_const<T>::type, EntryType *>::value ||
0245                           std::is_same<typename std::remove_const<T>::type, void *>::value,
0246                       int>::type = 0>
0247         Vc_ALWAYS_INLINE Vc_PURE operator T()
0248         {
0249             return entries();
0250         }
0251         template <typename T,
0252                   typename std::enable_if<std::is_same<T, const EntryType *>::value ||
0253                                               std::is_same<T, const void *>::value,
0254                                           int>::type = 0>
0255         Vc_ALWAYS_INLINE Vc_PURE operator T() const
0256         {
0257             return entries();
0258         }
0259 #endif
0260 
0261         /**
0262          *
0263          */
0264         template<typename Flags>
0265         Vc_ALWAYS_INLINE MemoryRange<V, Parent, Flags> range(size_t firstIndex, size_t lastIndex, Flags) {
0266             return MemoryRange<V, Parent, Flags>(p(), firstIndex, lastIndex);
0267         }
0268         Vc_ALWAYS_INLINE MemoryRange<V, Parent> range(size_t firstIndex, size_t lastIndex) {
0269             return MemoryRange<V, Parent>(p(), firstIndex, lastIndex);
0270         }
0271         template<typename Flags>
0272         Vc_ALWAYS_INLINE MemoryRange<const V, Parent, Flags> range(size_t firstIndex, size_t lastIndex, Flags) const {
0273             return MemoryRange<const V, Parent, Flags>(p(), firstIndex, lastIndex);
0274         }
0275         Vc_ALWAYS_INLINE MemoryRange<const V, Parent> range(size_t firstIndex, size_t lastIndex) const {
0276             return MemoryRange<const V, Parent>(p(), firstIndex, lastIndex);
0277         }
0278 
0279         /**
0280          * Returns the \p i-th scalar value in the memory.
0281          */
0282         Vc_ALWAYS_INLINE EntryType &operator[](size_t i) { return entries()[i]; }
0283         /// Const overload of the above function.
0284         Vc_ALWAYS_INLINE const EntryType &operator[](size_t i) const { return entries()[i]; }
0285 
0286         /**
0287          * Uses a vector gather to combine the entries at the indexes in \p i into the returned
0288          * vector object.
0289          *
0290          * \param i  An integer vector. It determines the entries to be gathered.
0291          * \returns  A vector object. Modification of this object will not modify the values in
0292          *           memory.
0293          *
0294          * \warning  The API of this function might change in future versions of Vc to additionally
0295          *           support scatters.
0296          */
0297         template<typename IndexT> Vc_ALWAYS_INLINE Vc_PURE V operator[](Vector<IndexT> i) const
0298         {
0299             return V(entries(), i);
0300         }
0301 };
0302 template<typename V, typename Parent, typename RowMemory> class MemoryDimensionBase<V, Parent, 2, RowMemory> // {{{1
0303 {
0304     private:
0305         Parent *p() { return static_cast<Parent *>(this); }
0306         const Parent *p() const { return static_cast<const Parent *>(this); }
0307     public:
0308         /**
0309          * The type of the scalar entries in the array.
0310          */
0311         typedef typename V::EntryType EntryType;
0312 
0313         static constexpr size_t rowCount() { return Parent::RowCount; }
0314 
0315         /**
0316          * Returns a pointer to the start of the allocated memory.
0317          */
0318         Vc_ALWAYS_INLINE Vc_PURE       EntryType *entries(size_t x = 0)       { return &p()->m_mem[x][0]; }
0319         /// Const overload of the above function.
0320         Vc_ALWAYS_INLINE Vc_PURE const EntryType *entries(size_t x = 0) const { return &p()->m_mem[x][0]; }
0321 
0322         /**
0323          * Returns the \p i,j-th scalar value in the memory.
0324          */
0325         Vc_ALWAYS_INLINE Vc_PURE EntryType &scalar(size_t i, size_t j) { return entries(i)[j]; }
0326         /// Const overload of the above function.
0327         Vc_ALWAYS_INLINE Vc_PURE const EntryType scalar(size_t i, size_t j) const { return entries(i)[j]; }
0328 
0329         /**
0330          * Returns the \p i-th row in the memory.
0331          */
0332         Vc_ALWAYS_INLINE Vc_PURE RowMemory &operator[](size_t i) {
0333             return p()->m_mem[i];
0334         }
0335         /// Const overload of the above function.
0336         Vc_ALWAYS_INLINE Vc_PURE const RowMemory &operator[](size_t i) const {
0337             return p()->m_mem[i];
0338         }
0339 
0340         /**
0341          * \return the number of rows in the array.
0342          *
0343          * \note This function can be eliminated by an optimizing compiler.
0344          */
0345         Vc_ALWAYS_INLINE Vc_PURE size_t rowsCount() const { return p()->rowsCount(); }
0346 };
0347 
0348 //dox{{{1
0349 /**
0350  * \headerfile memorybase.h <Vc/Memory>
0351  *
0352  * Common interface to all Memory classes, independent of allocation on the stack or heap.
0353  *
0354  * \param V The vector type you want to operate on. (e.g. float_v or uint_v)
0355  * \param Parent This type is the complete type of the class that derives from MemoryBase.
0356  * \param Dimension The number of dimensions the implementation provides.
0357  * \param RowMemory Class to be used to work on a single row.
0358  */
0359 template<typename V, typename Parent, int Dimension, typename RowMemory> class MemoryBase : public MemoryDimensionBase<V, Parent, Dimension, RowMemory> //{{{1
0360 {
0361     static_assert((V::size() * sizeof(typename V::EntryType)) % V::MemoryAlignment == 0,
0362                   "Vc::Memory can only be used for data-parallel types storing a number "
0363                   "of values that's a multiple of the memory alignment.");
0364 
0365     private:
0366         Parent *p() { return static_cast<Parent *>(this); }
0367         const Parent *p() const { return static_cast<const Parent *>(this); }
0368 
0369         template <class Flags>
0370         using vector_reference = MayAlias<MemoryVector<V, Flags>> &;
0371         template <class Flags>
0372         using const_vector_reference = const MayAlias<MemoryVector<const V, Flags>> &;
0373 
0374     public:
0375         /**
0376          * The type of the scalar entries in the array.
0377          */
0378         typedef typename V::EntryType EntryType;
0379 
0380         /**
0381          * \return the number of scalar entries in the array. This function is optimized away
0382          * if a constant size array is used.
0383          */
0384         Vc_ALWAYS_INLINE Vc_PURE size_t entriesCount() const { return p()->entriesCount(); }
0385         /**
0386          * \return the number of vector entries that span the array. This function is optimized away
0387          * if a constant size array is used.
0388          */
0389         Vc_ALWAYS_INLINE Vc_PURE size_t vectorsCount() const { return p()->vectorsCount(); }
0390 
0391         using MemoryDimensionBase<V, Parent, Dimension, RowMemory>::entries;
0392         using MemoryDimensionBase<V, Parent, Dimension, RowMemory>::scalar;
0393 
0394         /**
0395          * Return a (vectorized) iterator to the start of this memory object.
0396          */
0397         template<typename Flags = AlignedTag>
0398         Vc_ALWAYS_INLINE MemoryVectorIterator<      V, Flags> begin(Flags flags = Flags())       { return &firstVector(flags); }
0399         //! const overload of the above
0400         template<typename Flags = AlignedTag>
0401         Vc_ALWAYS_INLINE MemoryVectorIterator<const V, Flags> begin(Flags flags = Flags()) const { return &firstVector(flags); }
0402 
0403         /**
0404          * Return a (vectorized) iterator to the end of this memory object.
0405          */
0406         template<typename Flags = AlignedTag>
0407         Vc_ALWAYS_INLINE MemoryVectorIterator<      V, Flags>   end(Flags flags = Flags())       { return &lastVector(flags) + 1; }
0408         //! const overload of the above
0409         template<typename Flags = AlignedTag>
0410         Vc_ALWAYS_INLINE MemoryVectorIterator<const V, Flags>   end(Flags flags = Flags()) const { return &lastVector(flags) + 1; }
0411 
0412         /**
0413          * \param i Selects the offset, where the vector should be read.
0414          *
0415          * \return a smart object to wrap the \p i-th vector in the memory.
0416          *
0417          * The return value can be used as any other vector object. I.e. you can substitute
0418          * something like
0419          * \code
0420          * float_v a = ..., b = ...;
0421          * a += b;
0422          * \endcode
0423          * with
0424          * \code
0425          * mem.vector(i) += b;
0426          * \endcode
0427          *
0428          * This function ensures that only \em aligned loads and stores are used. Thus it only allows to
0429          * access memory at fixed strides. If access to known offsets from the aligned vectors is
0430          * needed the vector(size_t, int) function can be used.
0431          */
0432         template <typename Flags = AlignedTag>
0433         Vc_ALWAYS_INLINE Vc_PURE
0434             typename std::enable_if<!std::is_convertible<Flags, int>::value,
0435                                     vector_reference<Flags>>::type
0436             vector(size_t i, Flags = Flags())
0437         {
0438             return *aliasing_cast<MemoryVector<V, Flags>>(&entries()[i * V::Size]);
0439         }
0440         /** \brief Const overload of the above function
0441          *
0442          * \param i Selects the offset, where the vector should be read.
0443          *
0444          * \return a smart object to wrap the \p i-th vector in the memory.
0445          */
0446         template <typename Flags = AlignedTag>
0447         Vc_ALWAYS_INLINE Vc_PURE
0448             typename std::enable_if<!std::is_convertible<Flags, int>::value,
0449                                     const_vector_reference<Flags>>::type
0450             vector(size_t i, Flags = Flags()) const
0451         {
0452             return *aliasing_cast<MemoryVector<const V, Flags>>(&entries()[i * V::Size]);
0453         }
0454 
0455         /**
0456          * \return a smart object to wrap the vector starting from the \p i-th scalar entry in the memory.
0457          *
0458          * Example:
0459          * \code
0460          * Memory<float_v, N> mem;
0461          * mem.setZero();
0462          * for (int i = 0; i < mem.entriesCount(); i += float_v::Size) {
0463          *     mem.vectorAt(i) += b;
0464          * }
0465          * \endcode
0466          *
0467          * \param i      Specifies the scalar entry from where the vector will be loaded/stored. I.e. the
0468          * values scalar(i), scalar(i + 1), ..., scalar(i + V::Size - 1) will be read/overwritten.
0469          *
0470          * \param flags  You must take care to determine whether an unaligned load/store is
0471          * required. Per default an unaligned load/store is used. If \p i is a multiple of \c V::Size
0472          * you may want to pass Vc::Aligned here.
0473          */
0474         template <typename Flags = UnalignedTag>
0475         Vc_ALWAYS_INLINE Vc_PURE vector_reference<Flags> vectorAt(size_t i,
0476                                                                   Flags flags = Flags())
0477         {
0478             return *aliasing_cast<MemoryVector<V, Flags>>(&entries()[i]);
0479         }
0480         /** \brief Const overload of the above function
0481          *
0482          * \return a smart object to wrap the vector starting from the \p i-th scalar entry in the memory.
0483          *
0484          * \param i      Specifies the scalar entry from where the vector will be loaded/stored. I.e. the
0485          * values scalar(i), scalar(i + 1), ..., scalar(i + V::Size - 1) will be read/overwritten.
0486          *
0487          * \param flags  You must take care to determine whether an unaligned load/store is
0488          * required. Per default an unaligned load/store is used. If \p i is a multiple of \c V::Size
0489          * you may want to pass Vc::Aligned here.
0490          */
0491         template <typename Flags = UnalignedTag>
0492         Vc_ALWAYS_INLINE Vc_PURE const_vector_reference<Flags> vectorAt(
0493             size_t i, Flags flags = Flags()) const
0494         {
0495             return *aliasing_cast<MemoryVector<const V, Flags>>(&entries()[i]);
0496         }
0497 
0498         /**
0499          * \return a smart object to wrap the \p i-th vector + \p shift in the memory.
0500          *
0501          * This function ensures that only \em unaligned loads and stores are used.
0502          * It allows to access memory at any location aligned to the entry type.
0503          *
0504          * \param i Selects the memory location of the i-th vector. Thus if \p V::Size == 4 and
0505          *          \p i is set to 3 the base address for the load/store will be the 12th entry
0506          *          (same as \p &mem[12]).
0507          * \param shift Shifts the base address determined by parameter \p i by \p shift many
0508          *              entries. Thus \p vector(3, 1) for \p V::Size == 4 will load/store the
0509          *              13th - 16th entries (same as \p &mem[13]).
0510          *
0511          * \note Any shift value is allowed as long as you make sure it stays within bounds of the
0512          * allocated memory. Shift values that are a multiple of \p V::Size will \em not result in
0513          * aligned loads. You have to use the above vector(size_t) function for aligned loads
0514          * instead.
0515          *
0516          * \note Thus a simple way to access vectors randomly is to set \p i to 0 and use \p shift as the
0517          * parameter to select the memory address:
0518          * \code
0519          * // don't use:
0520          * mem.vector(i / V::Size, i % V::Size) += 1;
0521          * // instead use:
0522          * mem.vector(0, i) += 1;
0523          * \endcode
0524          */
0525         template <typename ShiftT, typename Flags = decltype(Unaligned)>
0526         Vc_ALWAYS_INLINE Vc_PURE typename std::enable_if<
0527             std::is_convertible<ShiftT, int>::value,
0528             vector_reference<decltype(std::declval<Flags>() | Unaligned)>>::type
0529         vector(size_t i, ShiftT shift, Flags = Flags())
0530         {
0531             return *aliasing_cast<
0532                 MemoryVector<V, decltype(std::declval<Flags>() | Unaligned)>>(
0533                 &entries()[i * V::Size + shift]);
0534         }
0535         /// Const overload of the above function.
0536         template <typename ShiftT, typename Flags = decltype(Unaligned)>
0537         Vc_ALWAYS_INLINE Vc_PURE typename std::enable_if<
0538             std::is_convertible<ShiftT, int>::value,
0539             const_vector_reference<decltype(std::declval<Flags>() | Unaligned)>>::type
0540         vector(size_t i, ShiftT shift, Flags = Flags()) const
0541         {
0542             return *aliasing_cast<
0543                 MemoryVector<const V, decltype(std::declval<Flags>() | Unaligned)>>(
0544                 &entries()[i * V::Size + shift]);
0545         }
0546 
0547         /**
0548          * \return the first vector in the allocated memory.
0549          *
0550          * This function is simply a shorthand for vector(0).
0551          */
0552         template <typename Flags = AlignedTag>
0553         Vc_ALWAYS_INLINE Vc_PURE vector_reference<Flags> firstVector(Flags f = Flags())
0554         {
0555             return vector(0, f);
0556         }
0557         /// Const overload of the above function.
0558         template <typename Flags = AlignedTag>
0559         Vc_ALWAYS_INLINE Vc_PURE const_vector_reference<Flags> firstVector(
0560             Flags f = Flags()) const
0561         {
0562             return vector(0, f);
0563         }
0564 
0565         /**
0566          * \return the last vector in the allocated memory.
0567          *
0568          * This function is simply a shorthand for vector(vectorsCount() - 1).
0569          */
0570         template <typename Flags = AlignedTag>
0571         Vc_ALWAYS_INLINE Vc_PURE vector_reference<Flags> lastVector(Flags f = Flags())
0572         {
0573             return vector(vectorsCount() - 1, f);
0574         }
0575         /// Const overload of the above function.
0576         template <typename Flags = AlignedTag>
0577         Vc_ALWAYS_INLINE Vc_PURE const_vector_reference<Flags> lastVector(
0578             Flags f = Flags()) const
0579         {
0580             return vector(vectorsCount() - 1, f);
0581         }
0582 
0583         Vc_ALWAYS_INLINE Vc_PURE V gather(const unsigned char  *indexes) const { return V(entries(), typename V::IndexType(indexes, Vc::Unaligned)); }
0584         Vc_ALWAYS_INLINE Vc_PURE V gather(const unsigned short *indexes) const { return V(entries(), typename V::IndexType(indexes, Vc::Unaligned)); }
0585         Vc_ALWAYS_INLINE Vc_PURE V gather(const unsigned int   *indexes) const { return V(entries(), typename V::IndexType(indexes, Vc::Unaligned)); }
0586         Vc_ALWAYS_INLINE Vc_PURE V gather(const unsigned long  *indexes) const { return V(entries(), typename V::IndexType(indexes, Vc::Unaligned)); }
0587 
0588         /**
0589          * Zero the whole memory area.
0590          */
0591         Vc_ALWAYS_INLINE void setZero() {
0592             V zero(Vc::Zero);
0593             for (size_t i = 0; i < vectorsCount(); ++i) {
0594                 vector(i) = zero;
0595             }
0596         }
0597 
0598         /**
0599          * Assign a value to all vectors in the array.
0600          */
0601         template<typename U>
0602         Vc_ALWAYS_INLINE Parent &operator=(U &&x) {
0603             for (size_t i = 0; i < vectorsCount(); ++i) {
0604                 vector(i) = std::forward<U>(x);
0605             }
0606         }
0607 
0608         /**
0609          * (Inefficient) shorthand to add up two arrays.
0610          */
0611         template<typename P2, typename RM>
0612         inline Parent &operator+=(const MemoryBase<V, P2, Dimension, RM> &rhs) {
0613             assert(vectorsCount() == rhs.vectorsCount());
0614             for (size_t i = 0; i < vectorsCount(); ++i) {
0615                 vector(i) += rhs.vector(i);
0616             }
0617             return static_cast<Parent &>(*this);
0618         }
0619 
0620         /**
0621          * (Inefficient) shorthand to subtract two arrays.
0622          */
0623         template<typename P2, typename RM>
0624         inline Parent &operator-=(const MemoryBase<V, P2, Dimension, RM> &rhs) {
0625             assert(vectorsCount() == rhs.vectorsCount());
0626             for (size_t i = 0; i < vectorsCount(); ++i) {
0627                 vector(i) -= rhs.vector(i);
0628             }
0629             return static_cast<Parent &>(*this);
0630         }
0631 
0632         /**
0633          * (Inefficient) shorthand to multiply two arrays.
0634          */
0635         template<typename P2, typename RM>
0636         inline Parent &operator*=(const MemoryBase<V, P2, Dimension, RM> &rhs) {
0637             assert(vectorsCount() == rhs.vectorsCount());
0638             for (size_t i = 0; i < vectorsCount(); ++i) {
0639                 vector(i) *= rhs.vector(i);
0640             }
0641             return static_cast<Parent &>(*this);
0642         }
0643 
0644         /**
0645          * (Inefficient) shorthand to divide two arrays.
0646          */
0647         template<typename P2, typename RM>
0648         inline Parent &operator/=(const MemoryBase<V, P2, Dimension, RM> &rhs) {
0649             assert(vectorsCount() == rhs.vectorsCount());
0650             for (size_t i = 0; i < vectorsCount(); ++i) {
0651                 vector(i) /= rhs.vector(i);
0652             }
0653             return static_cast<Parent &>(*this);
0654         }
0655 
0656         /**
0657          * (Inefficient) shorthand to add a value to an array.
0658          */
0659         inline Parent &operator+=(EntryType rhs) {
0660             V v(rhs);
0661             for (size_t i = 0; i < vectorsCount(); ++i) {
0662                 vector(i) += v;
0663             }
0664             return static_cast<Parent &>(*this);
0665         }
0666 
0667         /**
0668          * (Inefficient) shorthand to subtract a value from an array.
0669          */
0670         inline Parent &operator-=(EntryType rhs) {
0671             V v(rhs);
0672             for (size_t i = 0; i < vectorsCount(); ++i) {
0673                 vector(i) -= v;
0674             }
0675             return static_cast<Parent &>(*this);
0676         }
0677 
0678         /**
0679          * (Inefficient) shorthand to multiply a value to an array.
0680          */
0681         inline Parent &operator*=(EntryType rhs) {
0682             V v(rhs);
0683             for (size_t i = 0; i < vectorsCount(); ++i) {
0684                 vector(i) *= v;
0685             }
0686             return static_cast<Parent &>(*this);
0687         }
0688 
0689         /**
0690          * (Inefficient) shorthand to divide an array with a value.
0691          */
0692         inline Parent &operator/=(EntryType rhs) {
0693             V v(rhs);
0694             for (size_t i = 0; i < vectorsCount(); ++i) {
0695                 vector(i) /= v;
0696             }
0697             return static_cast<Parent &>(*this);
0698         }
0699 
0700         /**
0701          * (Inefficient) shorthand compare equality of two arrays.
0702          */
0703         template<typename P2, typename RM>
0704         inline bool operator==(const MemoryBase<V, P2, Dimension, RM> &rhs) const {
0705             assert(vectorsCount() == rhs.vectorsCount());
0706             for (size_t i = 0; i < vectorsCount(); ++i) {
0707                 if (!(V(vector(i)) == V(rhs.vector(i))).isFull()) {
0708                     return false;
0709                 }
0710             }
0711             return true;
0712         }
0713 
0714         /**
0715          * (Inefficient) shorthand compare two arrays.
0716          */
0717         template<typename P2, typename RM>
0718         inline bool operator!=(const MemoryBase<V, P2, Dimension, RM> &rhs) const {
0719             assert(vectorsCount() == rhs.vectorsCount());
0720             for (size_t i = 0; i < vectorsCount(); ++i) {
0721                 if (!(V(vector(i)) == V(rhs.vector(i))).isEmpty()) {
0722                     return false;
0723                 }
0724             }
0725             return true;
0726         }
0727 
0728         /**
0729          * (Inefficient) shorthand compare two arrays.
0730          */
0731         template<typename P2, typename RM>
0732         inline bool operator<(const MemoryBase<V, P2, Dimension, RM> &rhs) const {
0733             assert(vectorsCount() == rhs.vectorsCount());
0734             for (size_t i = 0; i < vectorsCount(); ++i) {
0735                 if (!(V(vector(i)) < V(rhs.vector(i))).isFull()) {
0736                     return false;
0737                 }
0738             }
0739             return true;
0740         }
0741 
0742         /**
0743          * (Inefficient) shorthand compare two arrays.
0744          */
0745         template<typename P2, typename RM>
0746         inline bool operator<=(const MemoryBase<V, P2, Dimension, RM> &rhs) const {
0747             assert(vectorsCount() == rhs.vectorsCount());
0748             for (size_t i = 0; i < vectorsCount(); ++i) {
0749                 if (!(V(vector(i)) <= V(rhs.vector(i))).isFull()) {
0750                     return false;
0751                 }
0752             }
0753             return true;
0754         }
0755 
0756         /**
0757          * (Inefficient) shorthand compare two arrays.
0758          */
0759         template<typename P2, typename RM>
0760         inline bool operator>(const MemoryBase<V, P2, Dimension, RM> &rhs) const {
0761             assert(vectorsCount() == rhs.vectorsCount());
0762             for (size_t i = 0; i < vectorsCount(); ++i) {
0763                 if (!(V(vector(i)) > V(rhs.vector(i))).isFull()) {
0764                     return false;
0765                 }
0766             }
0767             return true;
0768         }
0769 
0770         /**
0771          * (Inefficient) shorthand compare two arrays.
0772          */
0773         template<typename P2, typename RM>
0774         inline bool operator>=(const MemoryBase<V, P2, Dimension, RM> &rhs) const {
0775             assert(vectorsCount() == rhs.vectorsCount());
0776             for (size_t i = 0; i < vectorsCount(); ++i) {
0777                 if (!(V(vector(i)) >= V(rhs.vector(i))).isFull()) {
0778                     return false;
0779                 }
0780             }
0781             return true;
0782         }
0783 };
0784 
0785 namespace Detail
0786 {
0787 template <typename V,
0788           typename ParentL,
0789           typename ParentR,
0790           int Dimension,
0791           typename RowMemoryL,
0792           typename RowMemoryR>
0793 inline void copyVectors(MemoryBase<V, ParentL, Dimension, RowMemoryL> &dst,
0794                         const MemoryBase<V, ParentR, Dimension, RowMemoryR> &src)
0795 {
0796     const size_t vectorsCount = dst.vectorsCount();
0797     size_t i = 3;
0798     for (; i < vectorsCount; i += 4) {
0799         const V tmp3 = src.vector(i - 3);
0800         const V tmp2 = src.vector(i - 2);
0801         const V tmp1 = src.vector(i - 1);
0802         const V tmp0 = src.vector(i - 0);
0803         dst.vector(i - 3) = tmp3;
0804         dst.vector(i - 2) = tmp2;
0805         dst.vector(i - 1) = tmp1;
0806         dst.vector(i - 0) = tmp0;
0807     }
0808     for (i -= 3; i < vectorsCount; ++i) {
0809         dst.vector(i) = src.vector(i);
0810     }
0811 }
0812 } // namespace Detail
0813 
0814 }  // namespace Common
0815 }  // namespace Vc
0816 
0817 #endif // VC_COMMON_MEMORYBASE_H_
0818 
0819 // vim: foldmethod=marker