Vc  1.4.3
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
403 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
861  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 #ifndef _MSC_VER
1362  // this check potentially moves it past the end of a container, which is UB. Some STL
1363  // implementations, like MS STL, trap this.
1364  Vc_ASSERT(&*it + 1 == &*(it + 1));
1365 #endif
1366  return V(&*it, Vc::Unaligned);
1367 }
1368 
1369 template <typename It, typename V>
1370 Vc_INTRINSIC V fromIterator(enable_if<Traits::is_simd_vector<V>::value &&
1371  !Traits::has_contiguous_storage<It>::value,
1372  It>
1373  it)
1374 {
1375  V r;
1376  for (size_t j = 0; j < V::size(); ++j, ++it) {
1377  r[j] = *it;
1378  }
1379  return r;
1380 }
1381 
1382 // Note: §13.5.6 says: “An expression x->m is interpreted as (x.operator->())->m for a
1383 // class object x of type T if T::operator->() exists and if the operator is selected as
1384 // the best match function by the overload resolution mechanism (13.3).”
1385 template <typename T, typename value_vector, Mutable> class Pointer;
1386 
1395 template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::Yes>
1396 {
1397  static constexpr auto Size = value_vector::size();
1398 
1399 public:
1401  value_vector *operator->() { return &data; }
1402 
1407  Pointer() = delete;
1408  Pointer(const Pointer &) = delete;
1409  Pointer &operator=(const Pointer &) = delete;
1410  Pointer &operator=(Pointer &&) = delete;
1411 
1413  Pointer(Pointer &&) = default;
1414 
1420  ~Pointer()
1421  {
1422  // store data back to where it came from
1423  for (size_t i = 0; i < Size; ++i, ++begin_iterator) {
1424  *begin_iterator = extract(data, i);
1425  }
1426  }
1427 
1429  Pointer(const T &it) : data(fromIterator<T, value_vector>(it)), begin_iterator(it) {}
1430 
1431 private:
1433  value_vector data;
1435  T begin_iterator;
1436 };
1442 template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::No>
1443 {
1444  static constexpr auto Size = value_vector::size();
1445 
1446 public:
1447  const value_vector *operator->() const { return &data; }
1448 
1449  Pointer() = delete;
1450  Pointer(const Pointer &) = delete;
1451  Pointer &operator=(const Pointer &) = delete;
1452  Pointer &operator=(Pointer &&) = delete;
1453 
1454  Pointer(Pointer &&) = default; // required for returning the Pointer
1455 
1456  Pointer(const T &it) : data(fromIterator<T, value_vector>(it)) {}
1457 
1458 private:
1459  value_vector data;
1460 };
1461 
1474 template <typename T, typename value_vector, Mutable M> class Reference;
1475 
1477 template <typename T, typename value_vector>
1478 class Reference<T, value_vector, Mutable::Yes> : public value_vector
1479 {
1480  static constexpr auto Size = value_vector::size();
1481 
1482  using reference = typename std::add_lvalue_reference<T>::type;
1483  reference scalar_it;
1484 
1485 public:
1488  Reference(reference first_it)
1489  : value_vector(fromIterator<T, value_vector>(first_it)), scalar_it(first_it)
1490  {
1491  }
1492 
1494  Reference(const Reference &) = delete;
1495  Reference(Reference &&) = default;
1496  Reference &operator=(const Reference &) = delete;
1497  Reference &operator=(Reference &&) = delete;
1498 
1504  void operator=(const value_vector &x)
1505  {
1506  static_cast<value_vector &>(*this) = x;
1507  auto it = scalar_it;
1508  for (size_t i = 0; i < Size; ++i, ++it) {
1509  *it = extract(x, i);
1510  }
1511  }
1512 };
1513 #define Vc_OP(op_) \
1514  template <typename T0, typename V0, typename T1, typename V1> \
1515  decltype(std::declval<const V0 &>() op_ std::declval<const V1 &>()) operator op_( \
1516  const Reference<T0, V0, Mutable::Yes> &x, \
1517  const Reference<T1, V1, Mutable::Yes> &y) \
1518  { \
1519  return static_cast<const V0 &>(x) op_ static_cast<const V1 &>(y); \
1520  }
1521 Vc_ALL_COMPARES(Vc_OP);
1522 Vc_ALL_ARITHMETICS(Vc_OP);
1523 Vc_ALL_BINARY(Vc_OP);
1524 Vc_ALL_LOGICAL(Vc_OP);
1525 Vc_ALL_SHIFTS(Vc_OP);
1526 #undef Vc_OP
1527 
1529 template <typename T, typename value_vector>
1530 class Reference<T, value_vector, Mutable::No> : public value_vector
1531 {
1532  static constexpr auto Size = value_vector::size();
1533 
1534 public:
1535  Reference(const T &it) : value_vector(fromIterator<T, value_vector>(it)) {}
1536 
1537  Reference(const Reference &) = delete;
1538  Reference(Reference &&) = default;
1539  Reference &operator=(const Reference &) = delete;
1540  Reference &operator=(Reference &&) = delete;
1541 
1543  void operator=(const value_vector &x) = delete;
1544 };
1545 
1546 template <typename T, size_t N,
1547  IteratorDetails::Mutable M =
1548  (Traits::is_output_iterator<T>::value ? Mutable::Yes : Mutable::No),
1549  typename V = simdize<typename std::iterator_traits<T>::value_type, N>,
1550  size_t Size = V::Size,
1551  typename = typename std::iterator_traits<T>::iterator_category>
1552 class Iterator;
1553 
1554 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size_>
1555 class Iterator<T, N, M, V, Size_, std::forward_iterator_tag>
1556  : public std::iterator<typename std::iterator_traits<T>::iterator_category, V,
1557  typename std::iterator_traits<T>::difference_type,
1558  IteratorDetails::Pointer<T, V, M>,
1559  IteratorDetails::Reference<T, V, M>>
1560 {
1561 public:
1562  using pointer = IteratorDetails::Pointer<T, V, M>;
1563  using reference = IteratorDetails::Reference<T, V, M>;
1564  using const_pointer = IteratorDetails::Pointer<T, V, IteratorDetails::Mutable::No>;
1565  using const_reference =
1566  IteratorDetails::Reference<T, V, IteratorDetails::Mutable::No>;
1567 
1569  static constexpr std::size_t size() { return Size_; }
1570  static constexpr std::size_t Size = Size_;
1571 
1572  Iterator() = default;
1573 
1580  Iterator(const T &x) : scalar_it(x) {}
1584  Iterator(T &&x) : scalar_it(std::move(x)) {}
1588  Iterator &operator=(const T &x)
1589  {
1590  scalar_it = x;
1591  return *this;
1592  }
1596  Iterator &operator=(T &&x)
1597  {
1598  scalar_it = std::move(x);
1599  return *this;
1600  }
1601 
1603  Iterator(const Iterator &) = default;
1605  Iterator(Iterator &&) = default;
1607  Iterator &operator=(const Iterator &) = default;
1609  Iterator &operator=(Iterator &&) = default;
1610 
1612  Iterator &operator++()
1613  {
1614  std::advance(scalar_it, Size);
1615  return *this;
1616  }
1618  Iterator operator++(int)
1619  {
1620  Iterator copy(*this);
1621  operator++();
1622  return copy;
1623  }
1624 
1633  bool operator==(const Iterator &rhs) const
1634  {
1635 #ifndef NDEBUG
1636  if (scalar_it == rhs.scalar_it) {
1637  return true;
1638  } else {
1639  T it(scalar_it);
1640  for (size_t i = 1; i < Size; ++i) {
1641  Vc_ASSERT((++it != rhs.scalar_it));
1642  }
1643  return false;
1644  }
1645 #else
1646  return scalar_it == rhs.scalar_it;
1647 #endif
1648  }
1657  bool operator!=(const Iterator &rhs) const
1658  {
1659  return !operator==(rhs);
1660  }
1661 
1662  pointer operator->() { return scalar_it; }
1663 
1670  reference operator*() { return scalar_it; }
1671 
1672  const_pointer operator->() const { return scalar_it; }
1673 
1681  const_reference operator*() const { return scalar_it; }
1682 
1696  operator const T &() const { return scalar_it; }
1697 
1698 protected:
1699  T scalar_it;
1700 };
1701 
1706 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1707 class Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1708  : public Iterator<T, N, M, V, Size, std::forward_iterator_tag>
1709 {
1710  using Base = Iterator<T, N, M, V, Size, std::forward_iterator_tag>;
1711 
1712 protected:
1713  using Base::scalar_it;
1714 
1715 public:
1716  using pointer = typename Base::pointer;
1717  using reference = typename Base::reference;
1718  using const_pointer = typename Base::const_pointer;
1719  using const_reference = typename Base::const_reference;
1720 
1721  using Iterator<T, N, M, V, Size,
1722  std::forward_iterator_tag>::Iterator; // in short: "using
1723  // Base::Iterator", but that
1724  // confuses ICC
1726  Iterator &operator--()
1727  {
1728  std::advance(scalar_it, -Size);
1729  return *this;
1730  }
1732  Iterator operator--(int)
1733  {
1734  Iterator copy(*this);
1735  operator--();
1736  return copy;
1737  }
1738 };
1739 
1744 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1745 class Iterator<T, N, M, V, Size, std::random_access_iterator_tag>
1746  : public Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1747 {
1749 
1750 protected:
1751  using Base::scalar_it;
1752 
1753 public:
1754  using pointer = typename Base::pointer;
1755  using reference = typename Base::reference;
1756  using const_pointer = typename Base::const_pointer;
1757  using const_reference = typename Base::const_reference;
1758  using difference_type = typename std::iterator_traits<T>::difference_type;
1759 
1761  Iterator; // in short: "using Base::Iterator", but that confuses ICC
1762 
1763  Iterator &operator+=(difference_type n)
1764  {
1765  scalar_it += n * difference_type(Size);
1766  return *this;
1767  }
1768  Iterator operator+(difference_type n) const { return Iterator(*this) += n; }
1769 
1770  Iterator &operator-=(difference_type n)
1771  {
1772  scalar_it -= n * difference_type(Size);
1773  return *this;
1774  }
1775  Iterator operator-(difference_type n) const { return Iterator(*this) -= n; }
1776 
1777  difference_type operator-(const Iterator &rhs) const
1778  {
1779  constexpr difference_type n = Size;
1780  Vc_ASSERT((scalar_it - rhs.scalar_it) % n ==
1781  0); // if this fails the two iterators are not a multiple of the vector
1782  // width apart. The distance would be fractional and that doesn't
1783  // make too much sense for iteration. Therefore, it is a
1784  // precondition for the distance of the two iterators to be a
1785  // multiple of Size.
1786  return (scalar_it - rhs.scalar_it) / n;
1787  }
1788 
1793  bool operator<(const Iterator &rhs) const
1794  {
1795  return rhs.scalar_it - scalar_it >= difference_type(Size);
1796  }
1797 
1798  bool operator>(const Iterator &rhs) const
1799  {
1800  return scalar_it - rhs.scalar_it >= difference_type(Size);
1801  }
1802 
1803  bool operator<=(const Iterator &rhs) const
1804  {
1805  return rhs.scalar_it - scalar_it >= difference_type(Size) - 1;
1806  }
1807 
1808  bool operator>=(const Iterator &rhs) const
1809  {
1810  return scalar_it - rhs.scalar_it >= difference_type(Size) - 1;
1811  }
1812 
1813  reference operator[](difference_type i) { return *(*this + i); }
1814  const_reference operator[](difference_type i) const { return *(*this + i); }
1815 };
1816 
1817 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1818 Iterator<T, N, M, V, Size, std::random_access_iterator_tag> operator+(
1819  typename Iterator<T, N, M, V, Size, std::random_access_iterator_tag>::difference_type
1820  n,
1821  const Iterator<T, N, M, V, Size, std::random_access_iterator_tag> &i)
1822 {
1823  return i + n;
1824 }
1825 
1826 } // namespace IteratorDetails }}}
1827 
1836 template <typename T, size_t N, typename MT>
1837 struct ReplaceTypes<T, N, MT, Category::ForwardIterator>
1838 {
1839  using type = IteratorDetails::Iterator<T, N>;
1840 };
1841 template <typename T, size_t N, typename MT>
1842 struct ReplaceTypes<T, N, MT, Category::BidirectionalIterator>
1843 {
1844  using type = IteratorDetails::Iterator<T, N>;
1845 };
1846 template <typename T, size_t N, typename MT>
1847 struct ReplaceTypes<T, N, MT, Category::RandomAccessIterator>
1848 {
1849  using type = IteratorDetails::Iterator<T, N>;
1850 };
1851 
1855 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1856  std::size_t Offset>
1857 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size_<S>::value && M::Size == N), void>
1858  conditional_assign(Adapter<S, T, N> &, const M &, const U &)
1859 {
1860 }
1861 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1862  std::size_t Offset = 0>
1863 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size_<S>::value && M::Size == N), void>
1864  conditional_assign(Adapter<S, T, N> &lhs, const M &mask, const U &rhs)
1865 {
1866  using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1867  using M2 = typename V::mask_type;
1868  conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask), get_dispatcher<Offset>(rhs));
1869  conditional_assign<Op, S, T, N, M, U, Offset + 1>(lhs, mask, rhs);
1870 }
1871 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1872  std::size_t Offset>
1873 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size_<S>::value && M::Size == N), void>
1874  conditional_assign(Adapter<S, T, N> &, const M &)
1875 {
1876 }
1877 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1878  std::size_t Offset = 0>
1879 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size_<S>::value && M::Size == N), void>
1880  conditional_assign(Adapter<S, T, N> &lhs, const M &mask)
1881 {
1882  using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1883  using M2 = typename V::mask_type;
1884  conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask));
1885  conditional_assign<Op, S, T, N, M, Offset + 1>(lhs, mask);
1886 }
1887 
1889 } // namespace SimdizeDetail
1890 
1891 // user API {{{
1910 template <typename T, size_t N = 0, typename MT = void>
1911 using simdize = SimdizeDetail::simdize<T, N, MT>;
1912 
1932 #define Vc_SIMDIZE_INTERFACE(MEMBERS_) \
1933  template <std::size_t N_> \
1934  inline auto vc_get_()->decltype(std::get<N_>(std::tie MEMBERS_)) \
1935  { \
1936  return std::get<N_>(std::tie MEMBERS_); \
1937  } \
1938  template <std::size_t N_> \
1939  inline auto vc_get_() const->decltype(std::get<N_>(std::tie MEMBERS_)) \
1940  { \
1941  return std::get<N_>(std::tie MEMBERS_); \
1942  } \
1943  enum : std::size_t { \
1944  tuple_size = std::tuple_size<decltype(std::make_tuple MEMBERS_)>::value \
1945  }
1946 // }}}
1947 } // namespace Vc
1948 
1949 namespace std // {{{
1950 {
1952 } // namespace std }}}
1953 
1954 #endif // VC_COMMON_SIMDIZE_H_
1955 
1956 // vim: foldmethod=marker
An allocator that uses global new and supports over-aligned types, as per [C++11 20....
Definition: Allocator:129
bool operator<(const Iterator &rhs) const
Returns whether all entries accessed via iterator dereferencing come before the iterator rhs.
Definition: simdize.h:1793
This is the iterator type created when applying simdize to a bidirectional iterator type.
Definition: simdize.h:1709
Iterator & operator--()
Advances the iterator by one vector width, or respectively N scalar steps.
Definition: simdize.h:1726
result_vector_type< L, R > operator+(L &&lhs, R &&rhs)
Applies + component-wise and concurrently.
Definition: simdarray.h:1722
result_vector_type< L, R > operator-(L &&lhs, R &&rhs)
Applies - component-wise and concurrently.
Definition: simdarray.h:1722
result_vector_type< L, R > operator*(L &&lhs, R &&rhs)
Applies * component-wise and concurrently.
Definition: simdarray.h:1722
void swap(Adapter< S, T, N > &a, std::size_t i, S &x)
Swaps one scalar object x with a SIMD slot at offset i in the simdized object a.
Definition: simdize.h:1108
SimdizeDetail::simdize< T, N, MT > simdize
Definition: simdize.h:1911
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
constexpr UnalignedTag Unaligned
Use this object for a flags parameter to request unaligned loads and stores.
void free(T *p)
Frees memory that was allocated with Vc::malloc.
Definition: malloc.h:163
Vector Classes Namespace.
Definition: dox.h:585
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
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