Vc  1.4.1
SIMD Vector Classes for C++
simdize.h
1 /* This file is part of the Vc library. {{{
2 Copyright © 2014-2015 Matthias Kretz <kretz@kde.org>
3 
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are met:
6  * Redistributions of source code must retain the above copyright
7  notice, this list of conditions and the following disclaimer.
8  * Redistributions in binary form must reproduce the above copyright
9  notice, this list of conditions and the following disclaimer in the
10  documentation and/or other materials provided with the distribution.
11  * Neither the names of contributing organizations nor the
12  names of its contributors may be used to endorse or promote products
13  derived from this software without specific prior written permission.
14 
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
19 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 }}}*/
27 
28 #ifndef VC_COMMON_SIMDIZE_H_
29 #define VC_COMMON_SIMDIZE_H_
30 
31 #include <tuple>
32 #include <array>
33 
34 #include "../Allocator"
35 #include "interleavedmemory.h"
36 
122 namespace Vc_VERSIONED_NAMESPACE
123 {
130 namespace SimdizeDetail // {{{
131 {
136 using std::is_same;
137 using std::is_base_of;
138 using std::false_type;
139 using std::true_type;
140 using std::iterator_traits;
141 using std::conditional;
142 using std::size_t;
143 
148 template <typename... Ts> struct Typelist;
149 
153 enum class Category {
155  None,
157  ArithmeticVectorizable,
159  InputIterator,
161  OutputIterator,
163  ForwardIterator,
165  BidirectionalIterator,
167  RandomAccessIterator,
169  ClassTemplate
170 };
171 
176 template <typename T, typename ItCat = typename T::iterator_category>
177 constexpr Category iteratorCategories(int, ItCat * = nullptr)
178 {
179  return is_base_of<std::random_access_iterator_tag, ItCat>::value
180  ? Category::RandomAccessIterator
181  : is_base_of<std::bidirectional_iterator_tag, ItCat>::value
182  ? Category::BidirectionalIterator
183  : is_base_of<std::forward_iterator_tag, ItCat>::value
184  ? Category::ForwardIterator
185  : is_base_of<std::output_iterator_tag, ItCat>::value
186  ? Category::OutputIterator
187  : is_base_of<std::input_iterator_tag, ItCat>::value
188  ? Category::InputIterator
189  : Category::None;
190 }
194 template <typename T>
195 constexpr enable_if<std::is_pointer<T>::value, Category> iteratorCategories(float)
196 {
197  return Category::RandomAccessIterator;
198 }
202 template <typename T> constexpr Category iteratorCategories(...)
203 {
204  return Category::None;
205 }
206 
210 template <typename T> struct is_class_template : public false_type
211 {
212 };
213 template <template <typename...> class C, typename... Ts>
214 struct is_class_template<C<Ts...>> : public true_type
215 {
216 };
217 
221 template <typename T> constexpr Category typeCategory()
222 {
223  return (is_same<T, bool>::value || is_same<T, short>::value ||
224  is_same<T, unsigned short>::value || is_same<T, int>::value ||
225  is_same<T, unsigned int>::value || is_same<T, float>::value ||
226  is_same<T, double>::value)
227  ? Category::ArithmeticVectorizable
228  : iteratorCategories<T>(int()) != Category::None
229  ? iteratorCategories<T>(int())
230  : is_class_template<T>::value ? Category::ClassTemplate
231  : Category::None;
232 }
233 
239 template <typename T, size_t TupleSize = std::tuple_size<T>::value>
240 constexpr size_t determine_tuple_size()
241 {
242  return TupleSize;
243 }
244 template <typename T, size_t TupleSize = T::tuple_size>
245 constexpr size_t determine_tuple_size(size_t = T::tuple_size)
246 {
247  return TupleSize;
248 }
249 
250 // workaround for MSVC limitation: constexpr functions in template arguments
251 // confuse the compiler
252 template <typename T> struct determine_tuple_size_
253 : public std::integral_constant<size_t, determine_tuple_size<T>()>
254 {};
255 
256 namespace
257 {
258 template <typename T> struct The_simdization_for_the_requested_type_is_not_implemented;
259 } // unnamed namespace
260 
273 template <typename T, size_t N, typename MT, Category = typeCategory<T>()>
274 struct ReplaceTypes : public The_simdization_for_the_requested_type_is_not_implemented<T>
275 {
276 };
277 
282 template <typename T, size_t N, typename MT> struct ReplaceTypes<T, N, MT, Category::None>
283 {
284  typedef T type;
285 };
286 
291 template <typename T, size_t N = 0, typename MT = void>
292 using simdize = typename SimdizeDetail::ReplaceTypes<T, N, MT>::type;
293 
294 // Alias for Vector<T, Abi> with size() == N, or SimdArray<T, N> otherwise.
295 template <class T, size_t N,
296  class Best = typename Common::select_best_vector_type<T, N>::type>
297 using deduce_vector_t =
298  typename std::conditional<Best::size() == N, Best, SimdArray<T, N>>::type;
299 
304 template <typename T, size_t N, typename MT>
305 struct ReplaceTypes<T, N, MT, Category::ArithmeticVectorizable>
306  : public conditional<N == 0, Vector<T>, deduce_vector_t<T, N>> {
307 };
308 
313 template <size_t N, typename MT>
314 struct ReplaceTypes<bool, N, MT, Category::ArithmeticVectorizable>
315  : public std::enable_if<true, typename ReplaceTypes<MT, N, MT>::type::mask_type> {
316 };
320 template <size_t N>
321 struct ReplaceTypes<bool, N, void, Category::ArithmeticVectorizable>
322  : public ReplaceTypes<bool, N, float, Category::ArithmeticVectorizable>
323 {
324 };
325 
332 template <size_t N, typename MT, typename Replaced, typename... Remaining>
333 struct SubstituteOneByOne;
334 
339 template <size_t N, typename MT, typename... Replaced, typename T,
340  typename... Remaining>
341 struct SubstituteOneByOne<N, MT, Typelist<Replaced...>, T, Remaining...>
342 {
343 private:
348  template <typename U, size_t M = U::Size>
349  static std::integral_constant<size_t, M> size_or_0(int);
350  template <typename U> static std::integral_constant<size_t, 0> size_or_0(...);
351 
353  using V = simdize<T, N, MT>;
354 
359  static constexpr auto NewN = N != 0 ? N : decltype(size_or_0<V>(int()))::value;
360 
366  typedef conditional_t<(N != NewN && is_same<MT, void>::value),
367  conditional_t<is_same<T, bool>::value, float, T>, MT> NewMT;
368 
369 public:
373  using type = typename SubstituteOneByOne<NewN, NewMT, Typelist<Replaced..., V>,
374  Remaining...>::type;
375 };
376 
379 template <size_t Size, typename... Replaced> struct SubstitutedBase;
381 template <typename Replaced> struct SubstitutedBase<1, Replaced> {
382  template <typename ValueT, template <typename, ValueT...> class C, ValueT... Values>
383  using SubstitutedWithValues = C<Replaced, Values...>;
384 };
386 template <typename R0, typename R1> struct SubstitutedBase<2, R0, R1>
387 {
388  template <typename ValueT, template <typename, typename, ValueT...> class C,
389  ValueT... Values>
390  using SubstitutedWithValues = C<R0, R1, Values...>;
391 };
393 template <typename R0, typename R1, typename R2> struct SubstitutedBase<3, R0, R1, R2>
394 {
395  template <typename ValueT, template <typename, typename, typename, ValueT...> class C,
396  ValueT... Values>
397  using SubstitutedWithValues = C<R0, R1, R2, Values...>;
398 };
399 #if defined Vc_ICC || defined Vc_MSVC
400 #define Vc_VALUE_PACK_EXPANSION_IS_BROKEN 1
401 #endif
402 template <typename... Replaced> struct SubstitutedBase<4, Replaced...> {
404 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
405  template <typename ValueT,
406  template <typename, typename, typename, typename, ValueT...> class C,
407  ValueT... Values>
408  using SubstitutedWithValues = C<Replaced..., Values...>;
409 #endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
410 };
412 template <typename... Replaced> struct SubstitutedBase<5, Replaced...> {
413 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
414  template <typename ValueT, template <typename, typename, typename, typename, typename,
415  ValueT...> class C,
416  ValueT... Values>
417  using SubstitutedWithValues = C<Replaced..., Values...>;
418 #endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
419 };
421 template <typename... Replaced> struct SubstitutedBase<6, Replaced...> {
422 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
423  template <typename ValueT, template <typename, typename, typename, typename, typename,
424  typename, ValueT...> class C,
425  ValueT... Values>
426  using SubstitutedWithValues = C<Replaced..., Values...>;
427 #endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
428 };
430 template <typename... Replaced> struct SubstitutedBase<7, Replaced...> {
431 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
432  template <typename ValueT, template <typename, typename, typename, typename, typename,
433  typename, typename, ValueT...> class C,
434  ValueT... Values>
435  using SubstitutedWithValues = C<Replaced..., Values...>;
436 #endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
437 };
439 template <typename... Replaced> struct SubstitutedBase<8, Replaced...> {
440 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
441  template <typename ValueT, template <typename, typename, typename, typename, typename,
442  typename, typename, typename, ValueT...> class C,
443  ValueT... Values>
444  using SubstitutedWithValues = C<Replaced..., Values...>;
445 #endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
446 };
447 
453 template <size_t N_, typename MT, typename Replaced0, typename... Replaced>
454 struct SubstituteOneByOne<N_, MT, Typelist<Replaced0, Replaced...>>
455 {
459  struct type
460  : public SubstitutedBase<sizeof...(Replaced) + 1, Replaced0, Replaced...> {
461  static constexpr auto N = N_;
466  template <template <typename...> class C>
467  using Substituted = C<Replaced0, Replaced...>;
468  };
469 };
470 
487 template <typename Scalar, typename Base, size_t N> class Adapter;
488 
493 template <template <typename...> class C, typename... Ts, size_t N, typename MT>
494 struct ReplaceTypes<C<Ts...>, N, MT, Category::ClassTemplate>
495 {
497  using SubstitutionResult =
498  typename SubstituteOneByOne<N, MT, Typelist<>, Ts...>::type;
504  using Vectorized = typename SubstitutionResult::template Substituted<C>;
510  using type = conditional_t<is_same<C<Ts...>, Vectorized>::value, C<Ts...>,
511  Adapter<C<Ts...>, Vectorized, SubstitutionResult::N>>;
512 };
513 
519 #ifdef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
520 // ICC barfs on packs of values
521 #define Vc_DEFINE_NONTYPE_REPLACETYPES_(ValueType_) \
522  template <template <typename, ValueType_...> class C, typename T, ValueType_ Value0, \
523  ValueType_... Values> \
524  struct is_class_template<C<T, Value0, Values...>> : public true_type { \
525  }; \
526  template <template <typename, typename, ValueType_...> class C, typename T0, \
527  typename T1, ValueType_ Value0, ValueType_... Values> \
528  struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type { \
529  }; \
530  template <template <typename, typename, typename, ValueType_...> class C, \
531  typename T0, typename T1, typename T2, ValueType_ Value0, \
532  ValueType_... Values> \
533  struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type { \
534  }; \
535  template <template <typename, typename, typename, typename, ValueType_...> class C, \
536  typename T0, typename T1, typename T2, typename T3, ValueType_ Value0, \
537  ValueType_... Values> \
538  struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type { \
539  }; \
540  template <template <typename, typename, typename, typename, typename, ValueType_...> \
541  class C, \
542  typename T0, typename T1, typename T2, typename T3, typename T4, \
543  ValueType_ Value0, ValueType_... Values> \
544  struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
545  : public true_type { \
546  }; \
547  template <template <typename, typename, typename, typename, typename, typename, \
548  ValueType_...> class C, \
549  typename T0, typename T1, typename T2, typename T3, typename T4, \
550  typename T5, ValueType_ Value0, ValueType_... Values> \
551  struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
552  : public true_type { \
553  }; \
554  template <template <typename, typename, typename, typename, typename, typename, \
555  typename, ValueType_...> class C, \
556  typename T0, typename T1, typename T2, typename T3, typename T4, \
557  typename T5, typename T6, ValueType_ Value0, ValueType_... Values> \
558  struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
559  : public true_type { \
560  }; \
561  template <template <typename, ValueType_> class C, typename T0, ValueType_ Value0, \
562  size_t N, typename MT> \
563  struct ReplaceTypes<C<T0, Value0>, N, MT, Category::ClassTemplate> { \
564  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
565  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
566  Substituted; \
567  static constexpr auto NN = tmp::N; \
568  typedef conditional_t<is_same<C<T0, Value0>, Substituted>::value, C<T0, Value0>, \
569  Adapter<C<T0, Value0>, Substituted, NN>> type; \
570  }; \
571  template <template <typename, typename, ValueType_> class C, typename T0, \
572  typename T1, ValueType_ Value0, size_t N, typename MT> \
573  struct ReplaceTypes<C<T0, T1, Value0>, N, MT, Category::ClassTemplate> { \
574  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
575  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
576  Substituted; \
577  static constexpr auto NN = tmp::N; \
578  typedef conditional_t<is_same<C<T0, T1, Value0>, Substituted>::value, \
579  C<T0, T1, Value0>, \
580  Adapter<C<T0, T1, Value0>, Substituted, NN>> type; \
581  }; \
582  template <template <typename, typename, typename, ValueType_> class C, typename T0, \
583  typename T1, typename T2, ValueType_ Value0, size_t N, typename MT> \
584  struct ReplaceTypes<C<T0, T1, T2, Value0>, N, MT, Category::ClassTemplate> { \
585  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
586  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
587  Substituted; \
588  static constexpr auto NN = tmp::N; \
589  typedef conditional_t<is_same<C<T0, T1, T2, Value0>, Substituted>::value, \
590  C<T0, T1, T2, Value0>, \
591  Adapter<C<T0, T1, T2, Value0>, Substituted, NN>> type; \
592  }
593 #else
594 #define Vc_DEFINE_NONTYPE_REPLACETYPES_(ValueType_) \
595  template <template <typename, ValueType_...> class C, typename T, ValueType_ Value0, \
596  ValueType_... Values> \
597  struct is_class_template<C<T, Value0, Values...>> : public true_type { \
598  }; \
599  template <template <typename, typename, ValueType_...> class C, typename T0, \
600  typename T1, ValueType_ Value0, ValueType_... Values> \
601  struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type { \
602  }; \
603  template <template <typename, typename, typename, ValueType_...> class C, \
604  typename T0, typename T1, typename T2, ValueType_ Value0, \
605  ValueType_... Values> \
606  struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type { \
607  }; \
608  template <template <typename, typename, typename, typename, ValueType_...> class C, \
609  typename T0, typename T1, typename T2, typename T3, ValueType_ Value0, \
610  ValueType_... Values> \
611  struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type { \
612  }; \
613  template <template <typename, typename, typename, typename, typename, ValueType_...> \
614  class C, \
615  typename T0, typename T1, typename T2, typename T3, typename T4, \
616  ValueType_ Value0, ValueType_... Values> \
617  struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
618  : public true_type { \
619  }; \
620  template <template <typename, typename, typename, typename, typename, typename, \
621  ValueType_...> class C, \
622  typename T0, typename T1, typename T2, typename T3, typename T4, \
623  typename T5, ValueType_ Value0, ValueType_... Values> \
624  struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
625  : public true_type { \
626  }; \
627  template <template <typename, typename, typename, typename, typename, typename, \
628  typename, ValueType_...> class C, \
629  typename T0, typename T1, typename T2, typename T3, typename T4, \
630  typename T5, typename T6, ValueType_ Value0, ValueType_... Values> \
631  struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
632  : public true_type { \
633  }; \
634  template <template <typename, ValueType_...> class C, typename T0, \
635  ValueType_ Value0, ValueType_... Values, size_t N, typename MT> \
636  struct ReplaceTypes<C<T0, Value0, Values...>, N, MT, Category::ClassTemplate> { \
637  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
638  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
639  Values...> Substituted; \
640  static constexpr auto NN = tmp::N; \
641  typedef conditional_t<is_same<C<T0, Value0, Values...>, Substituted>::value, \
642  C<T0, Value0, Values...>, \
643  Adapter<C<T0, Value0, Values...>, Substituted, NN>> type; \
644  }; \
645  template <template <typename, typename, ValueType_...> class C, typename T0, \
646  typename T1, ValueType_ Value0, ValueType_... Values, size_t N, \
647  typename MT> \
648  struct ReplaceTypes<C<T0, T1, Value0, Values...>, N, MT, Category::ClassTemplate> { \
649  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
650  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
651  Values...> Substituted; \
652  static constexpr auto NN = tmp::N; \
653  typedef conditional_t<is_same<C<T0, T1, Value0, Values...>, Substituted>::value, \
654  C<T0, T1, Value0, Values...>, \
655  Adapter<C<T0, T1, Value0, Values...>, Substituted, NN>> \
656  type; \
657  }; \
658  template <template <typename, typename, typename, ValueType_...> class C, \
659  typename T0, typename T1, typename T2, ValueType_ Value0, \
660  ValueType_... Values, size_t N, typename MT> \
661  struct ReplaceTypes<C<T0, T1, T2, Value0, Values...>, N, MT, \
662  Category::ClassTemplate> { \
663  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
664  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
665  Values...> Substituted; \
666  static constexpr auto NN = tmp::N; \
667  typedef conditional_t< \
668  is_same<C<T0, T1, T2, Value0, Values...>, Substituted>::value, \
669  C<T0, T1, T2, Value0, Values...>, \
670  Adapter<C<T0, T1, T2, Value0, Values...>, Substituted, NN>> type; \
671  }
672 #endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
673 Vc_DEFINE_NONTYPE_REPLACETYPES_(bool);
674 Vc_DEFINE_NONTYPE_REPLACETYPES_(wchar_t);
675 Vc_DEFINE_NONTYPE_REPLACETYPES_(char);
676 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed char);
677 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned char);
678 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed short);
679 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned short);
680 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed int);
681 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned int);
682 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed long);
683 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned long);
684 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed long long);
685 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned long long);
686 #undef Vc_DEFINE_NONTYPE_REPLACETYPES_
687 
688 // preferred_construction {{{
689 namespace preferred_construction_impl
690 {
691 template <typename T> T create();
692 // 0: paren init
693 template <class Type, class... Init, class = decltype(Type(create<Init>()...))>
694 constexpr std::integral_constant<int, 0> test(int);
695 // 1: 1-brace init
696 template <class Type, class... Init, class = decltype(Type{create<Init>()...})>
697 constexpr std::integral_constant<int, 1> test(float);
698 // 2: 2-brace init
699 template <class Type, class... Init, class T, class = decltype(Type{{create<Init>()...}})>
700 constexpr std::integral_constant<int, 2> test(T);
701 // 3: no init at all
702 template <class Type, class... Init> constexpr std::integral_constant<int, 3> test(...);
703 } // namespace preferred_construction_impl
704 
705 template <class Type, class... Init>
706 constexpr inline decltype(preferred_construction_impl::test<Type, Init...>(0))
707 preferred_construction()
708 {
709  return {};
710 }
711 
712 // }}}
713 // get_dispatcher {{{
718 template <size_t I, typename T,
719  typename R = decltype(std::declval<T &>().template vc_get_<I>())>
720 R get_dispatcher(T &x, void * = nullptr)
721 {
722  return x.template vc_get_<I>();
723 }
724 template <size_t I, typename T,
725  typename R = decltype(std::declval<const T &>().template vc_get_<I>())>
726 R get_dispatcher(const T &x, void * = nullptr)
727 {
728  return x.template vc_get_<I>();
729 }
730 template <size_t I, typename T, typename R = decltype(std::get<I>(std::declval<T &>()))>
731 R get_dispatcher(T &x, int = 0)
732 {
733  return std::get<I>(x);
734 }
735 template <size_t I, typename T,
736  typename R = decltype(std::get<I>(std::declval<const T &>()))>
737 R get_dispatcher(const T &x, int = 0)
738 {
739  return std::get<I>(x);
740 }
741 
742 // }}}
743 // my_tuple_element {{{
744 template <size_t I, class T, class = void>
745 struct my_tuple_element : std::tuple_element<I, T> {
746 };
747 
748 template <size_t I, class T>
749 struct my_tuple_element<
750  I, T, typename std::conditional<
751  true, void, decltype(std::declval<T>().template vc_get_<I>())>::type> {
752  using type =
753  typename std::decay<decltype(std::declval<T>().template vc_get_<I>())>::type;
754 };
755 
756 // }}}
757 // homogeneous_sizeof {{{
763 template <class... Ts> struct homogeneous_sizeof;
764 template <class T, class = void> struct homogeneous_sizeof_one;
765 template <class T>
766 struct homogeneous_sizeof_one<T,
767  typename std::enable_if<std::is_arithmetic<T>::value>::type>
768  : std::integral_constant<size_t, sizeof(T)> {
769 };
770 template <class T0> struct homogeneous_sizeof<T0> : homogeneous_sizeof_one<T0> {
771 };
772 
773 template <class T0, class... Ts>
774 struct homogeneous_sizeof<T0, Ts...>
775  : std::integral_constant<size_t, homogeneous_sizeof<T0>::value ==
776  homogeneous_sizeof<Ts...>::value
777  ? homogeneous_sizeof<T0>::value
778  : 0> {
779 };
780 
781 template <class T, size_t... Is>
782 std::integral_constant<
783  size_t, homogeneous_sizeof<typename my_tuple_element<Is, T>::type...>::value>
784  homogeneous_sizeof_helper(index_sequence<Is...>);
785 
786 template <class T>
787 struct homogeneous_sizeof_one<T, typename std::enable_if<std::is_class<T>::value>::type>
788  : decltype(homogeneous_sizeof_helper<T>(
789  make_index_sequence<determine_tuple_size_<T>::value>())) {
790 };
791 
792 // }}}
793 // class Adapter {{{
794 template <typename Scalar, typename Base, size_t N> class Adapter : public Base
795 {
796 private:
798  template <std::size_t... Indexes, int X>
799  Adapter(Vc::index_sequence<Indexes...>, const Scalar,
800  std::integral_constant<int, X>)
801  {
802  static_assert(
803  X < 3, "Failed to construct an object of type Base. Neither via "
804  "parenthesis-init, brace-init, nor double-brace init appear to work.");
805  }
806 
808  template <std::size_t... Indexes>
809  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_,
810  std::integral_constant<int, 2>)
811  : Base{{get_dispatcher<Indexes>(x_)...}}
812  {
813  }
814 
816  template <std::size_t... Indexes>
817  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_,
818  std::integral_constant<int, 1>)
819  : Base{get_dispatcher<Indexes>(x_)...}
820  {
821  }
822 
824  template <std::size_t... Indexes>
825  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_,
826  std::integral_constant<int, 0>)
827  : Base(get_dispatcher<Indexes>(x_)...)
828  {
829  }
830 
831  template <std::size_t... Indexes>
832  Adapter(Vc::index_sequence<Indexes...> seq_, const Scalar &x_)
833  : Adapter(seq_, x_,
834  preferred_construction<Base, decltype(get_dispatcher<Indexes>(
835  std::declval<const Scalar &>()))...>())
836  {
837  }
838 
839 public:
841  static constexpr size_t size() { return N; }
842  static constexpr size_t Size = N;
843 
845  using base_type = Base;
848  using scalar_type = Scalar;
849 
852  Adapter() = default;
853 
855 #if defined Vc_CLANG && Vc_CLANG < 0x30700
856  Vc_INTRINSIC Adapter(const Adapter &x) : Base(x) {}
857 #else
858  Adapter(const Adapter &) = default;
859 #endif
860  Adapter(Adapter &&) = default;
863  Adapter &operator=(const Adapter &) = default;
865  Adapter &operator=(Adapter &&) = default;
866 
868  template <typename U, size_t TupleSize = determine_tuple_size_<Scalar>::value,
869  typename Seq = Vc::make_index_sequence<TupleSize>,
870  typename = enable_if<std::is_convertible<U, Scalar>::value>>
871  Adapter(U &&x_)
872  : Adapter(Seq(), static_cast<const Scalar &>(x_))
873  {
874  }
875 
877  template <class F,
878  class = decltype(static_cast<Scalar>(std::declval<F>()(
879  size_t())))> // F returns objects that are convertible to S
880  Adapter(F &&fun); // implementation below
881 
882  // }}}
884  template <typename A0, typename... Args,
885  typename = typename std::enable_if<
886  !Traits::is_index_sequence<A0>::value &&
887  (sizeof...(Args) > 0 || !std::is_convertible<A0, Scalar>::value)>::type>
888  Adapter(A0 &&arg0_, Args &&... arguments_)
889  : Base(std::forward<A0>(arg0_), std::forward<Args>(arguments_)...)
890  {
891  }
892 
894  template <typename T,
895  typename = decltype(Base(std::declval<const std::initializer_list<T> &>()))>
896  Adapter(const std::initializer_list<T> &l_)
897  : Base(l_)
898  {
899  }
900 
903  void *operator new(size_t size)
904  {
905  return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
906  }
907  void *operator new(size_t, void *p_) { return p_; }
908  void *operator new[](size_t size)
909  {
910  return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
911  }
912  void *operator new[](size_t , void *p_) { return p_; }
913  void operator delete(void *ptr_, size_t) { Vc::Common::free(ptr_); }
914  void operator delete(void *, void *) {}
915  void operator delete[](void *ptr_, size_t) { Vc::Common::free(ptr_); }
916  void operator delete[](void *, void *) {}
917 }; // }}}
918 // delete compare operators for Adapter {{{
923 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
924 inline void operator==(
925  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
926  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
927 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
928 inline void operator!=(
929  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
930  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
931 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
932 inline void operator<=(
933  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
934  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
935 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
936 inline void operator>=(
937  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
938  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
939 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
940 inline void operator<(
941  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
942  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
943 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
944 inline void operator>(
945  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
946  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
947 // }}}
949 } // namespace SimdizeDetail }}}
950 } // namespace Vc
951 
952 namespace std // {{{
953 {
957 template <typename Scalar, typename Base, size_t N>
958 class tuple_size<Vc::SimdizeDetail::Adapter<Scalar, Base, N>> : public tuple_size<Base>
959 {
960 };
964 template <size_t I, typename Scalar, typename Base, size_t N>
965 class tuple_element<I, Vc::SimdizeDetail::Adapter<Scalar, Base, N>>
966  : public tuple_element<I, Base>
967 {
968 };
969 // std::get does not need additional work because Vc::Adapter derives from
970 // C<Ts...> and therefore if get<N>(C<Ts...>) works it works for Adapter as well.
971 
976 template <typename S, typename T, size_t N>
977 class allocator<Vc::SimdizeDetail::Adapter<S, T, N>>
978  : public Vc::Allocator<Vc::SimdizeDetail::Adapter<S, T, N>>
979 {
980 public:
981  template <typename U> struct rebind
982  {
983  typedef std::allocator<U> other;
984  };
985 };
986 } // namespace std }}}
987 
988 namespace Vc_VERSIONED_NAMESPACE
989 {
990 namespace SimdizeDetail
991 {
1000 template <typename T> static inline T decay_workaround(const T &x) { return x; }
1001 
1002 // assign_impl {{{
1006 template <typename S, typename T, size_t N, size_t... Indexes>
1007 inline void assign_impl(Adapter<S, T, N> &a, size_t i, const S &x,
1008  Vc::index_sequence<Indexes...>)
1009 {
1010  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(x)))...> tmp(
1011  decay_workaround(get_dispatcher<Indexes>(x))...);
1012  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(tmp), 0)...};
1013  if (&unused == &unused) {}
1014 } // }}}
1015 // construct (parens, braces, double-braces) {{{
1016 template <class S, class... Args>
1017 S construct(std::integral_constant<int, 0>, Args &&... args)
1018 {
1019  return S(std::forward<Args>(args)...);
1020 }
1021 template <class S, class... Args>
1022 S construct(std::integral_constant<int, 1>, Args &&... args)
1023 {
1024  return S{std::forward<Args>(args)...};
1025 }
1026 template <class S, class... Args>
1027 S construct(std::integral_constant<int, 2>, Args &&... args)
1028 {
1029  return S{{std::forward<Args>(args)...}};
1030 }
1031 // }}}
1032 // extract_impl {{{
1036 template <typename S, typename T, size_t N, size_t... Indexes>
1037 inline S extract_impl(const Adapter<S, T, N> &a, size_t i, Vc::index_sequence<Indexes...>)
1038 {
1039  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[i]))...> tmp(
1040  decay_workaround(get_dispatcher<Indexes>(a)[i])...);
1041  return construct<S>(
1042  preferred_construction<S, decltype(decay_workaround(
1043  get_dispatcher<Indexes>(a)[i]))...>(),
1044  decay_workaround(get_dispatcher<Indexes>(a)[i])...);
1045  //return S(get_dispatcher<Indexes>(tmp)...);
1046 }
1047 // }}}
1048 // shifted_impl {{{
1049 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1050 inline Adapter<S, T, N> shifted_impl(const Adapter<S, T, N> &a, int shift,
1051  Vc::index_sequence<Indexes...>)
1052 {
1053  Adapter<S, T, N> r;
1054  auto &&unused = {(get_dispatcher<Indexes>(r) = get_dispatcher<Indexes>(a).shifted(shift), 0)...};
1055  if (&unused == &unused) {}
1056  return r;
1057 }
1058 // }}}
1059 // shifted(Adapter) {{{
1068 template <typename S, typename T, size_t N>
1069 inline Adapter<S, T, N> shifted(const Adapter<S, T, N> &a, int shift)
1070 {
1071  return shifted_impl(a, shift, Vc::make_index_sequence<determine_tuple_size<T>()>());
1072 }
1073 // }}}
1074 // swap_impl {{{
1078 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1079 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, S &x,
1080  Vc::index_sequence<Indexes...>)
1081 {
1082  const auto &a_const = a;
1083  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a_const)[0]))...>
1084  tmp{decay_workaround(get_dispatcher<Indexes>(a_const)[i])...};
1085  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(x), 0)...};
1086  auto &&unused2 = {(get_dispatcher<Indexes>(x) = get_dispatcher<Indexes>(tmp), 0)...};
1087  if (&unused == &unused2) {}
1088 }
1089 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1090 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b,
1091  std::size_t j, Vc::index_sequence<Indexes...>)
1092 {
1093  const auto &a_const = a;
1094  const auto &b_const = b;
1095  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a_const)[0]))...>
1096  tmp{decay_workaround(get_dispatcher<Indexes>(a_const)[i])...};
1097  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(b_const)[j], 0)...};
1098  auto &&unused2 = {(get_dispatcher<Indexes>(b)[j] = get_dispatcher<Indexes>(tmp), 0)...};
1099  if (&unused == &unused2) {}
1100 }
1101 // }}}
1102 // swap(Adapter) {{{
1107 template <typename S, typename T, std::size_t N>
1108 inline void swap(Adapter<S, T, N> &a, std::size_t i, S &x)
1109 {
1110  swap_impl(a, i, x, Vc::make_index_sequence<determine_tuple_size<T>()>());
1111 }
1112 template <typename S, typename T, std::size_t N>
1113 inline void swap(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b, std::size_t j)
1114 {
1115  swap_impl(a, i, b, j, Vc::make_index_sequence<determine_tuple_size<T>()>());
1116 }
1117 // }}}
1118 template <typename A> class Scalar // {{{
1119 {
1120  using reference = typename std::add_lvalue_reference<A>::type;
1121  using S = typename A::scalar_type;
1122  using IndexSeq = Vc::make_index_sequence<determine_tuple_size<S>()>;
1123 
1124 public:
1125  Scalar(reference aa, size_t ii) : a(aa), i(ii) {}
1126 
1127  // delete copy and move to keep the type a pure proxy temporary object.
1128  Scalar(const Scalar &) = delete;
1129  Scalar(Scalar &&) = delete;
1130  Scalar &operator=(const Scalar &) = delete;
1131  Scalar &operator=(Scalar &&) = delete;
1132 
1133  void operator=(const S &x) { assign_impl(a, i, x, IndexSeq()); }
1134  operator S() const { return extract_impl(a, i, IndexSeq()); }
1135 
1136  template <typename AA>
1137  friend inline void swap(Scalar<AA> &&a, typename AA::scalar_type &b);
1138  template <typename AA>
1139  friend inline void swap(typename AA::scalar_type &b, Scalar<AA> &&a);
1140  template <typename AA> friend inline void swap(Scalar<AA> &&a, Scalar<AA> &&b);
1141 
1142 private:
1143  reference a;
1144  size_t i;
1145 }; // }}}
1146 // swap(Scalar) {{{
1149 template <typename A> inline void swap(Scalar<A> &&a, typename A::scalar_type &b)
1150 {
1151  swap_impl(a.a, a.i, b, typename Scalar<A>::IndexSeq());
1152 }
1155 template <typename A> inline void swap(typename A::scalar_type &b, Scalar<A> &&a)
1156 {
1157  swap_impl(a.a, a.i, b, typename Scalar<A>::IndexSeq());
1158 }
1159 
1160 template <typename A> inline void swap(Scalar<A> &&a, Scalar<A> &&b)
1161 {
1162  swap_impl(a.a, a.i, b.a, b.i, typename Scalar<A>::IndexSeq());
1163 }
1164 // }}}
1165 // load_interleaved_impl {{{
1166 template <class S, class T, size_t N, size_t... I>
1167 inline void load_interleaved_impl(Vc::index_sequence<I...>, Adapter<S, T, N> &a,
1168  const S *mem)
1169 {
1171  wrapper(const_cast<S *>(mem));
1172  Vc::tie(get_dispatcher<I>(a)...) = wrapper[0];
1173 }
1174 // }}}
1175 // store_interleaved_impl {{{
1176 template <class S, class T, size_t N, size_t... I>
1177 inline void store_interleaved_impl(Vc::index_sequence<I...>, const Adapter<S, T, N> &a,
1178  S *mem)
1179 {
1181  mem);
1182  wrapper[0] = Vc::tie(get_dispatcher<I>(a)...);
1183 }
1184 // }}}
1185 template <typename A> class Interface // {{{
1186 {
1187  using reference = typename std::add_lvalue_reference<A>::type;
1188  using IndexSeq =
1189  Vc::make_index_sequence<determine_tuple_size<typename A::scalar_type>()>;
1190 
1191 public:
1192  Interface(reference aa) : a(aa) {}
1193 
1194  Scalar<A> operator[](size_t i)
1195  {
1196  return {a, i};
1197  }
1198  typename A::scalar_type operator[](size_t i) const
1199  {
1200  return extract_impl(a, i, IndexSeq());
1201  }
1202 
1203  A shifted(int amount) const
1204  {
1205  return shifted_impl(a, amount, IndexSeq());
1206  }
1207 
1208  void load(const typename A::scalar_type *mem) { load_interleaved(*this, mem); }
1209  void store(typename A::scalar_type *mem) { store_interleaved(*this, mem); }
1210 
1211 private:
1212  reference a;
1213 }; // }}}
1214 } // namespace SimdizeDetail
1215 // assign {{{
1220 template <typename S, typename T, size_t N>
1221 inline void assign(SimdizeDetail::Adapter<S, T, N> &a, size_t i, const S &x)
1222 {
1223  SimdizeDetail::assign_impl(
1224  a, i, x, Vc::make_index_sequence<SimdizeDetail::determine_tuple_size<T>()>());
1225 }
1229 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
1230 Vc_INTRINSIC void assign(V &v, size_t i, typename V::EntryType x)
1231 {
1232  v[i] = x;
1233 }
1234 // }}}
1235 // extract {{{
1240 template <typename S, typename T, size_t N>
1241 inline S extract(const SimdizeDetail::Adapter<S, T, N> &a, size_t i)
1242 {
1243  return SimdizeDetail::extract_impl(
1244  a, i, Vc::make_index_sequence<SimdizeDetail::determine_tuple_size<S>()>());
1245 }
1249 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
1250 Vc_INTRINSIC typename V::EntryType extract(const V &v, size_t i)
1251 {
1252  return v[i];
1253 }
1254 // }}}
1255 // load_interleaved {{{
1256 template <class S, class T, size_t N>
1257 inline void load_interleaved(SimdizeDetail::Adapter<S, T, N> &a, const S *mem)
1258 {
1259  if (SimdizeDetail::homogeneous_sizeof<S>::value == 0) {
1260  Common::unrolled_loop<std::size_t, 0, N>(
1261  [&](std::size_t i) { assign(a, i, mem[i]); });
1262  } else {
1263  constexpr size_t TupleSize = SimdizeDetail::determine_tuple_size_<S>::value;
1264  SimdizeDetail::load_interleaved_impl(Vc::make_index_sequence<TupleSize>(), a,
1265  mem);
1266  }
1267 }
1268 template <
1269  class V, class T,
1270  class = enable_if<Traits::is_simd_vector<V>::value && std::is_arithmetic<T>::value>>
1271 Vc_INTRINSIC void load_interleaved(V &a, const T *mem)
1272 {
1273  a.load(mem, Vc::Unaligned);
1274 }
1275 // }}}
1276 // store_interleaved {{{
1277 template <class S, class T, size_t N>
1278 inline void store_interleaved(const SimdizeDetail::Adapter<S, T, N> &a, S *mem)
1279 {
1280  if (SimdizeDetail::homogeneous_sizeof<S>::value == 0) {
1281  Common::unrolled_loop<std::size_t, 0, N>(
1282  [&](std::size_t i) { mem[i] = extract(a, i); });
1283  } else {
1284  constexpr size_t TupleSize = SimdizeDetail::determine_tuple_size_<S>::value;
1285  SimdizeDetail::store_interleaved_impl(Vc::make_index_sequence<TupleSize>(), a,
1286  mem);
1287  }
1288 }
1289 template <
1290  class V, class T,
1291  class = enable_if<Traits::is_simd_vector<V>::value && std::is_arithmetic<T>::value>>
1292 Vc_INTRINSIC void store_interleaved(const V &a, T *mem)
1293 {
1294  a.store(mem, Vc::Unaligned);
1295 }
1296 // }}}
1297 // decorate(Adapter) {{{
1298 template <typename S, typename T, size_t N>
1299 SimdizeDetail::Interface<SimdizeDetail::Adapter<S, T, N>> decorate(
1300  SimdizeDetail::Adapter<S, T, N> &a)
1301 {
1302  return {a};
1303 }
1304 template <typename S, typename T, size_t N>
1305 const SimdizeDetail::Interface<const SimdizeDetail::Adapter<S, T, N>> decorate(
1306  const SimdizeDetail::Adapter<S, T, N> &a)
1307 {
1308  return {a};
1309 }
1310 template <class V, class = typename std::enable_if<
1312 V &&decorate(V &&v)
1313 {
1314  return std::forward<V>(v);
1315 }
1316 // }}}
1317 namespace SimdizeDetail
1318 {
1319 // Adapter::Adapter(F) Generator {{{
1320 template <typename Scalar, typename Base, size_t N>
1321 template <class F, class>
1322 Adapter<Scalar, Base, N>::Adapter(F &&fun)
1323 {
1324  for (size_t i = 0; i < N; ++i) {
1325  Vc::assign(*this, i, fun(i));
1326  }
1327 }
1328 // }}}
1329 namespace IteratorDetails // {{{
1330 {
1331 enum class Mutable { Yes, No };
1332 
1333 template <typename It, typename V, size_t I, size_t End>
1334 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I == End), It>)
1335 {
1336  return {};
1337 }
1338 template <typename It, typename V, size_t I, size_t End>
1339 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I < End), It> it)
1340 {
1341  V r = fromIteratorImpl<It, V, I + 1, End>(it);
1342  Traits::decay<decltype(get_dispatcher<I>(r))> tmp;
1343  for (size_t j = 0; j < V::size(); ++j, ++it) {
1344  tmp[j] = get_dispatcher<I>(*it);
1345  }
1346  get_dispatcher<I>(r) = tmp;
1347  return r;
1348 }
1349 template <typename It, typename V>
1350 Vc_INTRINSIC V fromIterator(enable_if<!Traits::is_simd_vector<V>::value, const It &> it)
1351 {
1352  return fromIteratorImpl<It, V, 0, determine_tuple_size<V>()>(it);
1353 }
1354 template <typename It, typename V>
1355 Vc_INTRINSIC V fromIterator(enable_if<Traits::is_simd_vector<V>::value, It> it)
1356 {
1357  V r;
1358  for (size_t j = 0; j < V::size(); ++j, ++it) {
1359  r[j] = *it;
1360  }
1361  return r;
1362 }
1363 
1364 // Note: §13.5.6 says: “An expression x->m is interpreted as (x.operator->())->m for a
1365 // class object x of type T if T::operator->() exists and if the operator is selected as
1366 // the best match function by the overload resolution mechanism (13.3).”
1367 template <typename T, typename value_vector, Mutable> class Pointer;
1368 
1377 template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::Yes>
1378 {
1379  static constexpr auto Size = value_vector::size();
1380 
1381 public:
1383  value_vector *operator->() { return &data; }
1384 
1389  Pointer() = delete;
1390  Pointer(const Pointer &) = delete;
1391  Pointer &operator=(const Pointer &) = delete;
1392  Pointer &operator=(Pointer &&) = delete;
1393 
1395  Pointer(Pointer &&) = default;
1396 
1402  ~Pointer()
1403  {
1404  // store data back to where it came from
1405  for (size_t i = 0; i < Size; ++i, ++begin_iterator) {
1406  *begin_iterator = extract(data, i);
1407  }
1408  }
1409 
1411  Pointer(const T &it) : data(fromIterator<T, value_vector>(it)), begin_iterator(it) {}
1412 
1413 private:
1415  value_vector data;
1417  T begin_iterator;
1418 };
1424 template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::No>
1425 {
1426  static constexpr auto Size = value_vector::size();
1427 
1428 public:
1429  const value_vector *operator->() const { return &data; }
1430 
1431  Pointer() = delete;
1432  Pointer(const Pointer &) = delete;
1433  Pointer &operator=(const Pointer &) = delete;
1434  Pointer &operator=(Pointer &&) = delete;
1435 
1436  Pointer(Pointer &&) = default; // required for returning the Pointer
1437 
1438  Pointer(const T &it) : data(fromIterator<T, value_vector>(it)) {}
1439 
1440 private:
1441  value_vector data;
1442 };
1443 
1456 template <typename T, typename value_vector, Mutable M> class Reference;
1457 
1459 template <typename T, typename value_vector>
1460 class Reference<T, value_vector, Mutable::Yes> : public value_vector
1461 {
1462  static constexpr auto Size = value_vector::size();
1463 
1464  using reference = typename std::add_lvalue_reference<T>::type;
1465  reference scalar_it;
1466 
1467 public:
1470  Reference(reference first_it)
1471  : value_vector(fromIterator<T, value_vector>(first_it)), scalar_it(first_it)
1472  {
1473  }
1474 
1476  Reference(const Reference &) = delete;
1477  Reference(Reference &&) = default;
1478  Reference &operator=(const Reference &) = delete;
1479  Reference &operator=(Reference &&) = delete;
1480 
1486  void operator=(const value_vector &x)
1487  {
1488  static_cast<value_vector &>(*this) = x;
1489  auto it = scalar_it;
1490  for (size_t i = 0; i < Size; ++i, ++it) {
1491  *it = extract(x, i);
1492  }
1493  }
1494 };
1495 #define Vc_OP(op_) \
1496  template <typename T0, typename V0, typename T1, typename V1> \
1497  decltype(std::declval<const V0 &>() op_ std::declval<const V1 &>()) operator op_( \
1498  const Reference<T0, V0, Mutable::Yes> &x, \
1499  const Reference<T1, V1, Mutable::Yes> &y) \
1500  { \
1501  return static_cast<const V0 &>(x) op_ static_cast<const V1 &>(y); \
1502  }
1503 Vc_ALL_COMPARES(Vc_OP);
1504 Vc_ALL_ARITHMETICS(Vc_OP);
1505 Vc_ALL_BINARY(Vc_OP);
1506 Vc_ALL_LOGICAL(Vc_OP);
1507 Vc_ALL_SHIFTS(Vc_OP);
1508 #undef Vc_OP
1509 
1511 template <typename T, typename value_vector>
1512 class Reference<T, value_vector, Mutable::No> : public value_vector
1513 {
1514  static constexpr auto Size = value_vector::size();
1515 
1516 public:
1517  Reference(const T &it) : value_vector(fromIterator<T, value_vector>(it)) {}
1518 
1519  Reference(const Reference &) = delete;
1520  Reference(Reference &&) = default;
1521  Reference &operator=(const Reference &) = delete;
1522  Reference &operator=(Reference &&) = delete;
1523 
1525  void operator=(const value_vector &x) = delete;
1526 };
1527 
1528 template <typename T, size_t N,
1529  IteratorDetails::Mutable M =
1530  (Traits::is_output_iterator<T>::value ? Mutable::Yes : Mutable::No),
1531  typename V = simdize<typename std::iterator_traits<T>::value_type, N>,
1532  size_t Size = V::Size,
1533  typename = typename std::iterator_traits<T>::iterator_category>
1534 class Iterator;
1535 
1536 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size_>
1537 class Iterator<T, N, M, V, Size_, std::forward_iterator_tag>
1538  : public std::iterator<typename std::iterator_traits<T>::iterator_category, V,
1539  typename std::iterator_traits<T>::difference_type,
1540  IteratorDetails::Pointer<T, V, M>,
1541  IteratorDetails::Reference<T, V, M>>
1542 {
1543 public:
1544  using pointer = IteratorDetails::Pointer<T, V, M>;
1545  using reference = IteratorDetails::Reference<T, V, M>;
1546  using const_pointer = IteratorDetails::Pointer<T, V, IteratorDetails::Mutable::No>;
1547  using const_reference =
1548  IteratorDetails::Reference<T, V, IteratorDetails::Mutable::No>;
1549 
1551  static constexpr std::size_t size() { return Size_; }
1552  static constexpr std::size_t Size = Size_;
1553 
1554  Iterator() = default;
1555 
1562  Iterator(const T &x) : scalar_it(x) {}
1566  Iterator(T &&x) : scalar_it(std::move(x)) {}
1570  Iterator &operator=(const T &x)
1571  {
1572  scalar_it = x;
1573  return *this;
1574  }
1578  Iterator &operator=(T &&x)
1579  {
1580  scalar_it = std::move(x);
1581  return *this;
1582  }
1583 
1585  Iterator(const Iterator &) = default;
1587  Iterator(Iterator &&) = default;
1589  Iterator &operator=(const Iterator &) = default;
1591  Iterator &operator=(Iterator &&) = default;
1592 
1594  Iterator &operator++()
1595  {
1596  std::advance(scalar_it, Size);
1597  return *this;
1598  }
1600  Iterator operator++(int)
1601  {
1602  Iterator copy(*this);
1603  operator++();
1604  return copy;
1605  }
1606 
1615  bool operator==(const Iterator &rhs) const
1616  {
1617 #ifndef NDEBUG
1618  if (scalar_it == rhs.scalar_it) {
1619  return true;
1620  } else {
1621  T it(scalar_it);
1622  for (size_t i = 1; i < Size; ++i) {
1623  Vc_ASSERT((++it != rhs.scalar_it));
1624  }
1625  return false;
1626  }
1627 #else
1628  return scalar_it == rhs.scalar_it;
1629 #endif
1630  }
1639  bool operator!=(const Iterator &rhs) const
1640  {
1641  return !operator==(rhs);
1642  }
1643 
1644  pointer operator->() { return scalar_it; }
1645 
1652  reference operator*() { return scalar_it; }
1653 
1654  const_pointer operator->() const { return scalar_it; }
1655 
1663  const_reference operator*() const { return scalar_it; }
1664 
1678  operator const T &() const { return scalar_it; }
1679 
1680 protected:
1681  T scalar_it;
1682 };
1683 
1688 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1689 class Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1690  : public Iterator<T, N, M, V, Size, std::forward_iterator_tag>
1691 {
1692  using Base = Iterator<T, N, M, V, Size, std::forward_iterator_tag>;
1693 
1694 protected:
1695  using Base::scalar_it;
1696 
1697 public:
1698  using pointer = typename Base::pointer;
1699  using reference = typename Base::reference;
1700  using const_pointer = typename Base::const_pointer;
1701  using const_reference = typename Base::const_reference;
1702 
1703  using Iterator<T, N, M, V, Size,
1704  std::forward_iterator_tag>::Iterator; // in short: "using
1705  // Base::Iterator", but that
1706  // confuses ICC
1708  Iterator &operator--()
1709  {
1710  std::advance(scalar_it, -Size);
1711  return *this;
1712  }
1714  Iterator operator--(int)
1715  {
1716  Iterator copy(*this);
1717  operator--();
1718  return copy;
1719  }
1720 };
1721 
1726 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1727 class Iterator<T, N, M, V, Size, std::random_access_iterator_tag>
1728  : public Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1729 {
1731 
1732 protected:
1733  using Base::scalar_it;
1734 
1735 public:
1736  using pointer = typename Base::pointer;
1737  using reference = typename Base::reference;
1738  using const_pointer = typename Base::const_pointer;
1739  using const_reference = typename Base::const_reference;
1740  using difference_type = typename std::iterator_traits<T>::difference_type;
1741 
1743  Iterator; // in short: "using Base::Iterator", but that confuses ICC
1744 
1745  Iterator &operator+=(difference_type n)
1746  {
1747  scalar_it += n * difference_type(Size);
1748  return *this;
1749  }
1750  Iterator operator+(difference_type n) const { return Iterator(*this) += n; }
1751 
1752  Iterator &operator-=(difference_type n)
1753  {
1754  scalar_it -= n * difference_type(Size);
1755  return *this;
1756  }
1757  Iterator operator-(difference_type n) const { return Iterator(*this) -= n; }
1758 
1759  difference_type operator-(const Iterator &rhs) const
1760  {
1761  constexpr difference_type n = Size;
1762  Vc_ASSERT((scalar_it - rhs.scalar_it) % n ==
1763  0); // if this fails the two iterators are not a multiple of the vector
1764  // width apart. The distance would be fractional and that doesn't
1765  // make too much sense for iteration. Therefore, it is a
1766  // precondition for the distance of the two iterators to be a
1767  // multiple of Size.
1768  return (scalar_it - rhs.scalar_it) / n;
1769  }
1770 
1775  bool operator<(const Iterator &rhs) const
1776  {
1777  return rhs.scalar_it - scalar_it >= difference_type(Size);
1778  }
1779 
1780  bool operator>(const Iterator &rhs) const
1781  {
1782  return scalar_it - rhs.scalar_it >= difference_type(Size);
1783  }
1784 
1785  bool operator<=(const Iterator &rhs) const
1786  {
1787  return rhs.scalar_it - scalar_it >= difference_type(Size) - 1;
1788  }
1789 
1790  bool operator>=(const Iterator &rhs) const
1791  {
1792  return scalar_it - rhs.scalar_it >= difference_type(Size) - 1;
1793  }
1794 
1795  reference operator[](difference_type i) { return *(*this + i); }
1796  const_reference operator[](difference_type i) const { return *(*this + i); }
1797 };
1798 
1799 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1801  typename Iterator<T, N, M, V, Size, std::random_access_iterator_tag>::difference_type
1802  n,
1804 {
1805  return i + n;
1806 }
1807 
1808 } // namespace IteratorDetails }}}
1809 
1818 template <typename T, size_t N, typename MT>
1819 struct ReplaceTypes<T, N, MT, Category::ForwardIterator>
1820 {
1821  using type = IteratorDetails::Iterator<T, N>;
1822 };
1823 template <typename T, size_t N, typename MT>
1824 struct ReplaceTypes<T, N, MT, Category::BidirectionalIterator>
1825 {
1826  using type = IteratorDetails::Iterator<T, N>;
1827 };
1828 template <typename T, size_t N, typename MT>
1829 struct ReplaceTypes<T, N, MT, Category::RandomAccessIterator>
1830 {
1831  using type = IteratorDetails::Iterator<T, N>;
1832 };
1833 
1837 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1838  std::size_t Offset>
1839 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size_<S>::value && M::Size == N), void>
1840  conditional_assign(Adapter<S, T, N> &, const M &, const U &)
1841 {
1842 }
1843 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1844  std::size_t Offset = 0>
1845 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size_<S>::value && M::Size == N), void>
1846  conditional_assign(Adapter<S, T, N> &lhs, const M &mask, const U &rhs)
1847 {
1848  using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1849  using M2 = typename V::mask_type;
1850  conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask), get_dispatcher<Offset>(rhs));
1851  conditional_assign<Op, S, T, N, M, U, Offset + 1>(lhs, mask, rhs);
1852 }
1853 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1854  std::size_t Offset>
1855 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size_<S>::value && M::Size == N), void>
1856  conditional_assign(Adapter<S, T, N> &, const M &)
1857 {
1858 }
1859 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1860  std::size_t Offset = 0>
1861 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size_<S>::value && M::Size == N), void>
1862  conditional_assign(Adapter<S, T, N> &lhs, const M &mask)
1863 {
1864  using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1865  using M2 = typename V::mask_type;
1866  conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask));
1867  conditional_assign<Op, S, T, N, M, Offset + 1>(lhs, mask);
1868 }
1869 
1871 } // namespace SimdizeDetail
1872 
1873 // user API {{{
1892 template <typename T, size_t N = 0, typename MT = void>
1893 using simdize = SimdizeDetail::simdize<T, N, MT>;
1894 
1914 #define Vc_SIMDIZE_INTERFACE(MEMBERS_) \
1915  template <std::size_t N_> \
1916  inline auto vc_get_()->decltype(std::get<N_>(std::tie MEMBERS_)) \
1917  { \
1918  return std::get<N_>(std::tie MEMBERS_); \
1919  } \
1920  template <std::size_t N_> \
1921  inline auto vc_get_() const->decltype(std::get<N_>(std::tie MEMBERS_)) \
1922  { \
1923  return std::get<N_>(std::tie MEMBERS_); \
1924  } \
1925  enum : std::size_t { \
1926  tuple_size = std::tuple_size<decltype(std::make_tuple MEMBERS_)>::value \
1927  }
1928 // }}}
1929 } // namespace Vc
1930 
1931 namespace std // {{{
1932 {
1933 using Vc::SimdizeDetail::swap;
1934 } // namespace std }}}
1935 
1936 #endif // VC_COMMON_SIMDIZE_H_
1937 
1938 // vim: foldmethod=marker
void free(T *p)
Frees memory that was allocated with Vc::malloc.
Definition: malloc.h:163
bool operator<(const Iterator &rhs) const
Returns whether all entries accessed via iterator dereferencing come before the iterator rhs...
Definition: simdize.h:1775
result_vector_type< L, R > operator-(L &&lhs, R &&rhs)
Applies - component-wise and concurrently.
Definition: simdarray.h:1721
Definition: vector.h:248
result_vector_type< L, R > operator*(L &&lhs, R &&rhs)
Applies * component-wise and concurrently.
Definition: simdarray.h:1721
SimdizeDetail::simdize< T, N, MT > simdize
Definition: simdize.h:1893
Wraps a pointer to memory with convenience functions to access it via vectors.
void assign(SimdizeDetail::Adapter< S, T, N > &a, size_t i, const S &x)
Assigns one scalar object x to a SIMD slot at offset i in the simdized object a.
Definition: simdize.h:1221
An allocator that uses global new and supports over-aligned types, as per [C++11 20.6.9].
Definition: Allocator:128
Identifies any SIMD vector type (independent of implementation or whether it&#39;s SimdArray<T, N>).
Definition: type_traits.h:128
result_vector_type< L, R > operator+(L &&lhs, R &&rhs)
Applies + component-wise and concurrently.
Definition: simdarray.h:1721
Iterator & operator--()
Advances the iterator by one vector width, or respectively N scalar steps.
Definition: simdize.h:1708
Adapter< S, T, N > shifted(const Adapter< S, T, N > &a, int shift)
Returns a new vectorized object where each entry is shifted by shift.
Definition: simdize.h:1069
This is the iterator type created when applying simdize to a random access iterator type...
Definition: simdize.h:1727
Vector Classes Namespace.
Definition: dox.h:584
This is the iterator type created when applying simdize to a bidirectional iterator type...
Definition: simdize.h:1689
S extract(const SimdizeDetail::Adapter< S, T, N > &a, size_t i)
Extracts and returns one scalar object from a SIMD slot at offset i in the simdized object a...
Definition: simdize.h:1241
constexpr UnalignedTag Unaligned
Use this object for a flags parameter to request unaligned loads and stores.