Vc  1.3.80-dev
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 // homogeneous_sizeof {{{
751 template <class... Ts> struct homogeneous_sizeof;
752 template <class T, class = void> struct homogeneous_sizeof_one;
753 
754 template <class T, size_t... Is>
755 std::integral_constant<size_t,
756  homogeneous_sizeof<typename std::remove_reference<decltype(
757  get_dispatcher<Is>(std::declval<T>()))>::type...>::value>
758 homogeneous_sizeof_helper(index_sequence<Is...>);
759 
760 template <class T>
761 struct homogeneous_sizeof_one<T,
762  typename std::enable_if<std::is_arithmetic<T>::value>::type>
763  : std::integral_constant<size_t, sizeof(T)> {
764 };
765 
766 template <class T>
767 struct homogeneous_sizeof_one<T, typename std::enable_if<std::is_class<T>::value>::type>
768  : decltype(homogeneous_sizeof_helper<T>(
769  make_index_sequence<determine_tuple_size_<T>::value>())) {
770 };
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 // class Adapter {{{
784 template <typename Scalar, typename Base, size_t N> class Adapter : public Base
785 {
786 private:
788  template <std::size_t... Indexes, int X>
789  Adapter(Vc::index_sequence<Indexes...>, const Scalar,
790  std::integral_constant<int, X>)
791  {
792  static_assert(
793  X < 3, "Failed to construct an object of type Base. Neither via "
794  "parenthesis-init, brace-init, nor double-brace init appear to work.");
795  }
796 
798  template <std::size_t... Indexes>
799  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_,
800  std::integral_constant<int, 2>)
801  : Base{{get_dispatcher<Indexes>(x_)...}}
802  {
803  }
804 
806  template <std::size_t... Indexes>
807  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_,
808  std::integral_constant<int, 1>)
809  : Base{get_dispatcher<Indexes>(x_)...}
810  {
811  }
812 
814  template <std::size_t... Indexes>
815  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_,
816  std::integral_constant<int, 0>)
817  : Base(get_dispatcher<Indexes>(x_)...)
818  {
819  }
820 
821  template <std::size_t... Indexes>
822  Adapter(Vc::index_sequence<Indexes...> seq_, const Scalar &x_)
823  : Adapter(seq_, x_,
824  preferred_construction<Base, decltype(get_dispatcher<Indexes>(
825  std::declval<const Scalar &>()))...>())
826  {
827  }
828 
829 public:
831  static constexpr size_t size() { return N; }
832  static constexpr size_t Size = N;
833 
835  using base_type = Base;
838  using scalar_type = Scalar;
839 
842  Adapter() = default;
843 
845 #if defined Vc_CLANG && Vc_CLANG < 0x30700
846  Vc_INTRINSIC Adapter(const Adapter &x) : Base(x) {}
847 #else
848  Adapter(const Adapter &) = default;
849 #endif
850  Adapter(Adapter &&) = default;
853  Adapter &operator=(const Adapter &) = default;
855  Adapter &operator=(Adapter &&) = default;
856 
858  template <typename U, size_t TupleSize = determine_tuple_size_<Scalar>::value,
859  typename Seq = Vc::make_index_sequence<TupleSize>,
860  typename = enable_if<std::is_convertible<U, Scalar>::value>>
861  Adapter(U &&x_)
862  : Adapter(Seq(), static_cast<const Scalar &>(x_))
863  {
864  }
865 
867  template <class F,
868  class = decltype(static_cast<Scalar>(std::declval<F>()(
869  size_t())))> // F returns objects that are convertible to S
870  Adapter(F &&fun)
871  {
872  for (size_t i = 0; i < N; ++i) {
873  assign(*this, i, fun(i));
874  }
875  }
876 
877  // }}}
879  template <typename A0, typename... Args,
880  typename = typename std::enable_if<
881  !Traits::is_index_sequence<A0>::value &&
882  (sizeof...(Args) > 0 || !std::is_convertible<A0, Scalar>::value)>::type>
883  Adapter(A0 &&arg0_, Args &&... arguments_)
884  : Base(std::forward<A0>(arg0_), std::forward<Args>(arguments_)...)
885  {
886  }
887 
889  template <typename T,
890  typename = decltype(Base(std::declval<const std::initializer_list<T> &>()))>
891  Adapter(const std::initializer_list<T> &l_)
892  : Base(l_)
893  {
894  }
895 
898  void *operator new(size_t size)
899  {
900  return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
901  }
902  void *operator new(size_t, void *p_) { return p_; }
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 delete(void *ptr_, size_t) { Vc::Common::free(ptr_); }
909  void operator delete(void *, void *) {}
910  void operator delete[](void *ptr_, size_t) { Vc::Common::free(ptr_); }
911  void operator delete[](void *, void *) {}
912 }; // }}}
913 // delete compare operators for Adapter {{{
918 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
919 inline void operator==(
920  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
921  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
922 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
923 inline void operator!=(
924  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
925  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
926 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
927 inline void operator<=(
928  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
929  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
930 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
931 inline void operator>=(
932  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
933  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
934 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
935 inline void operator<(
936  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
937  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
938 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
939 inline void operator>(
940  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
941  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
942 // }}}
944 } // namespace SimdizeDetail }}}
945 } // namespace Vc
946 
947 namespace std // {{{
948 {
952 template <typename Scalar, typename Base, size_t N>
953 class tuple_size<Vc::SimdizeDetail::Adapter<Scalar, Base, N>> : public tuple_size<Base>
954 {
955 };
959 template <size_t I, typename Scalar, typename Base, size_t N>
960 class tuple_element<I, Vc::SimdizeDetail::Adapter<Scalar, Base, N>>
961  : public tuple_element<I, Base>
962 {
963 };
964 // std::get does not need additional work because Vc::Adapter derives from
965 // C<Ts...> and therefore if get<N>(C<Ts...>) works it works for Adapter as well.
966 
971 template <typename S, typename T, size_t N>
972 class allocator<Vc::SimdizeDetail::Adapter<S, T, N>>
973  : public Vc::Allocator<Vc::SimdizeDetail::Adapter<S, T, N>>
974 {
975 public:
976  template <typename U> struct rebind
977  {
978  typedef std::allocator<U> other;
979  };
980 };
981 } // namespace std }}}
982 
983 namespace Vc_VERSIONED_NAMESPACE
984 {
985 namespace SimdizeDetail
986 {
995 template <typename T> static inline T decay_workaround(const T &x) { return x; }
996 
997 // assign_impl {{{
1001 template <typename S, typename T, size_t N, size_t... Indexes>
1002 inline void assign_impl(Adapter<S, T, N> &a, size_t i, const S &x,
1003  Vc::index_sequence<Indexes...>)
1004 {
1005  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(x)))...> tmp(
1006  decay_workaround(get_dispatcher<Indexes>(x))...);
1007  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(tmp), 0)...};
1008  if (&unused == &unused) {}
1009 } // }}}
1010 // construct (parens, braces, double-braces) {{{
1011 template <class S, class... Args>
1012 S construct(std::integral_constant<int, 0>, Args &&... args)
1013 {
1014  return S(std::forward<Args>(args)...);
1015 }
1016 template <class S, class... Args>
1017 S construct(std::integral_constant<int, 1>, Args &&... args)
1018 {
1019  return S{std::forward<Args>(args)...};
1020 }
1021 template <class S, class... Args>
1022 S construct(std::integral_constant<int, 2>, Args &&... args)
1023 {
1024  return S{{std::forward<Args>(args)...}};
1025 }
1026 // }}}
1027 // extract_impl {{{
1031 template <typename S, typename T, size_t N, size_t... Indexes>
1032 inline S extract_impl(const Adapter<S, T, N> &a, size_t i, Vc::index_sequence<Indexes...>)
1033 {
1034  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[i]))...> tmp(
1035  decay_workaround(get_dispatcher<Indexes>(a)[i])...);
1036  return construct<S>(
1037  preferred_construction<S, decltype(decay_workaround(
1038  get_dispatcher<Indexes>(a)[i]))...>(),
1039  decay_workaround(get_dispatcher<Indexes>(a)[i])...);
1040  //return S(get_dispatcher<Indexes>(tmp)...);
1041 }
1042 // }}}
1043 // shifted_impl {{{
1044 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1045 inline Adapter<S, T, N> shifted_impl(const Adapter<S, T, N> &a, int shift,
1046  Vc::index_sequence<Indexes...>)
1047 {
1048  Adapter<S, T, N> r;
1049  auto &&unused = {(get_dispatcher<Indexes>(r) = get_dispatcher<Indexes>(a).shifted(shift), 0)...};
1050  if (&unused == &unused) {}
1051  return r;
1052 }
1053 // }}}
1054 // shifted(Adapter) {{{
1063 template <typename S, typename T, size_t N>
1064 inline Adapter<S, T, N> shifted(const Adapter<S, T, N> &a, int shift)
1065 {
1066  return shifted_impl(a, shift, Vc::make_index_sequence<determine_tuple_size<T>()>());
1067 }
1068 // }}}
1069 // swap_impl {{{
1073 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1074 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, S &x,
1075  Vc::index_sequence<Indexes...>)
1076 {
1077  const auto &a_const = a;
1078  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a_const)[0]))...>
1079  tmp{decay_workaround(get_dispatcher<Indexes>(a_const)[i])...};
1080  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(x), 0)...};
1081  auto &&unused2 = {(get_dispatcher<Indexes>(x) = get_dispatcher<Indexes>(tmp), 0)...};
1082  if (&unused == &unused2) {}
1083 }
1084 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1085 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b,
1086  std::size_t j, Vc::index_sequence<Indexes...>)
1087 {
1088  const auto &a_const = a;
1089  const auto &b_const = b;
1090  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a_const)[0]))...>
1091  tmp{decay_workaround(get_dispatcher<Indexes>(a_const)[i])...};
1092  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(b_const)[j], 0)...};
1093  auto &&unused2 = {(get_dispatcher<Indexes>(b)[j] = get_dispatcher<Indexes>(tmp), 0)...};
1094  if (&unused == &unused2) {}
1095 }
1096 // }}}
1097 // swap(Adapter) {{{
1102 template <typename S, typename T, std::size_t N>
1103 inline void swap(Adapter<S, T, N> &a, std::size_t i, S &x)
1104 {
1105  swap_impl(a, i, x, Vc::make_index_sequence<determine_tuple_size<T>()>());
1106 }
1107 template <typename S, typename T, std::size_t N>
1108 inline void swap(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b, std::size_t j)
1109 {
1110  swap_impl(a, i, b, j, Vc::make_index_sequence<determine_tuple_size<T>()>());
1111 }
1112 // }}}
1113 template <typename A> class Scalar // {{{
1114 {
1115  using reference = typename std::add_lvalue_reference<A>::type;
1116  using S = typename A::scalar_type;
1117  using IndexSeq = Vc::make_index_sequence<determine_tuple_size<S>()>;
1118 
1119 public:
1120  Scalar(reference aa, size_t ii) : a(aa), i(ii) {}
1121 
1122  // delete copy and move to keep the type a pure proxy temporary object.
1123  Scalar(const Scalar &) = delete;
1124  Scalar(Scalar &&) = delete;
1125  Scalar &operator=(const Scalar &) = delete;
1126  Scalar &operator=(Scalar &&) = delete;
1127 
1128  void operator=(const S &x) { assign_impl(a, i, x, IndexSeq()); }
1129  operator S() const { return extract_impl(a, i, IndexSeq()); }
1130 
1131  template <typename AA>
1132  friend inline void swap(Scalar<AA> &&a, typename AA::scalar_type &b);
1133  template <typename AA>
1134  friend inline void swap(typename AA::scalar_type &b, Scalar<AA> &&a);
1135  template <typename AA> friend inline void swap(Scalar<AA> &&a, Scalar<AA> &&b);
1136 
1137 private:
1138  reference a;
1139  size_t i;
1140 }; // }}}
1141 // swap(Scalar) {{{
1144 template <typename A> inline void swap(Scalar<A> &&a, typename A::scalar_type &b)
1145 {
1146  swap_impl(a.a, a.i, b, typename Scalar<A>::IndexSeq());
1147 }
1150 template <typename A> inline void swap(typename A::scalar_type &b, Scalar<A> &&a)
1151 {
1152  swap_impl(a.a, a.i, b, typename Scalar<A>::IndexSeq());
1153 }
1154 
1155 template <typename A> inline void swap(Scalar<A> &&a, Scalar<A> &&b)
1156 {
1157  swap_impl(a.a, a.i, b.a, b.i, typename Scalar<A>::IndexSeq());
1158 }
1159 // }}}
1160 // load_interleaved_impl {{{
1161 template <class S, class T, size_t N, size_t... I>
1162 inline void load_interleaved_impl(Vc::index_sequence<I...>, Adapter<S, T, N> &a,
1163  const S *mem)
1164 {
1165  const InterleavedMemoryWrapper<S, decltype(decay_workaround(get_dispatcher<0>(a)))>
1166  wrapper(const_cast<S *>(mem));
1167  Vc::tie(get_dispatcher<I>(a)...) = wrapper[0];
1168 }
1169 // }}}
1170 // store_interleaved_impl {{{
1171 template <class S, class T, size_t N, size_t... I>
1172 inline void store_interleaved_impl(Vc::index_sequence<I...>, const Adapter<S, T, N> &a,
1173  S *mem)
1174 {
1175  InterleavedMemoryWrapper<S, decltype(decay_workaround(get_dispatcher<0>(a)))> wrapper(
1176  mem);
1177  wrapper[0] = Vc::tie(get_dispatcher<I>(a)...);
1178 }
1179 // }}}
1180 template <typename A> class Interface // {{{
1181 {
1182  using reference = typename std::add_lvalue_reference<A>::type;
1183  using IndexSeq =
1184  Vc::make_index_sequence<determine_tuple_size<typename A::scalar_type>()>;
1185 
1186 public:
1187  Interface(reference aa) : a(aa) {}
1188 
1189  Scalar<A> operator[](size_t i)
1190  {
1191  return {a, i};
1192  }
1193  typename A::scalar_type operator[](size_t i) const
1194  {
1195  return extract_impl(a, i, IndexSeq());
1196  }
1197 
1198  A shifted(int amount) const
1199  {
1200  return shifted_impl(a, amount, IndexSeq());
1201  }
1202 
1203  void load(const typename A::scalar_type *mem) { load_interleaved(*this, mem); }
1204  void store(typename A::scalar_type *mem) { store_interleaved(*this, mem); }
1205 
1206 private:
1207  reference a;
1208 }; // }}}
1209 } // namespace SimdizeDetail
1210 // assign {{{
1215 template <typename S, typename T, size_t N>
1216 inline void assign(SimdizeDetail::Adapter<S, T, N> &a, size_t i, const S &x)
1217 {
1218  SimdizeDetail::assign_impl(
1219  a, i, x, Vc::make_index_sequence<SimdizeDetail::determine_tuple_size<T>()>());
1220 }
1224 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
1225 Vc_INTRINSIC void assign(V &v, size_t i, typename V::EntryType x)
1226 {
1227  v[i] = x;
1228 }
1229 // }}}
1230 // extract {{{
1235 template <typename S, typename T, size_t N>
1236 inline S extract(const SimdizeDetail::Adapter<S, T, N> &a, size_t i)
1237 {
1238  return SimdizeDetail::extract_impl(
1239  a, i, Vc::make_index_sequence<SimdizeDetail::determine_tuple_size<S>()>());
1240 }
1244 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
1245 Vc_INTRINSIC typename V::EntryType extract(const V &v, size_t i)
1246 {
1247  return v[i];
1248 }
1249 // }}}
1250 // load_interleaved {{{
1251 template <class S, class T, size_t N>
1252 inline void load_interleaved(SimdizeDetail::Adapter<S, T, N> &a, const S *mem)
1253 {
1254  if (SimdizeDetail::homogeneous_sizeof<S>::value == 0) {
1255  Common::unrolled_loop<std::size_t, 0, N>(
1256  [&](std::size_t i) { assign(a, i, mem[i]); });
1257  } else {
1258  constexpr size_t TupleSize = SimdizeDetail::determine_tuple_size_<S>::value;
1259  SimdizeDetail::load_interleaved_impl(Vc::make_index_sequence<TupleSize>(), a,
1260  mem);
1261  }
1262 }
1263 template <
1264  class V, class T,
1265  class = enable_if<Traits::is_simd_vector<V>::value && std::is_arithmetic<T>::value>>
1266 Vc_INTRINSIC void load_interleaved(V &a, const T *mem)
1267 {
1268  a.load(mem, Vc::Unaligned);
1269 }
1270 // }}}
1271 // store_interleaved {{{
1272 template <class S, class T, size_t N>
1273 inline void store_interleaved(const SimdizeDetail::Adapter<S, T, N> &a, S *mem)
1274 {
1275  if (SimdizeDetail::homogeneous_sizeof<S>::value == 0) {
1276  Common::unrolled_loop<std::size_t, 0, N>(
1277  [&](std::size_t i) { mem[i] = extract(a, i); });
1278  } else {
1279  constexpr size_t TupleSize = SimdizeDetail::determine_tuple_size_<S>::value;
1280  SimdizeDetail::store_interleaved_impl(Vc::make_index_sequence<TupleSize>(), a,
1281  mem);
1282  }
1283 }
1284 template <
1285  class V, class T,
1286  class = enable_if<Traits::is_simd_vector<V>::value && std::is_arithmetic<T>::value>>
1287 Vc_INTRINSIC void store_interleaved(const V &a, T *mem)
1288 {
1289  a.store(mem, Vc::Unaligned);
1290 }
1291 // }}}
1292 // decorate(Adapter) {{{
1293 template <typename S, typename T, size_t N>
1294 SimdizeDetail::Interface<SimdizeDetail::Adapter<S, T, N>> decorate(
1295  SimdizeDetail::Adapter<S, T, N> &a)
1296 {
1297  return {a};
1298 }
1299 template <typename S, typename T, size_t N>
1300 const SimdizeDetail::Interface<const SimdizeDetail::Adapter<S, T, N>> decorate(
1301  const SimdizeDetail::Adapter<S, T, N> &a)
1302 {
1303  return {a};
1304 }
1305 template <class V, class = typename std::enable_if<
1307 V &&decorate(V &&v)
1308 {
1309  return std::forward<V>(v);
1310 }
1311 // }}}
1312 namespace SimdizeDetail
1313 {
1314 namespace IteratorDetails // {{{
1315 {
1316 enum class Mutable { Yes, No };
1317 
1318 template <typename It, typename V, size_t I, size_t End>
1319 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I == End), It>)
1320 {
1321  return {};
1322 }
1323 template <typename It, typename V, size_t I, size_t End>
1324 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I < End), It> it)
1325 {
1326  V r = fromIteratorImpl<It, V, I + 1, End>(it);
1327  Traits::decay<decltype(get_dispatcher<I>(r))> tmp;
1328  for (size_t j = 0; j < V::size(); ++j, ++it) {
1329  tmp[j] = get_dispatcher<I>(*it);
1330  }
1331  get_dispatcher<I>(r) = tmp;
1332  return r;
1333 }
1334 template <typename It, typename V>
1335 Vc_INTRINSIC V fromIterator(enable_if<!Traits::is_simd_vector<V>::value, const It &> it)
1336 {
1337  return fromIteratorImpl<It, V, 0, determine_tuple_size<V>()>(it);
1338 }
1339 template <typename It, typename V>
1340 Vc_INTRINSIC V fromIterator(enable_if<Traits::is_simd_vector<V>::value, It> it)
1341 {
1342  V r;
1343  for (size_t j = 0; j < V::size(); ++j, ++it) {
1344  r[j] = *it;
1345  }
1346  return r;
1347 }
1348 
1349 // Note: §13.5.6 says: “An expression x->m is interpreted as (x.operator->())->m for a
1350 // class object x of type T if T::operator->() exists and if the operator is selected as
1351 // the best match function by the overload resolution mechanism (13.3).”
1352 template <typename T, typename value_vector, Mutable> class Pointer;
1353 
1362 template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::Yes>
1363 {
1364  static constexpr auto Size = value_vector::size();
1365 
1366 public:
1368  value_vector *operator->() { return &data; }
1369 
1374  Pointer() = delete;
1375  Pointer(const Pointer &) = delete;
1376  Pointer &operator=(const Pointer &) = delete;
1377  Pointer &operator=(Pointer &&) = delete;
1378 
1380  Pointer(Pointer &&) = default;
1381 
1387  ~Pointer()
1388  {
1389  // store data back to where it came from
1390  for (size_t i = 0; i < Size; ++i, ++begin_iterator) {
1391  *begin_iterator = extract(data, i);
1392  }
1393  }
1394 
1396  Pointer(const T &it) : data(fromIterator<T, value_vector>(it)), begin_iterator(it) {}
1397 
1398 private:
1400  value_vector data;
1402  T begin_iterator;
1403 };
1409 template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::No>
1410 {
1411  static constexpr auto Size = value_vector::size();
1412 
1413 public:
1414  const value_vector *operator->() const { return &data; }
1415 
1416  Pointer() = delete;
1417  Pointer(const Pointer &) = delete;
1418  Pointer &operator=(const Pointer &) = delete;
1419  Pointer &operator=(Pointer &&) = delete;
1420 
1421  Pointer(Pointer &&) = default; // required for returning the Pointer
1422 
1423  Pointer(const T &it) : data(fromIterator<T, value_vector>(it)) {}
1424 
1425 private:
1426  value_vector data;
1427 };
1428 
1441 template <typename T, typename value_vector, Mutable M> class Reference;
1442 
1444 template <typename T, typename value_vector>
1445 class Reference<T, value_vector, Mutable::Yes> : public value_vector
1446 {
1447  static constexpr auto Size = value_vector::size();
1448 
1449  using reference = typename std::add_lvalue_reference<T>::type;
1450  reference scalar_it;
1451 
1452 public:
1455  Reference(reference first_it)
1456  : value_vector(fromIterator<T, value_vector>(first_it)), scalar_it(first_it)
1457  {
1458  }
1459 
1461  Reference(const Reference &) = delete;
1462  Reference(Reference &&) = default;
1463  Reference &operator=(const Reference &) = delete;
1464  Reference &operator=(Reference &&) = delete;
1465 
1471  void operator=(const value_vector &x)
1472  {
1473  static_cast<value_vector &>(*this) = x;
1474  auto it = scalar_it;
1475  for (size_t i = 0; i < Size; ++i, ++it) {
1476  *it = extract(x, i);
1477  }
1478  }
1479 };
1480 #define Vc_OP(op_) \
1481  template <typename T0, typename V0, typename T1, typename V1> \
1482  decltype(std::declval<const V0 &>() op_ std::declval<const V1 &>()) operator op_( \
1483  const Reference<T0, V0, Mutable::Yes> &x, \
1484  const Reference<T1, V1, Mutable::Yes> &y) \
1485  { \
1486  return static_cast<const V0 &>(x) op_ static_cast<const V1 &>(y); \
1487  }
1488 Vc_ALL_COMPARES(Vc_OP);
1489 Vc_ALL_ARITHMETICS(Vc_OP);
1490 Vc_ALL_BINARY(Vc_OP);
1491 Vc_ALL_LOGICAL(Vc_OP);
1492 Vc_ALL_SHIFTS(Vc_OP);
1493 #undef Vc_OP
1494 
1496 template <typename T, typename value_vector>
1497 class Reference<T, value_vector, Mutable::No> : public value_vector
1498 {
1499  static constexpr auto Size = value_vector::size();
1500 
1501 public:
1502  Reference(const T &it) : value_vector(fromIterator<T, value_vector>(it)) {}
1503 
1504  Reference(const Reference &) = delete;
1505  Reference(Reference &&) = default;
1506  Reference &operator=(const Reference &) = delete;
1507  Reference &operator=(Reference &&) = delete;
1508 
1510  void operator=(const value_vector &x) = delete;
1511 };
1512 
1513 template <typename T, size_t N,
1514  IteratorDetails::Mutable M =
1515  (Traits::is_output_iterator<T>::value ? Mutable::Yes : Mutable::No),
1516  typename V = simdize<typename std::iterator_traits<T>::value_type, N>,
1517  size_t Size = V::Size,
1518  typename = typename std::iterator_traits<T>::iterator_category>
1519 class Iterator;
1520 
1521 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size_>
1522 class Iterator<T, N, M, V, Size_, std::forward_iterator_tag>
1523  : public std::iterator<typename std::iterator_traits<T>::iterator_category, V,
1524  typename std::iterator_traits<T>::difference_type,
1525  IteratorDetails::Pointer<T, V, M>,
1526  IteratorDetails::Reference<T, V, M>>
1527 {
1528 public:
1529  using pointer = IteratorDetails::Pointer<T, V, M>;
1530  using reference = IteratorDetails::Reference<T, V, M>;
1531  using const_pointer = IteratorDetails::Pointer<T, V, IteratorDetails::Mutable::No>;
1532  using const_reference =
1533  IteratorDetails::Reference<T, V, IteratorDetails::Mutable::No>;
1534 
1536  static constexpr std::size_t size() { return Size_; }
1537  static constexpr std::size_t Size = Size_;
1538 
1539  Iterator() = default;
1540 
1547  Iterator(const T &x) : scalar_it(x) {}
1551  Iterator(T &&x) : scalar_it(std::move(x)) {}
1555  Iterator &operator=(const T &x)
1556  {
1557  scalar_it = x;
1558  return *this;
1559  }
1563  Iterator &operator=(T &&x)
1564  {
1565  scalar_it = std::move(x);
1566  return *this;
1567  }
1568 
1570  Iterator(const Iterator &) = default;
1572  Iterator(Iterator &&) = default;
1574  Iterator &operator=(const Iterator &) = default;
1576  Iterator &operator=(Iterator &&) = default;
1577 
1579  Iterator &operator++()
1580  {
1581  std::advance(scalar_it, Size);
1582  return *this;
1583  }
1585  Iterator operator++(int)
1586  {
1587  Iterator copy(*this);
1588  operator++();
1589  return copy;
1590  }
1591 
1600  bool operator==(const Iterator &rhs) const
1601  {
1602 #ifndef NDEBUG
1603  if (scalar_it == rhs.scalar_it) {
1604  return true;
1605  } else {
1606  T it(scalar_it);
1607  for (size_t i = 1; i < Size; ++i) {
1608  Vc_ASSERT((++it != rhs.scalar_it));
1609  }
1610  return false;
1611  }
1612 #else
1613  return scalar_it == rhs.scalar_it;
1614 #endif
1615  }
1624  bool operator!=(const Iterator &rhs) const
1625  {
1626  return !operator==(rhs);
1627  }
1628 
1629  pointer operator->() { return scalar_it; }
1630 
1637  reference operator*() { return scalar_it; }
1638 
1639  const_pointer operator->() const { return scalar_it; }
1640 
1648  const_reference operator*() const { return scalar_it; }
1649 
1663  operator const T &() const { return scalar_it; }
1664 
1665 protected:
1666  T scalar_it;
1667 };
1668 
1673 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1674 class Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1675  : public Iterator<T, N, M, V, Size, std::forward_iterator_tag>
1676 {
1677  using Base = Iterator<T, N, M, V, Size, std::forward_iterator_tag>;
1678 
1679 protected:
1680  using Base::scalar_it;
1681 
1682 public:
1683  using pointer = typename Base::pointer;
1684  using reference = typename Base::reference;
1685  using const_pointer = typename Base::const_pointer;
1686  using const_reference = typename Base::const_reference;
1687 
1688  using Iterator<T, N, M, V, Size,
1689  std::forward_iterator_tag>::Iterator; // in short: "using
1690  // Base::Iterator", but that
1691  // confuses ICC
1693  Iterator &operator--()
1694  {
1695  std::advance(scalar_it, -Size);
1696  return *this;
1697  }
1699  Iterator operator--(int)
1700  {
1701  Iterator copy(*this);
1702  operator--();
1703  return copy;
1704  }
1705 };
1706 
1711 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1712 class Iterator<T, N, M, V, Size, std::random_access_iterator_tag>
1713  : public Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1714 {
1716 
1717 protected:
1718  using Base::scalar_it;
1719 
1720 public:
1721  using pointer = typename Base::pointer;
1722  using reference = typename Base::reference;
1723  using const_pointer = typename Base::const_pointer;
1724  using const_reference = typename Base::const_reference;
1725  using difference_type = typename std::iterator_traits<T>::difference_type;
1726 
1728  Iterator; // in short: "using Base::Iterator", but that confuses ICC
1729 
1730  Iterator &operator+=(difference_type n)
1731  {
1732  scalar_it += n * difference_type(Size);
1733  return *this;
1734  }
1735  Iterator operator+(difference_type n) const { return Iterator(*this) += n; }
1736 
1737  Iterator &operator-=(difference_type n)
1738  {
1739  scalar_it -= n * difference_type(Size);
1740  return *this;
1741  }
1742  Iterator operator-(difference_type n) const { return Iterator(*this) -= n; }
1743 
1744  difference_type operator-(const Iterator &rhs) const
1745  {
1746  constexpr difference_type n = Size;
1747  Vc_ASSERT((scalar_it - rhs.scalar_it) % n ==
1748  0); // if this fails the two iterators are not a multiple of the vector
1749  // width apart. The distance would be fractional and that doesn't
1750  // make too much sense for iteration. Therefore, it is a
1751  // precondition for the distance of the two iterators to be a
1752  // multiple of Size.
1753  return (scalar_it - rhs.scalar_it) / n;
1754  }
1755 
1760  bool operator<(const Iterator &rhs) const
1761  {
1762  return rhs.scalar_it - scalar_it >= difference_type(Size);
1763  }
1764 
1765  bool operator>(const Iterator &rhs) const
1766  {
1767  return scalar_it - rhs.scalar_it >= difference_type(Size);
1768  }
1769 
1770  bool operator<=(const Iterator &rhs) const
1771  {
1772  return rhs.scalar_it - scalar_it >= difference_type(Size) - 1;
1773  }
1774 
1775  bool operator>=(const Iterator &rhs) const
1776  {
1777  return scalar_it - rhs.scalar_it >= difference_type(Size) - 1;
1778  }
1779 
1780  reference operator[](difference_type i) { return *(*this + i); }
1781  const_reference operator[](difference_type i) const { return *(*this + i); }
1782 };
1783 
1784 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1786  typename Iterator<T, N, M, V, Size, std::random_access_iterator_tag>::difference_type
1787  n,
1789 {
1790  return i + n;
1791 }
1792 
1793 } // namespace IteratorDetails }}}
1794 
1803 template <typename T, size_t N, typename MT>
1804 struct ReplaceTypes<T, N, MT, Category::ForwardIterator>
1805 {
1806  using type = IteratorDetails::Iterator<T, N>;
1807 };
1808 template <typename T, size_t N, typename MT>
1809 struct ReplaceTypes<T, N, MT, Category::BidirectionalIterator>
1810 {
1811  using type = IteratorDetails::Iterator<T, N>;
1812 };
1813 template <typename T, size_t N, typename MT>
1814 struct ReplaceTypes<T, N, MT, Category::RandomAccessIterator>
1815 {
1816  using type = IteratorDetails::Iterator<T, N>;
1817 };
1818 
1822 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1823  std::size_t Offset>
1824 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size_<S>::value && M::Size == N), void>
1825  conditional_assign(Adapter<S, T, N> &, const M &, const U &)
1826 {
1827 }
1828 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1829  std::size_t Offset = 0>
1830 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size_<S>::value && M::Size == N), void>
1831  conditional_assign(Adapter<S, T, N> &lhs, const M &mask, const U &rhs)
1832 {
1833  using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1834  using M2 = typename V::mask_type;
1835  conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask), get_dispatcher<Offset>(rhs));
1836  conditional_assign<Op, S, T, N, M, U, Offset + 1>(lhs, mask, rhs);
1837 }
1838 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1839  std::size_t Offset>
1840 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size_<S>::value && M::Size == N), void>
1841  conditional_assign(Adapter<S, T, N> &, const M &)
1842 {
1843 }
1844 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1845  std::size_t Offset = 0>
1846 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size_<S>::value && M::Size == N), void>
1847  conditional_assign(Adapter<S, T, N> &lhs, const M &mask)
1848 {
1849  using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1850  using M2 = typename V::mask_type;
1851  conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask));
1852  conditional_assign<Op, S, T, N, M, Offset + 1>(lhs, mask);
1853 }
1854 
1856 } // namespace SimdizeDetail
1857 
1858 // user API {{{
1877 template <typename T, size_t N = 0, typename MT = void>
1878 using simdize = SimdizeDetail::simdize<T, N, MT>;
1879 
1899 #define Vc_SIMDIZE_INTERFACE(MEMBERS_) \
1900  template <std::size_t N_> \
1901  inline auto vc_get_()->decltype(std::get<N_>(std::tie MEMBERS_)) \
1902  { \
1903  return std::get<N_>(std::tie MEMBERS_); \
1904  } \
1905  template <std::size_t N_> \
1906  inline auto vc_get_() const->decltype(std::get<N_>(std::tie MEMBERS_)) \
1907  { \
1908  return std::get<N_>(std::tie MEMBERS_); \
1909  } \
1910  enum : std::size_t { \
1911  tuple_size = std::tuple_size<decltype(std::make_tuple MEMBERS_)>::value \
1912  }
1913 // }}}
1914 } // namespace Vc
1915 
1916 namespace std // {{{
1917 {
1918 using Vc::SimdizeDetail::swap;
1919 } // namespace std }}}
1920 
1921 #endif // VC_COMMON_SIMDIZE_H_
1922 
1923 // 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:1760
result_vector_type< L, R > operator-(L &&lhs, R &&rhs)
Applies - component-wise and concurrently.
Definition: simdarray.h:1662
Definition: vector.h:249
result_vector_type< L, R > operator*(L &&lhs, R &&rhs)
Applies * component-wise and concurrently.
Definition: simdarray.h:1662
SimdizeDetail::simdize< T, N, MT > simdize
Definition: simdize.h:1878
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:1216
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:143
result_vector_type< L, R > operator+(L &&lhs, R &&rhs)
Applies + component-wise and concurrently.
Definition: simdarray.h:1662
Iterator & operator--()
Advances the iterator by one vector width, or respectively N scalar steps.
Definition: simdize.h:1693
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:1064
This is the iterator type created when applying simdize to a random access iterator type...
Definition: simdize.h:1712
Vector Classes Namespace.
Definition: dox.h:584
This is the iterator type created when applying simdize to a bidirectional iterator type...
Definition: simdize.h:1674
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:1236
constexpr UnalignedTag Unaligned
Use this object for a flags parameter to request unaligned loads and stores.