Vc  1.4.0
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 template <bool B, typename T, typename F>
144 using conditional_t = typename conditional<B, T, F>::type;
145 
150 template <typename... Ts> struct Typelist;
151 
155 enum class Category {
157  None,
159  ArithmeticVectorizable,
161  InputIterator,
163  OutputIterator,
165  ForwardIterator,
167  BidirectionalIterator,
169  RandomAccessIterator,
171  ClassTemplate
172 };
173 
178 template <typename T, typename ItCat = typename T::iterator_category>
179 constexpr Category iteratorCategories(int, ItCat * = nullptr)
180 {
181  return is_base_of<std::random_access_iterator_tag, ItCat>::value
182  ? Category::RandomAccessIterator
183  : is_base_of<std::bidirectional_iterator_tag, ItCat>::value
184  ? Category::BidirectionalIterator
185  : is_base_of<std::forward_iterator_tag, ItCat>::value
186  ? Category::ForwardIterator
187  : is_base_of<std::output_iterator_tag, ItCat>::value
188  ? Category::OutputIterator
189  : is_base_of<std::input_iterator_tag, ItCat>::value
190  ? Category::InputIterator
191  : Category::None;
192 }
196 template <typename T>
197 constexpr enable_if<std::is_pointer<T>::value, Category> iteratorCategories(float)
198 {
199  return Category::RandomAccessIterator;
200 }
204 template <typename T> constexpr Category iteratorCategories(...)
205 {
206  return Category::None;
207 }
208 
212 template <typename T> struct is_class_template : public false_type
213 {
214 };
215 template <template <typename...> class C, typename... Ts>
216 struct is_class_template<C<Ts...>> : public true_type
217 {
218 };
219 
223 template <typename T> constexpr Category typeCategory()
224 {
225  return (is_same<T, bool>::value || is_same<T, short>::value ||
226  is_same<T, unsigned short>::value || is_same<T, int>::value ||
227  is_same<T, unsigned int>::value || is_same<T, float>::value ||
228  is_same<T, double>::value)
229  ? Category::ArithmeticVectorizable
230  : iteratorCategories<T>(int()) != Category::None
231  ? iteratorCategories<T>(int())
232  : is_class_template<T>::value ? Category::ClassTemplate
233  : Category::None;
234 }
235 
241 template <typename T, size_t TupleSize = std::tuple_size<T>::value>
242 constexpr size_t determine_tuple_size()
243 {
244  return TupleSize;
245 }
246 template <typename T, size_t TupleSize = T::tuple_size>
247 constexpr size_t determine_tuple_size(size_t = T::tuple_size)
248 {
249  return TupleSize;
250 }
251 
252 // workaround for MSVC limitation: constexpr functions in template arguments
253 // confuse the compiler
254 template <typename T> struct determine_tuple_size_
255 : public std::integral_constant<size_t, determine_tuple_size<T>()>
256 {};
257 
258 namespace
259 {
260 template <typename T> struct The_simdization_for_the_requested_type_is_not_implemented;
261 } // unnamed namespace
262 
275 template <typename T, size_t N, typename MT, Category = typeCategory<T>()>
276 struct ReplaceTypes : public The_simdization_for_the_requested_type_is_not_implemented<T>
277 {
278 };
279 
284 template <typename T, size_t N, typename MT> struct ReplaceTypes<T, N, MT, Category::None>
285 {
286  typedef T type;
287 };
288 
293 template <typename T, size_t N = 0, typename MT = void>
294 using simdize = typename SimdizeDetail::ReplaceTypes<T, N, MT>::type;
295 
296 // Alias for Vector<T, Abi> with size() == N, or SimdArray<T, N> otherwise.
297 template <class T, size_t N,
298  class Best = typename Common::select_best_vector_type<T, N>::type>
299 using deduce_vector_t =
300  typename std::conditional<Best::size() == N, Best, SimdArray<T, N>>::type;
301 
306 template <typename T, size_t N, typename MT>
307 struct ReplaceTypes<T, N, MT, Category::ArithmeticVectorizable>
308  : public conditional<N == 0, Vector<T>, deduce_vector_t<T, N>> {
309 };
310 
315 template <size_t N, typename MT>
316 struct ReplaceTypes<bool, N, MT, Category::ArithmeticVectorizable>
317  : public std::enable_if<true, typename ReplaceTypes<MT, N, MT>::type::mask_type> {
318 };
322 template <size_t N>
323 struct ReplaceTypes<bool, N, void, Category::ArithmeticVectorizable>
324  : public ReplaceTypes<bool, N, float, Category::ArithmeticVectorizable>
325 {
326 };
327 
334 template <size_t N, typename MT, typename Replaced, typename... Remaining>
335 struct SubstituteOneByOne;
336 
341 template <size_t N, typename MT, typename... Replaced, typename T,
342  typename... Remaining>
343 struct SubstituteOneByOne<N, MT, Typelist<Replaced...>, T, Remaining...>
344 {
345 private:
350  template <typename U, size_t M = U::Size>
351  static std::integral_constant<size_t, M> size_or_0(int);
352  template <typename U> static std::integral_constant<size_t, 0> size_or_0(...);
353 
355  using V = simdize<T, N, MT>;
356 
361  static constexpr auto NewN = N != 0 ? N : decltype(size_or_0<V>(int()))::value;
362 
368  typedef conditional_t<(N != NewN && is_same<MT, void>::value),
369  conditional_t<is_same<T, bool>::value, float, T>, MT> NewMT;
370 
371 public:
375  using type = typename SubstituteOneByOne<NewN, NewMT, Typelist<Replaced..., V>,
376  Remaining...>::type;
377 };
378 
381 template <size_t Size, typename... Replaced> struct SubstitutedBase;
383 template <typename Replaced> struct SubstitutedBase<1, Replaced> {
384  template <typename ValueT, template <typename, ValueT...> class C, ValueT... Values>
385  using SubstitutedWithValues = C<Replaced, Values...>;
386 };
388 template <typename R0, typename R1> struct SubstitutedBase<2, R0, R1>
389 {
390  template <typename ValueT, template <typename, typename, ValueT...> class C,
391  ValueT... Values>
392  using SubstitutedWithValues = C<R0, R1, Values...>;
393 };
395 template <typename R0, typename R1, typename R2> struct SubstitutedBase<3, R0, R1, R2>
396 {
397  template <typename ValueT, template <typename, typename, typename, ValueT...> class C,
398  ValueT... Values>
399  using SubstitutedWithValues = C<R0, R1, R2, Values...>;
400 };
401 #if defined Vc_ICC || defined Vc_MSVC
402 #define Vc_VALUE_PACK_EXPANSION_IS_BROKEN 1
403 #endif
404 template <typename... Replaced> struct SubstitutedBase<4, Replaced...> {
406 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
407  template <typename ValueT,
408  template <typename, typename, typename, typename, ValueT...> class C,
409  ValueT... Values>
410  using SubstitutedWithValues = C<Replaced..., Values...>;
411 #endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
412 };
414 template <typename... Replaced> struct SubstitutedBase<5, Replaced...> {
415 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
416  template <typename ValueT, template <typename, typename, typename, typename, typename,
417  ValueT...> class C,
418  ValueT... Values>
419  using SubstitutedWithValues = C<Replaced..., Values...>;
420 #endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
421 };
423 template <typename... Replaced> struct SubstitutedBase<6, Replaced...> {
424 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
425  template <typename ValueT, template <typename, typename, typename, typename, typename,
426  typename, ValueT...> class C,
427  ValueT... Values>
428  using SubstitutedWithValues = C<Replaced..., Values...>;
429 #endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
430 };
432 template <typename... Replaced> struct SubstitutedBase<7, Replaced...> {
433 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
434  template <typename ValueT, template <typename, typename, typename, typename, typename,
435  typename, typename, ValueT...> class C,
436  ValueT... Values>
437  using SubstitutedWithValues = C<Replaced..., Values...>;
438 #endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
439 };
441 template <typename... Replaced> struct SubstitutedBase<8, Replaced...> {
442 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
443  template <typename ValueT, template <typename, typename, typename, typename, typename,
444  typename, typename, typename, ValueT...> class C,
445  ValueT... Values>
446  using SubstitutedWithValues = C<Replaced..., Values...>;
447 #endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
448 };
449 
455 template <size_t N_, typename MT, typename Replaced0, typename... Replaced>
456 struct SubstituteOneByOne<N_, MT, Typelist<Replaced0, Replaced...>>
457 {
461  struct type
462  : public SubstitutedBase<sizeof...(Replaced) + 1, Replaced0, Replaced...> {
463  static constexpr auto N = N_;
468  template <template <typename...> class C>
469  using Substituted = C<Replaced0, Replaced...>;
470  };
471 };
472 
489 template <typename Scalar, typename Base, size_t N> class Adapter;
490 
495 template <template <typename...> class C, typename... Ts, size_t N, typename MT>
496 struct ReplaceTypes<C<Ts...>, N, MT, Category::ClassTemplate>
497 {
499  using SubstitutionResult =
500  typename SubstituteOneByOne<N, MT, Typelist<>, Ts...>::type;
506  using Vectorized = typename SubstitutionResult::template Substituted<C>;
512  using type = conditional_t<is_same<C<Ts...>, Vectorized>::value, C<Ts...>,
513  Adapter<C<Ts...>, Vectorized, SubstitutionResult::N>>;
514 };
515 
521 #ifdef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
522 // ICC barfs on packs of values
523 #define Vc_DEFINE_NONTYPE_REPLACETYPES_(ValueType_) \
524  template <template <typename, ValueType_...> class C, typename T, ValueType_ Value0, \
525  ValueType_... Values> \
526  struct is_class_template<C<T, Value0, Values...>> : public true_type { \
527  }; \
528  template <template <typename, typename, ValueType_...> class C, typename T0, \
529  typename T1, ValueType_ Value0, ValueType_... Values> \
530  struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type { \
531  }; \
532  template <template <typename, typename, typename, ValueType_...> class C, \
533  typename T0, typename T1, typename T2, ValueType_ Value0, \
534  ValueType_... Values> \
535  struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type { \
536  }; \
537  template <template <typename, typename, typename, typename, ValueType_...> class C, \
538  typename T0, typename T1, typename T2, typename T3, ValueType_ Value0, \
539  ValueType_... Values> \
540  struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type { \
541  }; \
542  template <template <typename, typename, typename, typename, typename, ValueType_...> \
543  class C, \
544  typename T0, typename T1, typename T2, typename T3, typename T4, \
545  ValueType_ Value0, ValueType_... Values> \
546  struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
547  : public true_type { \
548  }; \
549  template <template <typename, typename, typename, typename, typename, typename, \
550  ValueType_...> class C, \
551  typename T0, typename T1, typename T2, typename T3, typename T4, \
552  typename T5, ValueType_ Value0, ValueType_... Values> \
553  struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
554  : public true_type { \
555  }; \
556  template <template <typename, typename, typename, typename, typename, typename, \
557  typename, ValueType_...> class C, \
558  typename T0, typename T1, typename T2, typename T3, typename T4, \
559  typename T5, typename T6, ValueType_ Value0, ValueType_... Values> \
560  struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
561  : public true_type { \
562  }; \
563  template <template <typename, ValueType_> class C, typename T0, ValueType_ Value0, \
564  size_t N, typename MT> \
565  struct ReplaceTypes<C<T0, Value0>, N, MT, Category::ClassTemplate> { \
566  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
567  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
568  Substituted; \
569  static constexpr auto NN = tmp::N; \
570  typedef conditional_t<is_same<C<T0, Value0>, Substituted>::value, C<T0, Value0>, \
571  Adapter<C<T0, Value0>, Substituted, NN>> type; \
572  }; \
573  template <template <typename, typename, ValueType_> class C, typename T0, \
574  typename T1, ValueType_ Value0, size_t N, typename MT> \
575  struct ReplaceTypes<C<T0, T1, Value0>, N, MT, Category::ClassTemplate> { \
576  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
577  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
578  Substituted; \
579  static constexpr auto NN = tmp::N; \
580  typedef conditional_t<is_same<C<T0, T1, Value0>, Substituted>::value, \
581  C<T0, T1, Value0>, \
582  Adapter<C<T0, T1, Value0>, Substituted, NN>> type; \
583  }; \
584  template <template <typename, typename, typename, ValueType_> class C, typename T0, \
585  typename T1, typename T2, ValueType_ Value0, size_t N, typename MT> \
586  struct ReplaceTypes<C<T0, T1, T2, Value0>, N, MT, Category::ClassTemplate> { \
587  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
588  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
589  Substituted; \
590  static constexpr auto NN = tmp::N; \
591  typedef conditional_t<is_same<C<T0, T1, T2, Value0>, Substituted>::value, \
592  C<T0, T1, T2, Value0>, \
593  Adapter<C<T0, T1, T2, Value0>, Substituted, NN>> type; \
594  }
595 #else
596 #define Vc_DEFINE_NONTYPE_REPLACETYPES_(ValueType_) \
597  template <template <typename, ValueType_...> class C, typename T, ValueType_ Value0, \
598  ValueType_... Values> \
599  struct is_class_template<C<T, Value0, Values...>> : public true_type { \
600  }; \
601  template <template <typename, typename, ValueType_...> class C, typename T0, \
602  typename T1, ValueType_ Value0, ValueType_... Values> \
603  struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type { \
604  }; \
605  template <template <typename, typename, typename, ValueType_...> class C, \
606  typename T0, typename T1, typename T2, ValueType_ Value0, \
607  ValueType_... Values> \
608  struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type { \
609  }; \
610  template <template <typename, typename, typename, typename, ValueType_...> class C, \
611  typename T0, typename T1, typename T2, typename T3, ValueType_ Value0, \
612  ValueType_... Values> \
613  struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type { \
614  }; \
615  template <template <typename, typename, typename, typename, typename, ValueType_...> \
616  class C, \
617  typename T0, typename T1, typename T2, typename T3, typename T4, \
618  ValueType_ Value0, ValueType_... Values> \
619  struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
620  : public true_type { \
621  }; \
622  template <template <typename, typename, typename, typename, typename, typename, \
623  ValueType_...> class C, \
624  typename T0, typename T1, typename T2, typename T3, typename T4, \
625  typename T5, ValueType_ Value0, ValueType_... Values> \
626  struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
627  : public true_type { \
628  }; \
629  template <template <typename, typename, typename, typename, typename, typename, \
630  typename, ValueType_...> class C, \
631  typename T0, typename T1, typename T2, typename T3, typename T4, \
632  typename T5, typename T6, ValueType_ Value0, ValueType_... Values> \
633  struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
634  : public true_type { \
635  }; \
636  template <template <typename, ValueType_...> class C, typename T0, \
637  ValueType_ Value0, ValueType_... Values, size_t N, typename MT> \
638  struct ReplaceTypes<C<T0, Value0, Values...>, N, MT, Category::ClassTemplate> { \
639  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
640  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
641  Values...> Substituted; \
642  static constexpr auto NN = tmp::N; \
643  typedef conditional_t<is_same<C<T0, Value0, Values...>, Substituted>::value, \
644  C<T0, Value0, Values...>, \
645  Adapter<C<T0, Value0, Values...>, Substituted, NN>> type; \
646  }; \
647  template <template <typename, typename, ValueType_...> class C, typename T0, \
648  typename T1, ValueType_ Value0, ValueType_... Values, size_t N, \
649  typename MT> \
650  struct ReplaceTypes<C<T0, T1, Value0, Values...>, N, MT, Category::ClassTemplate> { \
651  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
652  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
653  Values...> Substituted; \
654  static constexpr auto NN = tmp::N; \
655  typedef conditional_t<is_same<C<T0, T1, Value0, Values...>, Substituted>::value, \
656  C<T0, T1, Value0, Values...>, \
657  Adapter<C<T0, T1, Value0, Values...>, Substituted, NN>> \
658  type; \
659  }; \
660  template <template <typename, typename, typename, ValueType_...> class C, \
661  typename T0, typename T1, typename T2, ValueType_ Value0, \
662  ValueType_... Values, size_t N, typename MT> \
663  struct ReplaceTypes<C<T0, T1, T2, Value0, Values...>, N, MT, \
664  Category::ClassTemplate> { \
665  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
666  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
667  Values...> Substituted; \
668  static constexpr auto NN = tmp::N; \
669  typedef conditional_t< \
670  is_same<C<T0, T1, T2, Value0, Values...>, Substituted>::value, \
671  C<T0, T1, T2, Value0, Values...>, \
672  Adapter<C<T0, T1, T2, Value0, Values...>, Substituted, NN>> type; \
673  }
674 #endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
675 Vc_DEFINE_NONTYPE_REPLACETYPES_(bool);
676 Vc_DEFINE_NONTYPE_REPLACETYPES_(wchar_t);
677 Vc_DEFINE_NONTYPE_REPLACETYPES_(char);
678 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed char);
679 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned char);
680 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed short);
681 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned short);
682 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed int);
683 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned int);
684 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed long);
685 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned long);
686 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed long long);
687 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned long long);
688 #undef Vc_DEFINE_NONTYPE_REPLACETYPES_
689 
690 // preferred_construction {{{
691 namespace preferred_construction_impl
692 {
693 template <typename T> T create();
694 // 0: paren init
695 template <class Type, class... Init, class = decltype(Type(create<Init>()...))>
696 constexpr std::integral_constant<int, 0> test(int);
697 // 1: 1-brace init
698 template <class Type, class... Init, class = decltype(Type{create<Init>()...})>
699 constexpr std::integral_constant<int, 1> test(float);
700 // 2: 2-brace init
701 template <class Type, class... Init, class T, class = decltype(Type{{create<Init>()...}})>
702 constexpr std::integral_constant<int, 2> test(T);
703 // 3: no init at all
704 template <class Type, class... Init> constexpr std::integral_constant<int, 3> test(...);
705 } // namespace preferred_construction_impl
706 
707 template <class Type, class... Init>
708 constexpr inline decltype(preferred_construction_impl::test<Type, Init...>(0))
709 preferred_construction()
710 {
711  return {};
712 }
713 
714 // }}}
715 // get_dispatcher {{{
720 template <size_t I, typename T,
721  typename R = decltype(std::declval<T &>().template vc_get_<I>())>
722 R get_dispatcher(T &x, void * = nullptr)
723 {
724  return x.template vc_get_<I>();
725 }
726 template <size_t I, typename T,
727  typename R = decltype(std::declval<const T &>().template vc_get_<I>())>
728 R get_dispatcher(const T &x, void * = nullptr)
729 {
730  return x.template vc_get_<I>();
731 }
732 template <size_t I, typename T, typename R = decltype(std::get<I>(std::declval<T &>()))>
733 R get_dispatcher(T &x, int = 0)
734 {
735  return std::get<I>(x);
736 }
737 template <size_t I, typename T,
738  typename R = decltype(std::get<I>(std::declval<const T &>()))>
739 R get_dispatcher(const T &x, int = 0)
740 {
741  return std::get<I>(x);
742 }
743 
744 // }}}
745 // my_tuple_element {{{
746 template <size_t I, class T, class = void>
747 struct my_tuple_element : std::tuple_element<I, T> {
748 };
749 
750 template <size_t I, class T>
751 struct my_tuple_element<
752  I, T, typename std::conditional<
753  true, void, decltype(std::declval<T>().template vc_get_<I>())>::type> {
754  using type =
755  typename std::decay<decltype(std::declval<T>().template vc_get_<I>())>::type;
756 };
757 
758 // }}}
759 // homogeneous_sizeof {{{
765 template <class... Ts> struct homogeneous_sizeof;
766 template <class T, class = void> struct homogeneous_sizeof_one;
767 template <class T>
768 struct homogeneous_sizeof_one<T,
769  typename std::enable_if<std::is_arithmetic<T>::value>::type>
770  : std::integral_constant<size_t, sizeof(T)> {
771 };
772 template <class T0> struct homogeneous_sizeof<T0> : homogeneous_sizeof_one<T0> {
773 };
774 
775 template <class T0, class... Ts>
776 struct homogeneous_sizeof<T0, Ts...>
777  : std::integral_constant<size_t, homogeneous_sizeof<T0>::value ==
778  homogeneous_sizeof<Ts...>::value
779  ? homogeneous_sizeof<T0>::value
780  : 0> {
781 };
782 
783 template <class T, size_t... Is>
784 std::integral_constant<
785  size_t, homogeneous_sizeof<typename my_tuple_element<Is, T>::type...>::value>
786  homogeneous_sizeof_helper(index_sequence<Is...>);
787 
788 template <class T>
789 struct homogeneous_sizeof_one<T, typename std::enable_if<std::is_class<T>::value>::type>
790  : decltype(homogeneous_sizeof_helper<T>(
791  make_index_sequence<determine_tuple_size_<T>::value>())) {
792 };
793 
794 // }}}
795 // class Adapter {{{
796 template <typename Scalar, typename Base, size_t N> class Adapter : public Base
797 {
798 private:
800  template <std::size_t... Indexes, int X>
801  Adapter(Vc::index_sequence<Indexes...>, const Scalar,
802  std::integral_constant<int, X>)
803  {
804  static_assert(
805  X < 3, "Failed to construct an object of type Base. Neither via "
806  "parenthesis-init, brace-init, nor double-brace init appear to work.");
807  }
808 
810  template <std::size_t... Indexes>
811  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_,
812  std::integral_constant<int, 2>)
813  : Base{{get_dispatcher<Indexes>(x_)...}}
814  {
815  }
816 
818  template <std::size_t... Indexes>
819  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_,
820  std::integral_constant<int, 1>)
821  : Base{get_dispatcher<Indexes>(x_)...}
822  {
823  }
824 
826  template <std::size_t... Indexes>
827  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_,
828  std::integral_constant<int, 0>)
829  : Base(get_dispatcher<Indexes>(x_)...)
830  {
831  }
832 
833  template <std::size_t... Indexes>
834  Adapter(Vc::index_sequence<Indexes...> seq_, const Scalar &x_)
835  : Adapter(seq_, x_,
836  preferred_construction<Base, decltype(get_dispatcher<Indexes>(
837  std::declval<const Scalar &>()))...>())
838  {
839  }
840 
841 public:
843  static constexpr size_t size() { return N; }
844  static constexpr size_t Size = N;
845 
847  using base_type = Base;
850  using scalar_type = Scalar;
851 
854  Adapter() = default;
855 
857 #if defined Vc_CLANG && Vc_CLANG < 0x30700
858  Vc_INTRINSIC Adapter(const Adapter &x) : Base(x) {}
859 #else
860  Adapter(const Adapter &) = default;
861 #endif
862  Adapter(Adapter &&) = default;
865  Adapter &operator=(const Adapter &) = default;
867  Adapter &operator=(Adapter &&) = default;
868 
870  template <typename U, size_t TupleSize = determine_tuple_size_<Scalar>::value,
871  typename Seq = Vc::make_index_sequence<TupleSize>,
872  typename = enable_if<std::is_convertible<U, Scalar>::value>>
873  Adapter(U &&x_)
874  : Adapter(Seq(), static_cast<const Scalar &>(x_))
875  {
876  }
877 
879  template <class F,
880  class = decltype(static_cast<Scalar>(std::declval<F>()(
881  size_t())))> // F returns objects that are convertible to S
882  Adapter(F &&fun); // implementation below
883 
884  // }}}
886  template <typename A0, typename... Args,
887  typename = typename std::enable_if<
888  !Traits::is_index_sequence<A0>::value &&
889  (sizeof...(Args) > 0 || !std::is_convertible<A0, Scalar>::value)>::type>
890  Adapter(A0 &&arg0_, Args &&... arguments_)
891  : Base(std::forward<A0>(arg0_), std::forward<Args>(arguments_)...)
892  {
893  }
894 
896  template <typename T,
897  typename = decltype(Base(std::declval<const std::initializer_list<T> &>()))>
898  Adapter(const std::initializer_list<T> &l_)
899  : Base(l_)
900  {
901  }
902 
905  void *operator new(size_t size)
906  {
907  return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
908  }
909  void *operator new(size_t, void *p_) { return p_; }
910  void *operator new[](size_t size)
911  {
912  return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
913  }
914  void *operator new[](size_t , void *p_) { return p_; }
915  void operator delete(void *ptr_, size_t) { Vc::Common::free(ptr_); }
916  void operator delete(void *, void *) {}
917  void operator delete[](void *ptr_, size_t) { Vc::Common::free(ptr_); }
918  void operator delete[](void *, void *) {}
919 }; // }}}
920 // delete compare operators for Adapter {{{
925 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
926 inline void operator==(
927  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
928  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
929 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
930 inline void operator!=(
931  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
932  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
933 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
934 inline void operator<=(
935  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
936  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
937 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
938 inline void operator>=(
939  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
940  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
941 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
942 inline void operator<(
943  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
944  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
945 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
946 inline void operator>(
947  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
948  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
949 // }}}
951 } // namespace SimdizeDetail }}}
952 } // namespace Vc
953 
954 namespace std // {{{
955 {
959 template <typename Scalar, typename Base, size_t N>
960 class tuple_size<Vc::SimdizeDetail::Adapter<Scalar, Base, N>> : public tuple_size<Base>
961 {
962 };
966 template <size_t I, typename Scalar, typename Base, size_t N>
967 class tuple_element<I, Vc::SimdizeDetail::Adapter<Scalar, Base, N>>
968  : public tuple_element<I, Base>
969 {
970 };
971 // std::get does not need additional work because Vc::Adapter derives from
972 // C<Ts...> and therefore if get<N>(C<Ts...>) works it works for Adapter as well.
973 
978 template <typename S, typename T, size_t N>
979 class allocator<Vc::SimdizeDetail::Adapter<S, T, N>>
980  : public Vc::Allocator<Vc::SimdizeDetail::Adapter<S, T, N>>
981 {
982 public:
983  template <typename U> struct rebind
984  {
985  typedef std::allocator<U> other;
986  };
987 };
988 } // namespace std }}}
989 
990 namespace Vc_VERSIONED_NAMESPACE
991 {
992 namespace SimdizeDetail
993 {
1002 template <typename T> static inline T decay_workaround(const T &x) { return x; }
1003 
1004 // assign_impl {{{
1008 template <typename S, typename T, size_t N, size_t... Indexes>
1009 inline void assign_impl(Adapter<S, T, N> &a, size_t i, const S &x,
1010  Vc::index_sequence<Indexes...>)
1011 {
1012  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(x)))...> tmp(
1013  decay_workaround(get_dispatcher<Indexes>(x))...);
1014  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(tmp), 0)...};
1015  if (&unused == &unused) {}
1016 } // }}}
1017 // construct (parens, braces, double-braces) {{{
1018 template <class S, class... Args>
1019 S construct(std::integral_constant<int, 0>, Args &&... args)
1020 {
1021  return S(std::forward<Args>(args)...);
1022 }
1023 template <class S, class... Args>
1024 S construct(std::integral_constant<int, 1>, Args &&... args)
1025 {
1026  return S{std::forward<Args>(args)...};
1027 }
1028 template <class S, class... Args>
1029 S construct(std::integral_constant<int, 2>, Args &&... args)
1030 {
1031  return S{{std::forward<Args>(args)...}};
1032 }
1033 // }}}
1034 // extract_impl {{{
1038 template <typename S, typename T, size_t N, size_t... Indexes>
1039 inline S extract_impl(const Adapter<S, T, N> &a, size_t i, Vc::index_sequence<Indexes...>)
1040 {
1041  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[i]))...> tmp(
1042  decay_workaround(get_dispatcher<Indexes>(a)[i])...);
1043  return construct<S>(
1044  preferred_construction<S, decltype(decay_workaround(
1045  get_dispatcher<Indexes>(a)[i]))...>(),
1046  decay_workaround(get_dispatcher<Indexes>(a)[i])...);
1047  //return S(get_dispatcher<Indexes>(tmp)...);
1048 }
1049 // }}}
1050 // shifted_impl {{{
1051 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1052 inline Adapter<S, T, N> shifted_impl(const Adapter<S, T, N> &a, int shift,
1053  Vc::index_sequence<Indexes...>)
1054 {
1055  Adapter<S, T, N> r;
1056  auto &&unused = {(get_dispatcher<Indexes>(r) = get_dispatcher<Indexes>(a).shifted(shift), 0)...};
1057  if (&unused == &unused) {}
1058  return r;
1059 }
1060 // }}}
1061 // shifted(Adapter) {{{
1070 template <typename S, typename T, size_t N>
1071 inline Adapter<S, T, N> shifted(const Adapter<S, T, N> &a, int shift)
1072 {
1073  return shifted_impl(a, shift, Vc::make_index_sequence<determine_tuple_size<T>()>());
1074 }
1075 // }}}
1076 // swap_impl {{{
1080 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1081 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, S &x,
1082  Vc::index_sequence<Indexes...>)
1083 {
1084  const auto &a_const = a;
1085  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a_const)[0]))...>
1086  tmp{decay_workaround(get_dispatcher<Indexes>(a_const)[i])...};
1087  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(x), 0)...};
1088  auto &&unused2 = {(get_dispatcher<Indexes>(x) = get_dispatcher<Indexes>(tmp), 0)...};
1089  if (&unused == &unused2) {}
1090 }
1091 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1092 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b,
1093  std::size_t j, Vc::index_sequence<Indexes...>)
1094 {
1095  const auto &a_const = a;
1096  const auto &b_const = b;
1097  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a_const)[0]))...>
1098  tmp{decay_workaround(get_dispatcher<Indexes>(a_const)[i])...};
1099  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(b_const)[j], 0)...};
1100  auto &&unused2 = {(get_dispatcher<Indexes>(b)[j] = get_dispatcher<Indexes>(tmp), 0)...};
1101  if (&unused == &unused2) {}
1102 }
1103 // }}}
1104 // swap(Adapter) {{{
1109 template <typename S, typename T, std::size_t N>
1110 inline void swap(Adapter<S, T, N> &a, std::size_t i, S &x)
1111 {
1112  swap_impl(a, i, x, Vc::make_index_sequence<determine_tuple_size<T>()>());
1113 }
1114 template <typename S, typename T, std::size_t N>
1115 inline void swap(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b, std::size_t j)
1116 {
1117  swap_impl(a, i, b, j, Vc::make_index_sequence<determine_tuple_size<T>()>());
1118 }
1119 // }}}
1120 template <typename A> class Scalar // {{{
1121 {
1122  using reference = typename std::add_lvalue_reference<A>::type;
1123  using S = typename A::scalar_type;
1124  using IndexSeq = Vc::make_index_sequence<determine_tuple_size<S>()>;
1125 
1126 public:
1127  Scalar(reference aa, size_t ii) : a(aa), i(ii) {}
1128 
1129  // delete copy and move to keep the type a pure proxy temporary object.
1130  Scalar(const Scalar &) = delete;
1131  Scalar(Scalar &&) = delete;
1132  Scalar &operator=(const Scalar &) = delete;
1133  Scalar &operator=(Scalar &&) = delete;
1134 
1135  void operator=(const S &x) { assign_impl(a, i, x, IndexSeq()); }
1136  operator S() const { return extract_impl(a, i, IndexSeq()); }
1137 
1138  template <typename AA>
1139  friend inline void swap(Scalar<AA> &&a, typename AA::scalar_type &b);
1140  template <typename AA>
1141  friend inline void swap(typename AA::scalar_type &b, Scalar<AA> &&a);
1142  template <typename AA> friend inline void swap(Scalar<AA> &&a, Scalar<AA> &&b);
1143 
1144 private:
1145  reference a;
1146  size_t i;
1147 }; // }}}
1148 // swap(Scalar) {{{
1151 template <typename A> inline void swap(Scalar<A> &&a, typename A::scalar_type &b)
1152 {
1153  swap_impl(a.a, a.i, b, typename Scalar<A>::IndexSeq());
1154 }
1157 template <typename A> inline void swap(typename A::scalar_type &b, Scalar<A> &&a)
1158 {
1159  swap_impl(a.a, a.i, b, typename Scalar<A>::IndexSeq());
1160 }
1161 
1162 template <typename A> inline void swap(Scalar<A> &&a, Scalar<A> &&b)
1163 {
1164  swap_impl(a.a, a.i, b.a, b.i, typename Scalar<A>::IndexSeq());
1165 }
1166 // }}}
1167 // load_interleaved_impl {{{
1168 template <class S, class T, size_t N, size_t... I>
1169 inline void load_interleaved_impl(Vc::index_sequence<I...>, Adapter<S, T, N> &a,
1170  const S *mem)
1171 {
1173  wrapper(const_cast<S *>(mem));
1174  Vc::tie(get_dispatcher<I>(a)...) = wrapper[0];
1175 }
1176 // }}}
1177 // store_interleaved_impl {{{
1178 template <class S, class T, size_t N, size_t... I>
1179 inline void store_interleaved_impl(Vc::index_sequence<I...>, const Adapter<S, T, N> &a,
1180  S *mem)
1181 {
1183  mem);
1184  wrapper[0] = Vc::tie(get_dispatcher<I>(a)...);
1185 }
1186 // }}}
1187 template <typename A> class Interface // {{{
1188 {
1189  using reference = typename std::add_lvalue_reference<A>::type;
1190  using IndexSeq =
1191  Vc::make_index_sequence<determine_tuple_size<typename A::scalar_type>()>;
1192 
1193 public:
1194  Interface(reference aa) : a(aa) {}
1195 
1196  Scalar<A> operator[](size_t i)
1197  {
1198  return {a, i};
1199  }
1200  typename A::scalar_type operator[](size_t i) const
1201  {
1202  return extract_impl(a, i, IndexSeq());
1203  }
1204 
1205  A shifted(int amount) const
1206  {
1207  return shifted_impl(a, amount, IndexSeq());
1208  }
1209 
1210  void load(const typename A::scalar_type *mem) { load_interleaved(*this, mem); }
1211  void store(typename A::scalar_type *mem) { store_interleaved(*this, mem); }
1212 
1213 private:
1214  reference a;
1215 }; // }}}
1216 } // namespace SimdizeDetail
1217 // assign {{{
1222 template <typename S, typename T, size_t N>
1223 inline void assign(SimdizeDetail::Adapter<S, T, N> &a, size_t i, const S &x)
1224 {
1225  SimdizeDetail::assign_impl(
1226  a, i, x, Vc::make_index_sequence<SimdizeDetail::determine_tuple_size<T>()>());
1227 }
1231 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
1232 Vc_INTRINSIC void assign(V &v, size_t i, typename V::EntryType x)
1233 {
1234  v[i] = x;
1235 }
1236 // }}}
1237 // extract {{{
1242 template <typename S, typename T, size_t N>
1243 inline S extract(const SimdizeDetail::Adapter<S, T, N> &a, size_t i)
1244 {
1245  return SimdizeDetail::extract_impl(
1246  a, i, Vc::make_index_sequence<SimdizeDetail::determine_tuple_size<S>()>());
1247 }
1251 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
1252 Vc_INTRINSIC typename V::EntryType extract(const V &v, size_t i)
1253 {
1254  return v[i];
1255 }
1256 // }}}
1257 // load_interleaved {{{
1258 template <class S, class T, size_t N>
1259 inline void load_interleaved(SimdizeDetail::Adapter<S, T, N> &a, const S *mem)
1260 {
1261  if (SimdizeDetail::homogeneous_sizeof<S>::value == 0) {
1262  Common::unrolled_loop<std::size_t, 0, N>(
1263  [&](std::size_t i) { assign(a, i, mem[i]); });
1264  } else {
1265  constexpr size_t TupleSize = SimdizeDetail::determine_tuple_size_<S>::value;
1266  SimdizeDetail::load_interleaved_impl(Vc::make_index_sequence<TupleSize>(), a,
1267  mem);
1268  }
1269 }
1270 template <
1271  class V, class T,
1272  class = enable_if<Traits::is_simd_vector<V>::value && std::is_arithmetic<T>::value>>
1273 Vc_INTRINSIC void load_interleaved(V &a, const T *mem)
1274 {
1275  a.load(mem, Vc::Unaligned);
1276 }
1277 // }}}
1278 // store_interleaved {{{
1279 template <class S, class T, size_t N>
1280 inline void store_interleaved(const SimdizeDetail::Adapter<S, T, N> &a, S *mem)
1281 {
1282  if (SimdizeDetail::homogeneous_sizeof<S>::value == 0) {
1283  Common::unrolled_loop<std::size_t, 0, N>(
1284  [&](std::size_t i) { mem[i] = extract(a, i); });
1285  } else {
1286  constexpr size_t TupleSize = SimdizeDetail::determine_tuple_size_<S>::value;
1287  SimdizeDetail::store_interleaved_impl(Vc::make_index_sequence<TupleSize>(), a,
1288  mem);
1289  }
1290 }
1291 template <
1292  class V, class T,
1293  class = enable_if<Traits::is_simd_vector<V>::value && std::is_arithmetic<T>::value>>
1294 Vc_INTRINSIC void store_interleaved(const V &a, T *mem)
1295 {
1296  a.store(mem, Vc::Unaligned);
1297 }
1298 // }}}
1299 // decorate(Adapter) {{{
1300 template <typename S, typename T, size_t N>
1301 SimdizeDetail::Interface<SimdizeDetail::Adapter<S, T, N>> decorate(
1302  SimdizeDetail::Adapter<S, T, N> &a)
1303 {
1304  return {a};
1305 }
1306 template <typename S, typename T, size_t N>
1307 const SimdizeDetail::Interface<const SimdizeDetail::Adapter<S, T, N>> decorate(
1308  const SimdizeDetail::Adapter<S, T, N> &a)
1309 {
1310  return {a};
1311 }
1312 template <class V, class = typename std::enable_if<
1314 V &&decorate(V &&v)
1315 {
1316  return std::forward<V>(v);
1317 }
1318 // }}}
1319 namespace SimdizeDetail
1320 {
1321 // Adapter::Adapter(F) Generator {{{
1322 template <typename Scalar, typename Base, size_t N>
1323 template <class F, class>
1324 Adapter<Scalar, Base, N>::Adapter(F &&fun)
1325 {
1326  for (size_t i = 0; i < N; ++i) {
1327  Vc::assign(*this, i, fun(i));
1328  }
1329 }
1330 // }}}
1331 namespace IteratorDetails // {{{
1332 {
1333 enum class Mutable { Yes, No };
1334 
1335 template <typename It, typename V, size_t I, size_t End>
1336 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I == End), It>)
1337 {
1338  return {};
1339 }
1340 template <typename It, typename V, size_t I, size_t End>
1341 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I < End), It> it)
1342 {
1343  V r = fromIteratorImpl<It, V, I + 1, End>(it);
1344  Traits::decay<decltype(get_dispatcher<I>(r))> tmp;
1345  for (size_t j = 0; j < V::size(); ++j, ++it) {
1346  tmp[j] = get_dispatcher<I>(*it);
1347  }
1348  get_dispatcher<I>(r) = tmp;
1349  return r;
1350 }
1351 template <typename It, typename V>
1352 Vc_INTRINSIC V fromIterator(enable_if<!Traits::is_simd_vector<V>::value, const It &> it)
1353 {
1354  return fromIteratorImpl<It, V, 0, determine_tuple_size<V>()>(it);
1355 }
1356 template <typename It, typename V>
1357 Vc_INTRINSIC V fromIterator(enable_if<Traits::is_simd_vector<V>::value, It> it)
1358 {
1359  V r;
1360  for (size_t j = 0; j < V::size(); ++j, ++it) {
1361  r[j] = *it;
1362  }
1363  return r;
1364 }
1365 
1366 // Note: §13.5.6 says: “An expression x->m is interpreted as (x.operator->())->m for a
1367 // class object x of type T if T::operator->() exists and if the operator is selected as
1368 // the best match function by the overload resolution mechanism (13.3).”
1369 template <typename T, typename value_vector, Mutable> class Pointer;
1370 
1379 template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::Yes>
1380 {
1381  static constexpr auto Size = value_vector::size();
1382 
1383 public:
1385  value_vector *operator->() { return &data; }
1386 
1391  Pointer() = delete;
1392  Pointer(const Pointer &) = delete;
1393  Pointer &operator=(const Pointer &) = delete;
1394  Pointer &operator=(Pointer &&) = delete;
1395 
1397  Pointer(Pointer &&) = default;
1398 
1404  ~Pointer()
1405  {
1406  // store data back to where it came from
1407  for (size_t i = 0; i < Size; ++i, ++begin_iterator) {
1408  *begin_iterator = extract(data, i);
1409  }
1410  }
1411 
1413  Pointer(const T &it) : data(fromIterator<T, value_vector>(it)), begin_iterator(it) {}
1414 
1415 private:
1417  value_vector data;
1419  T begin_iterator;
1420 };
1426 template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::No>
1427 {
1428  static constexpr auto Size = value_vector::size();
1429 
1430 public:
1431  const value_vector *operator->() const { return &data; }
1432 
1433  Pointer() = delete;
1434  Pointer(const Pointer &) = delete;
1435  Pointer &operator=(const Pointer &) = delete;
1436  Pointer &operator=(Pointer &&) = delete;
1437 
1438  Pointer(Pointer &&) = default; // required for returning the Pointer
1439 
1440  Pointer(const T &it) : data(fromIterator<T, value_vector>(it)) {}
1441 
1442 private:
1443  value_vector data;
1444 };
1445 
1458 template <typename T, typename value_vector, Mutable M> class Reference;
1459 
1461 template <typename T, typename value_vector>
1462 class Reference<T, value_vector, Mutable::Yes> : public value_vector
1463 {
1464  static constexpr auto Size = value_vector::size();
1465 
1466  using reference = typename std::add_lvalue_reference<T>::type;
1467  reference scalar_it;
1468 
1469 public:
1472  Reference(reference first_it)
1473  : value_vector(fromIterator<T, value_vector>(first_it)), scalar_it(first_it)
1474  {
1475  }
1476 
1478  Reference(const Reference &) = delete;
1479  Reference(Reference &&) = default;
1480  Reference &operator=(const Reference &) = delete;
1481  Reference &operator=(Reference &&) = delete;
1482 
1488  void operator=(const value_vector &x)
1489  {
1490  static_cast<value_vector &>(*this) = x;
1491  auto it = scalar_it;
1492  for (size_t i = 0; i < Size; ++i, ++it) {
1493  *it = extract(x, i);
1494  }
1495  }
1496 };
1497 #define Vc_OP(op_) \
1498  template <typename T0, typename V0, typename T1, typename V1> \
1499  decltype(std::declval<const V0 &>() op_ std::declval<const V1 &>()) operator op_( \
1500  const Reference<T0, V0, Mutable::Yes> &x, \
1501  const Reference<T1, V1, Mutable::Yes> &y) \
1502  { \
1503  return static_cast<const V0 &>(x) op_ static_cast<const V1 &>(y); \
1504  }
1505 Vc_ALL_COMPARES(Vc_OP);
1506 Vc_ALL_ARITHMETICS(Vc_OP);
1507 Vc_ALL_BINARY(Vc_OP);
1508 Vc_ALL_LOGICAL(Vc_OP);
1509 Vc_ALL_SHIFTS(Vc_OP);
1510 #undef Vc_OP
1511 
1513 template <typename T, typename value_vector>
1514 class Reference<T, value_vector, Mutable::No> : public value_vector
1515 {
1516  static constexpr auto Size = value_vector::size();
1517 
1518 public:
1519  Reference(const T &it) : value_vector(fromIterator<T, value_vector>(it)) {}
1520 
1521  Reference(const Reference &) = delete;
1522  Reference(Reference &&) = default;
1523  Reference &operator=(const Reference &) = delete;
1524  Reference &operator=(Reference &&) = delete;
1525 
1527  void operator=(const value_vector &x) = delete;
1528 };
1529 
1530 template <typename T, size_t N,
1531  IteratorDetails::Mutable M =
1532  (Traits::is_output_iterator<T>::value ? Mutable::Yes : Mutable::No),
1533  typename V = simdize<typename std::iterator_traits<T>::value_type, N>,
1534  size_t Size = V::Size,
1535  typename = typename std::iterator_traits<T>::iterator_category>
1536 class Iterator;
1537 
1538 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size_>
1539 class Iterator<T, N, M, V, Size_, std::forward_iterator_tag>
1540  : public std::iterator<typename std::iterator_traits<T>::iterator_category, V,
1541  typename std::iterator_traits<T>::difference_type,
1542  IteratorDetails::Pointer<T, V, M>,
1543  IteratorDetails::Reference<T, V, M>>
1544 {
1545 public:
1546  using pointer = IteratorDetails::Pointer<T, V, M>;
1547  using reference = IteratorDetails::Reference<T, V, M>;
1548  using const_pointer = IteratorDetails::Pointer<T, V, IteratorDetails::Mutable::No>;
1549  using const_reference =
1550  IteratorDetails::Reference<T, V, IteratorDetails::Mutable::No>;
1551 
1553  static constexpr std::size_t size() { return Size_; }
1554  static constexpr std::size_t Size = Size_;
1555 
1556  Iterator() = default;
1557 
1564  Iterator(const T &x) : scalar_it(x) {}
1568  Iterator(T &&x) : scalar_it(std::move(x)) {}
1572  Iterator &operator=(const T &x)
1573  {
1574  scalar_it = x;
1575  return *this;
1576  }
1580  Iterator &operator=(T &&x)
1581  {
1582  scalar_it = std::move(x);
1583  return *this;
1584  }
1585 
1587  Iterator(const Iterator &) = default;
1589  Iterator(Iterator &&) = default;
1591  Iterator &operator=(const Iterator &) = default;
1593  Iterator &operator=(Iterator &&) = default;
1594 
1596  Iterator &operator++()
1597  {
1598  std::advance(scalar_it, Size);
1599  return *this;
1600  }
1602  Iterator operator++(int)
1603  {
1604  Iterator copy(*this);
1605  operator++();
1606  return copy;
1607  }
1608 
1617  bool operator==(const Iterator &rhs) const
1618  {
1619 #ifndef NDEBUG
1620  if (scalar_it == rhs.scalar_it) {
1621  return true;
1622  } else {
1623  T it(scalar_it);
1624  for (size_t i = 1; i < Size; ++i) {
1625  Vc_ASSERT((++it != rhs.scalar_it));
1626  }
1627  return false;
1628  }
1629 #else
1630  return scalar_it == rhs.scalar_it;
1631 #endif
1632  }
1641  bool operator!=(const Iterator &rhs) const
1642  {
1643  return !operator==(rhs);
1644  }
1645 
1646  pointer operator->() { return scalar_it; }
1647 
1654  reference operator*() { return scalar_it; }
1655 
1656  const_pointer operator->() const { return scalar_it; }
1657 
1665  const_reference operator*() const { return scalar_it; }
1666 
1680  operator const T &() const { return scalar_it; }
1681 
1682 protected:
1683  T scalar_it;
1684 };
1685 
1690 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1691 class Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1692  : public Iterator<T, N, M, V, Size, std::forward_iterator_tag>
1693 {
1694  using Base = Iterator<T, N, M, V, Size, std::forward_iterator_tag>;
1695 
1696 protected:
1697  using Base::scalar_it;
1698 
1699 public:
1700  using pointer = typename Base::pointer;
1701  using reference = typename Base::reference;
1702  using const_pointer = typename Base::const_pointer;
1703  using const_reference = typename Base::const_reference;
1704 
1705  using Iterator<T, N, M, V, Size,
1706  std::forward_iterator_tag>::Iterator; // in short: "using
1707  // Base::Iterator", but that
1708  // confuses ICC
1710  Iterator &operator--()
1711  {
1712  std::advance(scalar_it, -Size);
1713  return *this;
1714  }
1716  Iterator operator--(int)
1717  {
1718  Iterator copy(*this);
1719  operator--();
1720  return copy;
1721  }
1722 };
1723 
1728 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1729 class Iterator<T, N, M, V, Size, std::random_access_iterator_tag>
1730  : public Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1731 {
1733 
1734 protected:
1735  using Base::scalar_it;
1736 
1737 public:
1738  using pointer = typename Base::pointer;
1739  using reference = typename Base::reference;
1740  using const_pointer = typename Base::const_pointer;
1741  using const_reference = typename Base::const_reference;
1742  using difference_type = typename std::iterator_traits<T>::difference_type;
1743 
1745  Iterator; // in short: "using Base::Iterator", but that confuses ICC
1746 
1747  Iterator &operator+=(difference_type n)
1748  {
1749  scalar_it += n * difference_type(Size);
1750  return *this;
1751  }
1752  Iterator operator+(difference_type n) const { return Iterator(*this) += n; }
1753 
1754  Iterator &operator-=(difference_type n)
1755  {
1756  scalar_it -= n * difference_type(Size);
1757  return *this;
1758  }
1759  Iterator operator-(difference_type n) const { return Iterator(*this) -= n; }
1760 
1761  difference_type operator-(const Iterator &rhs) const
1762  {
1763  constexpr difference_type n = Size;
1764  Vc_ASSERT((scalar_it - rhs.scalar_it) % n ==
1765  0); // if this fails the two iterators are not a multiple of the vector
1766  // width apart. The distance would be fractional and that doesn't
1767  // make too much sense for iteration. Therefore, it is a
1768  // precondition for the distance of the two iterators to be a
1769  // multiple of Size.
1770  return (scalar_it - rhs.scalar_it) / n;
1771  }
1772 
1777  bool operator<(const Iterator &rhs) const
1778  {
1779  return rhs.scalar_it - scalar_it >= difference_type(Size);
1780  }
1781 
1782  bool operator>(const Iterator &rhs) const
1783  {
1784  return scalar_it - rhs.scalar_it >= difference_type(Size);
1785  }
1786 
1787  bool operator<=(const Iterator &rhs) const
1788  {
1789  return rhs.scalar_it - scalar_it >= difference_type(Size) - 1;
1790  }
1791 
1792  bool operator>=(const Iterator &rhs) const
1793  {
1794  return scalar_it - rhs.scalar_it >= difference_type(Size) - 1;
1795  }
1796 
1797  reference operator[](difference_type i) { return *(*this + i); }
1798  const_reference operator[](difference_type i) const { return *(*this + i); }
1799 };
1800 
1801 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1803  typename Iterator<T, N, M, V, Size, std::random_access_iterator_tag>::difference_type
1804  n,
1806 {
1807  return i + n;
1808 }
1809 
1810 } // namespace IteratorDetails }}}
1811 
1820 template <typename T, size_t N, typename MT>
1821 struct ReplaceTypes<T, N, MT, Category::ForwardIterator>
1822 {
1823  using type = IteratorDetails::Iterator<T, N>;
1824 };
1825 template <typename T, size_t N, typename MT>
1826 struct ReplaceTypes<T, N, MT, Category::BidirectionalIterator>
1827 {
1828  using type = IteratorDetails::Iterator<T, N>;
1829 };
1830 template <typename T, size_t N, typename MT>
1831 struct ReplaceTypes<T, N, MT, Category::RandomAccessIterator>
1832 {
1833  using type = IteratorDetails::Iterator<T, N>;
1834 };
1835 
1839 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1840  std::size_t Offset>
1841 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size_<S>::value && M::Size == N), void>
1842  conditional_assign(Adapter<S, T, N> &, const M &, const U &)
1843 {
1844 }
1845 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1846  std::size_t Offset = 0>
1847 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size_<S>::value && M::Size == N), void>
1848  conditional_assign(Adapter<S, T, N> &lhs, const M &mask, const U &rhs)
1849 {
1850  using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1851  using M2 = typename V::mask_type;
1852  conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask), get_dispatcher<Offset>(rhs));
1853  conditional_assign<Op, S, T, N, M, U, Offset + 1>(lhs, mask, rhs);
1854 }
1855 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
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 &)
1859 {
1860 }
1861 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
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)
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));
1869  conditional_assign<Op, S, T, N, M, Offset + 1>(lhs, mask);
1870 }
1871 
1873 } // namespace SimdizeDetail
1874 
1875 // user API {{{
1894 template <typename T, size_t N = 0, typename MT = void>
1895 using simdize = SimdizeDetail::simdize<T, N, MT>;
1896 
1916 #define Vc_SIMDIZE_INTERFACE(MEMBERS_) \
1917  template <std::size_t N_> \
1918  inline auto vc_get_()->decltype(std::get<N_>(std::tie MEMBERS_)) \
1919  { \
1920  return std::get<N_>(std::tie MEMBERS_); \
1921  } \
1922  template <std::size_t N_> \
1923  inline auto vc_get_() const->decltype(std::get<N_>(std::tie MEMBERS_)) \
1924  { \
1925  return std::get<N_>(std::tie MEMBERS_); \
1926  } \
1927  enum : std::size_t { \
1928  tuple_size = std::tuple_size<decltype(std::make_tuple MEMBERS_)>::value \
1929  }
1930 // }}}
1931 } // namespace Vc
1932 
1933 namespace std // {{{
1934 {
1935 using Vc::SimdizeDetail::swap;
1936 } // namespace std }}}
1937 
1938 #endif // VC_COMMON_SIMDIZE_H_
1939 
1940 // vim: foldmethod=marker
void free(T *p)
Frees memory that was allocated with Vc::malloc.
Definition: memory.h:102
bool operator<(const Iterator &rhs) const
Returns whether all entries accessed via iterator dereferencing come before the iterator rhs...
Definition: simdize.h:1777
result_vector_type< L, R > operator-(L &&lhs, R &&rhs)
Applies - component-wise and concurrently.
Definition: simdarray.h:1682
Definition: vector.h:249
result_vector_type< L, R > operator*(L &&lhs, R &&rhs)
Applies * component-wise and concurrently.
Definition: simdarray.h:1682
SimdizeDetail::simdize< T, N, MT > simdize
Definition: simdize.h:1895
Wraps a pointer to memory with convenience functions to access it via vectors.
void assign(SimdizeDetail::Adapter< S, T, N > &a, size_t i, const S &x)
Assigns one scalar object x to a SIMD slot at offset i in the simdized object a.
Definition: simdize.h:1223
An allocator that uses global new and supports over-aligned types, as per [C++11 20.6.9].
Definition: Allocator:128
Identifies any SIMD vector type (independent of implementation or whether it&#39;s SimdArray<T, N>).
Definition: type_traits.h:136
result_vector_type< L, R > operator+(L &&lhs, R &&rhs)
Applies + component-wise and concurrently.
Definition: simdarray.h:1682
Iterator & operator--()
Advances the iterator by one vector width, or respectively N scalar steps.
Definition: simdize.h:1710
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:1071
This is the iterator type created when applying simdize to a random access iterator type...
Definition: simdize.h:1729
Vector Classes Namespace.
Definition: dox.h:584
This is the iterator type created when applying simdize to a bidirectional iterator type...
Definition: simdize.h:1691
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:1243
constexpr UnalignedTag Unaligned
Use this object for a flags parameter to request unaligned loads and stores.