Vc  1.3.2-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 
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 static_assert(
680  !is_constructible_with_single_paren<int, std::tuple<int, int, int>>::value,
681  "is_constructible_with_single_paren<int> does not work as expected");
682 static_assert(
683  is_constructible_with_single_paren<std::tuple<int, int, int>, int, int, int>::value,
684  "is_constructible_with_single_paren<tuple> does not work as expected");
685 static_assert(
686  !is_constructible_with_single_paren<std::array<int, 3>, int, int, int>::value,
687  "is_constructible_with_single_paren<array> does not work as expected");
688 
689 namespace is_constructible_with_single_brace_impl
690 {
691 template <typename T> T create();
692 #ifdef Vc_ICC
693 template <typename Class, typename... Args> char test(int);
694 #elif defined Vc_CLANG || defined Vc_APPLECLANG
695 template <typename Class, typename... Args, typename = decltype(Class{create<Args>()...})>
696 char test(int);
697 #else
698 template <typename Class, typename... Args>
699 typename std::conditional<
700 #ifndef Vc_ICC
701  0 !=
702 #endif
703  sizeof(Class{create<Args>()...}),
704  char, char>::type
705 test(int);
706 #endif
707 template <typename Class, typename... Args> double test(...);
708 } // namespace is_constructible_with_single_brace_impl
709 
710 template <typename Class, typename... Args>
711 struct is_constructible_with_single_brace
712  : public std::integral_constant<
713  bool,
714  1 == sizeof(is_constructible_with_single_brace_impl::test<Class, Args...>(1))> {
715 };
716 #ifndef Vc_ICC
717 static_assert(
718  !is_constructible_with_single_brace<int, std::tuple<int, int, int>>::value,
719  "is_constructible_with_single_brace<int> does not work as expected");
720 #endif
721 static_assert(
722  is_constructible_with_single_brace<std::tuple<int, int, int>, int, int, int>::value,
723  "is_constructible_with_single_brace<tuple> does not work as expected");
724 static_assert(
725  is_constructible_with_single_brace<std::array<int, 3>, int, int, int>::value,
726  "is_constructible_with_single_brace<array> does not work as expected");
727 
728 namespace is_constructible_with_double_brace_impl
729 {
730 template <typename T> T create();
731 #if defined Vc_CLANG || defined Vc_APPLECLANG
732 template <typename Class, typename... Args,
733  typename = decltype(Class{{create<Args>()...}})>
734 char test(int);
735 #else
736 template <typename Class, typename... Args>
737 typename std::conditional<
738 #ifndef Vc_ICC
739  0 !=
740 #endif
741  sizeof(Class{{create<Args>()...}}),
742  char, char>::type
743 test(int);
744 #endif
745 template <typename Class, typename... Args> double test(...);
746 } // namespace is_constructible_with_double_brace_impl
747 
748 template <typename Class, typename... Args>
749 struct is_constructible_with_double_brace
750  : public std::integral_constant<
751  bool,
752  1 == sizeof(is_constructible_with_double_brace_impl::test<Class, Args...>(1))> {
753 };
754 #if !(defined Vc_CLANG || defined Vc_APPLECLANG)
755 // clang allows int{{1}} but warns that it's wrong. Thus the assertion fails. If I expect
756 // the incorrect answer from clang, the assertion won't fail, but the compiler warns about
757 // the trait invocation. Annoying feature...
758 static_assert(
759  !is_constructible_with_double_brace<int, int>::value,
760  "is_constructible_with_double_brace<int> does not work as expected");
761 #endif
762 static_assert(
763  !is_constructible_with_double_brace<std::tuple<int, int, int>, int, int, int>::value,
764  "is_constructible_with_double_brace<tuple> does not work as expected");
765 static_assert(is_constructible_with_double_brace<std::array<int, 3>, int, int, int>::value,
766  "is_constructible_with_double_brace<array> does not work as expected");
767 
768 template <size_t I, typename T,
769  typename R = decltype(std::declval<T &>().template vc_get_<I>())>
770 R get_dispatcher(T &x, void * = nullptr)
771 {
772  return x.template vc_get_<I>();
773 }
774 template <size_t I, typename T,
775  typename R = decltype(std::declval<const T &>().template vc_get_<I>())>
776 R get_dispatcher(const T &x, void * = nullptr)
777 {
778  return x.template vc_get_<I>();
779 }
780 template <size_t I, typename T, typename R = decltype(std::get<I>(std::declval<T &>()))>
781 R get_dispatcher(T &x, int = 0)
782 {
783  return std::get<I>(x);
784 }
785 template <size_t I, typename T,
786  typename R = decltype(std::get<I>(std::declval<const T &>()))>
787 R get_dispatcher(const T &x, int = 0)
788 {
789  return std::get<I>(x);
790 }
791 
792 
793 // see above
794 template <typename Scalar, typename Base, size_t N> class Adapter : public Base
795 {
796 private:
798  template <std::size_t... Indexes, typename T>
799  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_, T, std::true_type)
800  : Base{{get_dispatcher<Indexes>(x_)...}}
801  {
802  }
803 
805  template <std::size_t... Indexes>
806  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_, std::false_type,
807  std::false_type)
808  : Base{get_dispatcher<Indexes>(x_)...}
809  {
810  }
811 
813  template <std::size_t... Indexes>
814  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_, std::true_type,
815  std::false_type)
816  : Base(get_dispatcher<Indexes>(x_)...)
817  {
818  }
819 
820  template <std::size_t... Indexes>
821  Adapter(Vc::index_sequence<Indexes...> seq_, const Scalar &x_)
822  : Adapter(seq_, x_,
823  std::integral_constant<
824  bool, is_constructible_with_single_paren<
825  Base, decltype(get_dispatcher<Indexes>(
826  std::declval<const Scalar &>()))...>::value>(),
827  std::integral_constant<
828  bool, is_constructible_with_double_brace<
829  Base, decltype(get_dispatcher<Indexes>(
830  std::declval<const Scalar &>()))...>::value>())
831  {
832  }
833 
834 public:
836  static constexpr size_t size() { return N; }
837  static constexpr size_t Size = N;
838 
840  using base_type = Base;
843  using scalar_type = Scalar;
844 
847  Adapter() = default;
848 
850 #if defined Vc_CLANG && Vc_CLANG < 0x30700
851  Vc_INTRINSIC Adapter(const Adapter &x) : Base(x) {}
852 #else
853  Adapter(const Adapter &) = default;
854 #endif
855  Adapter(Adapter &&) = default;
858  Adapter &operator=(const Adapter &) = default;
860  Adapter &operator=(Adapter &&) = default;
861 
863  template <typename U, size_t TupleSize = determine_tuple_size_<Scalar>::value,
864  typename Seq = Vc::make_index_sequence<TupleSize>,
865  typename = enable_if<std::is_convertible<U, Scalar>::value>>
866  Adapter(U &&x_)
867  : Adapter(Seq(), static_cast<const Scalar &>(x_))
868  {
869  }
870 
872  template <typename A0, typename... Args,
873  typename = typename std::enable_if<
874  !Traits::is_index_sequence<A0>::value &&
875  (sizeof...(Args) > 0 || !std::is_convertible<A0, Scalar>::value)>::type>
876  Adapter(A0 &&arg0_, Args &&... arguments_)
877  : Base(std::forward<A0>(arg0_), std::forward<Args>(arguments_)...)
878  {
879  }
880 
882  template <typename T,
883  typename = decltype(Base(std::declval<const std::initializer_list<T> &>()))>
884  Adapter(const std::initializer_list<T> &l_)
885  : Base(l_)
886  {
887  }
888 
891  void *operator new(size_t size)
892  {
893  return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
894  }
895  void *operator new(size_t, void *p_) { return p_; }
896  void *operator new[](size_t size)
897  {
898  return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
899  }
900  void *operator new[](size_t , void *p_) { return p_; }
901  void operator delete(void *ptr_, size_t) { Vc::Common::free(ptr_); }
902  void operator delete(void *, void *) {}
903  void operator delete[](void *ptr_, size_t) { Vc::Common::free(ptr_); }
904  void operator delete[](void *, void *) {}
905 };
906 
911 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
912 inline void operator==(
913  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
914  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
915 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
916 inline void operator!=(
917  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
918  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
919 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
920 inline void operator<=(
921  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
922  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
923 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
924 inline void operator>=(
925  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
926  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
927 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
928 inline void operator<(
929  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
930  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
931 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
932 inline void operator>(
933  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
934  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
935 
937 } // namespace SimdizeDetail
938 } // namespace Vc
939 
940 namespace std
941 {
945 template <typename Scalar, typename Base, size_t N>
946 class tuple_size<Vc::SimdizeDetail::Adapter<Scalar, Base, N>> : public tuple_size<Base>
947 {
948 };
952 template <size_t I, typename Scalar, typename Base, size_t N>
953 class tuple_element<I, Vc::SimdizeDetail::Adapter<Scalar, Base, N>>
954  : public tuple_element<I, Base>
955 {
956 };
957 // std::get does not need additional work because Vc::Adapter derives from
958 // C<Ts...> and therefore if get<N>(C<Ts...>) works it works for Adapter as well.
959 
964 template <typename S, typename T, size_t N>
965 class allocator<Vc::SimdizeDetail::Adapter<S, T, N>>
966  : public Vc::Allocator<Vc::SimdizeDetail::Adapter<S, T, N>>
967 {
968 public:
969  template <typename U> struct rebind
970  {
971  typedef std::allocator<U> other;
972  };
973 };
974 } // namespace std
975 
976 namespace Vc_VERSIONED_NAMESPACE
977 {
978 namespace SimdizeDetail
979 {
988 template <typename T> static inline T decay_workaround(const T &x) { return x; }
989 
993 template <typename S, typename T, size_t N, size_t... Indexes>
994 inline void assign_impl(Adapter<S, T, N> &a, size_t i, const S &x,
995  Vc::index_sequence<Indexes...>)
996 {
997  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(x)))...> tmp(
998  decay_workaround(get_dispatcher<Indexes>(x))...);
999  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(tmp), 0)...};
1000  if (&unused == &unused) {}
1001 }
1002 
1007 template <typename S, typename T, size_t N>
1008 inline void assign(Adapter<S, T, N> &a, size_t i, const S &x)
1009 {
1010  assign_impl(a, i, x, Vc::make_index_sequence<determine_tuple_size<T>()>());
1011 }
1015 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
1016 Vc_INTRINSIC void assign(V &v, size_t i, typename V::EntryType x)
1017 {
1018  v[i] = x;
1019 }
1020 
1024 template <typename S, typename T, size_t N, size_t... Indexes>
1025 inline S extract_impl(const Adapter<S, T, N> &a, size_t i, Vc::index_sequence<Indexes...>)
1026 {
1027  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[i]))...> tmp(
1028  decay_workaround(get_dispatcher<Indexes>(a)[i])...);
1029  return S(get_dispatcher<Indexes>(tmp)...);
1030 }
1031 
1036 template <typename S, typename T, size_t N>
1037 inline S extract(const Adapter<S, T, N> &a, size_t i)
1038 {
1039  return extract_impl(a, i, Vc::make_index_sequence<determine_tuple_size<S>()>());
1040 }
1044 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
1045 Vc_INTRINSIC typename V::EntryType extract(const V &v, size_t i)
1046 {
1047  return v[i];
1048 }
1049 
1050 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1051 inline Adapter<S, T, N> shifted_impl(const Adapter<S, T, N> &a, int shift,
1052  Vc::index_sequence<Indexes...>)
1053 {
1054  Adapter<S, T, N> r;
1055  auto &&unused = {(get_dispatcher<Indexes>(r) = get_dispatcher<Indexes>(a).shifted(shift), 0)...};
1056  if (&unused == &unused) {}
1057  return r;
1058 }
1059 
1068 template <typename S, typename T, size_t N>
1069 inline Adapter<S, T, N> shifted(const Adapter<S, T, N> &a, int shift)
1070 {
1071  return shifted_impl(a, shift, Vc::make_index_sequence<determine_tuple_size<T>()>());
1072 }
1073 
1077 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1078 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, S &x,
1079  Vc::index_sequence<Indexes...>)
1080 {
1081  const auto &a_const = a;
1082  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a_const)[0]))...>
1083  tmp{decay_workaround(get_dispatcher<Indexes>(a_const)[i])...};
1084  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(x), 0)...};
1085  auto &&unused2 = {(get_dispatcher<Indexes>(x) = get_dispatcher<Indexes>(tmp), 0)...};
1086  if (&unused == &unused2) {}
1087 }
1088 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1089 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b,
1090  std::size_t j, Vc::index_sequence<Indexes...>)
1091 {
1092  const auto &a_const = a;
1093  const auto &b_const = b;
1094  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a_const)[0]))...>
1095  tmp{decay_workaround(get_dispatcher<Indexes>(a_const)[i])...};
1096  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(b_const)[j], 0)...};
1097  auto &&unused2 = {(get_dispatcher<Indexes>(b)[j] = get_dispatcher<Indexes>(tmp), 0)...};
1098  if (&unused == &unused2) {}
1099 }
1100 
1105 template <typename S, typename T, std::size_t N>
1106 inline void swap(Adapter<S, T, N> &a, std::size_t i, S &x)
1107 {
1108  swap_impl(a, i, x, Vc::make_index_sequence<determine_tuple_size<T>()>());
1109 }
1110 template <typename S, typename T, std::size_t N>
1111 inline void swap(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b, std::size_t j)
1112 {
1113  swap_impl(a, i, b, j, Vc::make_index_sequence<determine_tuple_size<T>()>());
1114 }
1115 
1116 template <typename A> class Scalar
1117 {
1118  using reference = typename std::add_lvalue_reference<A>::type;
1119  using S = typename A::scalar_type;
1120  using IndexSeq = Vc::make_index_sequence<determine_tuple_size<S>()>;
1121 
1122 public:
1123  Scalar(reference aa, size_t ii) : a(aa), i(ii) {}
1124 
1125  // delete copy and move to keep the type a pure proxy temporary object.
1126  Scalar(const Scalar &) = delete;
1127  Scalar(Scalar &&) = delete;
1128  Scalar &operator=(const Scalar &) = delete;
1129  Scalar &operator=(Scalar &&) = delete;
1130 
1131  void operator=(const S &x) { assign_impl(a, i, x, IndexSeq()); }
1132  operator S() const { return extract_impl(a, i, IndexSeq()); }
1133 
1134  template <typename AA>
1135  friend inline void swap(Scalar<AA> &&a, typename AA::scalar_type &b);
1136  template <typename AA>
1137  friend inline void swap(typename AA::scalar_type &b, Scalar<AA> &&a);
1138  template <typename AA> friend inline void swap(Scalar<AA> &&a, Scalar<AA> &&b);
1139 
1140 private:
1141  reference a;
1142  size_t i;
1143 };
1144 
1147 template <typename A> inline void swap(Scalar<A> &&a, typename A::scalar_type &b)
1148 {
1149  swap_impl(a.a, a.i, b, typename Scalar<A>::IndexSeq());
1150 }
1153 template <typename A> inline void swap(typename A::scalar_type &b, Scalar<A> &&a)
1154 {
1155  swap_impl(a.a, a.i, b, typename Scalar<A>::IndexSeq());
1156 }
1157 
1158 template <typename A> inline void swap(Scalar<A> &&a, Scalar<A> &&b)
1159 {
1160  swap_impl(a.a, a.i, b.a, b.i, typename Scalar<A>::IndexSeq());
1161 }
1162 
1163 template <typename A> class Interface
1164 {
1165  using reference = typename std::add_lvalue_reference<A>::type;
1166  using IndexSeq =
1167  Vc::make_index_sequence<determine_tuple_size<typename A::scalar_type>()>;
1168 
1169 public:
1170  Interface(reference aa) : a(aa) {}
1171 
1172  Scalar<A> operator[](size_t i)
1173  {
1174  return {a, i};
1175  }
1176  typename A::scalar_type operator[](size_t i) const
1177  {
1178  return extract_impl(a, i, IndexSeq());
1179  }
1180 
1181  A shifted(int amount) const
1182  {
1183  return shifted_impl(a, amount, IndexSeq());
1184  }
1185 
1186 private:
1187  reference a;
1188 };
1189 
1190 template <typename S, typename T, size_t N>
1191 Interface<Adapter<S, T, N>> decorate(Adapter<S, T, N> &a)
1192 {
1193  return {a};
1194 }
1195 template <typename S, typename T, size_t N>
1196 const Interface<const Adapter<S, T, N>> decorate(const Adapter<S, T, N> &a)
1197 {
1198  return {a};
1199 }
1200 
1201 namespace IteratorDetails
1202 {
1203 enum class Mutable { Yes, No };
1204 
1205 template <typename It, typename V, size_t I, size_t End>
1206 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I == End), It>)
1207 {
1208  return {};
1209 }
1210 template <typename It, typename V, size_t I, size_t End>
1211 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I < End), It> it)
1212 {
1213  V r = fromIteratorImpl<It, V, I + 1, End>(it);
1214  Traits::decay<decltype(get_dispatcher<I>(r))> tmp;
1215  for (size_t j = 0; j < V::size(); ++j, ++it) {
1216  tmp[j] = get_dispatcher<I>(*it);
1217  }
1218  get_dispatcher<I>(r) = tmp;
1219  return r;
1220 }
1221 template <typename It, typename V>
1222 Vc_INTRINSIC V fromIterator(enable_if<!Traits::is_simd_vector<V>::value, const It &> it)
1223 {
1224  return fromIteratorImpl<It, V, 0, determine_tuple_size<V>()>(it);
1225 }
1226 template <typename It, typename V>
1227 Vc_INTRINSIC V fromIterator(enable_if<Traits::is_simd_vector<V>::value, It> it)
1228 {
1229  V r;
1230  for (size_t j = 0; j < V::size(); ++j, ++it) {
1231  r[j] = *it;
1232  }
1233  return r;
1234 }
1235 
1236 // Note: §13.5.6 says: “An expression x->m is interpreted as (x.operator->())->m for a
1237 // class object x of type T if T::operator->() exists and if the operator is selected as
1238 // the best match function by the overload resolution mechanism (13.3).”
1239 template <typename T, typename value_vector, Mutable> class Pointer;
1240 
1249 template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::Yes>
1250 {
1251  static constexpr auto Size = value_vector::size();
1252 
1253 public:
1255  value_vector *operator->() { return &data; }
1256 
1261  Pointer() = delete;
1262  Pointer(const Pointer &) = delete;
1263  Pointer &operator=(const Pointer &) = delete;
1264  Pointer &operator=(Pointer &&) = delete;
1265 
1267  Pointer(Pointer &&) = default;
1268 
1274  ~Pointer()
1275  {
1276  // store data back to where it came from
1277  for (size_t i = 0; i < Size; ++i, ++begin_iterator) {
1278  *begin_iterator = extract(data, i);
1279  }
1280  }
1281 
1283  Pointer(const T &it) : data(fromIterator<T, value_vector>(it)), begin_iterator(it) {}
1284 
1285 private:
1287  value_vector data;
1289  T begin_iterator;
1290 };
1296 template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::No>
1297 {
1298  static constexpr auto Size = value_vector::size();
1299 
1300 public:
1301  const value_vector *operator->() const { return &data; }
1302 
1303  Pointer() = delete;
1304  Pointer(const Pointer &) = delete;
1305  Pointer &operator=(const Pointer &) = delete;
1306  Pointer &operator=(Pointer &&) = delete;
1307 
1308  Pointer(Pointer &&) = default; // required for returning the Pointer
1309 
1310  Pointer(const T &it) : data(fromIterator<T, value_vector>(it)) {}
1311 
1312 private:
1313  value_vector data;
1314 };
1315 
1328 template <typename T, typename value_vector, Mutable M> class Reference;
1329 
1331 template <typename T, typename value_vector>
1332 class Reference<T, value_vector, Mutable::Yes> : public value_vector
1333 {
1334  static constexpr auto Size = value_vector::size();
1335 
1336  using reference = typename std::add_lvalue_reference<T>::type;
1337  reference scalar_it;
1338 
1339 public:
1342  Reference(reference first_it)
1343  : value_vector(fromIterator<T, value_vector>(first_it)), scalar_it(first_it)
1344  {
1345  }
1346 
1348  Reference(const Reference &) = delete;
1349  Reference(Reference &&) = default;
1350  Reference &operator=(const Reference &) = delete;
1351  Reference &operator=(Reference &&) = delete;
1352 
1358  void operator=(const value_vector &x)
1359  {
1360  static_cast<value_vector &>(*this) = x;
1361  auto it = scalar_it;
1362  for (size_t i = 0; i < Size; ++i, ++it) {
1363  *it = extract(x, i);
1364  }
1365  }
1366 };
1367 #define Vc_OP(op_) \
1368  template <typename T0, typename V0, typename T1, typename V1> \
1369  decltype(std::declval<const V0 &>() op_ std::declval<const V1 &>()) operator op_( \
1370  const Reference<T0, V0, Mutable::Yes> &x, \
1371  const Reference<T1, V1, Mutable::Yes> &y) \
1372  { \
1373  return static_cast<const V0 &>(x) op_ static_cast<const V1 &>(y); \
1374  }
1375 Vc_ALL_COMPARES(Vc_OP);
1376 Vc_ALL_ARITHMETICS(Vc_OP);
1377 Vc_ALL_BINARY(Vc_OP);
1378 Vc_ALL_LOGICAL(Vc_OP);
1379 Vc_ALL_SHIFTS(Vc_OP);
1380 #undef Vc_OP
1381 
1383 template <typename T, typename value_vector>
1384 class Reference<T, value_vector, Mutable::No> : public value_vector
1385 {
1386  static constexpr auto Size = value_vector::size();
1387 
1388 public:
1389  Reference(const T &it) : value_vector(fromIterator<T, value_vector>(it)) {}
1390 
1391  Reference(const Reference &) = delete;
1392  Reference(Reference &&) = default;
1393  Reference &operator=(const Reference &) = delete;
1394  Reference &operator=(Reference &&) = delete;
1395 
1397  void operator=(const value_vector &x) = delete;
1398 };
1399 
1400 template <typename T, size_t N,
1401  IteratorDetails::Mutable M =
1402  (Traits::is_output_iterator<T>::value ? Mutable::Yes : Mutable::No),
1403  typename V = simdize<typename std::iterator_traits<T>::value_type, N>,
1404  size_t Size = V::Size,
1405  typename = typename std::iterator_traits<T>::iterator_category>
1406 class Iterator;
1407 
1408 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size_>
1409 class Iterator<T, N, M, V, Size_, std::forward_iterator_tag>
1410  : public std::iterator<typename std::iterator_traits<T>::iterator_category, V,
1411  typename std::iterator_traits<T>::difference_type,
1412  IteratorDetails::Pointer<T, V, M>,
1413  IteratorDetails::Reference<T, V, M>>
1414 {
1415 public:
1416  using pointer = IteratorDetails::Pointer<T, V, M>;
1417  using reference = IteratorDetails::Reference<T, V, M>;
1418  using const_pointer = IteratorDetails::Pointer<T, V, IteratorDetails::Mutable::No>;
1419  using const_reference =
1420  IteratorDetails::Reference<T, V, IteratorDetails::Mutable::No>;
1421 
1423  static constexpr std::size_t size() { return Size_; }
1424  static constexpr std::size_t Size = Size_;
1425 
1426  Iterator() = default;
1427 
1434  Iterator(const T &x) : scalar_it(x) {}
1438  Iterator(T &&x) : scalar_it(std::move(x)) {}
1442  Iterator &operator=(const T &x)
1443  {
1444  scalar_it = x;
1445  return *this;
1446  }
1450  Iterator &operator=(T &&x)
1451  {
1452  scalar_it = std::move(x);
1453  return *this;
1454  }
1455 
1457  Iterator(const Iterator &) = default;
1459  Iterator(Iterator &&) = default;
1461  Iterator &operator=(const Iterator &) = default;
1463  Iterator &operator=(Iterator &&) = default;
1464 
1466  Iterator &operator++()
1467  {
1468  std::advance(scalar_it, Size);
1469  return *this;
1470  }
1472  Iterator operator++(int)
1473  {
1474  Iterator copy(*this);
1475  operator++();
1476  return copy;
1477  }
1478 
1487  bool operator==(const Iterator &rhs) const
1488  {
1489 #ifndef NDEBUG
1490  if (scalar_it == rhs.scalar_it) {
1491  return true;
1492  } else {
1493  T it(scalar_it);
1494  for (size_t i = 1; i < Size; ++i) {
1495  Vc_ASSERT((++it != rhs.scalar_it));
1496  }
1497  return false;
1498  }
1499 #else
1500  return scalar_it == rhs.scalar_it;
1501 #endif
1502  }
1511  bool operator!=(const Iterator &rhs) const
1512  {
1513  return !operator==(rhs);
1514  }
1515 
1516  pointer operator->() { return scalar_it; }
1517 
1524  reference operator*() { return scalar_it; }
1525 
1526  const_pointer operator->() const { return scalar_it; }
1527 
1535  const_reference operator*() const { return scalar_it; }
1536 
1550  operator const T &() const { return scalar_it; }
1551 
1552 protected:
1553  T scalar_it;
1554 };
1555 
1560 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1561 class Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1562  : public Iterator<T, N, M, V, Size, std::forward_iterator_tag>
1563 {
1564  using Base = Iterator<T, N, M, V, Size, std::forward_iterator_tag>;
1565 
1566 protected:
1567  using Base::scalar_it;
1568 
1569 public:
1570  using pointer = typename Base::pointer;
1571  using reference = typename Base::reference;
1572  using const_pointer = typename Base::const_pointer;
1573  using const_reference = typename Base::const_reference;
1574 
1575  using Iterator<T, N, M, V, Size,
1576  std::forward_iterator_tag>::Iterator; // in short: "using
1577  // Base::Iterator", but that
1578  // confuses ICC
1580  Iterator &operator--()
1581  {
1582  std::advance(scalar_it, -Size);
1583  return *this;
1584  }
1586  Iterator operator--(int)
1587  {
1588  Iterator copy(*this);
1589  operator--();
1590  return copy;
1591  }
1592 };
1593 
1598 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1599 class Iterator<T, N, M, V, Size, std::random_access_iterator_tag>
1600  : public Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1601 {
1603 
1604 protected:
1605  using Base::scalar_it;
1606 
1607 public:
1608  using pointer = typename Base::pointer;
1609  using reference = typename Base::reference;
1610  using const_pointer = typename Base::const_pointer;
1611  using const_reference = typename Base::const_reference;
1612  using difference_type = typename std::iterator_traits<T>::difference_type;
1613 
1615  Iterator; // in short: "using Base::Iterator", but that confuses ICC
1616 
1617  Iterator &operator+=(difference_type n)
1618  {
1619  scalar_it += n * difference_type(Size);
1620  return *this;
1621  }
1622  Iterator operator+(difference_type n) const { return Iterator(*this) += n; }
1623 
1624  Iterator &operator-=(difference_type n)
1625  {
1626  scalar_it -= n * difference_type(Size);
1627  return *this;
1628  }
1629  Iterator operator-(difference_type n) const { return Iterator(*this) -= n; }
1630 
1631  difference_type operator-(const Iterator &rhs) const
1632  {
1633  constexpr difference_type n = Size;
1634  Vc_ASSERT((scalar_it - rhs.scalar_it) % n ==
1635  0); // if this fails the two iterators are not a multiple of the vector
1636  // width apart. The distance would be fractional and that doesn't
1637  // make too much sense for iteration. Therefore, it is a
1638  // precondition for the distance of the two iterators to be a
1639  // multiple of Size.
1640  return (scalar_it - rhs.scalar_it) / n;
1641  }
1642 
1647  bool operator<(const Iterator &rhs) const
1648  {
1649  return rhs.scalar_it - scalar_it >= difference_type(Size);
1650  }
1651 
1652  bool operator>(const Iterator &rhs) const
1653  {
1654  return scalar_it - rhs.scalar_it >= difference_type(Size);
1655  }
1656 
1657  bool operator<=(const Iterator &rhs) const
1658  {
1659  return rhs.scalar_it - scalar_it >= difference_type(Size) - 1;
1660  }
1661 
1662  bool operator>=(const Iterator &rhs) const
1663  {
1664  return scalar_it - rhs.scalar_it >= difference_type(Size) - 1;
1665  }
1666 
1667  reference operator[](difference_type i) { return *(*this + i); }
1668  const_reference operator[](difference_type i) const { return *(*this + i); }
1669 };
1670 
1671 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1672 Iterator<T, N, M, V, Size, std::random_access_iterator_tag> operator+(
1673  typename Iterator<T, N, M, V, Size, std::random_access_iterator_tag>::difference_type
1674  n,
1675  const Iterator<T, N, M, V, Size, std::random_access_iterator_tag> &i)
1676 {
1677  return i + n;
1678 }
1679 
1680 } // namespace IteratorDetails
1681 
1690 template <typename T, size_t N, typename MT>
1691 struct ReplaceTypes<T, N, MT, Category::ForwardIterator>
1692 {
1693  using type = IteratorDetails::Iterator<T, N>;
1694 };
1695 template <typename T, size_t N, typename MT>
1696 struct ReplaceTypes<T, N, MT, Category::BidirectionalIterator>
1697 {
1698  using type = IteratorDetails::Iterator<T, N>;
1699 };
1700 template <typename T, size_t N, typename MT>
1701 struct ReplaceTypes<T, N, MT, Category::RandomAccessIterator>
1702 {
1703  using type = IteratorDetails::Iterator<T, N>;
1704 };
1705 
1709 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1710  std::size_t Offset>
1711 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size_<S>::value && M::Size == N), void>
1712  conditional_assign(Adapter<S, T, N> &, const M &, const U &)
1713 {
1714 }
1715 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1716  std::size_t Offset = 0>
1717 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size_<S>::value && M::Size == N), void>
1718  conditional_assign(Adapter<S, T, N> &lhs, const M &mask, const U &rhs)
1719 {
1720  using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1721  using M2 = typename V::mask_type;
1722  conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask), get_dispatcher<Offset>(rhs));
1723  conditional_assign<Op, S, T, N, M, U, Offset + 1>(lhs, mask, rhs);
1724 }
1725 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1726  std::size_t Offset>
1727 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size_<S>::value && M::Size == N), void>
1728  conditional_assign(Adapter<S, T, N> &, const M &)
1729 {
1730 }
1731 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1732  std::size_t Offset = 0>
1733 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size_<S>::value && M::Size == N), void>
1734  conditional_assign(Adapter<S, T, N> &lhs, const M &mask)
1735 {
1736  using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1737  using M2 = typename V::mask_type;
1738  conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask));
1739  conditional_assign<Op, S, T, N, M, Offset + 1>(lhs, mask);
1740 }
1741 
1743 } // namespace SimdizeDetail
1744 
1763 template <typename T, size_t N = 0, typename MT = void>
1764 using simdize = SimdizeDetail::simdize<T, N, MT>;
1765 
1785 #define Vc_SIMDIZE_INTERFACE(MEMBERS_) \
1786  template <std::size_t N_> \
1787  inline auto vc_get_()->decltype(std::get<N_>(std::tie MEMBERS_)) \
1788  { \
1789  return std::get<N_>(std::tie MEMBERS_); \
1790  } \
1791  template <std::size_t N_> \
1792  inline auto vc_get_() const->decltype(std::get<N_>(std::tie MEMBERS_)) \
1793  { \
1794  return std::get<N_>(std::tie MEMBERS_); \
1795  } \
1796  enum : std::size_t { \
1797  tuple_size = std::tuple_size<decltype(std::make_tuple MEMBERS_)>::value \
1798  }
1799 
1800 } // namespace Vc
1801 
1802 namespace std
1803 {
1804 using Vc::SimdizeDetail::swap;
1805 } // namespace std
1806 
1807 #endif // VC_COMMON_SIMDIZE_H_
1808 
1809 // 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:1647
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:1764
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:1037
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:1008
Iterator & operator--()
Advances the iterator by one vector width, or respectively N scalar steps.
Definition: simdize.h:1580
Adapter< S, T, N > shifted(const Adapter< S, T, N > &a, int shift)
Returns a new vectorized object where each entry is shifted by shift.
Definition: simdize.h:1069
Vector Classes Namespace.
Definition: cpuid.h:32
This is the iterator type created when applying simdize to a bidirectional iterator type...
Definition: simdize.h:1561