Back to home page

EIC code displayed by LXR

 
 

    


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

0001 /*  This file is part of the Vc library. {{{
0002 Copyright © 2013-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_SUBSCRIPT_H_
0029 #define VC_COMMON_SUBSCRIPT_H_
0030 
0031 #include <initializer_list>
0032 #include <type_traits>
0033 #include <vector>
0034 #include "types.h"
0035 #include "macros.h"
0036 #include <assert.h>
0037 
0038 namespace Vc_VERSIONED_NAMESPACE
0039 {
0040 namespace Common
0041 {
0042 // AdaptSubscriptOperator {{{
0043 template <typename Base> class AdaptSubscriptOperator : public Base
0044 {
0045 public:
0046     // perfect forward all Base constructors
0047     template <typename... Args>
0048     Vc_ALWAYS_INLINE AdaptSubscriptOperator(Args &&... arguments)
0049         : Base(std::forward<Args>(arguments)...)
0050     {
0051     }
0052 
0053     // perfect forward all Base constructors
0054     template <typename T>
0055     Vc_ALWAYS_INLINE AdaptSubscriptOperator(std::initializer_list<T> l)
0056         : Base(l)
0057     {
0058     }
0059 
0060     // explicitly enable Base::operator[] because the following would hide it
0061     using Base::operator[];
0062 
0063     /// \internal forward to non-member subscript_operator function
0064     template <typename I,
0065               typename = enable_if<!std::is_arithmetic<
0066                   typename std::decay<I>::type>::value>  // arithmetic types
0067                                                          // should always use
0068                                                          // Base::operator[] and
0069                                                          // never match this one
0070               >
0071     Vc_ALWAYS_INLINE auto operator[](I &&arg_)
0072         -> decltype(subscript_operator(*this, std::forward<I>(arg_)))
0073     {
0074         return subscript_operator(*this, std::forward<I>(arg_));
0075     }
0076 
0077     // const overload of the above
0078     template <typename I, typename = enable_if<
0079                               !std::is_arithmetic<typename std::decay<I>::type>::value>>
0080     Vc_ALWAYS_INLINE auto operator[](I &&arg_) const
0081         -> decltype(subscript_operator(*this, std::forward<I>(arg_)))
0082     {
0083         return subscript_operator(*this, std::forward<I>(arg_));
0084     }
0085 };
0086 
0087 // }}}
0088 // is_valid_indexvector {{{
0089 template <class T, class = decltype(convertIndexVector(std::declval<T>()))>
0090 std::true_type is_valid_indexvector(T &&);
0091 std::false_type is_valid_indexvector(...);
0092 
0093 template <class IndexVector, class Test = decltype(is_valid_indexvector(
0094                                  std::declval<const IndexVector &>()))>
0095 struct is_valid_indexvector_ : public std::integral_constant<bool, Test::value> {
0096 };
0097 static_assert(!is_valid_indexvector_<const int *>::value,
0098               "Pointer is incorrectly classified as valid index vector type");
0099 static_assert(is_valid_indexvector_<const int[4]>::value,
0100               "C-Array is incorrectly classified as invalid index vector type");
0101 
0102 // }}}
0103 // apply Scale (std::ratio) functions {{{1
0104 template <typename Scale, typename T>
0105 Vc_ALWAYS_INLINE enable_if<Scale::num == Scale::den, Traits::decay<T>> applyScale(T &&x)
0106 {
0107     return std::forward<T>(x);
0108 }
0109 
0110 template <typename Scale, typename T>
0111 Vc_ALWAYS_INLINE enable_if<
0112     Scale::num != Scale::den && Traits::has_multiply_operator<T, int>::value,
0113     Traits::decay<T>>
0114     applyScale(T &&x)
0115 {
0116     static_assert(Scale::num % Scale::den == 0,
0117                   "Non-integral index scaling requested. This typically happens only for "
0118                   "Vc::Scalar on 32-bit for gathers on double. You can work around the "
0119                   "issue by ensuring that all doubles in the structure are aligned on 8 "
0120                   "Bytes.");
0121     constexpr int value = Scale::num / Scale::den;
0122     Vc_ASSERT(Vc::all_of((x * value) / value == x));
0123     return std::forward<T>(x) * value;
0124 }
0125 
0126 template <typename Scale, typename T>
0127 Vc_ALWAYS_INLINE enable_if<
0128     Scale::num != Scale::den && !Traits::has_multiply_operator<T, int>::value,
0129     T>
0130     applyScale(T x)
0131 {
0132     static_assert(Scale::num % Scale::den == 0,
0133                   "Non-integral index scaling requested. This typically happens only for "
0134                   "Vc::Scalar on 32-bit for gathers on double. You can work around the "
0135                   "issue by ensuring that all doubles in the structure are aligned on 8 "
0136                   "Bytes.");
0137     constexpr int value = Scale::num / Scale::den;
0138     for (size_t i = 0; i < x.size(); ++i) {
0139         Vc_ASSERT((x[i] * value) / value == x[i]);
0140         x[i] *= value;
0141     }
0142     return x;
0143 }
0144 
0145 template <typename Scale, typename T, typename U,
0146           typename = enable_if<Traits::has_multiply_operator<T, int>::value &&
0147                                Traits::has_addition_operator<T, U>::value>>
0148 Vc_ALWAYS_INLINE typename std::decay<T>::type applyScaleAndAdd(T &&x, U &&y)
0149 {
0150     constexpr int value = Scale::num / Scale::den;
0151     if (value == 1) {  // static evaluation
0152         return std::forward<T>(x) + std::forward<U>(y);
0153     }
0154     return std::forward<T>(x) * value + std::forward<U>(y);
0155 }
0156 
0157 template <
0158     typename Scale, typename T, typename U,
0159     typename = enable_if<
0160         !(Traits::has_multiply_operator<T &, int>::value &&
0161           Traits::has_addition_operator<T &, decltype(std::declval<U>()[0])>::value) &&
0162         Traits::has_subscript_operator<U>::value>>
0163 Vc_ALWAYS_INLINE T applyScaleAndAdd(T x, U &&y)
0164 {
0165     constexpr int value = Scale::num / Scale::den;
0166     for (size_t i = 0; i < x.size(); ++i) {
0167         if (value == 1) {  // static evaluation
0168             x[i] = x[i] + y[i];
0169         } else {
0170             x[i] = x[i] * value + y[i];
0171         }
0172     }
0173     return x;
0174 }
0175 
0176 template <typename Scale, typename T, typename U>
0177 Vc_ALWAYS_INLINE enable_if<!(Traits::has_multiply_operator<T &, int>::value &&
0178                              Traits::has_addition_operator<T &, U>::value) &&
0179                                !Traits::has_subscript_operator<U>::value,
0180                            T>
0181     applyScaleAndAdd(T x, U &&y)
0182 {
0183     constexpr int value = Scale::num / Scale::den;
0184     for (size_t i = 0; i < x.size(); ++i) {
0185         if (value == 1) {  // static evaluation
0186             x[i] = x[i] + y;
0187         } else {
0188             x[i] = x[i] * value + y;
0189         }
0190     }
0191     return x;
0192 }
0193 
0194 // IndexVectorSizeMatches {{{1
0195 template <std::size_t MinSize,
0196           typename IndexT,
0197           bool = Traits::is_simd_vector<IndexT>::value>
0198 struct IndexVectorSizeMatches
0199     : public std::true_type  // you might expect this should be false_type here, but the point is
0200                              // that IndexT is a type where the size is not known at compile time.
0201                              // Thus it may be good but we cannot know from the type. The only check
0202                              // we could do is a runtime check, but the type is fine.
0203 {
0204 };
0205 
0206 template <std::size_t MinSize, typename V>
0207 struct IndexVectorSizeMatches<MinSize,
0208                               V,
0209                               true> : public std::integral_constant<bool, (MinSize <= V::Size)>
0210 {
0211 };
0212 
0213 template <std::size_t MinSize, typename T, std::size_t ArraySize>
0214 struct IndexVectorSizeMatches<MinSize,
0215                               T[ArraySize],
0216                               false> : public std::integral_constant<bool, (MinSize <= ArraySize)>
0217 {
0218 };
0219 
0220 template <std::size_t MinSize, typename T, std::size_t ArraySize>
0221 struct IndexVectorSizeMatches<MinSize,
0222                               std::array<T, ArraySize>,
0223                               false> : public std::integral_constant<bool, (MinSize <= ArraySize)>
0224 {
0225 };
0226 
0227 template <std::size_t MinSize, typename T, std::size_t ArraySize>
0228 struct IndexVectorSizeMatches<MinSize,
0229                               Vc::array<T, ArraySize>,
0230                               false> : public std::integral_constant<bool, (MinSize <= ArraySize)>
0231 {
0232 };
0233 
0234 template <std::size_t MinSize, typename T, std::ptrdiff_t N>
0235 struct IndexVectorSizeMatches<MinSize, Vc::Common::span<T, N>, false>
0236     : public std::integral_constant<bool, (N == -1 || static_cast<std::ptrdiff_t>(MinSize) <= N)> {
0237 };
0238 // SubscriptOperation {{{1
0239 template <
0240     typename T, typename IndexVector, typename Scale = std::ratio<1, 1>,
0241     bool = is_valid_indexvector_<IndexVector>::value>
0242 class SubscriptOperation
0243 {
0244     const IndexVector m_indexes;
0245     T *const m_address;
0246     using ScalarType = typename std::decay<T>::type;
0247 
0248     using IndexVectorScaled = Traits::decay<decltype(convertIndexVector(std::declval<const IndexVector &>()))>;
0249 
0250 public:
0251     // try to stop the user from forming lvalues of this type
0252     SubscriptOperation &operator=(const SubscriptOperation &) = delete;
0253     SubscriptOperation(const SubscriptOperation &) = delete;
0254 #ifndef __cpp_guaranteed_copy_elision
0255     constexpr SubscriptOperation(SubscriptOperation &&) = default;
0256 #endif
0257 
0258     template <typename U,
0259               typename = enable_if<((std::is_convertible<const U &, IndexVector>::value ||
0260                                      std::is_same<U, IndexVector>::value) &&
0261                                     std::is_copy_constructible<IndexVector>::value)>>
0262     constexpr Vc_ALWAYS_INLINE SubscriptOperation(T *address, const U &indexes)
0263         : m_indexes(indexes), m_address(address)
0264     {
0265     }
0266 
0267     template <std::size_t... Indexes>
0268     constexpr Vc_ALWAYS_INLINE SubscriptOperation(T *address, const IndexVector &indexes,
0269                                                   index_sequence<Indexes...>)
0270         : m_indexes{indexes[Indexes]...}, m_address(address)
0271     {}
0272 
0273     template <typename U>
0274     constexpr Vc_ALWAYS_INLINE SubscriptOperation(
0275         T *address, const U &indexes,
0276         enable_if<((std::is_convertible<const U &, IndexVector>::value ||
0277                     std::is_same<U, IndexVector>::value) &&
0278                    !std::is_copy_constructible<IndexVector>::value &&
0279                    std::is_array<IndexVector>::value &&
0280                    std::extent<IndexVector>::value > 0)> = nullarg)
0281         : SubscriptOperation(address, indexes,
0282                              make_index_sequence<std::extent<IndexVector>::value>())
0283     {
0284     }
0285 
0286     static constexpr bool need_explicit_scaling =
0287         Scale::num % Scale::den != 0 || Scale::num / Scale::den * sizeof(T) > 8;
0288 
0289     Vc_ALWAYS_INLINE
0290         GatherArguments<typename std::remove_cv<T>::type, IndexVectorScaled,
0291                         (need_explicit_scaling ? 1 : Scale::num / Scale::den)>
0292         gatherArguments() &&
0293     {
0294         static_assert(std::is_arithmetic<ScalarType>::value,
0295                       "Incorrect type for a SIMD vector gather. Must be an arithmetic type.");
0296         return {applyScale<typename std::conditional<need_explicit_scaling, Scale,
0297                                                      std::ratio<1, 1>>::type>(
0298                     convertIndexVector(m_indexes)),
0299                 m_address};
0300     }
0301 
0302     Vc_ALWAYS_INLINE ScatterArguments<T, IndexVectorScaled> scatterArguments() &&
0303     {
0304         static_assert(std::is_arithmetic<ScalarType>::value,
0305                       "Incorrect type for a SIMD vector scatter. Must be an arithmetic type.");
0306         return {applyScale<Scale>(convertIndexVector(m_indexes)), m_address};
0307     }
0308 
0309     template <typename V,
0310               typename = enable_if<(std::is_arithmetic<ScalarType>::value &&Traits::is_simd_vector<
0311                   V>::value &&IndexVectorSizeMatches<V::Size, IndexVector>::value)>>
0312     Vc_INTRINSIC operator V() &&
0313     {
0314         return V(static_cast<SubscriptOperation &&>(*this).gatherArguments());
0315     }
0316 
0317     template <typename V,
0318               typename = enable_if<(std::is_arithmetic<ScalarType>::value &&Traits::is_simd_vector<
0319                   V>::value &&IndexVectorSizeMatches<V::Size, IndexVector>::value)>>
0320     Vc_ALWAYS_INLINE SubscriptOperation &operator=(const V &rhs) &&
0321     {
0322         static_assert(std::is_arithmetic<ScalarType>::value,
0323                       "Incorrect type for a SIMD vector scatter. Must be an arithmetic type.");
0324         const auto indexes = applyScale<Scale>(convertIndexVector(m_indexes));
0325         rhs.scatter(m_address, indexes);
0326         return *this;
0327     }
0328 
0329     // precondition: m_address points to a struct/class/union
0330     template <
0331         typename U,
0332         typename S,  // S must be equal to T. Still we require this template parameter -
0333         // otherwise instantiation of SubscriptOperation would only be valid for
0334         // structs/unions.
0335         typename = enable_if<std::is_same<S, typename std::remove_cv<T>::type>::value &&(
0336             std::is_class<T>::value || std::is_union<T>::value)>>
0337     Vc_ALWAYS_INLINE auto operator[](U S::*member) &&
0338         -> SubscriptOperation<
0339               typename std::conditional<std::is_const<T>::value,
0340                                         const typename std::remove_reference<U>::type,
0341                                         typename std::remove_reference<U>::type>::type,
0342               IndexVector,
0343               // By passing the scale factor as a fraction of integers in the template
0344               // arguments the value does not lose information if the division yields a
0345               // non-integral value. This could happen e.g. for a struct of struct (S2 {
0346               // S1, char }, with sizeof(S1) = 16, sizeof(S2) = 20. Then scale would be
0347               // 20/16)
0348               std::ratio_multiply<Scale, std::ratio<sizeof(S), sizeof(U)>>>
0349     {
0350         static_assert(std::is_same<Traits::decay<decltype(m_address->*member)>,
0351                                    Traits::decay<U>>::value,
0352                       "Type mismatch that should be impossible.");
0353         // TODO: check whether scale really works for unions correctly
0354         return {&(m_address->*member), m_indexes};
0355     }
0356 
0357     /*
0358      * The following functions allow subscripting of nested arrays. But
0359      * there are two cases of containers and only one that we want to support:
0360      * 1. actual arrays (e.g. T[N] or std::array<T, N>)
0361      * 2. dynamically allocated vectors (e.g. std::vector<T>)
0362      *
0363      * For (1.) the offset calculation is straightforward.
0364      * For (2.) the m_address pointer points to memory where pointers are
0365      * stored to the actual data. Meaning the data can be scattered
0366      * freely in memory (and far away from what m_address points to). Supporting this leads to
0367      * serious trouble with the pointer (it does not really point to the start of a memory
0368      * region anymore) and inefficient code. The user is better off to write a loop that assigns the
0369      * scalars to the vector object sequentially.
0370      */
0371 
0372 private:
0373     // The following is a workaround for MSVC 2015 Update 2. Whenever the ratio
0374     // in the return type of the following operator[] is encountered with a sizeof
0375     // expression that fails, MSVC decides to substitute a 0 for the sizeof instead of
0376     // just leaving the ratio instantiation alone via proper SFINAE. The make_ratio helper
0377     // ensures that the 0 from the sizeof failure does not reach the denominator of
0378     // std::ratio where it would hit a static_assert.
0379     template <intmax_t N, intmax_t D> struct make_ratio {
0380         using type = std::ratio<N, D == 0 ? 1 : D>;
0381     };
0382 
0383 public:
0384     // precondition: m_address points to a type that implements the subscript operator
0385     template <typename U>
0386     // U is only required to delay name lookup to the 2nd phase (on use).
0387     // This is necessary because m_address[0][index] is only a correct
0388     // expression if has_subscript_operator<T>::value is true.
0389     Vc_ALWAYS_INLINE auto operator[](U index) && -> typename std::enable_if<
0390 #ifndef Vc_IMPROVE_ERROR_MESSAGES
0391         Traits::has_no_allocated_data<T>::value &&
0392 #endif
0393             std::is_convertible<U, size_t>::value,
0394         SubscriptOperation<
0395             // the following decltype expression must depend on index and cannot
0396             // simply use [0][0] because it would yield an invalid expression in
0397             // case m_address[0] returns a struct/union
0398             typename std::remove_reference<decltype(m_address[0][index])>::type,
0399             IndexVector,
0400             std::ratio_multiply<
0401                 Scale,
0402                 typename make_ratio<sizeof(T), sizeof(m_address[0][index])>::type>>>::type
0403     {
0404         static_assert(Traits::has_subscript_operator<T>::value,
0405                       "The subscript operator was called on a type that does not implement it.\n");
0406         static_assert(Traits::has_no_allocated_data<T>::value,
0407                       "Invalid container type in gather/scatter operation.\nYou may only use "
0408                       "nested containers that store the data inside the object (such as builtin "
0409                       "arrays or std::array) but not containers that store data in allocated "
0410                       "memory (such as std::vector).\nSince this feature cannot be queried "
0411                       "generically at compile time you need to spezialize the "
0412                       "Vc::Traits::has_no_allocated_data_impl<T> type-trait for custom types that "
0413                       "meet the requirements.\n");
0414         static_assert(std::is_lvalue_reference<decltype(m_address[0][index])>::value,
0415                       "The container does not return an lvalue reference to the data at "
0416                       "the requested offset. This makes it impossible to execute a "
0417                       "gather operation.\n");
0418         return {&(m_address[0][index]), m_indexes};
0419     }
0420 
0421     // precondition: m_address points to a type that implements the subscript operator
0422     template <typename IT>
0423     Vc_ALWAYS_INLINE typename std::enable_if<
0424 #ifndef Vc_IMPROVE_ERROR_MESSAGES
0425         Traits::has_no_allocated_data<T>::value &&
0426             Traits::has_subscript_operator<T>::value &&
0427 #endif
0428             Traits::has_subscript_operator<IT>::value,
0429         SubscriptOperation<typename std::remove_reference<decltype(
0430                                m_address[0][std::declval<
0431                                    const IT &>()[0]]  // std::declval<IT>()[0] could
0432                                                       // be replaced with 0 if it
0433                                // were not for two-phase lookup. We need to make the
0434                                // m_address[0][0] expression dependent on IT
0435                                )>::type,
0436                            IndexVectorScaled,
0437                            std::ratio<1, 1>  // reset Scale to 1 since it is applied below
0438                            >>::type
0439     operator[](const IT &index) &&
0440     {
0441         static_assert(Traits::has_subscript_operator<T>::value,
0442                       "The subscript operator was called on a type that does not implement it.\n");
0443         static_assert(Traits::has_no_allocated_data<T>::value,
0444                       "Invalid container type in gather/scatter operation.\nYou may only use "
0445                       "nested containers that store the data inside the object (such as builtin "
0446                       "arrays or std::array) but not containers that store data in allocated "
0447                       "memory (such as std::vector).\nSince this feature cannot be queried "
0448                       "generically at compile time you need to spezialize the "
0449                       "Vc::Traits::has_no_allocated_data_impl<T> type-trait for custom types that "
0450                       "meet the requirements.\n");
0451         return {&(m_address[0][0]),
0452                 applyScaleAndAdd<std::ratio_multiply<
0453                     Scale, std::ratio<sizeof(T), sizeof(m_address[0][0])>>>(
0454                     convertIndexVector(m_indexes), index)};
0455     }
0456 };
0457 
0458 // specialization for invalid IndexVector type
0459 template <typename T, typename IndexVector, typename Scale>
0460 class SubscriptOperation<T, IndexVector, Scale, false>;
0461 
0462 // subscript_operator {{{1
0463 template <
0464     typename Container,
0465     typename IndexVector,
0466     typename = enable_if<
0467         Traits::has_subscript_operator<IndexVector>::value  // The index vector must provide [] for
0468                                                             // the implementations of gather/scatter
0469         &&Traits::has_contiguous_storage<Container>::value  // Container must use contiguous
0470                                                             // storage, otherwise the index vector
0471         // cannot be used as memory offsets, which is required for efficient
0472         // gather/scatter implementations
0473         &&std::is_lvalue_reference<decltype(*begin(std::declval<
0474             Container>()))>::value  // dereferencing the begin iterator must yield an lvalue
0475                                     // reference (const or non-const). Otherwise it is not possible
0476                                     // to determine a pointer to the data storage (see above).
0477         >>
0478 Vc_ALWAYS_INLINE SubscriptOperation<
0479     typename std::remove_reference<decltype(*begin(std::declval<Container>()))>::
0480         type,  // the type of the first value in the container is what the internal array pointer
0481                // has to point to. But if the subscript operator of the container returns a
0482                // reference we need to drop that part because it's useless information for us. But
0483                // const and volatile, as well as array rank/extent are interesting and need not be
0484                // dropped.
0485     typename std::remove_const<typename std::remove_reference<
0486         IndexVector>::type>::type  // keep volatile and possibly the array extent, but the const and
0487                                    // & parts of the type need to be removed because
0488                                    // SubscriptOperation explicitly adds them for its member type
0489     > subscript_operator(Container &&c, IndexVector &&indexes)
0490 {
0491     Vc_ASSERT(std::addressof(*begin(c)) + 1 ==
0492               std::addressof(*(begin(c) + 1)));  // runtime assertion for contiguous storage, this
0493                                                  // requires a RandomAccessIterator - but that
0494                                                  // should be given for a container with contiguous
0495                                                  // storage
0496     return {std::addressof(*begin(c)), std::forward<IndexVector>(indexes)};
0497 }
0498 
0499 /**
0500  * \internal
0501  * Implement subscripts of std::initializer_list. This function must be in the global scope
0502  * because Container arguments may be in any scope. The other argument is in std scope.
0503  *
0504  * -----
0505  * std::initializer_list does not have constexpr member functions in C++11, but from C++14 onwards
0506  * the world is a happier place. :)
0507  */
0508 template <typename Container, typename I>
0509 Vc_ALWAYS_INLINE Vc::Common::SubscriptOperation<
0510     typename std::remove_reference<decltype(std::declval<Container>()[0])>::type,
0511     const std::initializer_list<I> &> subscript_operator(Container &&vec,
0512                                                    const std::initializer_list<I> &indexes)
0513 {
0514     return {&vec[0], indexes};
0515 }
0516 //}}}1
0517 
0518 }  // namespace Common
0519 
0520 using Common::subscript_operator;
0521 
0522 }  // namespace Vc
0523 
0524 #endif // VC_COMMON_SUBSCRIPT_H_
0525 
0526 // vim: foldmethod=marker