Vc  1.2.0
SIMD Vector Classes for C++
simdize.h
1 /* This file is part of the Vc library. {{{
2 Copyright © 2014-2015 Matthias Kretz <kretz@kde.org>
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7  * Redistributions of source code must retain the above copyright
8  notice, this list of conditions and the following disclaimer.
9  * Redistributions in binary form must reproduce the above copyright
10  notice, this list of conditions and the following disclaimer in the
11  documentation and/or other materials provided with the distribution.
12  * Neither the names of contributing organizations nor the
13  names of its contributors may be used to endorse or promote products
14  derived from this software without specific prior written permission.
15 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 }}}*/
28 
29 #ifndef VC_COMMON_SIMDIZE_H_
30 #define VC_COMMON_SIMDIZE_H_
31 
32 #include <tuple>
33 #include <array>
34 
35 #include "macros.h"
36 
90 namespace Vc_VERSIONED_NAMESPACE
91 {
98 namespace SimdizeDetail
99 {
104 using std::is_same;
105 using std::is_base_of;
106 using std::false_type;
107 using std::true_type;
108 using std::iterator_traits;
109 using std::conditional;
110 using std::size_t;
111 template <bool B, typename T, typename F>
112 using conditional_t = typename conditional<B, T, F>::type;
113 
118 template <typename... Ts> struct Typelist;
119 
123 enum class Category {
125  None,
127  ArithmeticVectorizable,
129  InputIterator,
131  OutputIterator,
133  ForwardIterator,
135  BidirectionalIterator,
137  RandomAccessIterator,
139  ClassTemplate
140 };
141 
146 template <typename T,
147  typename ItCat = typename iterator_traits<T>::iterator_category>
148 constexpr Category iteratorCategories(int)
149 {
150  return is_base_of<std::random_access_iterator_tag, ItCat>::value
151  ? Category::RandomAccessIterator
152  : is_base_of<std::bidirectional_iterator_tag, ItCat>::value
153  ? Category::BidirectionalIterator
154  : is_base_of<std::forward_iterator_tag, ItCat>::value
155  ? Category::ForwardIterator
156  : is_base_of<std::output_iterator_tag, ItCat>::value
157  ? Category::OutputIterator
158  : is_base_of<std::input_iterator_tag, ItCat>::value
159  ? Category::InputIterator
160  : Category::None;
161 }
165 template <typename T> constexpr Category iteratorCategories(...)
166 {
167  return Category::None;
168 }
169 
173 template <typename T> struct is_class_template : public false_type
174 {
175 };
176 template <template <typename...> class C, typename... Ts>
177 struct is_class_template<C<Ts...>> : public true_type
178 {
179 };
180 
184 template <typename T> constexpr Category typeCategory()
185 {
186  return (is_same<T, bool>::value || is_same<T, short>::value ||
187  is_same<T, unsigned short>::value || is_same<T, int>::value ||
188  is_same<T, unsigned int>::value || is_same<T, float>::value ||
189  is_same<T, double>::value)
190  ? Category::ArithmeticVectorizable
191  : iteratorCategories<T>(int()) != Category::None
192  ? iteratorCategories<T>(int())
193  : is_class_template<T>::value ? Category::ClassTemplate
194  : Category::None;
195 }
196 
202 template <typename T, size_t TupleSize = std::tuple_size<T>::value>
203 constexpr size_t determine_tuple_size()
204 {
205  return TupleSize;
206 }
207 template <typename T, size_t TupleSize = T::tuple_size>
208 constexpr size_t determine_tuple_size(size_t = T::tuple_size)
209 {
210  return TupleSize;
211 }
212 
213 namespace
214 {
215 template <typename T> struct The_simdization_for_the_requested_type_is_not_implemented;
216 } // unnamed namespace
217 
230 template <typename T, size_t N, typename MT, Category = typeCategory<T>()>
231 struct ReplaceTypes : public The_simdization_for_the_requested_type_is_not_implemented<T>
232 {
233 };
234 
239 template <typename T, size_t N, typename MT> struct ReplaceTypes<T, N, MT, Category::None>
240 {
241  typedef T type;
242 };
243 
248 template <typename T, size_t N = 0, typename MT = void>
249 using simdize = typename SimdizeDetail::ReplaceTypes<T, N, MT>::type;
250 
255 template <typename T, size_t N, typename MT>
256 struct ReplaceTypes<T, N, MT, Category::ArithmeticVectorizable>
257  : public conditional<(N == 0 || Vector<T>::size() == N), Vector<T>, SimdArray<T, N>>
258 {
259 };
260 
265 template <size_t N, typename MT>
266 struct ReplaceTypes<bool, N, MT, Category::ArithmeticVectorizable>
267  : public conditional<(N == 0 || Mask<MT>::size() == N), Mask<MT>,
268  SimdMaskArray<MT, N>>
269 {
270 };
274 template <size_t N>
275 struct ReplaceTypes<bool, N, void, Category::ArithmeticVectorizable>
276  : public ReplaceTypes<bool, N, float, Category::ArithmeticVectorizable>
277 {
278 };
279 
286 template <size_t N, typename MT, typename Replaced, typename... Remaining>
287 struct SubstituteOneByOne;
288 
293 template <size_t N, typename MT, typename... Replaced, typename T,
294  typename... Remaining>
295 struct SubstituteOneByOne<N, MT, Typelist<Replaced...>, T, Remaining...>
296 {
297 private:
302  template <typename U, size_t M = U::size()>
303  static std::integral_constant<size_t, M> size_or_0(int);
304  template <typename U> static std::integral_constant<size_t, 0> size_or_0(...);
305 
307  using V = simdize<T, N, MT>;
308 
313  static constexpr auto NewN = N != 0 ? N : decltype(size_or_0<V>(int()))::value;
314 
320  typedef conditional_t<(N != NewN && is_same<MT, void>::value),
321  conditional_t<is_same<T, bool>::value, float, T>, MT> NewMT;
322 
323 public:
327  using type = typename SubstituteOneByOne<NewN, NewMT, Typelist<Replaced..., V>,
328  Remaining...>::type;
329 };
330 
333 template <size_t Size, typename... Replaced> struct SubstitutedBase;
335 template <typename Replaced> struct SubstitutedBase<1, Replaced> {
336  template <typename ValueT, template <typename, ValueT...> class C, ValueT... Values>
337  using SubstitutedWithValues = C<Replaced, Values...>;
338 };
340 template <typename R0, typename R1> struct SubstitutedBase<2, R0, R1>
341 {
342  template <typename ValueT, template <typename, typename, ValueT...> class C,
343  ValueT... Values>
344  using SubstitutedWithValues = C<R0, R1, Values...>;
345 };
347 template <typename R0, typename R1, typename R2> struct SubstitutedBase<3, R0, R1, R2>
348 {
349  template <typename ValueT, template <typename, typename, typename, ValueT...> class C,
350  ValueT... Values>
351  using SubstitutedWithValues = C<R0, R1, R2, Values...>;
352 };
354 template <typename... Replaced> struct SubstitutedBase<4, Replaced...> {
355 #ifndef Vc_ICC
356  template <typename ValueT,
357  template <typename, typename, typename, typename, ValueT...> class C,
358  ValueT... Values>
359  using SubstitutedWithValues = C<Replaced..., Values...>;
360 #endif // Vc_ICC
361 };
363 template <typename... Replaced> struct SubstitutedBase<5, Replaced...> {
364 #ifndef Vc_ICC
365  template <typename ValueT, template <typename, typename, typename, typename, typename,
366  ValueT...> class C,
367  ValueT... Values>
368  using SubstitutedWithValues = C<Replaced..., Values...>;
369 #endif // Vc_ICC
370 };
372 template <typename... Replaced> struct SubstitutedBase<6, Replaced...> {
373 #ifndef Vc_ICC
374  template <typename ValueT, template <typename, typename, typename, typename, typename,
375  typename, ValueT...> class C,
376  ValueT... Values>
377  using SubstitutedWithValues = C<Replaced..., Values...>;
378 #endif // Vc_ICC
379 };
381 template <typename... Replaced> struct SubstitutedBase<7, Replaced...> {
382 #ifndef Vc_ICC
383  template <typename ValueT, template <typename, typename, typename, typename, typename,
384  typename, typename, ValueT...> class C,
385  ValueT... Values>
386  using SubstitutedWithValues = C<Replaced..., Values...>;
387 #endif // Vc_ICC
388 };
390 template <typename... Replaced> struct SubstitutedBase<8, Replaced...> {
391 #ifndef Vc_ICC
392  template <typename ValueT, template <typename, typename, typename, typename, typename,
393  typename, typename, typename, ValueT...> class C,
394  ValueT... Values>
395  using SubstitutedWithValues = C<Replaced..., Values...>;
396 #endif // Vc_ICC
397 };
398 
404 template <size_t N_, typename MT, typename Replaced0, typename... Replaced>
405 struct SubstituteOneByOne<N_, MT, Typelist<Replaced0, Replaced...>>
406 {
410  struct type
411  : public SubstitutedBase<sizeof...(Replaced) + 1, Replaced0, Replaced...> {
412  static constexpr auto N = N_;
417  template <template <typename...> class C>
418  using Substituted = C<Replaced0, Replaced...>;
419  };
420 };
421 
438 template <typename Scalar, typename Base, size_t N> class Adapter;
439 
444 template <template <typename...> class C, typename... Ts, size_t N, typename MT>
445 struct ReplaceTypes<C<Ts...>, N, MT, Category::ClassTemplate>
446 {
448  using SubstitutionResult =
449  typename SubstituteOneByOne<N, MT, Typelist<>, Ts...>::type;
455  using Vectorized = typename SubstitutionResult::template Substituted<C>;
461  using type = conditional_t<is_same<C<Ts...>, Vectorized>::value, C<Ts...>,
462  Adapter<C<Ts...>, Vectorized, SubstitutionResult::N>>;
463 };
464 
470 #ifdef Vc_ICC
471 // ICC barfs on packs of values
472 #define Vc_DEFINE_NONTYPE_REPLACETYPES_(ValueType_) \
473  template <template <typename, ValueType_...> class C, typename T, ValueType_ Value0, \
474  ValueType_... Values> \
475  struct is_class_template<C<T, Value0, Values...>> : public true_type { \
476  }; \
477  template <template <typename, typename, ValueType_...> class C, typename T0, \
478  typename T1, ValueType_ Value0, ValueType_... Values> \
479  struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type { \
480  }; \
481  template <template <typename, typename, typename, ValueType_...> class C, \
482  typename T0, typename T1, typename T2, ValueType_ Value0, \
483  ValueType_... Values> \
484  struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type { \
485  }; \
486  template <template <typename, typename, typename, typename, ValueType_...> class C, \
487  typename T0, typename T1, typename T2, typename T3, ValueType_ Value0, \
488  ValueType_... Values> \
489  struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type { \
490  }; \
491  template <template <typename, typename, typename, typename, typename, ValueType_...> \
492  class C, \
493  typename T0, typename T1, typename T2, typename T3, typename T4, \
494  ValueType_ Value0, ValueType_... Values> \
495  struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
496  : public true_type { \
497  }; \
498  template <template <typename, typename, typename, typename, typename, typename, \
499  ValueType_...> class C, \
500  typename T0, typename T1, typename T2, typename T3, typename T4, \
501  typename T5, ValueType_ Value0, ValueType_... Values> \
502  struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
503  : public true_type { \
504  }; \
505  template <template <typename, typename, typename, typename, typename, typename, \
506  typename, ValueType_...> class C, \
507  typename T0, typename T1, typename T2, typename T3, typename T4, \
508  typename T5, typename T6, ValueType_ Value0, ValueType_... Values> \
509  struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
510  : public true_type { \
511  }; \
512  template <template <typename, ValueType_> class C, typename T0, ValueType_ Value0, \
513  size_t N, typename MT> \
514  struct ReplaceTypes<C<T0, Value0>, N, MT, Category::ClassTemplate> { \
515  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
516  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
517  Substituted; \
518  static constexpr auto NN = tmp::N; \
519  typedef conditional_t<is_same<C<T0, Value0>, Substituted>::value, C<T0, Value0>, \
520  Adapter<C<T0, Value0>, Substituted, NN>> type; \
521  }; \
522  template <template <typename, typename, ValueType_> class C, typename T0, \
523  typename T1, ValueType_ Value0, size_t N, typename MT> \
524  struct ReplaceTypes<C<T0, T1, Value0>, N, MT, Category::ClassTemplate> { \
525  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
526  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
527  Substituted; \
528  static constexpr auto NN = tmp::N; \
529  typedef conditional_t<is_same<C<T0, T1, Value0>, Substituted>::value, \
530  C<T0, T1, Value0>, \
531  Adapter<C<T0, T1, Value0>, Substituted, NN>> type; \
532  }; \
533  template <template <typename, typename, typename, ValueType_> class C, typename T0, \
534  typename T1, typename T2, ValueType_ Value0, size_t N, typename MT> \
535  struct ReplaceTypes<C<T0, T1, T2, Value0>, N, MT, Category::ClassTemplate> { \
536  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
537  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
538  Substituted; \
539  static constexpr auto NN = tmp::N; \
540  typedef conditional_t<is_same<C<T0, T1, T2, Value0>, Substituted>::value, \
541  C<T0, T1, T2, Value0>, \
542  Adapter<C<T0, T1, T2, Value0>, Substituted, NN>> type; \
543  }
544 #else
545 #define Vc_DEFINE_NONTYPE_REPLACETYPES_(ValueType_) \
546  template <template <typename, ValueType_...> class C, typename T, ValueType_ Value0, \
547  ValueType_... Values> \
548  struct is_class_template<C<T, Value0, Values...>> : public true_type { \
549  }; \
550  template <template <typename, typename, ValueType_...> class C, typename T0, \
551  typename T1, ValueType_ Value0, ValueType_... Values> \
552  struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type { \
553  }; \
554  template <template <typename, typename, typename, ValueType_...> class C, \
555  typename T0, typename T1, typename T2, ValueType_ Value0, \
556  ValueType_... Values> \
557  struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type { \
558  }; \
559  template <template <typename, typename, typename, typename, ValueType_...> class C, \
560  typename T0, typename T1, typename T2, typename T3, ValueType_ Value0, \
561  ValueType_... Values> \
562  struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type { \
563  }; \
564  template <template <typename, typename, typename, typename, typename, ValueType_...> \
565  class C, \
566  typename T0, typename T1, typename T2, typename T3, typename T4, \
567  ValueType_ Value0, ValueType_... Values> \
568  struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
569  : public true_type { \
570  }; \
571  template <template <typename, typename, typename, typename, typename, typename, \
572  ValueType_...> class C, \
573  typename T0, typename T1, typename T2, typename T3, typename T4, \
574  typename T5, ValueType_ Value0, ValueType_... Values> \
575  struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
576  : public true_type { \
577  }; \
578  template <template <typename, typename, typename, typename, typename, typename, \
579  typename, ValueType_...> class C, \
580  typename T0, typename T1, typename T2, typename T3, typename T4, \
581  typename T5, typename T6, ValueType_ Value0, ValueType_... Values> \
582  struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
583  : public true_type { \
584  }; \
585  template <template <typename, ValueType_...> class C, typename T0, \
586  ValueType_ Value0, ValueType_... Values, size_t N, typename MT> \
587  struct ReplaceTypes<C<T0, Value0, Values...>, N, MT, Category::ClassTemplate> { \
588  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
589  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
590  Values...> Substituted; \
591  static constexpr auto NN = tmp::N; \
592  typedef conditional_t<is_same<C<T0, Value0, Values...>, Substituted>::value, \
593  C<T0, Value0, Values...>, \
594  Adapter<C<T0, Value0, Values...>, Substituted, NN>> type; \
595  }; \
596  template <template <typename, typename, ValueType_...> class C, typename T0, \
597  typename T1, ValueType_ Value0, ValueType_... Values, size_t N, \
598  typename MT> \
599  struct ReplaceTypes<C<T0, T1, Value0, Values...>, N, MT, Category::ClassTemplate> { \
600  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
601  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
602  Values...> Substituted; \
603  static constexpr auto NN = tmp::N; \
604  typedef conditional_t<is_same<C<T0, T1, Value0, Values...>, Substituted>::value, \
605  C<T0, T1, Value0, Values...>, \
606  Adapter<C<T0, T1, Value0, Values...>, Substituted, NN>> \
607  type; \
608  }; \
609  template <template <typename, typename, typename, ValueType_...> class C, \
610  typename T0, typename T1, typename T2, ValueType_ Value0, \
611  ValueType_... Values, size_t N, typename MT> \
612  struct ReplaceTypes<C<T0, T1, T2, Value0, Values...>, N, MT, \
613  Category::ClassTemplate> { \
614  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
615  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
616  Values...> Substituted; \
617  static constexpr auto NN = tmp::N; \
618  typedef conditional_t< \
619  is_same<C<T0, T1, T2, Value0, Values...>, Substituted>::value, \
620  C<T0, T1, T2, Value0, Values...>, \
621  Adapter<C<T0, T1, T2, Value0, Values...>, Substituted, NN>> type; \
622  }
623 #endif // Vc_ICC
624 Vc_DEFINE_NONTYPE_REPLACETYPES_(bool);
625 Vc_DEFINE_NONTYPE_REPLACETYPES_(wchar_t);
626 Vc_DEFINE_NONTYPE_REPLACETYPES_(char);
627 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed char);
628 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned char);
629 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed short);
630 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned short);
631 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed int);
632 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned int);
633 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed long);
634 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned long);
635 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed long long);
636 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned long long);
637 #undef Vc_DEFINE_NONTYPE_REPLACETYPES_
638 
639 #ifdef Vc_ICC
640 // FIXME: find a proper workaround implementation for ICC
641 template <typename Class, typename... Args>
642 constexpr bool is_constructible_with_single_brace()
643 {
644  return true;
645 }
646 template <typename Class, typename... Args>
647 constexpr bool is_constructible_with_double_brace()
648 {
649  return false;
650 }
651 #else
652 namespace is_constructible_with_single_brace_impl
653 {
654 template <typename T> T create();
655 template <typename Class, typename... Args,
656  typename = decltype((Class{create<Args>()...}))>
657 std::true_type test(int);
658 template <typename Class, typename... Args> std::false_type test(...);
659 } // namespace is_constructible_with_single_brace_impl
660 
661 template <typename Class, typename... Args>
662 constexpr bool is_constructible_with_single_brace()
663 {
664  return decltype(
665  is_constructible_with_single_brace_impl::test<Class, Args...>(1))::value;
666 }
667 static_assert(
668  is_constructible_with_single_brace<std::tuple<int, int, int>, int, int, int>(), "");
669 static_assert(is_constructible_with_single_brace<std::array<int, 3>, int, int, int>(),
670  "");
671 
672 namespace is_constructible_with_double_brace_impl
673 {
674 template <typename T> T create();
675 template <typename Class, typename... Args,
676  typename = decltype(Class{{create<Args>()...}})>
677 std::true_type test(int);
678 template <typename Class, typename... Args> std::false_type test(...);
679 } // namespace is_constructible_with_double_brace_impl
680 
681 template <typename Class, typename... Args>
682 constexpr bool is_constructible_with_double_brace()
683 {
684  return decltype(
685  is_constructible_with_double_brace_impl::test<Class, Args...>(1))::value;
686 }
687 static_assert(
688  !is_constructible_with_double_brace<std::tuple<int, int, int>, int, int, int>(), "");
689 static_assert(is_constructible_with_double_brace<std::array<int, 3>, int, int, int>(),
690  "");
691 #endif
692 
693 template <size_t I, typename T,
694  typename R = decltype(std::declval<T &>().template vc_get_<I>())>
695 R get_dispatcher(T &x, void * = nullptr)
696 {
697  return x.template vc_get_<I>();
698 }
699 template <size_t I, typename T,
700  typename R = decltype(std::declval<const T &>().template vc_get_<I>())>
701 R get_dispatcher(const T &x, void * = nullptr)
702 {
703  return x.template vc_get_<I>();
704 }
705 template <size_t I, typename T, typename R = decltype(std::get<I>(std::declval<T &>()))>
706 R get_dispatcher(T &x, int = 0)
707 {
708  return std::get<I>(x);
709 }
710 template <size_t I, typename T,
711  typename R = decltype(std::get<I>(std::declval<const T &>()))>
712 R get_dispatcher(const T &x, int = 0)
713 {
714  return std::get<I>(x);
715 }
716 
717 
718 // see above
719 template <typename Scalar, typename Base, size_t N> class Adapter : public Base
720 {
721 private:
723  template <std::size_t... Indexes, typename T>
724  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_, T, std::true_type)
725  : Base{{get_dispatcher<Indexes>(x_)...}}
726  {
727  }
728 
730  template <std::size_t... Indexes>
731  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_, std::true_type,
732  std::false_type)
733  : Base{get_dispatcher<Indexes>(x_)...}
734  {
735  }
736 
738  template <std::size_t... Indexes>
739  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_, std::false_type,
740  std::false_type)
741  : Base(get_dispatcher<Indexes>(x_)...)
742  {
743  }
744 
745  template <std::size_t... Indexes>
746  Adapter(Vc::index_sequence<Indexes...> seq_, const Scalar &x_)
747  : Adapter(seq_, x_,
748  std::integral_constant<
749  bool, is_constructible_with_single_brace<
750  Base, decltype(get_dispatcher<Indexes>(
751  std::declval<const Scalar &>()))...>()>(),
752  std::integral_constant<
753  bool, is_constructible_with_double_brace<
754  Base, decltype(get_dispatcher<Indexes>(
755  std::declval<const Scalar &>()))...>()>())
756  {
757  }
758 
759 public:
761  static constexpr size_t size() { return N; }
762 
764  using base_type = Base;
767  using scalar_type = Scalar;
768 
771  Adapter() = default;
772 
774 #if defined Vc_CLANG && Vc_CLANG < 0x30700
775  Vc_INTRINSIC Adapter(const Adapter &x) : Base(x) {}
776 #else
777  Adapter(const Adapter &) = default;
778 #endif
779  Adapter(Adapter &&) = default;
782  Adapter &operator=(const Adapter &) = default;
784  Adapter &operator=(Adapter &&) = default;
785 
787  template <typename U, size_t TupleSize = determine_tuple_size<Scalar>(),
788  typename Seq = Vc::make_index_sequence<TupleSize>,
789  typename = enable_if<std::is_convertible<U, Scalar>::value>>
790  Adapter(U &&x_)
791  : Adapter(Seq(), static_cast<const Scalar &>(x_))
792  {
793  }
794 
796  template <typename A0, typename... Args,
797  typename = typename std::enable_if<
798  !Traits::is_index_sequence<A0>::value &&
799  (sizeof...(Args) > 0 || !std::is_convertible<A0, Scalar>::value)>::type>
800  Adapter(A0 &&arg0_, Args &&... arguments_)
801  : Base(std::forward<A0>(arg0_), std::forward<Args>(arguments_)...)
802  {
803  }
804 
806  template <typename T,
807  typename = decltype(Base(std::declval<const std::initializer_list<T> &>()))>
808  Adapter(const std::initializer_list<T> &l_)
809  : Base(l_)
810  {
811  }
812 
815  void *operator new(size_t size)
816  {
817  return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
818  }
819  void *operator new(size_t, void *p_) { return p_; }
820  void *operator new[](size_t size)
821  {
822  return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
823  }
824  void *operator new[](size_t , void *p_) { return p_; }
825  void operator delete(void *ptr_, size_t) { Vc::Common::free(ptr_); }
826  void operator delete(void *, void *) {}
827  void operator delete[](void *ptr_, size_t) { Vc::Common::free(ptr_); }
828  void operator delete[](void *, void *) {}
829 };
830 
835 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
836 inline bool operator==(
837  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
838  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
839 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
840 inline bool operator!=(
841  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
842  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
843 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
844 inline bool operator<=(
845  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
846  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
847 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
848 inline bool operator>=(
849  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
850  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
851 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
852 inline bool operator<(
853  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
854  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
855 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
856 inline bool operator>(
857  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
858  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
859 
861 } // namespace SimdizeDetail
862 } // namespace Vc
863 
864 namespace std
865 {
869 template <typename Scalar, typename Base, size_t N>
870 class tuple_size<Vc::SimdizeDetail::Adapter<Scalar, Base, N>> : public tuple_size<Base>
871 {
872 };
876 template <size_t I, typename Scalar, typename Base, size_t N>
877 class tuple_element<I, Vc::SimdizeDetail::Adapter<Scalar, Base, N>>
878  : public tuple_element<I, Base>
879 {
880 };
881 // std::get does not need additional work because Vc::Adapter derives from
882 // C<Ts...> and therefore if get<N>(C<Ts...>) works it works for Adapter as well.
883 
888 template <typename S, typename T, size_t N>
889 class allocator<Vc::SimdizeDetail::Adapter<S, T, N>>
890  : public Vc::Allocator<Vc::SimdizeDetail::Adapter<S, T, N>>
891 {
892 public:
893  template <typename U> struct rebind
894  {
895  typedef std::allocator<U> other;
896  };
897 };
898 } // namespace std
899 
900 namespace Vc_VERSIONED_NAMESPACE
901 {
902 namespace SimdizeDetail
903 {
912 template <typename T> static inline T decay_workaround(const T &x) { return x; }
913 
917 template <typename S, typename T, size_t N, size_t... Indexes>
918 inline void assign_impl(Adapter<S, T, N> &a, size_t i, const S &x,
919  Vc::index_sequence<Indexes...>)
920 {
921  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(x)))...> tmp(
922  decay_workaround(get_dispatcher<Indexes>(x))...);
923  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(tmp), 0)...};
924  if (&unused == &unused) {}
925 }
926 
931 template <typename S, typename T, size_t N>
932 inline void assign(Adapter<S, T, N> &a, size_t i, const S &x)
933 {
934  assign_impl(a, i, x, Vc::make_index_sequence<determine_tuple_size<T>()>());
935 }
939 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
940 Vc_INTRINSIC void assign(V &v, size_t i, typename V::EntryType x)
941 {
942  v[i] = x;
943 }
944 
948 template <typename S, typename T, size_t N, size_t... Indexes>
949 inline S extract_impl(const Adapter<S, T, N> &a, size_t i, Vc::index_sequence<Indexes...>)
950 {
951  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[i]))...> tmp(
952  decay_workaround(get_dispatcher<Indexes>(a)[i])...);
953  return S(get_dispatcher<Indexes>(tmp)...);
954 }
955 
960 template <typename S, typename T, size_t N>
961 inline S extract(const Adapter<S, T, N> &a, size_t i)
962 {
963  return extract_impl(a, i, Vc::make_index_sequence<determine_tuple_size<S>()>());
964 }
968 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
969 Vc_INTRINSIC typename V::EntryType extract(const V &v, size_t i)
970 {
971  return v[i];
972 }
973 
974 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
975 inline Adapter<S, T, N> shifted_impl(const Adapter<S, T, N> &a, int shift,
976  Vc::index_sequence<Indexes...>)
977 {
978  Adapter<S, T, N> r;
979  auto &&unused = {(get_dispatcher<Indexes>(r) = get_dispatcher<Indexes>(a).shifted(shift), 0)...};
980  if (&unused == &unused) {}
981  return r;
982 }
983 
992 template <typename S, typename T, size_t N>
993 inline Adapter<S, T, N> shifted(const Adapter<S, T, N> &a, int shift)
994 {
995  return shifted_impl(a, shift, Vc::make_index_sequence<determine_tuple_size<T>()>());
996 }
997 
1001 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1002 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, S &x,
1003  Vc::index_sequence<Indexes...>)
1004 {
1005  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[0]))...> tmp{
1006  decay_workaround(get_dispatcher<Indexes>(a)[i])...};
1007  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(x), 0)...};
1008  auto &&unused2 = {(get_dispatcher<Indexes>(x) = get_dispatcher<Indexes>(tmp), 0)...};
1009  if (&unused == &unused2) {}
1010 }
1011 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1012 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b,
1013  std::size_t j, Vc::index_sequence<Indexes...>)
1014 {
1015  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[0]))...> tmp{
1016  decay_workaround(get_dispatcher<Indexes>(a)[i])...};
1017  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(b)[j], 0)...};
1018  auto &&unused2 = {(get_dispatcher<Indexes>(b)[j] = get_dispatcher<Indexes>(tmp), 0)...};
1019  if (&unused == &unused2) {}
1020 }
1021 
1026 template <typename S, typename T, std::size_t N>
1027 inline void swap(Adapter<S, T, N> &a, std::size_t i, S &x)
1028 {
1029  swap_impl(a, i, x, Vc::make_index_sequence<determine_tuple_size<T>()>());
1030 }
1031 template <typename S, typename T, std::size_t N>
1032 inline void swap(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b, std::size_t j)
1033 {
1034  swap_impl(a, i, b, j, Vc::make_index_sequence<determine_tuple_size<T>()>());
1035 }
1036 
1037 template <typename A> class Scalar
1038 {
1039  using reference = typename std::add_lvalue_reference<A>::type;
1040  using S = typename A::scalar_type;
1041  using IndexSeq = Vc::make_index_sequence<determine_tuple_size<S>()>;
1042 
1043 public:
1044  Scalar(reference aa, size_t ii) : a(aa), i(ii) {}
1045 
1046  // delete copy and move to keep the type a pure proxy temporary object.
1047  Scalar(const Scalar &) = delete;
1048  Scalar(Scalar &&) = delete;
1049  Scalar &operator=(const Scalar &) = delete;
1050  Scalar &operator=(Scalar &&) = delete;
1051 
1052  void operator=(const S &x) { assign_impl(a, i, x, IndexSeq()); }
1053  operator S() const { return extract_impl(a, i, IndexSeq()); }
1054 
1055  template <typename AA>
1056  friend inline void swap(Scalar<AA> &&a, typename AA::scalar_type &b);
1057  template <typename AA>
1058  friend inline void swap(typename AA::scalar_type &b, Scalar<AA> &&a);
1059  template <typename AA> friend inline void swap(Scalar<AA> &&a, Scalar<AA> &&b);
1060 
1061 private:
1062  reference a;
1063  size_t i;
1064 };
1065 
1068 template <typename A> inline void swap(Scalar<A> &&a, typename A::scalar_type &b)
1069 {
1070  swap_impl(a.a, a.i, b, typename Scalar<A>::IndexSeq());
1071 }
1074 template <typename A> inline void swap(typename A::scalar_type &b, Scalar<A> &&a)
1075 {
1076  swap_impl(a.a, a.i, b, typename Scalar<A>::IndexSeq());
1077 }
1078 
1079 template <typename A> inline void swap(Scalar<A> &&a, Scalar<A> &&b)
1080 {
1081  swap_impl(a.a, a.i, b.a, b.i, typename Scalar<A>::IndexSeq());
1082 }
1083 
1084 template <typename A> class Interface
1085 {
1086  using reference = typename std::add_lvalue_reference<A>::type;
1087  using IndexSeq =
1088  Vc::make_index_sequence<determine_tuple_size<typename A::scalar_type>()>;
1089 
1090 public:
1091  Interface(reference aa) : a(aa) {}
1092 
1093  Scalar<A> operator[](size_t i)
1094  {
1095  return {a, i};
1096  }
1097  typename A::scalar_type operator[](size_t i) const
1098  {
1099  return extract_impl(a, i, IndexSeq());
1100  }
1101 
1102  A shifted(int amount) const
1103  {
1104  return shifted_impl(a, amount, IndexSeq());
1105  }
1106 
1107 private:
1108  reference a;
1109 };
1110 
1111 template <typename S, typename T, size_t N>
1112 Interface<Adapter<S, T, N>> decorate(Adapter<S, T, N> &a)
1113 {
1114  return {a};
1115 }
1116 template <typename S, typename T, size_t N>
1117 const Interface<const Adapter<S, T, N>> decorate(const Adapter<S, T, N> &a)
1118 {
1119  return {a};
1120 }
1121 
1122 namespace IteratorDetails
1123 {
1124 enum class Mutable { Yes, No };
1125 
1126 template <typename It, typename V, size_t I, size_t End>
1127 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I == End), It>)
1128 {
1129  return {};
1130 }
1131 template <typename It, typename V, size_t I, size_t End>
1132 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I < End), It> it)
1133 {
1134  V r = fromIteratorImpl<It, V, I + 1, End>(it);
1135  Traits::decay<decltype(get_dispatcher<I>(r))> tmp;
1136  for (size_t j = 0; j < V::size(); ++j, ++it) {
1137  tmp[j] = get_dispatcher<I>(*it);
1138  }
1139  get_dispatcher<I>(r) = tmp;
1140  return r;
1141 }
1142 template <typename It, typename V>
1143 Vc_INTRINSIC V fromIterator(enable_if<!Traits::is_simd_vector<V>::value, const It &> it)
1144 {
1145  return fromIteratorImpl<It, V, 0, determine_tuple_size<V>()>(it);
1146 }
1147 template <typename It, typename V>
1148 Vc_INTRINSIC V fromIterator(enable_if<Traits::is_simd_vector<V>::value, It> it)
1149 {
1150  V r;
1151  for (size_t j = 0; j < V::size(); ++j, ++it) {
1152  r[j] = *it;
1153  }
1154  return r;
1155 }
1156 
1157 // Note: §13.5.6 says: “An expression x->m is interpreted as (x.operator->())->m for a
1158 // class object x of type T if T::operator->() exists and if the operator is selected as
1159 // the best match function by the overload resolution mechanism (13.3).”
1160 template <typename T, typename value_vector, Mutable> class Pointer;
1161 
1170 template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::Yes>
1171 {
1172  static constexpr auto Size = value_vector::size();
1173 
1174 public:
1176  value_vector *operator->() { return &data; }
1177 
1182  Pointer() = delete;
1183  Pointer(const Pointer &) = delete;
1184  Pointer &operator=(const Pointer &) = delete;
1185  Pointer &operator=(Pointer &&) = delete;
1186 
1188  Pointer(Pointer &&) = default;
1189 
1195  ~Pointer()
1196  {
1197  // store data back to where it came from
1198  for (size_t i = 0; i < Size; ++i, ++begin_iterator) {
1199  *begin_iterator = extract(data, i);
1200  }
1201  }
1202 
1204  Pointer(const T &it) : data(fromIterator<T, value_vector>(it)), begin_iterator(it) {}
1205 
1206 private:
1208  value_vector data;
1210  T begin_iterator;
1211 };
1217 template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::No>
1218 {
1219  static constexpr auto Size = value_vector::size();
1220 
1221 public:
1222  const value_vector *operator->() const { return &data; }
1223 
1224  Pointer() = delete;
1225  Pointer(const Pointer &) = delete;
1226  Pointer &operator=(const Pointer &) = delete;
1227  Pointer &operator=(Pointer &&) = delete;
1228 
1229  Pointer(Pointer &&) = default; // required for returning the Pointer
1230 
1231  Pointer(const T &it) : data(fromIterator<T, value_vector>(it)) {}
1232 
1233 private:
1234  value_vector data;
1235 };
1236 
1249 template <typename T, typename value_vector, Mutable M> class Reference;
1250 
1252 template <typename T, typename value_vector>
1253 class Reference<T, value_vector, Mutable::Yes> : public value_vector
1254 {
1255  static constexpr auto Size = value_vector::size();
1256 
1257  using reference = typename std::add_lvalue_reference<T>::type;
1258  reference scalar_it;
1259 
1260 public:
1263  Reference(reference first_it)
1264  : value_vector(fromIterator<T, value_vector>(first_it)), scalar_it(first_it)
1265  {
1266  }
1267 
1269  Reference(const Reference &) = delete;
1270  Reference(Reference &&) = default;
1271  Reference &operator=(const Reference &) = delete;
1272  Reference &operator=(Reference &&) = delete;
1273 
1279  void operator=(const value_vector &x)
1280  {
1281  static_cast<value_vector &>(*this) = x;
1282  auto it = scalar_it;
1283  for (size_t i = 0; i < Size; ++i, ++it) {
1284  *it = extract(x, i);
1285  }
1286  }
1287 };
1288 #define Vc_OP(op_) \
1289  template <typename T0, typename V0, typename T1, typename V1> \
1290  decltype(std::declval<const V0 &>() op_ std::declval<const V1 &>()) operator op_( \
1291  const Reference<T0, V0, Mutable::Yes> &x, \
1292  const Reference<T1, V1, Mutable::Yes> &y) \
1293  { \
1294  return static_cast<const V0 &>(x) op_ static_cast<const V1 &>(y); \
1295  }
1296 Vc_ALL_COMPARES(Vc_OP);
1297 Vc_ALL_ARITHMETICS(Vc_OP);
1298 Vc_ALL_BINARY(Vc_OP);
1299 Vc_ALL_LOGICAL(Vc_OP);
1300 Vc_ALL_SHIFTS(Vc_OP);
1301 #undef Vc_OP
1302 
1304 template <typename T, typename value_vector>
1305 class Reference<T, value_vector, Mutable::No> : public value_vector
1306 {
1307  static constexpr auto Size = value_vector::size();
1308 
1309 public:
1310  Reference(const T &it) : value_vector(fromIterator<T, value_vector>(it)) {}
1311 
1312  Reference(const Reference &) = delete;
1313  Reference(Reference &&) = default;
1314  Reference &operator=(const Reference &) = delete;
1315  Reference &operator=(Reference &&) = delete;
1316 
1318  void operator=(const value_vector &x) = delete;
1319 };
1320 
1321 template <typename T, size_t N,
1322  IteratorDetails::Mutable M =
1323  (Traits::is_output_iterator<T>::value ? Mutable::Yes : Mutable::No),
1324  typename V = simdize<typename std::iterator_traits<T>::value_type, N>,
1325  size_t Size = V::size(),
1326  typename = typename std::iterator_traits<T>::iterator_category>
1327 class Iterator;
1328 
1329 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1330 class Iterator<T, N, M, V, Size, std::forward_iterator_tag>
1331  : public std::iterator<typename std::iterator_traits<T>::iterator_category, V,
1332  typename std::iterator_traits<T>::difference_type,
1333  IteratorDetails::Pointer<T, V, M>,
1334  IteratorDetails::Reference<T, V, M>>
1335 {
1336 public:
1337  using pointer = IteratorDetails::Pointer<T, V, M>;
1338  using reference = IteratorDetails::Reference<T, V, M>;
1339  using const_pointer = IteratorDetails::Pointer<T, V, IteratorDetails::Mutable::No>;
1340  using const_reference =
1341  IteratorDetails::Reference<T, V, IteratorDetails::Mutable::No>;
1342 
1344  static constexpr std::size_t size() { return Size; }
1345 
1346  Iterator() = default;
1347 
1354  Iterator(const T &x) : scalar_it(x) {}
1358  Iterator(T &&x) : scalar_it(std::move(x)) {}
1362  Iterator &operator=(const T &x)
1363  {
1364  scalar_it = x;
1365  return *this;
1366  }
1370  Iterator &operator=(T &&x)
1371  {
1372  scalar_it = std::move(x);
1373  return *this;
1374  }
1375 
1377  Iterator(const Iterator &) = default;
1379  Iterator(Iterator &&) = default;
1381  Iterator &operator=(const Iterator &) = default;
1383  Iterator &operator=(Iterator &&) = default;
1384 
1386  Iterator &operator++()
1387  {
1388  std::advance(scalar_it, Size);
1389  return *this;
1390  }
1392  Iterator operator++(int)
1393  {
1394  Iterator copy(*this);
1395  operator++();
1396  return copy;
1397  }
1398 
1407  bool operator==(const Iterator &rhs) const
1408  {
1409  T it(scalar_it);
1410  for (size_t i = 1; i < Size; ++i) {
1411  Vc_ASSERT((++it != rhs.scalar_it));
1412  }
1413  return scalar_it == rhs.scalar_it;
1414  }
1423  bool operator!=(const Iterator &rhs) const
1424  {
1425  T it(scalar_it);
1426  for (size_t i = 1; i < Size; ++i) {
1427  Vc_ASSERT((++it != rhs.scalar_it));
1428  }
1429  return scalar_it != rhs.scalar_it;
1430  }
1431 
1432  pointer operator->() { return scalar_it; }
1433 
1440  reference operator*() { return scalar_it; }
1441 
1442  const_pointer operator->() const { return scalar_it; }
1443 
1451  const_reference operator*() const { return scalar_it; }
1452 
1466  operator const T &() const { return scalar_it; }
1467 
1468 protected:
1469  T scalar_it;
1470 };
1471 
1476 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1477 class Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1478  : public Iterator<T, N, M, V, Size, std::forward_iterator_tag>
1479 {
1480  using Base = Iterator<T, N, M, V, Size, std::forward_iterator_tag>;
1481 
1482 protected:
1483  using Base::scalar_it;
1484 
1485 public:
1486  using pointer = typename Base::pointer;
1487  using reference = typename Base::reference;
1488  using const_pointer = typename Base::const_pointer;
1489  using const_reference = typename Base::const_reference;
1490 
1491  using Iterator<T, N, M, V, Size,
1492  std::forward_iterator_tag>::Iterator; // in short: "using
1493  // Base::Iterator", but that
1494  // confuses ICC
1496  Iterator &operator--()
1497  {
1498  std::advance(scalar_it, -Size);
1499  return *this;
1500  }
1502  Iterator operator--(int)
1503  {
1504  Iterator copy(*this);
1505  operator--();
1506  return copy;
1507  }
1508 };
1509 
1514 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1515 class Iterator<T, N, M, V, Size, std::random_access_iterator_tag>
1516  : public Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1517 {
1519 
1520 protected:
1521  using Base::scalar_it;
1522 
1523 public:
1524  using pointer = typename Base::pointer;
1525  using reference = typename Base::reference;
1526  using const_pointer = typename Base::const_pointer;
1527  using const_reference = typename Base::const_reference;
1528  using difference_type = typename std::iterator_traits<T>::difference_type;
1529 
1531  Iterator; // in short: "using Base::Iterator", but that confuses ICC
1532 
1533  Iterator &operator+=(difference_type n)
1534  {
1535  scalar_it += n * Size;
1536  return *this;
1537  }
1538  Iterator operator+(difference_type n) const { return Iterator(*this) += n; }
1539 
1540  Iterator &operator-=(difference_type n)
1541  {
1542  scalar_it -= n * Size;
1543  return *this;
1544  }
1545  Iterator operator-(difference_type n) const { return Iterator(*this) -= n; }
1546 
1547  difference_type operator-(const Iterator &rhs) const
1548  {
1549  constexpr difference_type n = Size;
1550  Vc_ASSERT((scalar_it - rhs.scalar_it) % n ==
1551  0); // if this fails the two iterators are not a multiple of the vector
1552  // width apart. The distance would be fractional and that doesn't
1553  // make too much sense for iteration. Therefore, it is a
1554  // precondition for the distance of the two iterators to be a
1555  // multiple of Size.
1556  return (scalar_it - rhs.scalar_it) / n;
1557  }
1558 
1563  bool operator<(const Iterator &rhs) const
1564  {
1565  return scalar_it + Size <= rhs.scalar_it;
1566  }
1567 
1568  bool operator>(const Iterator &rhs) const
1569  {
1570  return scalar_it >= rhs.scalar_it + Size;
1571  }
1572 
1573  bool operator<=(const Iterator &rhs) const
1574  {
1575  return scalar_it + (Size - 1) <= rhs.scalar_it;
1576  }
1577 
1578  bool operator>=(const Iterator &rhs) const
1579  {
1580  return scalar_it >= rhs.scalar_it + (Size - 1);
1581  }
1582 
1583  reference operator[](difference_type i) { return *(*this + i); }
1584  const_reference operator[](difference_type i) const { return *(*this + i); }
1585 };
1586 
1587 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1588 Iterator<T, N, M, V, Size, std::random_access_iterator_tag> operator+(
1589  typename Iterator<T, N, M, V, Size, std::random_access_iterator_tag>::difference_type
1590  n,
1591  const Iterator<T, N, M, V, Size, std::random_access_iterator_tag> &i)
1592 {
1593  return i + n;
1594 }
1595 
1596 } // namespace IteratorDetails
1597 
1606 template <typename T, size_t N, typename MT>
1607 struct ReplaceTypes<T, N, MT, Category::ForwardIterator>
1608 {
1609  using type = IteratorDetails::Iterator<T, N>;
1610 };
1611 template <typename T, size_t N, typename MT>
1612 struct ReplaceTypes<T, N, MT, Category::BidirectionalIterator>
1613 {
1614  using type = IteratorDetails::Iterator<T, N>;
1615 };
1616 template <typename T, size_t N, typename MT>
1617 struct ReplaceTypes<T, N, MT, Category::RandomAccessIterator>
1618 {
1619  using type = IteratorDetails::Iterator<T, N>;
1620 };
1621 
1625 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1626  std::size_t Offset>
1627 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size<S>() && M::size() == N), void>
1628  conditional_assign(Adapter<S, T, N> &, const M &, const U &)
1629 {
1630 }
1631 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1632  std::size_t Offset = 0>
1633 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size<S>() && M::size() == N), void>
1634  conditional_assign(Adapter<S, T, N> &lhs, const M &mask, const U &rhs)
1635 {
1636  using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1637  using M2 = typename V::mask_type;
1638  conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask), get_dispatcher<Offset>(rhs));
1639  conditional_assign<Op, S, T, N, M, U, Offset + 1>(lhs, mask, rhs);
1640 }
1641 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1642  std::size_t Offset>
1643 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size<S>() && M::size() == N), void>
1644  conditional_assign(Adapter<S, T, N> &, const M &)
1645 {
1646 }
1647 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1648  std::size_t Offset = 0>
1649 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size<S>() && M::size() == N), void>
1650  conditional_assign(Adapter<S, T, N> &lhs, const M &mask)
1651 {
1652  using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1653  using M2 = typename V::mask_type;
1654  conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask));
1655  conditional_assign<Op, S, T, N, M, Offset + 1>(lhs, mask);
1656 }
1657 
1659 } // namespace SimdizeDetail
1660 
1679 template <typename T, size_t N = 0, typename MT = void>
1680 using simdize = SimdizeDetail::simdize<T, N, MT>;
1681 
1701 #define Vc_SIMDIZE_INTERFACE(MEMBERS_) \
1702  template <std::size_t N_> \
1703  inline auto vc_get_()->decltype(std::get<N_>(std::tie MEMBERS_)) \
1704  { \
1705  return std::get<N_>(std::tie MEMBERS_); \
1706  } \
1707  template <std::size_t N_> \
1708  inline auto vc_get_() const->decltype(std::get<N_>(std::tie MEMBERS_)) \
1709  { \
1710  return std::get<N_>(std::tie MEMBERS_); \
1711  } \
1712  enum : std::size_t { \
1713  tuple_size = std::tuple_size<decltype(std::tie MEMBERS_)>::value \
1714  }
1715 
1716 } // namespace Vc
1717 
1718 namespace std
1719 {
1720 using Vc::SimdizeDetail::swap;
1721 } // namespace std
1722 
1723 #endif // VC_COMMON_SIMDIZE_H_
1724 
1725 // vim: foldmethod=marker
void free(T *p)
Frees memory that was allocated with Vc::malloc.
Definition: memory.h:103
bool operator<(const Iterator &rhs) const
Returns whether all entries accessed via iterator dereferencing come before the iterator rhs...
Definition: simdize.h:1563
result_vector_type< L, R > operator-(L &&lhs, R &&rhs)
Applies - component-wise and concurrently.
Definition: simdarray.h:1444
Definition: vector.h:258
result_vector_type< L, R > operator*(L &&lhs, R &&rhs)
Applies * component-wise and concurrently.
Definition: simdarray.h:1444
SimdizeDetail::simdize< T, N, MT > simdize
Definition: simdize.h:1680
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:961
An allocator that uses global new and supports over-aligned types, as per [C++11 20.6.9].
Definition: Allocator:129
result_vector_type< L, R > operator+(L &&lhs, R &&rhs)
Applies + component-wise and concurrently.
Definition: simdarray.h:1444
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:932
Iterator & operator--()
Advances the iterator by one vector width, or respectively N scalar steps.
Definition: simdize.h:1496
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:993
Vector Classes Namespace.
Definition: cpuid.h:33
This is the iterator type created when applying simdize to a bidirectional iterator type...
Definition: simdize.h:1477