Vc  1.3.3
SIMD Vector Classes for C++
simdize.h
1 /* This file is part of the Vc library. {{{
2 Copyright © 2014-2015 Matthias Kretz <kretz@kde.org>
3 
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are met:
6  * Redistributions of source code must retain the above copyright
7  notice, this list of conditions and the following disclaimer.
8  * Redistributions in binary form must reproduce the above copyright
9  notice, this list of conditions and the following disclaimer in the
10  documentation and/or other materials provided with the distribution.
11  * Neither the names of contributing organizations nor the
12  names of its contributors may be used to endorse or promote products
13  derived from this software without specific prior written permission.
14 
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
19 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 }}}*/
27 
28 #ifndef VC_COMMON_SIMDIZE_H_
29 #define VC_COMMON_SIMDIZE_H_
30 
31 #include <tuple>
32 #include <array>
33 
34 #include "macros.h"
35 
89 namespace Vc_VERSIONED_NAMESPACE
90 {
97 namespace SimdizeDetail
98 {
103 using std::is_same;
104 using std::is_base_of;
105 using std::false_type;
106 using std::true_type;
107 using std::iterator_traits;
108 using std::conditional;
109 using std::size_t;
110 template <bool B, typename T, typename F>
111 using conditional_t = typename conditional<B, T, F>::type;
112 
117 template <typename... Ts> struct Typelist;
118 
122 enum class Category {
124  None,
126  ArithmeticVectorizable,
128  InputIterator,
130  OutputIterator,
132  ForwardIterator,
134  BidirectionalIterator,
136  RandomAccessIterator,
138  ClassTemplate
139 };
140 
145 template <typename T, typename ItCat = typename T::iterator_category>
146 constexpr Category iteratorCategories(int, ItCat * = nullptr)
147 {
148  return is_base_of<std::random_access_iterator_tag, ItCat>::value
149  ? Category::RandomAccessIterator
150  : is_base_of<std::bidirectional_iterator_tag, ItCat>::value
151  ? Category::BidirectionalIterator
152  : is_base_of<std::forward_iterator_tag, ItCat>::value
153  ? Category::ForwardIterator
154  : is_base_of<std::output_iterator_tag, ItCat>::value
155  ? Category::OutputIterator
156  : is_base_of<std::input_iterator_tag, ItCat>::value
157  ? Category::InputIterator
158  : Category::None;
159 }
163 template <typename T>
164 constexpr enable_if<std::is_pointer<T>::value, Category> iteratorCategories(float)
165 {
166  return Category::RandomAccessIterator;
167 }
171 template <typename T> constexpr Category iteratorCategories(...)
172 {
173  return Category::None;
174 }
175 
179 template <typename T> struct is_class_template : public false_type
180 {
181 };
182 template <template <typename...> class C, typename... Ts>
183 struct is_class_template<C<Ts...>> : public true_type
184 {
185 };
186 
190 template <typename T> constexpr Category typeCategory()
191 {
192  return (is_same<T, bool>::value || is_same<T, short>::value ||
193  is_same<T, unsigned short>::value || is_same<T, int>::value ||
194  is_same<T, unsigned int>::value || is_same<T, float>::value ||
195  is_same<T, double>::value)
196  ? Category::ArithmeticVectorizable
197  : iteratorCategories<T>(int()) != Category::None
198  ? iteratorCategories<T>(int())
199  : is_class_template<T>::value ? Category::ClassTemplate
200  : Category::None;
201 }
202 
208 template <typename T, size_t TupleSize = std::tuple_size<T>::value>
209 constexpr size_t determine_tuple_size()
210 {
211  return TupleSize;
212 }
213 template <typename T, size_t TupleSize = T::tuple_size>
214 constexpr size_t determine_tuple_size(size_t = T::tuple_size)
215 {
216  return TupleSize;
217 }
218 
219 // workaround for MSVC limitation: constexpr functions in template arguments
220 // confuse the compiler
221 template <typename T> struct determine_tuple_size_
222 : public std::integral_constant<size_t, determine_tuple_size<T>()>
223 {};
224 
225 namespace
226 {
227 template <typename T> struct The_simdization_for_the_requested_type_is_not_implemented;
228 } // unnamed namespace
229 
242 template <typename T, size_t N, typename MT, Category = typeCategory<T>()>
243 struct ReplaceTypes : public The_simdization_for_the_requested_type_is_not_implemented<T>
244 {
245 };
246 
251 template <typename T, size_t N, typename MT> struct ReplaceTypes<T, N, MT, Category::None>
252 {
253  typedef T type;
254 };
255 
260 template <typename T, size_t N = 0, typename MT = void>
261 using simdize = typename SimdizeDetail::ReplaceTypes<T, N, MT>::type;
262 
267 template <typename T, size_t N, typename MT>
268 struct ReplaceTypes<T, N, MT, Category::ArithmeticVectorizable>
269  : public conditional<(N == 0 || Vector<T>::Size == N), Vector<T>, SimdArray<T, N>>
270 {
271 };
272 
277 template <size_t N, typename MT>
278 struct ReplaceTypes<bool, N, MT, Category::ArithmeticVectorizable>
279  : public conditional<(N == 0 || Mask<MT>::Size == N), Mask<MT>,
280  SimdMaskArray<MT, N>>
281 {
282 };
286 template <size_t N>
287 struct ReplaceTypes<bool, N, void, Category::ArithmeticVectorizable>
288  : public ReplaceTypes<bool, N, float, Category::ArithmeticVectorizable>
289 {
290 };
291 
298 template <size_t N, typename MT, typename Replaced, typename... Remaining>
299 struct SubstituteOneByOne;
300 
305 template <size_t N, typename MT, typename... Replaced, typename T,
306  typename... Remaining>
307 struct SubstituteOneByOne<N, MT, Typelist<Replaced...>, T, Remaining...>
308 {
309 private:
314  template <typename U, size_t M = U::Size>
315  static std::integral_constant<size_t, M> size_or_0(int);
316  template <typename U> static std::integral_constant<size_t, 0> size_or_0(...);
317 
319  using V = simdize<T, N, MT>;
320 
325  static constexpr auto NewN = N != 0 ? N : decltype(size_or_0<V>(int()))::value;
326 
332  typedef conditional_t<(N != NewN && is_same<MT, void>::value),
333  conditional_t<is_same<T, bool>::value, float, T>, MT> NewMT;
334 
335 public:
339  using type = typename SubstituteOneByOne<NewN, NewMT, Typelist<Replaced..., V>,
340  Remaining...>::type;
341 };
342 
345 template <size_t Size, typename... Replaced> struct SubstitutedBase;
347 template <typename Replaced> struct SubstitutedBase<1, Replaced> {
348  template <typename ValueT, template <typename, ValueT...> class C, ValueT... Values>
349  using SubstitutedWithValues = C<Replaced, Values...>;
350 };
352 template <typename R0, typename R1> struct SubstitutedBase<2, R0, R1>
353 {
354  template <typename ValueT, template <typename, typename, ValueT...> class C,
355  ValueT... Values>
356  using SubstitutedWithValues = C<R0, R1, Values...>;
357 };
359 template <typename R0, typename R1, typename R2> struct SubstitutedBase<3, R0, R1, R2>
360 {
361  template <typename ValueT, template <typename, typename, typename, ValueT...> class C,
362  ValueT... Values>
363  using SubstitutedWithValues = C<R0, R1, R2, Values...>;
364 };
365 #if defined Vc_ICC || defined Vc_MSVC
366 #define Vc_VALUE_PACK_EXPANSION_IS_BROKEN 1
367 #endif
368 template <typename... Replaced> struct SubstitutedBase<4, Replaced...> {
370 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
371  template <typename ValueT,
372  template <typename, typename, typename, typename, ValueT...> class C,
373  ValueT... Values>
374  using SubstitutedWithValues = C<Replaced..., Values...>;
375 #endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
376 };
378 template <typename... Replaced> struct SubstitutedBase<5, Replaced...> {
379 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
380  template <typename ValueT, template <typename, typename, typename, typename, typename,
381  ValueT...> class C,
382  ValueT... Values>
383  using SubstitutedWithValues = C<Replaced..., Values...>;
384 #endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
385 };
387 template <typename... Replaced> struct SubstitutedBase<6, Replaced...> {
388 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
389  template <typename ValueT, template <typename, typename, typename, typename, typename,
390  typename, ValueT...> class C,
391  ValueT... Values>
392  using SubstitutedWithValues = C<Replaced..., Values...>;
393 #endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
394 };
396 template <typename... Replaced> struct SubstitutedBase<7, Replaced...> {
397 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
398  template <typename ValueT, template <typename, typename, typename, typename, typename,
399  typename, typename, ValueT...> class C,
400  ValueT... Values>
401  using SubstitutedWithValues = C<Replaced..., Values...>;
402 #endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
403 };
405 template <typename... Replaced> struct SubstitutedBase<8, Replaced...> {
406 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
407  template <typename ValueT, template <typename, typename, typename, typename, typename,
408  typename, typename, typename, ValueT...> class C,
409  ValueT... Values>
410  using SubstitutedWithValues = C<Replaced..., Values...>;
411 #endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
412 };
413 
419 template <size_t N_, typename MT, typename Replaced0, typename... Replaced>
420 struct SubstituteOneByOne<N_, MT, Typelist<Replaced0, Replaced...>>
421 {
425  struct type
426  : public SubstitutedBase<sizeof...(Replaced) + 1, Replaced0, Replaced...> {
427  static constexpr auto N = N_;
432  template <template <typename...> class C>
433  using Substituted = C<Replaced0, Replaced...>;
434  };
435 };
436 
453 template <typename Scalar, typename Base, size_t N> class Adapter;
454 
459 template <template <typename...> class C, typename... Ts, size_t N, typename MT>
460 struct ReplaceTypes<C<Ts...>, N, MT, Category::ClassTemplate>
461 {
463  using SubstitutionResult =
464  typename SubstituteOneByOne<N, MT, Typelist<>, Ts...>::type;
470  using Vectorized = typename SubstitutionResult::template Substituted<C>;
476  using type = conditional_t<is_same<C<Ts...>, Vectorized>::value, C<Ts...>,
477  Adapter<C<Ts...>, Vectorized, SubstitutionResult::N>>;
478 };
479 
485 #ifdef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
486 // ICC barfs on packs of values
487 #define Vc_DEFINE_NONTYPE_REPLACETYPES_(ValueType_) \
488  template <template <typename, ValueType_...> class C, typename T, ValueType_ Value0, \
489  ValueType_... Values> \
490  struct is_class_template<C<T, Value0, Values...>> : public true_type { \
491  }; \
492  template <template <typename, typename, ValueType_...> class C, typename T0, \
493  typename T1, ValueType_ Value0, ValueType_... Values> \
494  struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type { \
495  }; \
496  template <template <typename, typename, typename, ValueType_...> class C, \
497  typename T0, typename T1, typename T2, ValueType_ Value0, \
498  ValueType_... Values> \
499  struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type { \
500  }; \
501  template <template <typename, typename, typename, typename, ValueType_...> class C, \
502  typename T0, typename T1, typename T2, typename T3, ValueType_ Value0, \
503  ValueType_... Values> \
504  struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type { \
505  }; \
506  template <template <typename, typename, typename, typename, typename, ValueType_...> \
507  class C, \
508  typename T0, typename T1, typename T2, typename T3, typename T4, \
509  ValueType_ Value0, ValueType_... Values> \
510  struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
511  : public true_type { \
512  }; \
513  template <template <typename, typename, typename, typename, typename, typename, \
514  ValueType_...> class C, \
515  typename T0, typename T1, typename T2, typename T3, typename T4, \
516  typename T5, ValueType_ Value0, ValueType_... Values> \
517  struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
518  : public true_type { \
519  }; \
520  template <template <typename, typename, typename, typename, typename, typename, \
521  typename, ValueType_...> class C, \
522  typename T0, typename T1, typename T2, typename T3, typename T4, \
523  typename T5, typename T6, ValueType_ Value0, ValueType_... Values> \
524  struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
525  : public true_type { \
526  }; \
527  template <template <typename, ValueType_> class C, typename T0, ValueType_ Value0, \
528  size_t N, typename MT> \
529  struct ReplaceTypes<C<T0, Value0>, N, MT, Category::ClassTemplate> { \
530  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
531  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
532  Substituted; \
533  static constexpr auto NN = tmp::N; \
534  typedef conditional_t<is_same<C<T0, Value0>, Substituted>::value, C<T0, Value0>, \
535  Adapter<C<T0, Value0>, Substituted, NN>> type; \
536  }; \
537  template <template <typename, typename, ValueType_> class C, typename T0, \
538  typename T1, ValueType_ Value0, size_t N, typename MT> \
539  struct ReplaceTypes<C<T0, T1, Value0>, N, MT, Category::ClassTemplate> { \
540  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
541  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
542  Substituted; \
543  static constexpr auto NN = tmp::N; \
544  typedef conditional_t<is_same<C<T0, T1, Value0>, Substituted>::value, \
545  C<T0, T1, Value0>, \
546  Adapter<C<T0, T1, Value0>, Substituted, NN>> type; \
547  }; \
548  template <template <typename, typename, typename, ValueType_> class C, typename T0, \
549  typename T1, typename T2, ValueType_ Value0, size_t N, typename MT> \
550  struct ReplaceTypes<C<T0, T1, T2, Value0>, N, MT, Category::ClassTemplate> { \
551  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
552  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
553  Substituted; \
554  static constexpr auto NN = tmp::N; \
555  typedef conditional_t<is_same<C<T0, T1, T2, Value0>, Substituted>::value, \
556  C<T0, T1, T2, Value0>, \
557  Adapter<C<T0, T1, T2, Value0>, Substituted, NN>> type; \
558  }
559 #else
560 #define Vc_DEFINE_NONTYPE_REPLACETYPES_(ValueType_) \
561  template <template <typename, ValueType_...> class C, typename T, ValueType_ Value0, \
562  ValueType_... Values> \
563  struct is_class_template<C<T, Value0, Values...>> : public true_type { \
564  }; \
565  template <template <typename, typename, ValueType_...> class C, typename T0, \
566  typename T1, ValueType_ Value0, ValueType_... Values> \
567  struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type { \
568  }; \
569  template <template <typename, typename, typename, ValueType_...> class C, \
570  typename T0, typename T1, typename T2, ValueType_ Value0, \
571  ValueType_... Values> \
572  struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type { \
573  }; \
574  template <template <typename, typename, typename, typename, ValueType_...> class C, \
575  typename T0, typename T1, typename T2, typename T3, ValueType_ Value0, \
576  ValueType_... Values> \
577  struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type { \
578  }; \
579  template <template <typename, typename, typename, typename, typename, ValueType_...> \
580  class C, \
581  typename T0, typename T1, typename T2, typename T3, typename T4, \
582  ValueType_ Value0, ValueType_... Values> \
583  struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
584  : public true_type { \
585  }; \
586  template <template <typename, typename, typename, typename, typename, typename, \
587  ValueType_...> class C, \
588  typename T0, typename T1, typename T2, typename T3, typename T4, \
589  typename T5, ValueType_ Value0, ValueType_... Values> \
590  struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
591  : public true_type { \
592  }; \
593  template <template <typename, typename, typename, typename, typename, typename, \
594  typename, ValueType_...> class C, \
595  typename T0, typename T1, typename T2, typename T3, typename T4, \
596  typename T5, typename T6, ValueType_ Value0, ValueType_... Values> \
597  struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
598  : public true_type { \
599  }; \
600  template <template <typename, ValueType_...> class C, typename T0, \
601  ValueType_ Value0, ValueType_... Values, size_t N, typename MT> \
602  struct ReplaceTypes<C<T0, Value0, Values...>, N, MT, Category::ClassTemplate> { \
603  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
604  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
605  Values...> Substituted; \
606  static constexpr auto NN = tmp::N; \
607  typedef conditional_t<is_same<C<T0, Value0, Values...>, Substituted>::value, \
608  C<T0, Value0, Values...>, \
609  Adapter<C<T0, Value0, Values...>, Substituted, NN>> type; \
610  }; \
611  template <template <typename, typename, ValueType_...> class C, typename T0, \
612  typename T1, ValueType_ Value0, ValueType_... Values, size_t N, \
613  typename MT> \
614  struct ReplaceTypes<C<T0, T1, Value0, Values...>, N, MT, Category::ClassTemplate> { \
615  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
616  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
617  Values...> Substituted; \
618  static constexpr auto NN = tmp::N; \
619  typedef conditional_t<is_same<C<T0, T1, Value0, Values...>, Substituted>::value, \
620  C<T0, T1, Value0, Values...>, \
621  Adapter<C<T0, T1, Value0, Values...>, Substituted, NN>> \
622  type; \
623  }; \
624  template <template <typename, typename, typename, ValueType_...> class C, \
625  typename T0, typename T1, typename T2, ValueType_ Value0, \
626  ValueType_... Values, size_t N, typename MT> \
627  struct ReplaceTypes<C<T0, T1, T2, Value0, Values...>, N, MT, \
628  Category::ClassTemplate> { \
629  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
630  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
631  Values...> Substituted; \
632  static constexpr auto NN = tmp::N; \
633  typedef conditional_t< \
634  is_same<C<T0, T1, T2, Value0, Values...>, Substituted>::value, \
635  C<T0, T1, T2, Value0, Values...>, \
636  Adapter<C<T0, T1, T2, Value0, Values...>, Substituted, NN>> type; \
637  }
638 #endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
639 Vc_DEFINE_NONTYPE_REPLACETYPES_(bool);
640 Vc_DEFINE_NONTYPE_REPLACETYPES_(wchar_t);
641 Vc_DEFINE_NONTYPE_REPLACETYPES_(char);
642 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed char);
643 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned char);
644 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed short);
645 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned short);
646 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed int);
647 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned int);
648 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed long);
649 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned long);
650 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed long long);
651 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned long long);
652 #undef Vc_DEFINE_NONTYPE_REPLACETYPES_
653 
654 namespace is_constructible_with_single_paren_impl
655 {
656 template <typename T> T create();
657 #if defined Vc_CLANG || defined Vc_APPLECLANG
658 template <typename Class, typename... Args, typename = decltype(Class(create<Args>()...))>
659 char test(int);
660 #else
661 template <typename Class, typename... Args>
662 typename std::conditional<
663 #ifndef Vc_ICC
664  0 !=
665 #endif
666  sizeof(Class(create<Args>()...)),
667  char, char>::type
668 test(int);
669 #endif
670 template <typename Class, typename... Args> double test(...);
671 } // namespace is_constructible_with_single_paren_impl
672 
673 template <typename Class, typename... Args>
674 struct is_constructible_with_single_paren
675  : public std::integral_constant<
676  bool,
677  1 == sizeof(is_constructible_with_single_paren_impl::test<Class, Args...>(1))> {
678 };
679 
680 namespace is_constructible_with_single_brace_impl
681 {
682 template <typename T> T create();
683 #ifdef Vc_ICC
684 template <typename Class, typename... Args> char test(int);
685 #elif defined Vc_CLANG || defined Vc_APPLECLANG
686 template <typename Class, typename... Args, typename = decltype(Class{create<Args>()...})>
687 char test(int);
688 #else
689 template <typename Class, typename... Args>
690 typename std::conditional<
691 #ifndef Vc_ICC
692  0 !=
693 #endif
694  sizeof(Class{create<Args>()...}),
695  char, char>::type
696 test(int);
697 #endif
698 template <typename Class, typename... Args> double test(...);
699 } // namespace is_constructible_with_single_brace_impl
700 
701 template <typename Class, typename... Args>
702 struct is_constructible_with_single_brace
703  : public std::integral_constant<
704  bool,
705  1 == sizeof(is_constructible_with_single_brace_impl::test<Class, Args...>(1))> {
706 };
707 
708 namespace is_constructible_with_double_brace_impl
709 {
710 template <typename T> T create();
711 #if defined Vc_CLANG || defined Vc_APPLECLANG
712 template <typename Class, typename... Args,
713  typename = decltype(Class{{create<Args>()...}})>
714 char test(int);
715 #else
716 template <typename Class, typename... Args>
717 typename std::conditional<
718 #ifndef Vc_ICC
719  0 !=
720 #endif
721  sizeof(Class{{create<Args>()...}}),
722  char, char>::type
723 test(int);
724 #endif
725 template <typename Class, typename... Args> double test(...);
726 } // namespace is_constructible_with_double_brace_impl
727 
728 template <typename Class, typename... Args>
729 struct is_constructible_with_double_brace
730  : public std::integral_constant<
731  bool,
732  1 == sizeof(is_constructible_with_double_brace_impl::test<Class, Args...>(1))> {
733 };
734 
735 template <size_t I, typename T,
736  typename R = decltype(std::declval<T &>().template vc_get_<I>())>
737 R get_dispatcher(T &x, void * = nullptr)
738 {
739  return x.template vc_get_<I>();
740 }
741 template <size_t I, typename T,
742  typename R = decltype(std::declval<const T &>().template vc_get_<I>())>
743 R get_dispatcher(const T &x, void * = nullptr)
744 {
745  return x.template vc_get_<I>();
746 }
747 template <size_t I, typename T, typename R = decltype(std::get<I>(std::declval<T &>()))>
748 R get_dispatcher(T &x, int = 0)
749 {
750  return std::get<I>(x);
751 }
752 template <size_t I, typename T,
753  typename R = decltype(std::get<I>(std::declval<const T &>()))>
754 R get_dispatcher(const T &x, int = 0)
755 {
756  return std::get<I>(x);
757 }
758 
759 
760 // see above
761 template <typename Scalar, typename Base, size_t N> class Adapter : public Base
762 {
763 private:
765  template <std::size_t... Indexes, typename T>
766  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_, T, std::true_type)
767  : Base{{get_dispatcher<Indexes>(x_)...}}
768  {
769  }
770 
772  template <std::size_t... Indexes>
773  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_, std::false_type,
774  std::false_type)
775  : Base{get_dispatcher<Indexes>(x_)...}
776  {
777  }
778 
780  template <std::size_t... Indexes>
781  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_, std::true_type,
782  std::false_type)
783  : Base(get_dispatcher<Indexes>(x_)...)
784  {
785  }
786 
787  template <std::size_t... Indexes>
788  Adapter(Vc::index_sequence<Indexes...> seq_, const Scalar &x_)
789  : Adapter(seq_, x_,
790  std::integral_constant<
791  bool, is_constructible_with_single_paren<
792  Base, decltype(get_dispatcher<Indexes>(
793  std::declval<const Scalar &>()))...>::value>(),
794  std::integral_constant<
795  bool, is_constructible_with_double_brace<
796  Base, decltype(get_dispatcher<Indexes>(
797  std::declval<const Scalar &>()))...>::value>())
798  {
799  }
800 
801 public:
803  static constexpr size_t size() { return N; }
804  static constexpr size_t Size = N;
805 
807  using base_type = Base;
810  using scalar_type = Scalar;
811 
814  Adapter() = default;
815 
817 #if defined Vc_CLANG && Vc_CLANG < 0x30700
818  Vc_INTRINSIC Adapter(const Adapter &x) : Base(x) {}
819 #else
820  Adapter(const Adapter &) = default;
821 #endif
822  Adapter(Adapter &&) = default;
825  Adapter &operator=(const Adapter &) = default;
827  Adapter &operator=(Adapter &&) = default;
828 
830  template <typename U, size_t TupleSize = determine_tuple_size_<Scalar>::value,
831  typename Seq = Vc::make_index_sequence<TupleSize>,
832  typename = enable_if<std::is_convertible<U, Scalar>::value>>
833  Adapter(U &&x_)
834  : Adapter(Seq(), static_cast<const Scalar &>(x_))
835  {
836  }
837 
839  template <typename A0, typename... Args,
840  typename = typename std::enable_if<
841  !Traits::is_index_sequence<A0>::value &&
842  (sizeof...(Args) > 0 || !std::is_convertible<A0, Scalar>::value)>::type>
843  Adapter(A0 &&arg0_, Args &&... arguments_)
844  : Base(std::forward<A0>(arg0_), std::forward<Args>(arguments_)...)
845  {
846  }
847 
849  template <typename T,
850  typename = decltype(Base(std::declval<const std::initializer_list<T> &>()))>
851  Adapter(const std::initializer_list<T> &l_)
852  : Base(l_)
853  {
854  }
855 
858  void *operator new(size_t size)
859  {
860  return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
861  }
862  void *operator new(size_t, void *p_) { return p_; }
863  void *operator new[](size_t size)
864  {
865  return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
866  }
867  void *operator new[](size_t , void *p_) { return p_; }
868  void operator delete(void *ptr_, size_t) { Vc::Common::free(ptr_); }
869  void operator delete(void *, void *) {}
870  void operator delete[](void *ptr_, size_t) { Vc::Common::free(ptr_); }
871  void operator delete[](void *, void *) {}
872 };
873 
878 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
879 inline void operator==(
880  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
881  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
882 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
883 inline void operator!=(
884  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
885  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
886 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
887 inline void operator<=(
888  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
889  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
890 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
891 inline void operator>=(
892  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
893  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
894 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
895 inline void operator<(
896  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
897  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
898 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
899 inline void operator>(
900  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
901  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
902 
904 } // namespace SimdizeDetail
905 } // namespace Vc
906 
907 namespace std
908 {
912 template <typename Scalar, typename Base, size_t N>
913 class tuple_size<Vc::SimdizeDetail::Adapter<Scalar, Base, N>> : public tuple_size<Base>
914 {
915 };
919 template <size_t I, typename Scalar, typename Base, size_t N>
920 class tuple_element<I, Vc::SimdizeDetail::Adapter<Scalar, Base, N>>
921  : public tuple_element<I, Base>
922 {
923 };
924 // std::get does not need additional work because Vc::Adapter derives from
925 // C<Ts...> and therefore if get<N>(C<Ts...>) works it works for Adapter as well.
926 
931 template <typename S, typename T, size_t N>
932 class allocator<Vc::SimdizeDetail::Adapter<S, T, N>>
933  : public Vc::Allocator<Vc::SimdizeDetail::Adapter<S, T, N>>
934 {
935 public:
936  template <typename U> struct rebind
937  {
938  typedef std::allocator<U> other;
939  };
940 };
941 } // namespace std
942 
943 namespace Vc_VERSIONED_NAMESPACE
944 {
945 namespace SimdizeDetail
946 {
955 template <typename T> static inline T decay_workaround(const T &x) { return x; }
956 
960 template <typename S, typename T, size_t N, size_t... Indexes>
961 inline void assign_impl(Adapter<S, T, N> &a, size_t i, const S &x,
962  Vc::index_sequence<Indexes...>)
963 {
964  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(x)))...> tmp(
965  decay_workaround(get_dispatcher<Indexes>(x))...);
966  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(tmp), 0)...};
967  if (&unused == &unused) {}
968 }
969 
974 template <typename S, typename T, size_t N>
975 inline void assign(Adapter<S, T, N> &a, size_t i, const S &x)
976 {
977  assign_impl(a, i, x, Vc::make_index_sequence<determine_tuple_size<T>()>());
978 }
982 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
983 Vc_INTRINSIC void assign(V &v, size_t i, typename V::EntryType x)
984 {
985  v[i] = x;
986 }
987 
991 template <typename S, typename T, size_t N, size_t... Indexes>
992 inline S extract_impl(const Adapter<S, T, N> &a, size_t i, Vc::index_sequence<Indexes...>)
993 {
994  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[i]))...> tmp(
995  decay_workaround(get_dispatcher<Indexes>(a)[i])...);
996  return S(get_dispatcher<Indexes>(tmp)...);
997 }
998 
1003 template <typename S, typename T, size_t N>
1004 inline S extract(const Adapter<S, T, N> &a, size_t i)
1005 {
1006  return extract_impl(a, i, Vc::make_index_sequence<determine_tuple_size<S>()>());
1007 }
1011 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
1012 Vc_INTRINSIC typename V::EntryType extract(const V &v, size_t i)
1013 {
1014  return v[i];
1015 }
1016 
1017 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1018 inline Adapter<S, T, N> shifted_impl(const Adapter<S, T, N> &a, int shift,
1019  Vc::index_sequence<Indexes...>)
1020 {
1021  Adapter<S, T, N> r;
1022  auto &&unused = {(get_dispatcher<Indexes>(r) = get_dispatcher<Indexes>(a).shifted(shift), 0)...};
1023  if (&unused == &unused) {}
1024  return r;
1025 }
1026 
1035 template <typename S, typename T, size_t N>
1036 inline Adapter<S, T, N> shifted(const Adapter<S, T, N> &a, int shift)
1037 {
1038  return shifted_impl(a, shift, Vc::make_index_sequence<determine_tuple_size<T>()>());
1039 }
1040 
1044 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1045 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, S &x,
1046  Vc::index_sequence<Indexes...>)
1047 {
1048  const auto &a_const = a;
1049  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a_const)[0]))...>
1050  tmp{decay_workaround(get_dispatcher<Indexes>(a_const)[i])...};
1051  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(x), 0)...};
1052  auto &&unused2 = {(get_dispatcher<Indexes>(x) = get_dispatcher<Indexes>(tmp), 0)...};
1053  if (&unused == &unused2) {}
1054 }
1055 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1056 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b,
1057  std::size_t j, Vc::index_sequence<Indexes...>)
1058 {
1059  const auto &a_const = a;
1060  const auto &b_const = b;
1061  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a_const)[0]))...>
1062  tmp{decay_workaround(get_dispatcher<Indexes>(a_const)[i])...};
1063  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(b_const)[j], 0)...};
1064  auto &&unused2 = {(get_dispatcher<Indexes>(b)[j] = get_dispatcher<Indexes>(tmp), 0)...};
1065  if (&unused == &unused2) {}
1066 }
1067 
1072 template <typename S, typename T, std::size_t N>
1073 inline void swap(Adapter<S, T, N> &a, std::size_t i, S &x)
1074 {
1075  swap_impl(a, i, x, Vc::make_index_sequence<determine_tuple_size<T>()>());
1076 }
1077 template <typename S, typename T, std::size_t N>
1078 inline void swap(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b, std::size_t j)
1079 {
1080  swap_impl(a, i, b, j, Vc::make_index_sequence<determine_tuple_size<T>()>());
1081 }
1082 
1083 template <typename A> class Scalar
1084 {
1085  using reference = typename std::add_lvalue_reference<A>::type;
1086  using S = typename A::scalar_type;
1087  using IndexSeq = Vc::make_index_sequence<determine_tuple_size<S>()>;
1088 
1089 public:
1090  Scalar(reference aa, size_t ii) : a(aa), i(ii) {}
1091 
1092  // delete copy and move to keep the type a pure proxy temporary object.
1093  Scalar(const Scalar &) = delete;
1094  Scalar(Scalar &&) = delete;
1095  Scalar &operator=(const Scalar &) = delete;
1096  Scalar &operator=(Scalar &&) = delete;
1097 
1098  void operator=(const S &x) { assign_impl(a, i, x, IndexSeq()); }
1099  operator S() const { return extract_impl(a, i, IndexSeq()); }
1100 
1101  template <typename AA>
1102  friend inline void swap(Scalar<AA> &&a, typename AA::scalar_type &b);
1103  template <typename AA>
1104  friend inline void swap(typename AA::scalar_type &b, Scalar<AA> &&a);
1105  template <typename AA> friend inline void swap(Scalar<AA> &&a, Scalar<AA> &&b);
1106 
1107 private:
1108  reference a;
1109  size_t i;
1110 };
1111 
1114 template <typename A> inline void swap(Scalar<A> &&a, typename A::scalar_type &b)
1115 {
1116  swap_impl(a.a, a.i, b, typename Scalar<A>::IndexSeq());
1117 }
1120 template <typename A> inline void swap(typename A::scalar_type &b, Scalar<A> &&a)
1121 {
1122  swap_impl(a.a, a.i, b, typename Scalar<A>::IndexSeq());
1123 }
1124 
1125 template <typename A> inline void swap(Scalar<A> &&a, Scalar<A> &&b)
1126 {
1127  swap_impl(a.a, a.i, b.a, b.i, typename Scalar<A>::IndexSeq());
1128 }
1129 
1130 template <typename A> class Interface
1131 {
1132  using reference = typename std::add_lvalue_reference<A>::type;
1133  using IndexSeq =
1134  Vc::make_index_sequence<determine_tuple_size<typename A::scalar_type>()>;
1135 
1136 public:
1137  Interface(reference aa) : a(aa) {}
1138 
1139  Scalar<A> operator[](size_t i)
1140  {
1141  return {a, i};
1142  }
1143  typename A::scalar_type operator[](size_t i) const
1144  {
1145  return extract_impl(a, i, IndexSeq());
1146  }
1147 
1148  A shifted(int amount) const
1149  {
1150  return shifted_impl(a, amount, IndexSeq());
1151  }
1152 
1153 private:
1154  reference a;
1155 };
1156 
1157 template <typename S, typename T, size_t N>
1158 Interface<Adapter<S, T, N>> decorate(Adapter<S, T, N> &a)
1159 {
1160  return {a};
1161 }
1162 template <typename S, typename T, size_t N>
1163 const Interface<const Adapter<S, T, N>> decorate(const Adapter<S, T, N> &a)
1164 {
1165  return {a};
1166 }
1167 
1168 namespace IteratorDetails
1169 {
1170 enum class Mutable { Yes, No };
1171 
1172 template <typename It, typename V, size_t I, size_t End>
1173 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I == End), It>)
1174 {
1175  return {};
1176 }
1177 template <typename It, typename V, size_t I, size_t End>
1178 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I < End), It> it)
1179 {
1180  V r = fromIteratorImpl<It, V, I + 1, End>(it);
1181  Traits::decay<decltype(get_dispatcher<I>(r))> tmp;
1182  for (size_t j = 0; j < V::size(); ++j, ++it) {
1183  tmp[j] = get_dispatcher<I>(*it);
1184  }
1185  get_dispatcher<I>(r) = tmp;
1186  return r;
1187 }
1188 template <typename It, typename V>
1189 Vc_INTRINSIC V fromIterator(enable_if<!Traits::is_simd_vector<V>::value, const It &> it)
1190 {
1191  return fromIteratorImpl<It, V, 0, determine_tuple_size<V>()>(it);
1192 }
1193 template <typename It, typename V>
1194 Vc_INTRINSIC V fromIterator(enable_if<Traits::is_simd_vector<V>::value, It> it)
1195 {
1196  V r;
1197  for (size_t j = 0; j < V::size(); ++j, ++it) {
1198  r[j] = *it;
1199  }
1200  return r;
1201 }
1202 
1203 // Note: §13.5.6 says: “An expression x->m is interpreted as (x.operator->())->m for a
1204 // class object x of type T if T::operator->() exists and if the operator is selected as
1205 // the best match function by the overload resolution mechanism (13.3).”
1206 template <typename T, typename value_vector, Mutable> class Pointer;
1207 
1216 template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::Yes>
1217 {
1218  static constexpr auto Size = value_vector::size();
1219 
1220 public:
1222  value_vector *operator->() { return &data; }
1223 
1228  Pointer() = delete;
1229  Pointer(const Pointer &) = delete;
1230  Pointer &operator=(const Pointer &) = delete;
1231  Pointer &operator=(Pointer &&) = delete;
1232 
1234  Pointer(Pointer &&) = default;
1235 
1241  ~Pointer()
1242  {
1243  // store data back to where it came from
1244  for (size_t i = 0; i < Size; ++i, ++begin_iterator) {
1245  *begin_iterator = extract(data, i);
1246  }
1247  }
1248 
1250  Pointer(const T &it) : data(fromIterator<T, value_vector>(it)), begin_iterator(it) {}
1251 
1252 private:
1254  value_vector data;
1256  T begin_iterator;
1257 };
1263 template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::No>
1264 {
1265  static constexpr auto Size = value_vector::size();
1266 
1267 public:
1268  const value_vector *operator->() const { return &data; }
1269 
1270  Pointer() = delete;
1271  Pointer(const Pointer &) = delete;
1272  Pointer &operator=(const Pointer &) = delete;
1273  Pointer &operator=(Pointer &&) = delete;
1274 
1275  Pointer(Pointer &&) = default; // required for returning the Pointer
1276 
1277  Pointer(const T &it) : data(fromIterator<T, value_vector>(it)) {}
1278 
1279 private:
1280  value_vector data;
1281 };
1282 
1295 template <typename T, typename value_vector, Mutable M> class Reference;
1296 
1298 template <typename T, typename value_vector>
1299 class Reference<T, value_vector, Mutable::Yes> : public value_vector
1300 {
1301  static constexpr auto Size = value_vector::size();
1302 
1303  using reference = typename std::add_lvalue_reference<T>::type;
1304  reference scalar_it;
1305 
1306 public:
1309  Reference(reference first_it)
1310  : value_vector(fromIterator<T, value_vector>(first_it)), scalar_it(first_it)
1311  {
1312  }
1313 
1315  Reference(const Reference &) = delete;
1316  Reference(Reference &&) = default;
1317  Reference &operator=(const Reference &) = delete;
1318  Reference &operator=(Reference &&) = delete;
1319 
1325  void operator=(const value_vector &x)
1326  {
1327  static_cast<value_vector &>(*this) = x;
1328  auto it = scalar_it;
1329  for (size_t i = 0; i < Size; ++i, ++it) {
1330  *it = extract(x, i);
1331  }
1332  }
1333 };
1334 #define Vc_OP(op_) \
1335  template <typename T0, typename V0, typename T1, typename V1> \
1336  decltype(std::declval<const V0 &>() op_ std::declval<const V1 &>()) operator op_( \
1337  const Reference<T0, V0, Mutable::Yes> &x, \
1338  const Reference<T1, V1, Mutable::Yes> &y) \
1339  { \
1340  return static_cast<const V0 &>(x) op_ static_cast<const V1 &>(y); \
1341  }
1342 Vc_ALL_COMPARES(Vc_OP);
1343 Vc_ALL_ARITHMETICS(Vc_OP);
1344 Vc_ALL_BINARY(Vc_OP);
1345 Vc_ALL_LOGICAL(Vc_OP);
1346 Vc_ALL_SHIFTS(Vc_OP);
1347 #undef Vc_OP
1348 
1350 template <typename T, typename value_vector>
1351 class Reference<T, value_vector, Mutable::No> : public value_vector
1352 {
1353  static constexpr auto Size = value_vector::size();
1354 
1355 public:
1356  Reference(const T &it) : value_vector(fromIterator<T, value_vector>(it)) {}
1357 
1358  Reference(const Reference &) = delete;
1359  Reference(Reference &&) = default;
1360  Reference &operator=(const Reference &) = delete;
1361  Reference &operator=(Reference &&) = delete;
1362 
1364  void operator=(const value_vector &x) = delete;
1365 };
1366 
1367 template <typename T, size_t N,
1368  IteratorDetails::Mutable M =
1369  (Traits::is_output_iterator<T>::value ? Mutable::Yes : Mutable::No),
1370  typename V = simdize<typename std::iterator_traits<T>::value_type, N>,
1371  size_t Size = V::Size,
1372  typename = typename std::iterator_traits<T>::iterator_category>
1373 class Iterator;
1374 
1375 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size_>
1376 class Iterator<T, N, M, V, Size_, std::forward_iterator_tag>
1377  : public std::iterator<typename std::iterator_traits<T>::iterator_category, V,
1378  typename std::iterator_traits<T>::difference_type,
1379  IteratorDetails::Pointer<T, V, M>,
1380  IteratorDetails::Reference<T, V, M>>
1381 {
1382 public:
1383  using pointer = IteratorDetails::Pointer<T, V, M>;
1384  using reference = IteratorDetails::Reference<T, V, M>;
1385  using const_pointer = IteratorDetails::Pointer<T, V, IteratorDetails::Mutable::No>;
1386  using const_reference =
1387  IteratorDetails::Reference<T, V, IteratorDetails::Mutable::No>;
1388 
1390  static constexpr std::size_t size() { return Size_; }
1391  static constexpr std::size_t Size = Size_;
1392 
1393  Iterator() = default;
1394 
1401  Iterator(const T &x) : scalar_it(x) {}
1405  Iterator(T &&x) : scalar_it(std::move(x)) {}
1409  Iterator &operator=(const T &x)
1410  {
1411  scalar_it = x;
1412  return *this;
1413  }
1417  Iterator &operator=(T &&x)
1418  {
1419  scalar_it = std::move(x);
1420  return *this;
1421  }
1422 
1424  Iterator(const Iterator &) = default;
1426  Iterator(Iterator &&) = default;
1428  Iterator &operator=(const Iterator &) = default;
1430  Iterator &operator=(Iterator &&) = default;
1431 
1433  Iterator &operator++()
1434  {
1435  std::advance(scalar_it, Size);
1436  return *this;
1437  }
1439  Iterator operator++(int)
1440  {
1441  Iterator copy(*this);
1442  operator++();
1443  return copy;
1444  }
1445 
1454  bool operator==(const Iterator &rhs) const
1455  {
1456 #ifndef NDEBUG
1457  if (scalar_it == rhs.scalar_it) {
1458  return true;
1459  } else {
1460  T it(scalar_it);
1461  for (size_t i = 1; i < Size; ++i) {
1462  Vc_ASSERT((++it != rhs.scalar_it));
1463  }
1464  return false;
1465  }
1466 #else
1467  return scalar_it == rhs.scalar_it;
1468 #endif
1469  }
1478  bool operator!=(const Iterator &rhs) const
1479  {
1480  return !operator==(rhs);
1481  }
1482 
1483  pointer operator->() { return scalar_it; }
1484 
1491  reference operator*() { return scalar_it; }
1492 
1493  const_pointer operator->() const { return scalar_it; }
1494 
1502  const_reference operator*() const { return scalar_it; }
1503 
1517  operator const T &() const { return scalar_it; }
1518 
1519 protected:
1520  T scalar_it;
1521 };
1522 
1527 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1528 class Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1529  : public Iterator<T, N, M, V, Size, std::forward_iterator_tag>
1530 {
1531  using Base = Iterator<T, N, M, V, Size, std::forward_iterator_tag>;
1532 
1533 protected:
1534  using Base::scalar_it;
1535 
1536 public:
1537  using pointer = typename Base::pointer;
1538  using reference = typename Base::reference;
1539  using const_pointer = typename Base::const_pointer;
1540  using const_reference = typename Base::const_reference;
1541 
1542  using Iterator<T, N, M, V, Size,
1543  std::forward_iterator_tag>::Iterator; // in short: "using
1544  // Base::Iterator", but that
1545  // confuses ICC
1547  Iterator &operator--()
1548  {
1549  std::advance(scalar_it, -Size);
1550  return *this;
1551  }
1553  Iterator operator--(int)
1554  {
1555  Iterator copy(*this);
1556  operator--();
1557  return copy;
1558  }
1559 };
1560 
1565 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1566 class Iterator<T, N, M, V, Size, std::random_access_iterator_tag>
1567  : public Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1568 {
1570 
1571 protected:
1572  using Base::scalar_it;
1573 
1574 public:
1575  using pointer = typename Base::pointer;
1576  using reference = typename Base::reference;
1577  using const_pointer = typename Base::const_pointer;
1578  using const_reference = typename Base::const_reference;
1579  using difference_type = typename std::iterator_traits<T>::difference_type;
1580 
1582  Iterator; // in short: "using Base::Iterator", but that confuses ICC
1583 
1584  Iterator &operator+=(difference_type n)
1585  {
1586  scalar_it += n * difference_type(Size);
1587  return *this;
1588  }
1589  Iterator operator+(difference_type n) const { return Iterator(*this) += n; }
1590 
1591  Iterator &operator-=(difference_type n)
1592  {
1593  scalar_it -= n * difference_type(Size);
1594  return *this;
1595  }
1596  Iterator operator-(difference_type n) const { return Iterator(*this) -= n; }
1597 
1598  difference_type operator-(const Iterator &rhs) const
1599  {
1600  constexpr difference_type n = Size;
1601  Vc_ASSERT((scalar_it - rhs.scalar_it) % n ==
1602  0); // if this fails the two iterators are not a multiple of the vector
1603  // width apart. The distance would be fractional and that doesn't
1604  // make too much sense for iteration. Therefore, it is a
1605  // precondition for the distance of the two iterators to be a
1606  // multiple of Size.
1607  return (scalar_it - rhs.scalar_it) / n;
1608  }
1609 
1614  bool operator<(const Iterator &rhs) const
1615  {
1616  return rhs.scalar_it - scalar_it >= difference_type(Size);
1617  }
1618 
1619  bool operator>(const Iterator &rhs) const
1620  {
1621  return scalar_it - rhs.scalar_it >= difference_type(Size);
1622  }
1623 
1624  bool operator<=(const Iterator &rhs) const
1625  {
1626  return rhs.scalar_it - scalar_it >= difference_type(Size) - 1;
1627  }
1628 
1629  bool operator>=(const Iterator &rhs) const
1630  {
1631  return scalar_it - rhs.scalar_it >= difference_type(Size) - 1;
1632  }
1633 
1634  reference operator[](difference_type i) { return *(*this + i); }
1635  const_reference operator[](difference_type i) const { return *(*this + i); }
1636 };
1637 
1638 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1639 Iterator<T, N, M, V, Size, std::random_access_iterator_tag> operator+(
1640  typename Iterator<T, N, M, V, Size, std::random_access_iterator_tag>::difference_type
1641  n,
1642  const Iterator<T, N, M, V, Size, std::random_access_iterator_tag> &i)
1643 {
1644  return i + n;
1645 }
1646 
1647 } // namespace IteratorDetails
1648 
1657 template <typename T, size_t N, typename MT>
1658 struct ReplaceTypes<T, N, MT, Category::ForwardIterator>
1659 {
1660  using type = IteratorDetails::Iterator<T, N>;
1661 };
1662 template <typename T, size_t N, typename MT>
1663 struct ReplaceTypes<T, N, MT, Category::BidirectionalIterator>
1664 {
1665  using type = IteratorDetails::Iterator<T, N>;
1666 };
1667 template <typename T, size_t N, typename MT>
1668 struct ReplaceTypes<T, N, MT, Category::RandomAccessIterator>
1669 {
1670  using type = IteratorDetails::Iterator<T, N>;
1671 };
1672 
1676 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1677  std::size_t Offset>
1678 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size_<S>::value && M::Size == N), void>
1679  conditional_assign(Adapter<S, T, N> &, const M &, const U &)
1680 {
1681 }
1682 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1683  std::size_t Offset = 0>
1684 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size_<S>::value && M::Size == N), void>
1685  conditional_assign(Adapter<S, T, N> &lhs, const M &mask, const U &rhs)
1686 {
1687  using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1688  using M2 = typename V::mask_type;
1689  conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask), get_dispatcher<Offset>(rhs));
1690  conditional_assign<Op, S, T, N, M, U, Offset + 1>(lhs, mask, rhs);
1691 }
1692 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1693  std::size_t Offset>
1694 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size_<S>::value && M::Size == N), void>
1695  conditional_assign(Adapter<S, T, N> &, const M &)
1696 {
1697 }
1698 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1699  std::size_t Offset = 0>
1700 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size_<S>::value && M::Size == N), void>
1701  conditional_assign(Adapter<S, T, N> &lhs, const M &mask)
1702 {
1703  using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1704  using M2 = typename V::mask_type;
1705  conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask));
1706  conditional_assign<Op, S, T, N, M, Offset + 1>(lhs, mask);
1707 }
1708 
1710 } // namespace SimdizeDetail
1711 
1730 template <typename T, size_t N = 0, typename MT = void>
1731 using simdize = SimdizeDetail::simdize<T, N, MT>;
1732 
1752 #define Vc_SIMDIZE_INTERFACE(MEMBERS_) \
1753  template <std::size_t N_> \
1754  inline auto vc_get_()->decltype(std::get<N_>(std::tie MEMBERS_)) \
1755  { \
1756  return std::get<N_>(std::tie MEMBERS_); \
1757  } \
1758  template <std::size_t N_> \
1759  inline auto vc_get_() const->decltype(std::get<N_>(std::tie MEMBERS_)) \
1760  { \
1761  return std::get<N_>(std::tie MEMBERS_); \
1762  } \
1763  enum : std::size_t { \
1764  tuple_size = std::tuple_size<decltype(std::make_tuple MEMBERS_)>::value \
1765  }
1766 
1767 } // namespace Vc
1768 
1769 namespace std
1770 {
1771 using Vc::SimdizeDetail::swap;
1772 } // namespace std
1773 
1774 #endif // VC_COMMON_SIMDIZE_H_
1775 
1776 // 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:1614
result_vector_type< L, R > operator-(L &&lhs, R &&rhs)
Applies - component-wise and concurrently.
Definition: simdarray.h:1611
Definition: vector.h:257
result_vector_type< L, R > operator*(L &&lhs, R &&rhs)
Applies * component-wise and concurrently.
Definition: simdarray.h:1611
SimdizeDetail::simdize< T, N, MT > simdize
Definition: simdize.h:1731
S extract(const 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:1004
An allocator that uses global new and supports over-aligned types, as per [C++11 20.6.9].
Definition: Allocator:128
result_vector_type< L, R > operator+(L &&lhs, R &&rhs)
Applies + component-wise and concurrently.
Definition: simdarray.h:1611
void assign(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:975
Iterator & operator--()
Advances the iterator by one vector width, or respectively N scalar steps.
Definition: simdize.h:1547
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:1036
Vector Classes Namespace.
Definition: cpuid.h:32
This is the iterator type created when applying simdize to a bidirectional iterator type...
Definition: simdize.h:1528