Vc  1.3.3-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 "macros.h"
35 
121 namespace Vc_VERSIONED_NAMESPACE
122 {
129 namespace SimdizeDetail
130 {
135 using std::is_same;
136 using std::is_base_of;
137 using std::false_type;
138 using std::true_type;
139 using std::iterator_traits;
140 using std::conditional;
141 using std::size_t;
142 template <bool B, typename T, typename F>
143 using conditional_t = typename conditional<B, T, F>::type;
144 
149 template <typename... Ts> struct Typelist;
150 
154 enum class Category {
156  None,
158  ArithmeticVectorizable,
160  InputIterator,
162  OutputIterator,
164  ForwardIterator,
166  BidirectionalIterator,
168  RandomAccessIterator,
170  ClassTemplate
171 };
172 
177 template <typename T, typename ItCat = typename T::iterator_category>
178 constexpr Category iteratorCategories(int, ItCat * = nullptr)
179 {
180  return is_base_of<std::random_access_iterator_tag, ItCat>::value
181  ? Category::RandomAccessIterator
182  : is_base_of<std::bidirectional_iterator_tag, ItCat>::value
183  ? Category::BidirectionalIterator
184  : is_base_of<std::forward_iterator_tag, ItCat>::value
185  ? Category::ForwardIterator
186  : is_base_of<std::output_iterator_tag, ItCat>::value
187  ? Category::OutputIterator
188  : is_base_of<std::input_iterator_tag, ItCat>::value
189  ? Category::InputIterator
190  : Category::None;
191 }
195 template <typename T>
196 constexpr enable_if<std::is_pointer<T>::value, Category> iteratorCategories(float)
197 {
198  return Category::RandomAccessIterator;
199 }
203 template <typename T> constexpr Category iteratorCategories(...)
204 {
205  return Category::None;
206 }
207 
211 template <typename T> struct is_class_template : public false_type
212 {
213 };
214 template <template <typename...> class C, typename... Ts>
215 struct is_class_template<C<Ts...>> : public true_type
216 {
217 };
218 
222 template <typename T> constexpr Category typeCategory()
223 {
224  return (is_same<T, bool>::value || is_same<T, short>::value ||
225  is_same<T, unsigned short>::value || is_same<T, int>::value ||
226  is_same<T, unsigned int>::value || is_same<T, float>::value ||
227  is_same<T, double>::value)
228  ? Category::ArithmeticVectorizable
229  : iteratorCategories<T>(int()) != Category::None
230  ? iteratorCategories<T>(int())
231  : is_class_template<T>::value ? Category::ClassTemplate
232  : Category::None;
233 }
234 
240 template <typename T, size_t TupleSize = std::tuple_size<T>::value>
241 constexpr size_t determine_tuple_size()
242 {
243  return TupleSize;
244 }
245 template <typename T, size_t TupleSize = T::tuple_size>
246 constexpr size_t determine_tuple_size(size_t = T::tuple_size)
247 {
248  return TupleSize;
249 }
250 
251 // workaround for MSVC limitation: constexpr functions in template arguments
252 // confuse the compiler
253 template <typename T> struct determine_tuple_size_
254 : public std::integral_constant<size_t, determine_tuple_size<T>()>
255 {};
256 
257 namespace
258 {
259 template <typename T> struct The_simdization_for_the_requested_type_is_not_implemented;
260 } // unnamed namespace
261 
274 template <typename T, size_t N, typename MT, Category = typeCategory<T>()>
275 struct ReplaceTypes : public The_simdization_for_the_requested_type_is_not_implemented<T>
276 {
277 };
278 
283 template <typename T, size_t N, typename MT> struct ReplaceTypes<T, N, MT, Category::None>
284 {
285  typedef T type;
286 };
287 
292 template <typename T, size_t N = 0, typename MT = void>
293 using simdize = typename SimdizeDetail::ReplaceTypes<T, N, MT>::type;
294 
299 template <typename T, size_t N, typename MT>
300 struct ReplaceTypes<T, N, MT, Category::ArithmeticVectorizable>
301  : public conditional<(N == 0 || Vector<T>::Size == N), Vector<T>, SimdArray<T, N>>
302 {
303 };
304 
309 template <size_t N, typename MT>
310 struct ReplaceTypes<bool, N, MT, Category::ArithmeticVectorizable>
311  : public conditional<(N == 0 || Mask<MT>::Size == N), Mask<MT>,
312  SimdMaskArray<MT, N>>
313 {
314 };
318 template <size_t N>
319 struct ReplaceTypes<bool, N, void, Category::ArithmeticVectorizable>
320  : public ReplaceTypes<bool, N, float, Category::ArithmeticVectorizable>
321 {
322 };
323 
330 template <size_t N, typename MT, typename Replaced, typename... Remaining>
331 struct SubstituteOneByOne;
332 
337 template <size_t N, typename MT, typename... Replaced, typename T,
338  typename... Remaining>
339 struct SubstituteOneByOne<N, MT, Typelist<Replaced...>, T, Remaining...>
340 {
341 private:
346  template <typename U, size_t M = U::Size>
347  static std::integral_constant<size_t, M> size_or_0(int);
348  template <typename U> static std::integral_constant<size_t, 0> size_or_0(...);
349 
351  using V = simdize<T, N, MT>;
352 
357  static constexpr auto NewN = N != 0 ? N : decltype(size_or_0<V>(int()))::value;
358 
364  typedef conditional_t<(N != NewN && is_same<MT, void>::value),
365  conditional_t<is_same<T, bool>::value, float, T>, MT> NewMT;
366 
367 public:
371  using type = typename SubstituteOneByOne<NewN, NewMT, Typelist<Replaced..., V>,
372  Remaining...>::type;
373 };
374 
377 template <size_t Size, typename... Replaced> struct SubstitutedBase;
379 template <typename Replaced> struct SubstitutedBase<1, Replaced> {
380  template <typename ValueT, template <typename, ValueT...> class C, ValueT... Values>
381  using SubstitutedWithValues = C<Replaced, Values...>;
382 };
384 template <typename R0, typename R1> struct SubstitutedBase<2, R0, R1>
385 {
386  template <typename ValueT, template <typename, typename, ValueT...> class C,
387  ValueT... Values>
388  using SubstitutedWithValues = C<R0, R1, Values...>;
389 };
391 template <typename R0, typename R1, typename R2> struct SubstitutedBase<3, R0, R1, R2>
392 {
393  template <typename ValueT, template <typename, typename, typename, ValueT...> class C,
394  ValueT... Values>
395  using SubstitutedWithValues = C<R0, R1, R2, Values...>;
396 };
397 #if defined Vc_ICC || defined Vc_MSVC
398 #define Vc_VALUE_PACK_EXPANSION_IS_BROKEN 1
399 #endif
400 template <typename... Replaced> struct SubstitutedBase<4, Replaced...> {
402 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
403  template <typename ValueT,
404  template <typename, typename, typename, typename, ValueT...> class C,
405  ValueT... Values>
406  using SubstitutedWithValues = C<Replaced..., Values...>;
407 #endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
408 };
410 template <typename... Replaced> struct SubstitutedBase<5, Replaced...> {
411 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
412  template <typename ValueT, template <typename, typename, typename, typename, typename,
413  ValueT...> class C,
414  ValueT... Values>
415  using SubstitutedWithValues = C<Replaced..., Values...>;
416 #endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
417 };
419 template <typename... Replaced> struct SubstitutedBase<6, Replaced...> {
420 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
421  template <typename ValueT, template <typename, typename, typename, typename, typename,
422  typename, ValueT...> class C,
423  ValueT... Values>
424  using SubstitutedWithValues = C<Replaced..., Values...>;
425 #endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
426 };
428 template <typename... Replaced> struct SubstitutedBase<7, Replaced...> {
429 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
430  template <typename ValueT, template <typename, typename, typename, typename, typename,
431  typename, typename, ValueT...> class C,
432  ValueT... Values>
433  using SubstitutedWithValues = C<Replaced..., Values...>;
434 #endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
435 };
437 template <typename... Replaced> struct SubstitutedBase<8, Replaced...> {
438 #ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
439  template <typename ValueT, template <typename, typename, typename, typename, typename,
440  typename, typename, typename, ValueT...> class C,
441  ValueT... Values>
442  using SubstitutedWithValues = C<Replaced..., Values...>;
443 #endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
444 };
445 
451 template <size_t N_, typename MT, typename Replaced0, typename... Replaced>
452 struct SubstituteOneByOne<N_, MT, Typelist<Replaced0, Replaced...>>
453 {
457  struct type
458  : public SubstitutedBase<sizeof...(Replaced) + 1, Replaced0, Replaced...> {
459  static constexpr auto N = N_;
464  template <template <typename...> class C>
465  using Substituted = C<Replaced0, Replaced...>;
466  };
467 };
468 
485 template <typename Scalar, typename Base, size_t N> class Adapter;
486 
491 template <template <typename...> class C, typename... Ts, size_t N, typename MT>
492 struct ReplaceTypes<C<Ts...>, N, MT, Category::ClassTemplate>
493 {
495  using SubstitutionResult =
496  typename SubstituteOneByOne<N, MT, Typelist<>, Ts...>::type;
502  using Vectorized = typename SubstitutionResult::template Substituted<C>;
508  using type = conditional_t<is_same<C<Ts...>, Vectorized>::value, C<Ts...>,
509  Adapter<C<Ts...>, Vectorized, SubstitutionResult::N>>;
510 };
511 
517 #ifdef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
518 // ICC barfs on packs of values
519 #define Vc_DEFINE_NONTYPE_REPLACETYPES_(ValueType_) \
520  template <template <typename, ValueType_...> class C, typename T, ValueType_ Value0, \
521  ValueType_... Values> \
522  struct is_class_template<C<T, Value0, Values...>> : public true_type { \
523  }; \
524  template <template <typename, typename, ValueType_...> class C, typename T0, \
525  typename T1, ValueType_ Value0, ValueType_... Values> \
526  struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type { \
527  }; \
528  template <template <typename, typename, typename, ValueType_...> class C, \
529  typename T0, typename T1, typename T2, ValueType_ Value0, \
530  ValueType_... Values> \
531  struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type { \
532  }; \
533  template <template <typename, typename, typename, typename, ValueType_...> class C, \
534  typename T0, typename T1, typename T2, typename T3, ValueType_ Value0, \
535  ValueType_... Values> \
536  struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type { \
537  }; \
538  template <template <typename, typename, typename, typename, typename, ValueType_...> \
539  class C, \
540  typename T0, typename T1, typename T2, typename T3, typename T4, \
541  ValueType_ Value0, ValueType_... Values> \
542  struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
543  : public true_type { \
544  }; \
545  template <template <typename, typename, typename, typename, typename, typename, \
546  ValueType_...> class C, \
547  typename T0, typename T1, typename T2, typename T3, typename T4, \
548  typename T5, ValueType_ Value0, ValueType_... Values> \
549  struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
550  : public true_type { \
551  }; \
552  template <template <typename, typename, typename, typename, typename, typename, \
553  typename, ValueType_...> class C, \
554  typename T0, typename T1, typename T2, typename T3, typename T4, \
555  typename T5, typename T6, ValueType_ Value0, ValueType_... Values> \
556  struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
557  : public true_type { \
558  }; \
559  template <template <typename, ValueType_> class C, typename T0, ValueType_ Value0, \
560  size_t N, typename MT> \
561  struct ReplaceTypes<C<T0, Value0>, N, MT, Category::ClassTemplate> { \
562  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
563  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
564  Substituted; \
565  static constexpr auto NN = tmp::N; \
566  typedef conditional_t<is_same<C<T0, Value0>, Substituted>::value, C<T0, Value0>, \
567  Adapter<C<T0, Value0>, Substituted, NN>> type; \
568  }; \
569  template <template <typename, typename, ValueType_> class C, typename T0, \
570  typename T1, ValueType_ Value0, size_t N, typename MT> \
571  struct ReplaceTypes<C<T0, T1, Value0>, N, MT, Category::ClassTemplate> { \
572  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
573  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
574  Substituted; \
575  static constexpr auto NN = tmp::N; \
576  typedef conditional_t<is_same<C<T0, T1, Value0>, Substituted>::value, \
577  C<T0, T1, Value0>, \
578  Adapter<C<T0, T1, Value0>, Substituted, NN>> type; \
579  }; \
580  template <template <typename, typename, typename, ValueType_> class C, typename T0, \
581  typename T1, typename T2, ValueType_ Value0, size_t N, typename MT> \
582  struct ReplaceTypes<C<T0, T1, T2, Value0>, N, MT, Category::ClassTemplate> { \
583  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
584  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
585  Substituted; \
586  static constexpr auto NN = tmp::N; \
587  typedef conditional_t<is_same<C<T0, T1, T2, Value0>, Substituted>::value, \
588  C<T0, T1, T2, Value0>, \
589  Adapter<C<T0, T1, T2, Value0>, Substituted, NN>> type; \
590  }
591 #else
592 #define Vc_DEFINE_NONTYPE_REPLACETYPES_(ValueType_) \
593  template <template <typename, ValueType_...> class C, typename T, ValueType_ Value0, \
594  ValueType_... Values> \
595  struct is_class_template<C<T, Value0, Values...>> : public true_type { \
596  }; \
597  template <template <typename, typename, ValueType_...> class C, typename T0, \
598  typename T1, ValueType_ Value0, ValueType_... Values> \
599  struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type { \
600  }; \
601  template <template <typename, typename, typename, ValueType_...> class C, \
602  typename T0, typename T1, typename T2, ValueType_ Value0, \
603  ValueType_... Values> \
604  struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type { \
605  }; \
606  template <template <typename, typename, typename, typename, ValueType_...> class C, \
607  typename T0, typename T1, typename T2, typename T3, ValueType_ Value0, \
608  ValueType_... Values> \
609  struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type { \
610  }; \
611  template <template <typename, typename, typename, typename, typename, ValueType_...> \
612  class C, \
613  typename T0, typename T1, typename T2, typename T3, typename T4, \
614  ValueType_ Value0, ValueType_... Values> \
615  struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
616  : public true_type { \
617  }; \
618  template <template <typename, typename, typename, typename, typename, typename, \
619  ValueType_...> class C, \
620  typename T0, typename T1, typename T2, typename T3, typename T4, \
621  typename T5, ValueType_ Value0, ValueType_... Values> \
622  struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
623  : public true_type { \
624  }; \
625  template <template <typename, typename, typename, typename, typename, typename, \
626  typename, ValueType_...> class C, \
627  typename T0, typename T1, typename T2, typename T3, typename T4, \
628  typename T5, typename T6, ValueType_ Value0, ValueType_... Values> \
629  struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
630  : public true_type { \
631  }; \
632  template <template <typename, ValueType_...> class C, typename T0, \
633  ValueType_ Value0, ValueType_... Values, size_t N, typename MT> \
634  struct ReplaceTypes<C<T0, Value0, Values...>, N, MT, Category::ClassTemplate> { \
635  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
636  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
637  Values...> Substituted; \
638  static constexpr auto NN = tmp::N; \
639  typedef conditional_t<is_same<C<T0, Value0, Values...>, Substituted>::value, \
640  C<T0, Value0, Values...>, \
641  Adapter<C<T0, Value0, Values...>, Substituted, NN>> type; \
642  }; \
643  template <template <typename, typename, ValueType_...> class C, typename T0, \
644  typename T1, ValueType_ Value0, ValueType_... Values, size_t N, \
645  typename MT> \
646  struct ReplaceTypes<C<T0, T1, Value0, Values...>, N, MT, Category::ClassTemplate> { \
647  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
648  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
649  Values...> Substituted; \
650  static constexpr auto NN = tmp::N; \
651  typedef conditional_t<is_same<C<T0, T1, Value0, Values...>, Substituted>::value, \
652  C<T0, T1, Value0, Values...>, \
653  Adapter<C<T0, T1, Value0, Values...>, Substituted, NN>> \
654  type; \
655  }; \
656  template <template <typename, typename, typename, ValueType_...> class C, \
657  typename T0, typename T1, typename T2, ValueType_ Value0, \
658  ValueType_... Values, size_t N, typename MT> \
659  struct ReplaceTypes<C<T0, T1, T2, Value0, Values...>, N, MT, \
660  Category::ClassTemplate> { \
661  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
662  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
663  Values...> Substituted; \
664  static constexpr auto NN = tmp::N; \
665  typedef conditional_t< \
666  is_same<C<T0, T1, T2, Value0, Values...>, Substituted>::value, \
667  C<T0, T1, T2, Value0, Values...>, \
668  Adapter<C<T0, T1, T2, Value0, Values...>, Substituted, NN>> type; \
669  }
670 #endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
671 Vc_DEFINE_NONTYPE_REPLACETYPES_(bool);
672 Vc_DEFINE_NONTYPE_REPLACETYPES_(wchar_t);
673 Vc_DEFINE_NONTYPE_REPLACETYPES_(char);
674 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed char);
675 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned char);
676 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed short);
677 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned short);
678 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed int);
679 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned int);
680 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed long);
681 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned long);
682 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed long long);
683 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned long long);
684 #undef Vc_DEFINE_NONTYPE_REPLACETYPES_
685 
686 namespace is_constructible_with_single_paren_impl
687 {
688 template <typename T> T create();
689 #if defined Vc_CLANG || defined Vc_APPLECLANG
690 template <typename Class, typename... Args, typename = decltype(Class(create<Args>()...))>
691 char test(int);
692 #else
693 template <typename Class, typename... Args>
694 typename std::conditional<
695 #ifndef Vc_ICC
696  0 !=
697 #endif
698  sizeof(Class(create<Args>()...)),
699  char, char>::type
700 test(int);
701 #endif
702 template <typename Class, typename... Args> double test(...);
703 } // namespace is_constructible_with_single_paren_impl
704 
705 template <typename Class, typename... Args>
706 struct is_constructible_with_single_paren
707  : public std::integral_constant<
708  bool,
709  1 == sizeof(is_constructible_with_single_paren_impl::test<Class, Args...>(1))> {
710 };
711 
712 namespace is_constructible_with_single_brace_impl
713 {
714 template <typename T> T create();
715 #ifdef Vc_ICC
716 template <typename Class, typename... Args> char test(int);
717 #elif defined Vc_CLANG || defined Vc_APPLECLANG
718 template <typename Class, typename... Args, typename = decltype(Class{create<Args>()...})>
719 char test(int);
720 #else
721 template <typename Class, typename... Args>
722 typename std::conditional<
723 #ifndef Vc_ICC
724  0 !=
725 #endif
726  sizeof(Class{create<Args>()...}),
727  char, char>::type
728 test(int);
729 #endif
730 template <typename Class, typename... Args> double test(...);
731 } // namespace is_constructible_with_single_brace_impl
732 
733 template <typename Class, typename... Args>
734 struct is_constructible_with_single_brace
735  : public std::integral_constant<
736  bool,
737  1 == sizeof(is_constructible_with_single_brace_impl::test<Class, Args...>(1))> {
738 };
739 
740 namespace is_constructible_with_double_brace_impl
741 {
742 template <typename T> T create();
743 #if defined Vc_CLANG || defined Vc_APPLECLANG
744 template <typename Class, typename... Args,
745  typename = decltype(Class{{create<Args>()...}})>
746 char test(int);
747 #else
748 template <typename Class, typename... Args>
749 typename std::conditional<
750 #ifndef Vc_ICC
751  0 !=
752 #endif
753  sizeof(Class{{create<Args>()...}}),
754  char, char>::type
755 test(int);
756 #endif
757 template <typename Class, typename... Args> double test(...);
758 } // namespace is_constructible_with_double_brace_impl
759 
760 template <typename Class, typename... Args>
761 struct is_constructible_with_double_brace
762  : public std::integral_constant<
763  bool,
764  1 == sizeof(is_constructible_with_double_brace_impl::test<Class, Args...>(1))> {
765 };
766 
767 template <size_t I, typename T,
768  typename R = decltype(std::declval<T &>().template vc_get_<I>())>
769 R get_dispatcher(T &x, void * = nullptr)
770 {
771  return x.template vc_get_<I>();
772 }
773 template <size_t I, typename T,
774  typename R = decltype(std::declval<const T &>().template vc_get_<I>())>
775 R get_dispatcher(const T &x, void * = nullptr)
776 {
777  return x.template vc_get_<I>();
778 }
779 template <size_t I, typename T, typename R = decltype(std::get<I>(std::declval<T &>()))>
780 R get_dispatcher(T &x, int = 0)
781 {
782  return std::get<I>(x);
783 }
784 template <size_t I, typename T,
785  typename R = decltype(std::get<I>(std::declval<const T &>()))>
786 R get_dispatcher(const T &x, int = 0)
787 {
788  return std::get<I>(x);
789 }
790 
791 
792 // see above
793 template <typename Scalar, typename Base, size_t N> class Adapter : public Base
794 {
795 private:
797  template <std::size_t... Indexes, typename T>
798  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_, T, std::true_type)
799  : Base{{get_dispatcher<Indexes>(x_)...}}
800  {
801  }
802 
804  template <std::size_t... Indexes>
805  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_, std::false_type,
806  std::false_type)
807  : Base{get_dispatcher<Indexes>(x_)...}
808  {
809  }
810 
812  template <std::size_t... Indexes>
813  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_, std::true_type,
814  std::false_type)
815  : Base(get_dispatcher<Indexes>(x_)...)
816  {
817  }
818 
819  template <std::size_t... Indexes>
820  Adapter(Vc::index_sequence<Indexes...> seq_, const Scalar &x_)
821  : Adapter(seq_, x_,
822  std::integral_constant<
823  bool, is_constructible_with_single_paren<
824  Base, decltype(get_dispatcher<Indexes>(
825  std::declval<const Scalar &>()))...>::value>(),
826  std::integral_constant<
827  bool, is_constructible_with_double_brace<
828  Base, decltype(get_dispatcher<Indexes>(
829  std::declval<const Scalar &>()))...>::value>())
830  {
831  }
832 
833 public:
835  static constexpr size_t size() { return N; }
836  static constexpr size_t Size = N;
837 
839  using base_type = Base;
842  using scalar_type = Scalar;
843 
846  Adapter() = default;
847 
849 #if defined Vc_CLANG && Vc_CLANG < 0x30700
850  Vc_INTRINSIC Adapter(const Adapter &x) : Base(x) {}
851 #else
852  Adapter(const Adapter &) = default;
853 #endif
854  Adapter(Adapter &&) = default;
857  Adapter &operator=(const Adapter &) = default;
859  Adapter &operator=(Adapter &&) = default;
860 
862  template <typename U, size_t TupleSize = determine_tuple_size_<Scalar>::value,
863  typename Seq = Vc::make_index_sequence<TupleSize>,
864  typename = enable_if<std::is_convertible<U, Scalar>::value>>
865  Adapter(U &&x_)
866  : Adapter(Seq(), static_cast<const Scalar &>(x_))
867  {
868  }
869 
871  template <typename A0, typename... Args,
872  typename = typename std::enable_if<
873  !Traits::is_index_sequence<A0>::value &&
874  (sizeof...(Args) > 0 || !std::is_convertible<A0, Scalar>::value)>::type>
875  Adapter(A0 &&arg0_, Args &&... arguments_)
876  : Base(std::forward<A0>(arg0_), std::forward<Args>(arguments_)...)
877  {
878  }
879 
881  template <typename T,
882  typename = decltype(Base(std::declval<const std::initializer_list<T> &>()))>
883  Adapter(const std::initializer_list<T> &l_)
884  : Base(l_)
885  {
886  }
887 
890  void *operator new(size_t size)
891  {
892  return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
893  }
894  void *operator new(size_t, void *p_) { return p_; }
895  void *operator new[](size_t size)
896  {
897  return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
898  }
899  void *operator new[](size_t , void *p_) { return p_; }
900  void operator delete(void *ptr_, size_t) { Vc::Common::free(ptr_); }
901  void operator delete(void *, void *) {}
902  void operator delete[](void *ptr_, size_t) { Vc::Common::free(ptr_); }
903  void operator delete[](void *, void *) {}
904 };
905 
910 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
911 inline void operator==(
912  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
913  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
914 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
915 inline void operator!=(
916  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
917  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
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 
936 } // namespace SimdizeDetail
937 } // namespace Vc
938 
939 namespace std
940 {
944 template <typename Scalar, typename Base, size_t N>
945 class tuple_size<Vc::SimdizeDetail::Adapter<Scalar, Base, N>> : public tuple_size<Base>
946 {
947 };
951 template <size_t I, typename Scalar, typename Base, size_t N>
952 class tuple_element<I, Vc::SimdizeDetail::Adapter<Scalar, Base, N>>
953  : public tuple_element<I, Base>
954 {
955 };
956 // std::get does not need additional work because Vc::Adapter derives from
957 // C<Ts...> and therefore if get<N>(C<Ts...>) works it works for Adapter as well.
958 
963 template <typename S, typename T, size_t N>
964 class allocator<Vc::SimdizeDetail::Adapter<S, T, N>>
965  : public Vc::Allocator<Vc::SimdizeDetail::Adapter<S, T, N>>
966 {
967 public:
968  template <typename U> struct rebind
969  {
970  typedef std::allocator<U> other;
971  };
972 };
973 } // namespace std
974 
975 namespace Vc_VERSIONED_NAMESPACE
976 {
977 namespace SimdizeDetail
978 {
987 template <typename T> static inline T decay_workaround(const T &x) { return x; }
988 
992 template <typename S, typename T, size_t N, size_t... Indexes>
993 inline void assign_impl(Adapter<S, T, N> &a, size_t i, const S &x,
994  Vc::index_sequence<Indexes...>)
995 {
996  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(x)))...> tmp(
997  decay_workaround(get_dispatcher<Indexes>(x))...);
998  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(tmp), 0)...};
999  if (&unused == &unused) {}
1000 }
1001 
1006 template <typename S, typename T, size_t N>
1007 inline void assign(Adapter<S, T, N> &a, size_t i, const S &x)
1008 {
1009  assign_impl(a, i, x, Vc::make_index_sequence<determine_tuple_size<T>()>());
1010 }
1014 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
1015 Vc_INTRINSIC void assign(V &v, size_t i, typename V::EntryType x)
1016 {
1017  v[i] = x;
1018 }
1019 
1023 template <typename S, typename T, size_t N, size_t... Indexes>
1024 inline S extract_impl(const Adapter<S, T, N> &a, size_t i, Vc::index_sequence<Indexes...>)
1025 {
1026  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[i]))...> tmp(
1027  decay_workaround(get_dispatcher<Indexes>(a)[i])...);
1028  return S(get_dispatcher<Indexes>(tmp)...);
1029 }
1030 
1035 template <typename S, typename T, size_t N>
1036 inline S extract(const Adapter<S, T, N> &a, size_t i)
1037 {
1038  return extract_impl(a, i, Vc::make_index_sequence<determine_tuple_size<S>()>());
1039 }
1043 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
1044 Vc_INTRINSIC typename V::EntryType extract(const V &v, size_t i)
1045 {
1046  return v[i];
1047 }
1048 
1049 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1050 inline Adapter<S, T, N> shifted_impl(const Adapter<S, T, N> &a, int shift,
1051  Vc::index_sequence<Indexes...>)
1052 {
1053  Adapter<S, T, N> r;
1054  auto &&unused = {(get_dispatcher<Indexes>(r) = get_dispatcher<Indexes>(a).shifted(shift), 0)...};
1055  if (&unused == &unused) {}
1056  return r;
1057 }
1058 
1067 template <typename S, typename T, size_t N>
1068 inline Adapter<S, T, N> shifted(const Adapter<S, T, N> &a, int shift)
1069 {
1070  return shifted_impl(a, shift, Vc::make_index_sequence<determine_tuple_size<T>()>());
1071 }
1072 
1076 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1077 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, S &x,
1078  Vc::index_sequence<Indexes...>)
1079 {
1080  const auto &a_const = a;
1081  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a_const)[0]))...>
1082  tmp{decay_workaround(get_dispatcher<Indexes>(a_const)[i])...};
1083  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(x), 0)...};
1084  auto &&unused2 = {(get_dispatcher<Indexes>(x) = get_dispatcher<Indexes>(tmp), 0)...};
1085  if (&unused == &unused2) {}
1086 }
1087 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1088 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b,
1089  std::size_t j, Vc::index_sequence<Indexes...>)
1090 {
1091  const auto &a_const = a;
1092  const auto &b_const = b;
1093  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a_const)[0]))...>
1094  tmp{decay_workaround(get_dispatcher<Indexes>(a_const)[i])...};
1095  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(b_const)[j], 0)...};
1096  auto &&unused2 = {(get_dispatcher<Indexes>(b)[j] = get_dispatcher<Indexes>(tmp), 0)...};
1097  if (&unused == &unused2) {}
1098 }
1099 
1104 template <typename S, typename T, std::size_t N>
1105 inline void swap(Adapter<S, T, N> &a, std::size_t i, S &x)
1106 {
1107  swap_impl(a, i, x, Vc::make_index_sequence<determine_tuple_size<T>()>());
1108 }
1109 template <typename S, typename T, std::size_t N>
1110 inline void swap(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b, std::size_t j)
1111 {
1112  swap_impl(a, i, b, j, Vc::make_index_sequence<determine_tuple_size<T>()>());
1113 }
1114 
1115 template <typename A> class Scalar
1116 {
1117  using reference = typename std::add_lvalue_reference<A>::type;
1118  using S = typename A::scalar_type;
1119  using IndexSeq = Vc::make_index_sequence<determine_tuple_size<S>()>;
1120 
1121 public:
1122  Scalar(reference aa, size_t ii) : a(aa), i(ii) {}
1123 
1124  // delete copy and move to keep the type a pure proxy temporary object.
1125  Scalar(const Scalar &) = delete;
1126  Scalar(Scalar &&) = delete;
1127  Scalar &operator=(const Scalar &) = delete;
1128  Scalar &operator=(Scalar &&) = delete;
1129 
1130  void operator=(const S &x) { assign_impl(a, i, x, IndexSeq()); }
1131  operator S() const { return extract_impl(a, i, IndexSeq()); }
1132 
1133  template <typename AA>
1134  friend inline void swap(Scalar<AA> &&a, typename AA::scalar_type &b);
1135  template <typename AA>
1136  friend inline void swap(typename AA::scalar_type &b, Scalar<AA> &&a);
1137  template <typename AA> friend inline void swap(Scalar<AA> &&a, Scalar<AA> &&b);
1138 
1139 private:
1140  reference a;
1141  size_t i;
1142 };
1143 
1146 template <typename A> inline void swap(Scalar<A> &&a, typename A::scalar_type &b)
1147 {
1148  swap_impl(a.a, a.i, b, typename Scalar<A>::IndexSeq());
1149 }
1152 template <typename A> inline void swap(typename A::scalar_type &b, Scalar<A> &&a)
1153 {
1154  swap_impl(a.a, a.i, b, typename Scalar<A>::IndexSeq());
1155 }
1156 
1157 template <typename A> inline void swap(Scalar<A> &&a, Scalar<A> &&b)
1158 {
1159  swap_impl(a.a, a.i, b.a, b.i, typename Scalar<A>::IndexSeq());
1160 }
1161 
1162 template <typename A> class Interface
1163 {
1164  using reference = typename std::add_lvalue_reference<A>::type;
1165  using IndexSeq =
1166  Vc::make_index_sequence<determine_tuple_size<typename A::scalar_type>()>;
1167 
1168 public:
1169  Interface(reference aa) : a(aa) {}
1170 
1171  Scalar<A> operator[](size_t i)
1172  {
1173  return {a, i};
1174  }
1175  typename A::scalar_type operator[](size_t i) const
1176  {
1177  return extract_impl(a, i, IndexSeq());
1178  }
1179 
1180  A shifted(int amount) const
1181  {
1182  return shifted_impl(a, amount, IndexSeq());
1183  }
1184 
1185 private:
1186  reference a;
1187 };
1188 
1189 template <typename S, typename T, size_t N>
1190 Interface<Adapter<S, T, N>> decorate(Adapter<S, T, N> &a)
1191 {
1192  return {a};
1193 }
1194 template <typename S, typename T, size_t N>
1195 const Interface<const Adapter<S, T, N>> decorate(const Adapter<S, T, N> &a)
1196 {
1197  return {a};
1198 }
1199 
1200 namespace IteratorDetails
1201 {
1202 enum class Mutable { Yes, No };
1203 
1204 template <typename It, typename V, size_t I, size_t End>
1205 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I == End), It>)
1206 {
1207  return {};
1208 }
1209 template <typename It, typename V, size_t I, size_t End>
1210 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I < End), It> it)
1211 {
1212  V r = fromIteratorImpl<It, V, I + 1, End>(it);
1213  Traits::decay<decltype(get_dispatcher<I>(r))> tmp;
1214  for (size_t j = 0; j < V::size(); ++j, ++it) {
1215  tmp[j] = get_dispatcher<I>(*it);
1216  }
1217  get_dispatcher<I>(r) = tmp;
1218  return r;
1219 }
1220 template <typename It, typename V>
1221 Vc_INTRINSIC V fromIterator(enable_if<!Traits::is_simd_vector<V>::value, const It &> it)
1222 {
1223  return fromIteratorImpl<It, V, 0, determine_tuple_size<V>()>(it);
1224 }
1225 template <typename It, typename V>
1226 Vc_INTRINSIC V fromIterator(enable_if<Traits::is_simd_vector<V>::value, It> it)
1227 {
1228  V r;
1229  for (size_t j = 0; j < V::size(); ++j, ++it) {
1230  r[j] = *it;
1231  }
1232  return r;
1233 }
1234 
1235 // Note: §13.5.6 says: “An expression x->m is interpreted as (x.operator->())->m for a
1236 // class object x of type T if T::operator->() exists and if the operator is selected as
1237 // the best match function by the overload resolution mechanism (13.3).”
1238 template <typename T, typename value_vector, Mutable> class Pointer;
1239 
1248 template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::Yes>
1249 {
1250  static constexpr auto Size = value_vector::size();
1251 
1252 public:
1254  value_vector *operator->() { return &data; }
1255 
1260  Pointer() = delete;
1261  Pointer(const Pointer &) = delete;
1262  Pointer &operator=(const Pointer &) = delete;
1263  Pointer &operator=(Pointer &&) = delete;
1264 
1266  Pointer(Pointer &&) = default;
1267 
1273  ~Pointer()
1274  {
1275  // store data back to where it came from
1276  for (size_t i = 0; i < Size; ++i, ++begin_iterator) {
1277  *begin_iterator = extract(data, i);
1278  }
1279  }
1280 
1282  Pointer(const T &it) : data(fromIterator<T, value_vector>(it)), begin_iterator(it) {}
1283 
1284 private:
1286  value_vector data;
1288  T begin_iterator;
1289 };
1295 template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::No>
1296 {
1297  static constexpr auto Size = value_vector::size();
1298 
1299 public:
1300  const value_vector *operator->() const { return &data; }
1301 
1302  Pointer() = delete;
1303  Pointer(const Pointer &) = delete;
1304  Pointer &operator=(const Pointer &) = delete;
1305  Pointer &operator=(Pointer &&) = delete;
1306 
1307  Pointer(Pointer &&) = default; // required for returning the Pointer
1308 
1309  Pointer(const T &it) : data(fromIterator<T, value_vector>(it)) {}
1310 
1311 private:
1312  value_vector data;
1313 };
1314 
1327 template <typename T, typename value_vector, Mutable M> class Reference;
1328 
1330 template <typename T, typename value_vector>
1331 class Reference<T, value_vector, Mutable::Yes> : public value_vector
1332 {
1333  static constexpr auto Size = value_vector::size();
1334 
1335  using reference = typename std::add_lvalue_reference<T>::type;
1336  reference scalar_it;
1337 
1338 public:
1341  Reference(reference first_it)
1342  : value_vector(fromIterator<T, value_vector>(first_it)), scalar_it(first_it)
1343  {
1344  }
1345 
1347  Reference(const Reference &) = delete;
1348  Reference(Reference &&) = default;
1349  Reference &operator=(const Reference &) = delete;
1350  Reference &operator=(Reference &&) = delete;
1351 
1357  void operator=(const value_vector &x)
1358  {
1359  static_cast<value_vector &>(*this) = x;
1360  auto it = scalar_it;
1361  for (size_t i = 0; i < Size; ++i, ++it) {
1362  *it = extract(x, i);
1363  }
1364  }
1365 };
1366 #define Vc_OP(op_) \
1367  template <typename T0, typename V0, typename T1, typename V1> \
1368  decltype(std::declval<const V0 &>() op_ std::declval<const V1 &>()) operator op_( \
1369  const Reference<T0, V0, Mutable::Yes> &x, \
1370  const Reference<T1, V1, Mutable::Yes> &y) \
1371  { \
1372  return static_cast<const V0 &>(x) op_ static_cast<const V1 &>(y); \
1373  }
1374 Vc_ALL_COMPARES(Vc_OP);
1375 Vc_ALL_ARITHMETICS(Vc_OP);
1376 Vc_ALL_BINARY(Vc_OP);
1377 Vc_ALL_LOGICAL(Vc_OP);
1378 Vc_ALL_SHIFTS(Vc_OP);
1379 #undef Vc_OP
1380 
1382 template <typename T, typename value_vector>
1383 class Reference<T, value_vector, Mutable::No> : public value_vector
1384 {
1385  static constexpr auto Size = value_vector::size();
1386 
1387 public:
1388  Reference(const T &it) : value_vector(fromIterator<T, value_vector>(it)) {}
1389 
1390  Reference(const Reference &) = delete;
1391  Reference(Reference &&) = default;
1392  Reference &operator=(const Reference &) = delete;
1393  Reference &operator=(Reference &&) = delete;
1394 
1396  void operator=(const value_vector &x) = delete;
1397 };
1398 
1399 template <typename T, size_t N,
1400  IteratorDetails::Mutable M =
1401  (Traits::is_output_iterator<T>::value ? Mutable::Yes : Mutable::No),
1402  typename V = simdize<typename std::iterator_traits<T>::value_type, N>,
1403  size_t Size = V::Size,
1404  typename = typename std::iterator_traits<T>::iterator_category>
1405 class Iterator;
1406 
1407 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size_>
1408 class Iterator<T, N, M, V, Size_, std::forward_iterator_tag>
1409  : public std::iterator<typename std::iterator_traits<T>::iterator_category, V,
1410  typename std::iterator_traits<T>::difference_type,
1411  IteratorDetails::Pointer<T, V, M>,
1412  IteratorDetails::Reference<T, V, M>>
1413 {
1414 public:
1415  using pointer = IteratorDetails::Pointer<T, V, M>;
1416  using reference = IteratorDetails::Reference<T, V, M>;
1417  using const_pointer = IteratorDetails::Pointer<T, V, IteratorDetails::Mutable::No>;
1418  using const_reference =
1419  IteratorDetails::Reference<T, V, IteratorDetails::Mutable::No>;
1420 
1422  static constexpr std::size_t size() { return Size_; }
1423  static constexpr std::size_t Size = Size_;
1424 
1425  Iterator() = default;
1426 
1433  Iterator(const T &x) : scalar_it(x) {}
1437  Iterator(T &&x) : scalar_it(std::move(x)) {}
1441  Iterator &operator=(const T &x)
1442  {
1443  scalar_it = x;
1444  return *this;
1445  }
1449  Iterator &operator=(T &&x)
1450  {
1451  scalar_it = std::move(x);
1452  return *this;
1453  }
1454 
1456  Iterator(const Iterator &) = default;
1458  Iterator(Iterator &&) = default;
1460  Iterator &operator=(const Iterator &) = default;
1462  Iterator &operator=(Iterator &&) = default;
1463 
1465  Iterator &operator++()
1466  {
1467  std::advance(scalar_it, Size);
1468  return *this;
1469  }
1471  Iterator operator++(int)
1472  {
1473  Iterator copy(*this);
1474  operator++();
1475  return copy;
1476  }
1477 
1486  bool operator==(const Iterator &rhs) const
1487  {
1488 #ifndef NDEBUG
1489  if (scalar_it == rhs.scalar_it) {
1490  return true;
1491  } else {
1492  T it(scalar_it);
1493  for (size_t i = 1; i < Size; ++i) {
1494  Vc_ASSERT((++it != rhs.scalar_it));
1495  }
1496  return false;
1497  }
1498 #else
1499  return scalar_it == rhs.scalar_it;
1500 #endif
1501  }
1510  bool operator!=(const Iterator &rhs) const
1511  {
1512  return !operator==(rhs);
1513  }
1514 
1515  pointer operator->() { return scalar_it; }
1516 
1523  reference operator*() { return scalar_it; }
1524 
1525  const_pointer operator->() const { return scalar_it; }
1526 
1534  const_reference operator*() const { return scalar_it; }
1535 
1549  operator const T &() const { return scalar_it; }
1550 
1551 protected:
1552  T scalar_it;
1553 };
1554 
1559 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1560 class Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1561  : public Iterator<T, N, M, V, Size, std::forward_iterator_tag>
1562 {
1563  using Base = Iterator<T, N, M, V, Size, std::forward_iterator_tag>;
1564 
1565 protected:
1566  using Base::scalar_it;
1567 
1568 public:
1569  using pointer = typename Base::pointer;
1570  using reference = typename Base::reference;
1571  using const_pointer = typename Base::const_pointer;
1572  using const_reference = typename Base::const_reference;
1573 
1574  using Iterator<T, N, M, V, Size,
1575  std::forward_iterator_tag>::Iterator; // in short: "using
1576  // Base::Iterator", but that
1577  // confuses ICC
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 };
1592 
1597 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1598 class Iterator<T, N, M, V, Size, std::random_access_iterator_tag>
1599  : public Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1600 {
1602 
1603 protected:
1604  using Base::scalar_it;
1605 
1606 public:
1607  using pointer = typename Base::pointer;
1608  using reference = typename Base::reference;
1609  using const_pointer = typename Base::const_pointer;
1610  using const_reference = typename Base::const_reference;
1611  using difference_type = typename std::iterator_traits<T>::difference_type;
1612 
1614  Iterator; // in short: "using Base::Iterator", but that confuses ICC
1615 
1616  Iterator &operator+=(difference_type n)
1617  {
1618  scalar_it += n * difference_type(Size);
1619  return *this;
1620  }
1621  Iterator operator+(difference_type n) const { return Iterator(*this) += n; }
1622 
1623  Iterator &operator-=(difference_type n)
1624  {
1625  scalar_it -= n * difference_type(Size);
1626  return *this;
1627  }
1628  Iterator operator-(difference_type n) const { return Iterator(*this) -= n; }
1629 
1630  difference_type operator-(const Iterator &rhs) const
1631  {
1632  constexpr difference_type n = Size;
1633  Vc_ASSERT((scalar_it - rhs.scalar_it) % n ==
1634  0); // if this fails the two iterators are not a multiple of the vector
1635  // width apart. The distance would be fractional and that doesn't
1636  // make too much sense for iteration. Therefore, it is a
1637  // precondition for the distance of the two iterators to be a
1638  // multiple of Size.
1639  return (scalar_it - rhs.scalar_it) / n;
1640  }
1641 
1646  bool operator<(const Iterator &rhs) const
1647  {
1648  return rhs.scalar_it - scalar_it >= difference_type(Size);
1649  }
1650 
1651  bool operator>(const Iterator &rhs) const
1652  {
1653  return scalar_it - rhs.scalar_it >= difference_type(Size);
1654  }
1655 
1656  bool operator<=(const Iterator &rhs) const
1657  {
1658  return rhs.scalar_it - scalar_it >= difference_type(Size) - 1;
1659  }
1660 
1661  bool operator>=(const Iterator &rhs) const
1662  {
1663  return scalar_it - rhs.scalar_it >= difference_type(Size) - 1;
1664  }
1665 
1666  reference operator[](difference_type i) { return *(*this + i); }
1667  const_reference operator[](difference_type i) const { return *(*this + i); }
1668 };
1669 
1670 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1672  typename Iterator<T, N, M, V, Size, std::random_access_iterator_tag>::difference_type
1673  n,
1675 {
1676  return i + n;
1677 }
1678 
1679 } // namespace IteratorDetails
1680 
1689 template <typename T, size_t N, typename MT>
1690 struct ReplaceTypes<T, N, MT, Category::ForwardIterator>
1691 {
1692  using type = IteratorDetails::Iterator<T, N>;
1693 };
1694 template <typename T, size_t N, typename MT>
1695 struct ReplaceTypes<T, N, MT, Category::BidirectionalIterator>
1696 {
1697  using type = IteratorDetails::Iterator<T, N>;
1698 };
1699 template <typename T, size_t N, typename MT>
1700 struct ReplaceTypes<T, N, MT, Category::RandomAccessIterator>
1701 {
1702  using type = IteratorDetails::Iterator<T, N>;
1703 };
1704 
1708 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1709  std::size_t Offset>
1710 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size_<S>::value && M::Size == N), void>
1711  conditional_assign(Adapter<S, T, N> &, const M &, const U &)
1712 {
1713 }
1714 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1715  std::size_t Offset = 0>
1716 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size_<S>::value && M::Size == N), void>
1717  conditional_assign(Adapter<S, T, N> &lhs, const M &mask, const U &rhs)
1718 {
1719  using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1720  using M2 = typename V::mask_type;
1721  conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask), get_dispatcher<Offset>(rhs));
1722  conditional_assign<Op, S, T, N, M, U, Offset + 1>(lhs, mask, rhs);
1723 }
1724 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1725  std::size_t Offset>
1726 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size_<S>::value && M::Size == N), void>
1727  conditional_assign(Adapter<S, T, N> &, const M &)
1728 {
1729 }
1730 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1731  std::size_t Offset = 0>
1732 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size_<S>::value && M::Size == N), void>
1733  conditional_assign(Adapter<S, T, N> &lhs, const M &mask)
1734 {
1735  using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1736  using M2 = typename V::mask_type;
1737  conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask));
1738  conditional_assign<Op, S, T, N, M, Offset + 1>(lhs, mask);
1739 }
1740 
1742 } // namespace SimdizeDetail
1743 
1762 template <typename T, size_t N = 0, typename MT = void>
1763 using simdize = SimdizeDetail::simdize<T, N, MT>;
1764 
1784 #define Vc_SIMDIZE_INTERFACE(MEMBERS_) \
1785  template <std::size_t N_> \
1786  inline auto vc_get_()->decltype(std::get<N_>(std::tie MEMBERS_)) \
1787  { \
1788  return std::get<N_>(std::tie MEMBERS_); \
1789  } \
1790  template <std::size_t N_> \
1791  inline auto vc_get_() const->decltype(std::get<N_>(std::tie MEMBERS_)) \
1792  { \
1793  return std::get<N_>(std::tie MEMBERS_); \
1794  } \
1795  enum : std::size_t { \
1796  tuple_size = std::tuple_size<decltype(std::make_tuple MEMBERS_)>::value \
1797  }
1798 
1799 } // namespace Vc
1800 
1801 namespace std
1802 {
1803 using Vc::SimdizeDetail::swap;
1804 } // namespace std
1805 
1806 #endif // VC_COMMON_SIMDIZE_H_
1807 
1808 // 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:1646
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:1763
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:1036
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: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:1007
Iterator & operator--()
Advances the iterator by one vector width, or respectively N scalar steps.
Definition: simdize.h:1579
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:1068
This is the iterator type created when applying simdize to a random access iterator type...
Definition: simdize.h:1598
Vector Classes Namespace.
Definition: cpuid.h:32
This is the iterator type created when applying simdize to a bidirectional iterator type...
Definition: simdize.h:1560