Vc  1.4.2
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 {
1170  const InterleavedMemoryWrapper<S, decltype(decay_workaround(get_dispatcher<0>(a)))>
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 {
1180  InterleavedMemoryWrapper<S, decltype(decay_workaround(get_dispatcher<0>(a)))> wrapper(
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<
1311  Traits::is_simd_vector<typename std::decay<V>::type>::value>>
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 
1355 template <typename It, typename V>
1356 Vc_INTRINSIC V fromIterator(
1357  enable_if<
1358  Traits::is_simd_vector<V>::value && Traits::has_contiguous_storage<It>::value, It>
1359  it)
1360 {
1361  Vc_ASSERT(&*it + 1 == &*(it + 1));
1362  return V(&*it, Vc::Unaligned);
1363 }
1364 
1365 template <typename It, typename V>
1366 Vc_INTRINSIC V fromIterator(enable_if<Traits::is_simd_vector<V>::value &&
1367  !Traits::has_contiguous_storage<It>::value,
1368  It>
1369  it)
1370 {
1371  V r;
1372  for (size_t j = 0; j < V::size(); ++j, ++it) {
1373  r[j] = *it;
1374  }
1375  return r;
1376 }
1377 
1378 // Note: §13.5.6 says: “An expression x->m is interpreted as (x.operator->())->m for a
1379 // class object x of type T if T::operator->() exists and if the operator is selected as
1380 // the best match function by the overload resolution mechanism (13.3).”
1381 template <typename T, typename value_vector, Mutable> class Pointer;
1382 
1391 template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::Yes>
1392 {
1393  static constexpr auto Size = value_vector::size();
1394 
1395 public:
1397  value_vector *operator->() { return &data; }
1398 
1403  Pointer() = delete;
1404  Pointer(const Pointer &) = delete;
1405  Pointer &operator=(const Pointer &) = delete;
1406  Pointer &operator=(Pointer &&) = delete;
1407 
1409  Pointer(Pointer &&) = default;
1410 
1416  ~Pointer()
1417  {
1418  // store data back to where it came from
1419  for (size_t i = 0; i < Size; ++i, ++begin_iterator) {
1420  *begin_iterator = extract(data, i);
1421  }
1422  }
1423 
1425  Pointer(const T &it) : data(fromIterator<T, value_vector>(it)), begin_iterator(it) {}
1426 
1427 private:
1429  value_vector data;
1431  T begin_iterator;
1432 };
1438 template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::No>
1439 {
1440  static constexpr auto Size = value_vector::size();
1441 
1442 public:
1443  const value_vector *operator->() const { return &data; }
1444 
1445  Pointer() = delete;
1446  Pointer(const Pointer &) = delete;
1447  Pointer &operator=(const Pointer &) = delete;
1448  Pointer &operator=(Pointer &&) = delete;
1449 
1450  Pointer(Pointer &&) = default; // required for returning the Pointer
1451 
1452  Pointer(const T &it) : data(fromIterator<T, value_vector>(it)) {}
1453 
1454 private:
1455  value_vector data;
1456 };
1457 
1470 template <typename T, typename value_vector, Mutable M> class Reference;
1471 
1473 template <typename T, typename value_vector>
1474 class Reference<T, value_vector, Mutable::Yes> : public value_vector
1475 {
1476  static constexpr auto Size = value_vector::size();
1477 
1478  using reference = typename std::add_lvalue_reference<T>::type;
1479  reference scalar_it;
1480 
1481 public:
1484  Reference(reference first_it)
1485  : value_vector(fromIterator<T, value_vector>(first_it)), scalar_it(first_it)
1486  {
1487  }
1488 
1490  Reference(const Reference &) = delete;
1491  Reference(Reference &&) = default;
1492  Reference &operator=(const Reference &) = delete;
1493  Reference &operator=(Reference &&) = delete;
1494 
1500  void operator=(const value_vector &x)
1501  {
1502  static_cast<value_vector &>(*this) = x;
1503  auto it = scalar_it;
1504  for (size_t i = 0; i < Size; ++i, ++it) {
1505  *it = extract(x, i);
1506  }
1507  }
1508 };
1509 #define Vc_OP(op_) \
1510  template <typename T0, typename V0, typename T1, typename V1> \
1511  decltype(std::declval<const V0 &>() op_ std::declval<const V1 &>()) operator op_( \
1512  const Reference<T0, V0, Mutable::Yes> &x, \
1513  const Reference<T1, V1, Mutable::Yes> &y) \
1514  { \
1515  return static_cast<const V0 &>(x) op_ static_cast<const V1 &>(y); \
1516  }
1517 Vc_ALL_COMPARES(Vc_OP);
1518 Vc_ALL_ARITHMETICS(Vc_OP);
1519 Vc_ALL_BINARY(Vc_OP);
1520 Vc_ALL_LOGICAL(Vc_OP);
1521 Vc_ALL_SHIFTS(Vc_OP);
1522 #undef Vc_OP
1523 
1525 template <typename T, typename value_vector>
1526 class Reference<T, value_vector, Mutable::No> : public value_vector
1527 {
1528  static constexpr auto Size = value_vector::size();
1529 
1530 public:
1531  Reference(const T &it) : value_vector(fromIterator<T, value_vector>(it)) {}
1532 
1533  Reference(const Reference &) = delete;
1534  Reference(Reference &&) = default;
1535  Reference &operator=(const Reference &) = delete;
1536  Reference &operator=(Reference &&) = delete;
1537 
1539  void operator=(const value_vector &x) = delete;
1540 };
1541 
1542 template <typename T, size_t N,
1543  IteratorDetails::Mutable M =
1544  (Traits::is_output_iterator<T>::value ? Mutable::Yes : Mutable::No),
1545  typename V = simdize<typename std::iterator_traits<T>::value_type, N>,
1546  size_t Size = V::Size,
1547  typename = typename std::iterator_traits<T>::iterator_category>
1548 class Iterator;
1549 
1550 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size_>
1551 class Iterator<T, N, M, V, Size_, std::forward_iterator_tag>
1552  : public std::iterator<typename std::iterator_traits<T>::iterator_category, V,
1553  typename std::iterator_traits<T>::difference_type,
1554  IteratorDetails::Pointer<T, V, M>,
1555  IteratorDetails::Reference<T, V, M>>
1556 {
1557 public:
1558  using pointer = IteratorDetails::Pointer<T, V, M>;
1559  using reference = IteratorDetails::Reference<T, V, M>;
1560  using const_pointer = IteratorDetails::Pointer<T, V, IteratorDetails::Mutable::No>;
1561  using const_reference =
1562  IteratorDetails::Reference<T, V, IteratorDetails::Mutable::No>;
1563 
1565  static constexpr std::size_t size() { return Size_; }
1566  static constexpr std::size_t Size = Size_;
1567 
1568  Iterator() = default;
1569 
1576  Iterator(const T &x) : scalar_it(x) {}
1580  Iterator(T &&x) : scalar_it(std::move(x)) {}
1584  Iterator &operator=(const T &x)
1585  {
1586  scalar_it = x;
1587  return *this;
1588  }
1592  Iterator &operator=(T &&x)
1593  {
1594  scalar_it = std::move(x);
1595  return *this;
1596  }
1597 
1599  Iterator(const Iterator &) = default;
1601  Iterator(Iterator &&) = default;
1603  Iterator &operator=(const Iterator &) = default;
1605  Iterator &operator=(Iterator &&) = default;
1606 
1608  Iterator &operator++()
1609  {
1610  std::advance(scalar_it, Size);
1611  return *this;
1612  }
1614  Iterator operator++(int)
1615  {
1616  Iterator copy(*this);
1617  operator++();
1618  return copy;
1619  }
1620 
1629  bool operator==(const Iterator &rhs) const
1630  {
1631 #ifndef NDEBUG
1632  if (scalar_it == rhs.scalar_it) {
1633  return true;
1634  } else {
1635  T it(scalar_it);
1636  for (size_t i = 1; i < Size; ++i) {
1637  Vc_ASSERT((++it != rhs.scalar_it));
1638  }
1639  return false;
1640  }
1641 #else
1642  return scalar_it == rhs.scalar_it;
1643 #endif
1644  }
1653  bool operator!=(const Iterator &rhs) const
1654  {
1655  return !operator==(rhs);
1656  }
1657 
1658  pointer operator->() { return scalar_it; }
1659 
1666  reference operator*() { return scalar_it; }
1667 
1668  const_pointer operator->() const { return scalar_it; }
1669 
1677  const_reference operator*() const { return scalar_it; }
1678 
1692  operator const T &() const { return scalar_it; }
1693 
1694 protected:
1695  T scalar_it;
1696 };
1697 
1702 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1703 class Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1704  : public Iterator<T, N, M, V, Size, std::forward_iterator_tag>
1705 {
1706  using Base = Iterator<T, N, M, V, Size, std::forward_iterator_tag>;
1707 
1708 protected:
1709  using Base::scalar_it;
1710 
1711 public:
1712  using pointer = typename Base::pointer;
1713  using reference = typename Base::reference;
1714  using const_pointer = typename Base::const_pointer;
1715  using const_reference = typename Base::const_reference;
1716 
1717  using Iterator<T, N, M, V, Size,
1718  std::forward_iterator_tag>::Iterator; // in short: "using
1719  // Base::Iterator", but that
1720  // confuses ICC
1722  Iterator &operator--()
1723  {
1724  std::advance(scalar_it, -Size);
1725  return *this;
1726  }
1728  Iterator operator--(int)
1729  {
1730  Iterator copy(*this);
1731  operator--();
1732  return copy;
1733  }
1734 };
1735 
1740 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1741 class Iterator<T, N, M, V, Size, std::random_access_iterator_tag>
1742  : public Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1743 {
1745 
1746 protected:
1747  using Base::scalar_it;
1748 
1749 public:
1750  using pointer = typename Base::pointer;
1751  using reference = typename Base::reference;
1752  using const_pointer = typename Base::const_pointer;
1753  using const_reference = typename Base::const_reference;
1754  using difference_type = typename std::iterator_traits<T>::difference_type;
1755 
1757  Iterator; // in short: "using Base::Iterator", but that confuses ICC
1758 
1759  Iterator &operator+=(difference_type n)
1760  {
1761  scalar_it += n * difference_type(Size);
1762  return *this;
1763  }
1764  Iterator operator+(difference_type n) const { return Iterator(*this) += n; }
1765 
1766  Iterator &operator-=(difference_type n)
1767  {
1768  scalar_it -= n * difference_type(Size);
1769  return *this;
1770  }
1771  Iterator operator-(difference_type n) const { return Iterator(*this) -= n; }
1772 
1773  difference_type operator-(const Iterator &rhs) const
1774  {
1775  constexpr difference_type n = Size;
1776  Vc_ASSERT((scalar_it - rhs.scalar_it) % n ==
1777  0); // if this fails the two iterators are not a multiple of the vector
1778  // width apart. The distance would be fractional and that doesn't
1779  // make too much sense for iteration. Therefore, it is a
1780  // precondition for the distance of the two iterators to be a
1781  // multiple of Size.
1782  return (scalar_it - rhs.scalar_it) / n;
1783  }
1784 
1789  bool operator<(const Iterator &rhs) const
1790  {
1791  return rhs.scalar_it - scalar_it >= difference_type(Size);
1792  }
1793 
1794  bool operator>(const Iterator &rhs) const
1795  {
1796  return scalar_it - rhs.scalar_it >= difference_type(Size);
1797  }
1798 
1799  bool operator<=(const Iterator &rhs) const
1800  {
1801  return rhs.scalar_it - scalar_it >= difference_type(Size) - 1;
1802  }
1803 
1804  bool operator>=(const Iterator &rhs) const
1805  {
1806  return scalar_it - rhs.scalar_it >= difference_type(Size) - 1;
1807  }
1808 
1809  reference operator[](difference_type i) { return *(*this + i); }
1810  const_reference operator[](difference_type i) const { return *(*this + i); }
1811 };
1812 
1813 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1814 Iterator<T, N, M, V, Size, std::random_access_iterator_tag> operator+(
1815  typename Iterator<T, N, M, V, Size, std::random_access_iterator_tag>::difference_type
1816  n,
1817  const Iterator<T, N, M, V, Size, std::random_access_iterator_tag> &i)
1818 {
1819  return i + n;
1820 }
1821 
1822 } // namespace IteratorDetails }}}
1823 
1832 template <typename T, size_t N, typename MT>
1833 struct ReplaceTypes<T, N, MT, Category::ForwardIterator>
1834 {
1835  using type = IteratorDetails::Iterator<T, N>;
1836 };
1837 template <typename T, size_t N, typename MT>
1838 struct ReplaceTypes<T, N, MT, Category::BidirectionalIterator>
1839 {
1840  using type = IteratorDetails::Iterator<T, N>;
1841 };
1842 template <typename T, size_t N, typename MT>
1843 struct ReplaceTypes<T, N, MT, Category::RandomAccessIterator>
1844 {
1845  using type = IteratorDetails::Iterator<T, N>;
1846 };
1847 
1851 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1852  std::size_t Offset>
1853 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size_<S>::value && M::Size == N), void>
1854  conditional_assign(Adapter<S, T, N> &, const M &, const U &)
1855 {
1856 }
1857 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1858  std::size_t Offset = 0>
1859 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size_<S>::value && M::Size == N), void>
1860  conditional_assign(Adapter<S, T, N> &lhs, const M &mask, const U &rhs)
1861 {
1862  using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1863  using M2 = typename V::mask_type;
1864  conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask), get_dispatcher<Offset>(rhs));
1865  conditional_assign<Op, S, T, N, M, U, Offset + 1>(lhs, mask, rhs);
1866 }
1867 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1868  std::size_t Offset>
1869 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size_<S>::value && M::Size == N), void>
1870  conditional_assign(Adapter<S, T, N> &, const M &)
1871 {
1872 }
1873 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1874  std::size_t Offset = 0>
1875 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size_<S>::value && M::Size == N), void>
1876  conditional_assign(Adapter<S, T, N> &lhs, const M &mask)
1877 {
1878  using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1879  using M2 = typename V::mask_type;
1880  conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask));
1881  conditional_assign<Op, S, T, N, M, Offset + 1>(lhs, mask);
1882 }
1883 
1885 } // namespace SimdizeDetail
1886 
1887 // user API {{{
1906 template <typename T, size_t N = 0, typename MT = void>
1907 using simdize = SimdizeDetail::simdize<T, N, MT>;
1908 
1928 #define Vc_SIMDIZE_INTERFACE(MEMBERS_) \
1929  template <std::size_t N_> \
1930  inline auto vc_get_()->decltype(std::get<N_>(std::tie MEMBERS_)) \
1931  { \
1932  return std::get<N_>(std::tie MEMBERS_); \
1933  } \
1934  template <std::size_t N_> \
1935  inline auto vc_get_() const->decltype(std::get<N_>(std::tie MEMBERS_)) \
1936  { \
1937  return std::get<N_>(std::tie MEMBERS_); \
1938  } \
1939  enum : std::size_t { \
1940  tuple_size = std::tuple_size<decltype(std::make_tuple MEMBERS_)>::value \
1941  }
1942 // }}}
1943 } // namespace Vc
1944 
1945 namespace std // {{{
1946 {
1947 using Vc::SimdizeDetail::swap;
1948 } // namespace std }}}
1949 
1950 #endif // VC_COMMON_SIMDIZE_H_
1951 
1952 // vim: foldmethod=marker
Vc::free
void free(T *p)
Frees memory that was allocated with Vc::malloc.
Definition: malloc.h:163
Vc::operator-
Vc_INTRINSIC result_vector_type< L, R > operator-(L &&lhs, R &&rhs)
Applies - component-wise and concurrently.
Definition: simdarray.h:1722
Vc::SimdizeDetail::IteratorDetails::Iterator< T, N, M, V, Size, std::bidirectional_iterator_tag >
This is the iterator type created when applying simdize to a bidirectional iterator type.
Definition: simdize.h:1703
Vc::Unaligned
constexpr UnalignedTag Unaligned
Use this object for a flags parameter to request unaligned loads and stores.
Definition: loadstoreflags.h:191
Vc
Vector Classes Namespace.
Definition: dox.h:586
Vc::SimdizeDetail::IteratorDetails::Iterator< T, N, M, V, Size, std::random_access_iterator_tag >::operator<
bool operator<(const Iterator &rhs) const
Returns whether all entries accessed via iterator dereferencing come before the iterator rhs.
Definition: simdize.h:1789
Vc::Allocator
An allocator that uses global new and supports over-aligned types, as per [C++11 20....
Definition: Allocator:128
Vc::assign
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
Vc::SimdizeDetail::IteratorDetails::Iterator< T, N, M, V, Size, std::bidirectional_iterator_tag >::operator--
Iterator & operator--()
Advances the iterator by one vector width, or respectively N scalar steps.
Definition: simdize.h:1722
Vc::SimdizeDetail::shifted
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
Vc::simdize
SimdizeDetail::simdize< T, N, MT > simdize
Definition: simdize.h:1907
Vc::operator+
result_vector_type< L, R > operator+(L &&lhs, R &&rhs)
Applies + component-wise and concurrently.
Definition: simdarray.h:1722
Vc::operator*
Vc_INTRINSIC result_vector_type< L, R > operator*(L &&lhs, R &&rhs)
Applies * component-wise and concurrently.
Definition: simdarray.h:1722
Vc::SimdizeDetail::IteratorDetails::Iterator< T, N, M, V, Size, std::bidirectional_iterator_tag >::operator--
Iterator operator--(int)
Postfix overload of the above.
Definition: simdize.h:1728
Vc::extract
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