Vc  1.1.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 
96 namespace Vc_VERSIONED_NAMESPACE
97 {
104 namespace SimdizeDetail
105 {
110 using std::is_same;
111 using std::is_base_of;
112 using std::false_type;
113 using std::true_type;
114 using std::iterator_traits;
115 using std::conditional;
116 using std::size_t;
117 template <bool B, typename T, typename F>
118 using conditional_t = typename conditional<B, T, F>::type;
119 
124 template <typename... Ts> struct Typelist;
125 
129 enum class Category {
131  None,
133  ArithmeticVectorizable,
135  InputIterator,
137  OutputIterator,
139  ForwardIterator,
141  BidirectionalIterator,
143  RandomAccessIterator,
145  ClassTemplate
146 };
147 
152 template <typename T,
153  typename ItCat = typename iterator_traits<T>::iterator_category>
154 constexpr Category iteratorCategories(int)
155 {
156  return is_base_of<std::random_access_iterator_tag, ItCat>::value
157  ? Category::RandomAccessIterator
158  : is_base_of<std::bidirectional_iterator_tag, ItCat>::value
159  ? Category::BidirectionalIterator
160  : is_base_of<std::forward_iterator_tag, ItCat>::value
161  ? Category::ForwardIterator
162  : is_base_of<std::output_iterator_tag, ItCat>::value
163  ? Category::OutputIterator
164  : is_base_of<std::input_iterator_tag, ItCat>::value
165  ? Category::InputIterator
166  : Category::None;
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 namespace
220 {
221 template <typename T> struct The_simdization_for_the_requested_type_is_not_implemented;
222 } // unnamed namespace
223 
236 template <typename T, size_t N, typename MT, Category = typeCategory<T>()>
237 struct ReplaceTypes : public The_simdization_for_the_requested_type_is_not_implemented<T>
238 {
239 };
240 
245 template <typename T, size_t N, typename MT> struct ReplaceTypes<T, N, MT, Category::None>
246 {
247  typedef T type;
248 };
249 
254 template <typename T, size_t N = 0, typename MT = void>
255 using simdize = typename SimdizeDetail::ReplaceTypes<T, N, MT>::type;
256 
261 template <typename T, size_t N, typename MT>
262 struct ReplaceTypes<T, N, MT, Category::ArithmeticVectorizable>
263  : public conditional<(N == 0 || Vector<T>::size() == N), Vector<T>, SimdArray<T, N>>
264 {
265 };
266 
271 template <size_t N, typename MT>
272 struct ReplaceTypes<bool, N, MT, Category::ArithmeticVectorizable>
273  : public conditional<(N == 0 || Mask<MT>::size() == N), Mask<MT>,
274  SimdMaskArray<MT, N>>
275 {
276 };
280 template <size_t N>
281 struct ReplaceTypes<bool, N, void, Category::ArithmeticVectorizable>
282  : public ReplaceTypes<bool, N, float, Category::ArithmeticVectorizable>
283 {
284 };
285 
292 template <size_t N, typename MT, typename Replaced, typename... Remaining>
293 struct SubstituteOneByOne;
294 
299 template <size_t N, typename MT, typename... Replaced, typename T,
300  typename... Remaining>
301 struct SubstituteOneByOne<N, MT, Typelist<Replaced...>, T, Remaining...>
302 {
303 private:
308  template <typename U, size_t M = U::size()>
309  static std::integral_constant<size_t, M> size_or_0(int);
310  template <typename U> static std::integral_constant<size_t, 0> size_or_0(...);
311 
313  using V = simdize<T, N, MT>;
314 
319  static constexpr auto NewN = N != 0 ? N : decltype(size_or_0<V>(int()))::value;
320 
326  typedef conditional_t<(N != NewN && is_same<MT, void>::value),
327  conditional_t<is_same<T, bool>::value, float, T>, MT> NewMT;
328 
329 public:
333  using type = typename SubstituteOneByOne<NewN, NewMT, Typelist<Replaced..., V>,
334  Remaining...>::type;
335 };
336 
339 template <size_t Size, typename... Replaced> struct SubstitutedBase;
341 template <typename Replaced> struct SubstitutedBase<1, Replaced> {
342  template <typename ValueT, template <typename, ValueT...> class C, ValueT... Values>
343  using SubstitutedWithValues = C<Replaced, Values...>;
344 };
346 template <typename R0, typename R1> struct SubstitutedBase<2, R0, R1>
347 {
348  template <typename ValueT, template <typename, typename, ValueT...> class C,
349  ValueT... Values>
350  using SubstitutedWithValues = C<R0, R1, Values...>;
351 };
353 template <typename R0, typename R1, typename R2> struct SubstitutedBase<3, R0, R1, R2>
354 {
355  template <typename ValueT, template <typename, typename, typename, ValueT...> class C,
356  ValueT... Values>
357  using SubstitutedWithValues = C<R0, R1, R2, Values...>;
358 };
360 template <typename... Replaced> struct SubstitutedBase<4, Replaced...> {
361 #ifndef Vc_ICC
362  template <typename ValueT,
363  template <typename, typename, typename, typename, ValueT...> class C,
364  ValueT... Values>
365  using SubstitutedWithValues = C<Replaced..., Values...>;
366 #endif // Vc_ICC
367 };
369 template <typename... Replaced> struct SubstitutedBase<5, Replaced...> {
370 #ifndef Vc_ICC
371  template <typename ValueT, template <typename, typename, typename, typename, typename,
372  ValueT...> class C,
373  ValueT... Values>
374  using SubstitutedWithValues = C<Replaced..., Values...>;
375 #endif // Vc_ICC
376 };
378 template <typename... Replaced> struct SubstitutedBase<6, Replaced...> {
379 #ifndef Vc_ICC
380  template <typename ValueT, template <typename, typename, typename, typename, typename,
381  typename, ValueT...> class C,
382  ValueT... Values>
383  using SubstitutedWithValues = C<Replaced..., Values...>;
384 #endif // Vc_ICC
385 };
387 template <typename... Replaced> struct SubstitutedBase<7, Replaced...> {
388 #ifndef Vc_ICC
389  template <typename ValueT, template <typename, typename, typename, typename, typename,
390  typename, typename, ValueT...> class C,
391  ValueT... Values>
392  using SubstitutedWithValues = C<Replaced..., Values...>;
393 #endif // Vc_ICC
394 };
396 template <typename... Replaced> struct SubstitutedBase<8, Replaced...> {
397 #ifndef Vc_ICC
398  template <typename ValueT, template <typename, typename, typename, typename, typename,
399  typename, typename, typename, ValueT...> class C,
400  ValueT... Values>
401  using SubstitutedWithValues = C<Replaced..., Values...>;
402 #endif // Vc_ICC
403 };
404 
410 template <size_t N_, typename MT, typename Replaced0, typename... Replaced>
411 struct SubstituteOneByOne<N_, MT, Typelist<Replaced0, Replaced...>>
412 {
416  struct type
417  : public SubstitutedBase<sizeof...(Replaced) + 1, Replaced0, Replaced...> {
418  static constexpr auto N = N_;
423  template <template <typename...> class C>
424  using Substituted = C<Replaced0, Replaced...>;
425  };
426 };
427 
444 template <typename Scalar, typename Base, size_t N> class Adapter;
445 
450 template <template <typename...> class C, typename... Ts, size_t N, typename MT>
451 struct ReplaceTypes<C<Ts...>, N, MT, Category::ClassTemplate>
452 {
454  using SubstitutionResult =
455  typename SubstituteOneByOne<N, MT, Typelist<>, Ts...>::type;
461  using Vectorized = typename SubstitutionResult::template Substituted<C>;
467  using type = conditional_t<is_same<C<Ts...>, Vectorized>::value, C<Ts...>,
468  Adapter<C<Ts...>, Vectorized, SubstitutionResult::N>>;
469 };
470 
476 #ifdef Vc_ICC
477 // ICC barfs on packs of values
478 #define Vc_DEFINE_NONTYPE_REPLACETYPES_(ValueType_) \
479  template <template <typename, ValueType_...> class C, typename T, ValueType_ Value0, \
480  ValueType_... Values> \
481  struct is_class_template<C<T, Value0, Values...>> : public true_type { \
482  }; \
483  template <template <typename, typename, ValueType_...> class C, typename T0, \
484  typename T1, ValueType_ Value0, ValueType_... Values> \
485  struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type { \
486  }; \
487  template <template <typename, typename, typename, ValueType_...> class C, \
488  typename T0, typename T1, typename T2, ValueType_ Value0, \
489  ValueType_... Values> \
490  struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type { \
491  }; \
492  template <template <typename, typename, typename, typename, ValueType_...> class C, \
493  typename T0, typename T1, typename T2, typename T3, ValueType_ Value0, \
494  ValueType_... Values> \
495  struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type { \
496  }; \
497  template <template <typename, typename, typename, typename, typename, ValueType_...> \
498  class C, \
499  typename T0, typename T1, typename T2, typename T3, typename T4, \
500  ValueType_ Value0, ValueType_... Values> \
501  struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
502  : public true_type { \
503  }; \
504  template <template <typename, typename, typename, typename, typename, typename, \
505  ValueType_...> class C, \
506  typename T0, typename T1, typename T2, typename T3, typename T4, \
507  typename T5, ValueType_ Value0, ValueType_... Values> \
508  struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
509  : public true_type { \
510  }; \
511  template <template <typename, typename, typename, typename, typename, typename, \
512  typename, ValueType_...> class C, \
513  typename T0, typename T1, typename T2, typename T3, typename T4, \
514  typename T5, typename T6, ValueType_ Value0, ValueType_... Values> \
515  struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
516  : public true_type { \
517  }; \
518  template <template <typename, ValueType_> class C, typename T0, ValueType_ Value0, \
519  size_t N, typename MT> \
520  struct ReplaceTypes<C<T0, Value0>, N, MT, Category::ClassTemplate> { \
521  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
522  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
523  Substituted; \
524  static constexpr auto NN = tmp::N; \
525  typedef conditional_t<is_same<C<T0, Value0>, Substituted>::value, C<T0, Value0>, \
526  Adapter<C<T0, Value0>, Substituted, NN>> type; \
527  }; \
528  template <template <typename, typename, ValueType_> class C, typename T0, \
529  typename T1, ValueType_ Value0, size_t N, typename MT> \
530  struct ReplaceTypes<C<T0, T1, Value0>, N, MT, Category::ClassTemplate> { \
531  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
532  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
533  Substituted; \
534  static constexpr auto NN = tmp::N; \
535  typedef conditional_t<is_same<C<T0, T1, Value0>, Substituted>::value, \
536  C<T0, T1, Value0>, \
537  Adapter<C<T0, T1, Value0>, Substituted, NN>> type; \
538  }; \
539  template <template <typename, typename, typename, ValueType_> class C, typename T0, \
540  typename T1, typename T2, ValueType_ Value0, size_t N, typename MT> \
541  struct ReplaceTypes<C<T0, T1, T2, Value0>, N, MT, Category::ClassTemplate> { \
542  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
543  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
544  Substituted; \
545  static constexpr auto NN = tmp::N; \
546  typedef conditional_t<is_same<C<T0, T1, T2, Value0>, Substituted>::value, \
547  C<T0, T1, T2, Value0>, \
548  Adapter<C<T0, T1, T2, Value0>, Substituted, NN>> type; \
549  }
550 #else
551 #define Vc_DEFINE_NONTYPE_REPLACETYPES_(ValueType_) \
552  template <template <typename, ValueType_...> class C, typename T, ValueType_ Value0, \
553  ValueType_... Values> \
554  struct is_class_template<C<T, Value0, Values...>> : public true_type { \
555  }; \
556  template <template <typename, typename, ValueType_...> class C, typename T0, \
557  typename T1, ValueType_ Value0, ValueType_... Values> \
558  struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type { \
559  }; \
560  template <template <typename, typename, typename, ValueType_...> class C, \
561  typename T0, typename T1, typename T2, ValueType_ Value0, \
562  ValueType_... Values> \
563  struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type { \
564  }; \
565  template <template <typename, typename, typename, typename, ValueType_...> class C, \
566  typename T0, typename T1, typename T2, typename T3, ValueType_ Value0, \
567  ValueType_... Values> \
568  struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type { \
569  }; \
570  template <template <typename, typename, typename, typename, typename, ValueType_...> \
571  class C, \
572  typename T0, typename T1, typename T2, typename T3, typename T4, \
573  ValueType_ Value0, ValueType_... Values> \
574  struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
575  : public true_type { \
576  }; \
577  template <template <typename, typename, typename, typename, typename, typename, \
578  ValueType_...> class C, \
579  typename T0, typename T1, typename T2, typename T3, typename T4, \
580  typename T5, ValueType_ Value0, ValueType_... Values> \
581  struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
582  : public true_type { \
583  }; \
584  template <template <typename, typename, typename, typename, typename, typename, \
585  typename, ValueType_...> class C, \
586  typename T0, typename T1, typename T2, typename T3, typename T4, \
587  typename T5, typename T6, ValueType_ Value0, ValueType_... Values> \
588  struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
589  : public true_type { \
590  }; \
591  template <template <typename, ValueType_...> class C, typename T0, \
592  ValueType_ Value0, ValueType_... Values, size_t N, typename MT> \
593  struct ReplaceTypes<C<T0, Value0, Values...>, N, MT, Category::ClassTemplate> { \
594  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
595  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
596  Values...> Substituted; \
597  static constexpr auto NN = tmp::N; \
598  typedef conditional_t<is_same<C<T0, Value0, Values...>, Substituted>::value, \
599  C<T0, Value0, Values...>, \
600  Adapter<C<T0, Value0, Values...>, Substituted, NN>> type; \
601  }; \
602  template <template <typename, typename, ValueType_...> class C, typename T0, \
603  typename T1, ValueType_ Value0, ValueType_... Values, size_t N, \
604  typename MT> \
605  struct ReplaceTypes<C<T0, T1, Value0, Values...>, N, MT, Category::ClassTemplate> { \
606  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
607  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
608  Values...> Substituted; \
609  static constexpr auto NN = tmp::N; \
610  typedef conditional_t<is_same<C<T0, T1, Value0, Values...>, Substituted>::value, \
611  C<T0, T1, Value0, Values...>, \
612  Adapter<C<T0, T1, Value0, Values...>, Substituted, NN>> \
613  type; \
614  }; \
615  template <template <typename, typename, typename, ValueType_...> class C, \
616  typename T0, typename T1, typename T2, ValueType_ Value0, \
617  ValueType_... Values, size_t N, typename MT> \
618  struct ReplaceTypes<C<T0, T1, T2, Value0, Values...>, N, MT, \
619  Category::ClassTemplate> { \
620  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
621  typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
622  Values...> Substituted; \
623  static constexpr auto NN = tmp::N; \
624  typedef conditional_t< \
625  is_same<C<T0, T1, T2, Value0, Values...>, Substituted>::value, \
626  C<T0, T1, T2, Value0, Values...>, \
627  Adapter<C<T0, T1, T2, Value0, Values...>, Substituted, NN>> type; \
628  }
629 #endif // Vc_ICC
630 Vc_DEFINE_NONTYPE_REPLACETYPES_(bool);
631 Vc_DEFINE_NONTYPE_REPLACETYPES_(wchar_t);
632 Vc_DEFINE_NONTYPE_REPLACETYPES_(char);
633 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed char);
634 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned char);
635 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed short);
636 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned short);
637 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed int);
638 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned int);
639 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed long);
640 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned long);
641 Vc_DEFINE_NONTYPE_REPLACETYPES_( signed long long);
642 Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned long long);
643 #undef Vc_DEFINE_NONTYPE_REPLACETYPES_
644 
645 #ifdef Vc_ICC
646 // FIXME: find a proper workaround implementation for ICC
647 template <typename Class, typename... Args>
648 constexpr bool is_constructible_with_single_brace()
649 {
650  return true;
651 }
652 template <typename Class, typename... Args>
653 constexpr bool is_constructible_with_double_brace()
654 {
655  return false;
656 }
657 #else
658 namespace is_constructible_with_single_brace_impl
659 {
660 template <typename T> T create();
661 template <typename Class, typename... Args,
662  typename = decltype((Class{create<Args>()...}))>
663 std::true_type test(int);
664 template <typename Class, typename... Args> std::false_type test(...);
665 } // namespace is_constructible_with_single_brace_impl
666 
667 template <typename Class, typename... Args>
668 constexpr bool is_constructible_with_single_brace()
669 {
670  return decltype(
671  is_constructible_with_single_brace_impl::test<Class, Args...>(1))::value;
672 }
673 static_assert(
674  is_constructible_with_single_brace<std::tuple<int, int, int>, int, int, int>(), "");
675 static_assert(is_constructible_with_single_brace<std::array<int, 3>, int, int, int>(),
676  "");
677 
678 namespace is_constructible_with_double_brace_impl
679 {
680 template <typename T> T create();
681 template <typename Class, typename... Args,
682  typename = decltype(Class{{create<Args>()...}})>
683 std::true_type test(int);
684 template <typename Class, typename... Args> std::false_type test(...);
685 } // namespace is_constructible_with_double_brace_impl
686 
687 template <typename Class, typename... Args>
688 constexpr bool is_constructible_with_double_brace()
689 {
690  return decltype(
691  is_constructible_with_double_brace_impl::test<Class, Args...>(1))::value;
692 }
693 static_assert(
694  !is_constructible_with_double_brace<std::tuple<int, int, int>, int, int, int>(), "");
695 static_assert(is_constructible_with_double_brace<std::array<int, 3>, int, int, int>(),
696  "");
697 #endif
698 
699 template <size_t I, typename T,
700  typename R = decltype(std::declval<T &>().template vc_get_<I>())>
701 R get_dispatcher(T &x, void * = nullptr)
702 {
703  return x.template vc_get_<I>();
704 }
705 template <size_t I, typename T,
706  typename R = decltype(std::declval<const T &>().template vc_get_<I>())>
707 R get_dispatcher(const T &x, void * = nullptr)
708 {
709  return x.template vc_get_<I>();
710 }
711 template <size_t I, typename T, typename R = decltype(std::get<I>(std::declval<T &>()))>
712 R get_dispatcher(T &x, int = 0)
713 {
714  return std::get<I>(x);
715 }
716 template <size_t I, typename T,
717  typename R = decltype(std::get<I>(std::declval<const T &>()))>
718 R get_dispatcher(const T &x, int = 0)
719 {
720  return std::get<I>(x);
721 }
722 
723 
724 // see above
725 template <typename Scalar, typename Base, size_t N> class Adapter : public Base
726 {
727 private:
729  template <std::size_t... Indexes, typename T>
730  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_, T, std::true_type)
731  : Base{{get_dispatcher<Indexes>(x_)...}}
732  {
733  }
734 
736  template <std::size_t... Indexes>
737  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_, std::true_type,
738  std::false_type)
739  : Base{get_dispatcher<Indexes>(x_)...}
740  {
741  }
742 
744  template <std::size_t... Indexes>
745  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_, std::false_type,
746  std::false_type)
747  : Base(get_dispatcher<Indexes>(x_)...)
748  {
749  }
750 
751  template <std::size_t... Indexes>
752  Adapter(Vc::index_sequence<Indexes...> seq_, const Scalar &x_)
753  : Adapter(seq_, x_,
754  std::integral_constant<
755  bool, is_constructible_with_single_brace<
756  Base, decltype(get_dispatcher<Indexes>(
757  std::declval<const Scalar &>()))...>()>(),
758  std::integral_constant<
759  bool, is_constructible_with_double_brace<
760  Base, decltype(get_dispatcher<Indexes>(
761  std::declval<const Scalar &>()))...>()>())
762  {
763  }
764 
765 public:
767  static constexpr size_t size() { return N; }
768 
770  using base_type = Base;
773  using scalar_type = Scalar;
774 
777  Adapter() = default;
778 
780 #if defined Vc_CLANG && Vc_CLANG < 0x30700
781  Vc_INTRINSIC Adapter(const Adapter &x) : Base(x) {}
782 #else
783  Adapter(const Adapter &) = default;
784 #endif
785  Adapter(Adapter &&) = default;
788  Adapter &operator=(const Adapter &) = default;
790  Adapter &operator=(Adapter &&) = default;
791 
793  template <typename U, size_t TupleSize = determine_tuple_size<Scalar>(),
794  typename Seq = Vc::make_index_sequence<TupleSize>,
795  typename = enable_if<std::is_convertible<U, Scalar>::value>>
796  Adapter(U &&x_)
797  : Adapter(Seq(), static_cast<const Scalar &>(x_))
798  {
799  }
800 
802  template <typename A0, typename... Args,
803  typename = typename std::enable_if<
804  !Traits::is_index_sequence<A0>::value &&
805  (sizeof...(Args) > 0 || !std::is_convertible<A0, Scalar>::value)>::type>
806  Adapter(A0 &&arg0_, Args &&... arguments_)
807  : Base(std::forward<A0>(arg0_), std::forward<Args>(arguments_)...)
808  {
809  }
810 
812  template <typename T,
813  typename = decltype(Base(std::declval<const std::initializer_list<T> &>()))>
814  Adapter(const std::initializer_list<T> &l_)
815  : Base(l_)
816  {
817  }
818 
821  void *operator new(size_t size)
822  {
823  return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
824  }
825  void *operator new(size_t, void *p_) { return p_; }
826  void *operator new[](size_t size)
827  {
828  return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
829  }
830  void *operator new[](size_t , void *p_) { return p_; }
831  void operator delete(void *ptr_, size_t) { Vc::Common::free(ptr_); }
832  void operator delete(void *, void *) {}
833  void operator delete[](void *ptr_, size_t) { Vc::Common::free(ptr_); }
834  void operator delete[](void *, void *) {}
835 };
836 
841 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
842 inline bool operator==(
843  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
844  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
845 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
846 inline bool operator!=(
847  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
848  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
849 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
850 inline bool operator<=(
851  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
852  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
853 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
854 inline bool operator>=(
855  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
856  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
857 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
858 inline bool operator<(
859  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
860  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
861 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
862 inline bool operator>(
863  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
864  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
865 
867 } // namespace SimdizeDetail
868 } // namespace Vc
869 
870 namespace std
871 {
875 template <typename Scalar, typename Base, size_t N>
876 class tuple_size<Vc::SimdizeDetail::Adapter<Scalar, Base, N>> : public tuple_size<Base>
877 {
878 };
882 template <size_t I, typename Scalar, typename Base, size_t N>
883 class tuple_element<I, Vc::SimdizeDetail::Adapter<Scalar, Base, N>>
884  : public tuple_element<I, Base>
885 {
886 };
887 // std::get does not need additional work because Vc::Adapter derives from
888 // C<Ts...> and therefore if get<N>(C<Ts...>) works it works for Adapter as well.
889 
894 template <typename S, typename T, size_t N>
895 class allocator<Vc::SimdizeDetail::Adapter<S, T, N>>
896  : public Vc::Allocator<Vc::SimdizeDetail::Adapter<S, T, N>>
897 {
898 public:
899  template <typename U> struct rebind
900  {
901  typedef std::allocator<U> other;
902  };
903 };
904 } // namespace std
905 
906 namespace Vc_VERSIONED_NAMESPACE
907 {
908 namespace SimdizeDetail
909 {
918 template <typename T> static inline T decay_workaround(const T &x) { return x; }
919 
923 template <typename S, typename T, size_t N, size_t... Indexes>
924 inline void assign_impl(Adapter<S, T, N> &a, size_t i, const S &x,
925  Vc::index_sequence<Indexes...>)
926 {
927  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(x)))...> tmp(
928  decay_workaround(get_dispatcher<Indexes>(x))...);
929  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(tmp), 0)...};
930  if (&unused == &unused) {}
931 }
932 
937 template <typename S, typename T, size_t N>
938 inline void assign(Adapter<S, T, N> &a, size_t i, const S &x)
939 {
940  assign_impl(a, i, x, Vc::make_index_sequence<determine_tuple_size<T>()>());
941 }
945 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
946 Vc_INTRINSIC void assign(V &v, size_t i, typename V::EntryType x)
947 {
948  v[i] = x;
949 }
950 
954 template <typename S, typename T, size_t N, size_t... Indexes>
955 inline S extract_impl(const Adapter<S, T, N> &a, size_t i, Vc::index_sequence<Indexes...>)
956 {
957  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[i]))...> tmp(
958  decay_workaround(get_dispatcher<Indexes>(a)[i])...);
959  return S(get_dispatcher<Indexes>(tmp)...);
960 }
961 
966 template <typename S, typename T, size_t N>
967 inline S extract(const Adapter<S, T, N> &a, size_t i)
968 {
969  return extract_impl(a, i, Vc::make_index_sequence<determine_tuple_size<S>()>());
970 }
974 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
975 Vc_INTRINSIC typename V::EntryType extract(const V &v, size_t i)
976 {
977  return v[i];
978 }
979 
980 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
981 inline Adapter<S, T, N> shifted_impl(const Adapter<S, T, N> &a, int shift,
982  Vc::index_sequence<Indexes...>)
983 {
984  Adapter<S, T, N> r;
985  auto &&unused = {(get_dispatcher<Indexes>(r) = get_dispatcher<Indexes>(a).shifted(shift), 0)...};
986  if (&unused == &unused) {}
987  return r;
988 }
989 
998 template <typename S, typename T, size_t N>
999 inline Adapter<S, T, N> shifted(const Adapter<S, T, N> &a, int shift)
1000 {
1001  return shifted_impl(a, shift, Vc::make_index_sequence<determine_tuple_size<T>()>());
1002 }
1003 
1007 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1008 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, S &x,
1009  Vc::index_sequence<Indexes...>)
1010 {
1011  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[0]))...> tmp{
1012  decay_workaround(get_dispatcher<Indexes>(a)[i])...};
1013  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(x), 0)...};
1014  auto &&unused2 = {(get_dispatcher<Indexes>(x) = get_dispatcher<Indexes>(tmp), 0)...};
1015  if (&unused == &unused2) {}
1016 }
1017 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1018 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b,
1019  std::size_t j, Vc::index_sequence<Indexes...>)
1020 {
1021  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[0]))...> tmp{
1022  decay_workaround(get_dispatcher<Indexes>(a)[i])...};
1023  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(b)[j], 0)...};
1024  auto &&unused2 = {(get_dispatcher<Indexes>(b)[j] = get_dispatcher<Indexes>(tmp), 0)...};
1025  if (&unused == &unused2) {}
1026 }
1027 
1032 template <typename S, typename T, std::size_t N>
1033 inline void swap(Adapter<S, T, N> &a, std::size_t i, S &x)
1034 {
1035  swap_impl(a, i, x, Vc::make_index_sequence<determine_tuple_size<T>()>());
1036 }
1037 template <typename S, typename T, std::size_t N>
1038 inline void swap(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b, std::size_t j)
1039 {
1040  swap_impl(a, i, b, j, Vc::make_index_sequence<determine_tuple_size<T>()>());
1041 }
1042 
1043 template <typename A> class Scalar
1044 {
1045  using reference = typename std::add_lvalue_reference<A>::type;
1046  using S = typename A::scalar_type;
1047  using IndexSeq = Vc::make_index_sequence<determine_tuple_size<S>()>;
1048 
1049 public:
1050  Scalar(reference aa, size_t ii) : a(aa), i(ii) {}
1051 
1052  // delete copy and move to keep the type a pure proxy temporary object.
1053  Scalar(const Scalar &) = delete;
1054  Scalar(Scalar &&) = delete;
1055  Scalar &operator=(const Scalar &) = delete;
1056  Scalar &operator=(Scalar &&) = delete;
1057 
1058  void operator=(const S &x) { assign_impl(a, i, x, IndexSeq()); }
1059  operator S() const { return extract_impl(a, i, IndexSeq()); }
1060 
1061  template <typename AA>
1062  friend inline void swap(Scalar<AA> &&a, typename AA::scalar_type &b);
1063  template <typename AA>
1064  friend inline void swap(typename AA::scalar_type &b, Scalar<AA> &&a);
1065  template <typename AA> friend inline void swap(Scalar<AA> &&a, Scalar<AA> &&b);
1066 
1067 private:
1068  reference a;
1069  size_t i;
1070 };
1071 
1074 template <typename A> inline void swap(Scalar<A> &&a, typename A::scalar_type &b)
1075 {
1076  swap_impl(a.a, a.i, b, typename Scalar<A>::IndexSeq());
1077 }
1080 template <typename A> inline void swap(typename A::scalar_type &b, Scalar<A> &&a)
1081 {
1082  swap_impl(a.a, a.i, b, typename Scalar<A>::IndexSeq());
1083 }
1084 
1085 template <typename A> inline void swap(Scalar<A> &&a, Scalar<A> &&b)
1086 {
1087  swap_impl(a.a, a.i, b.a, b.i, typename Scalar<A>::IndexSeq());
1088 }
1089 
1090 template <typename A> class Interface
1091 {
1092  using reference = typename std::add_lvalue_reference<A>::type;
1093  using IndexSeq =
1094  Vc::make_index_sequence<determine_tuple_size<typename A::scalar_type>()>;
1095 
1096 public:
1097  Interface(reference aa) : a(aa) {}
1098 
1099  Scalar<A> operator[](size_t i)
1100  {
1101  return {a, i};
1102  }
1103  typename A::scalar_type operator[](size_t i) const
1104  {
1105  return extract_impl(a, i, IndexSeq());
1106  }
1107 
1108  A shifted(int amount) const
1109  {
1110  return shifted_impl(a, amount, IndexSeq());
1111  }
1112 
1113 private:
1114  reference a;
1115 };
1116 
1117 template <typename S, typename T, size_t N>
1118 Interface<Adapter<S, T, N>> decorate(Adapter<S, T, N> &a)
1119 {
1120  return {a};
1121 }
1122 template <typename S, typename T, size_t N>
1123 const Interface<const Adapter<S, T, N>> decorate(const Adapter<S, T, N> &a)
1124 {
1125  return {a};
1126 }
1127 
1128 namespace IteratorDetails
1129 {
1130 enum class Mutable { Yes, No };
1131 
1132 template <typename It, typename V, size_t I, size_t End>
1133 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I == End), It>)
1134 {
1135  return {};
1136 }
1137 template <typename It, typename V, size_t I, size_t End>
1138 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I < End), It> it)
1139 {
1140  V r = fromIteratorImpl<It, V, I + 1, End>(it);
1141  Traits::decay<decltype(get_dispatcher<I>(r))> tmp;
1142  for (size_t j = 0; j < V::size(); ++j, ++it) {
1143  tmp[j] = get_dispatcher<I>(*it);
1144  }
1145  get_dispatcher<I>(r) = tmp;
1146  return r;
1147 }
1148 template <typename It, typename V>
1149 Vc_INTRINSIC V fromIterator(enable_if<!Traits::is_simd_vector<V>::value, const It &> it)
1150 {
1151  return fromIteratorImpl<It, V, 0, determine_tuple_size<V>()>(it);
1152 }
1153 template <typename It, typename V>
1154 Vc_INTRINSIC V fromIterator(enable_if<Traits::is_simd_vector<V>::value, It> it)
1155 {
1156  V r;
1157  for (size_t j = 0; j < V::size(); ++j, ++it) {
1158  r[j] = *it;
1159  }
1160  return r;
1161 }
1162 
1163 // Note: §13.5.6 says: “An expression x->m is interpreted as (x.operator->())->m for a
1164 // class object x of type T if T::operator->() exists and if the operator is selected as
1165 // the best match function by the overload resolution mechanism (13.3).”
1166 template <typename T, typename value_vector, Mutable> class Pointer;
1167 
1176 template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::Yes>
1177 {
1178  static constexpr auto Size = value_vector::size();
1179 
1180 public:
1182  value_vector *operator->() { return &data; }
1183 
1188  Pointer() = delete;
1189  Pointer(const Pointer &) = delete;
1190  Pointer &operator=(const Pointer &) = delete;
1191  Pointer &operator=(Pointer &&) = delete;
1192 
1194  Pointer(Pointer &&) = default;
1195 
1201  ~Pointer()
1202  {
1203  // store data back to where it came from
1204  for (size_t i = 0; i < Size; ++i, ++begin_iterator) {
1205  *begin_iterator = extract(data, i);
1206  }
1207  }
1208 
1210  Pointer(const T &it) : data(fromIterator<T, value_vector>(it)), begin_iterator(it) {}
1211 
1212 private:
1214  value_vector data;
1216  T begin_iterator;
1217 };
1223 template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::No>
1224 {
1225  static constexpr auto Size = value_vector::size();
1226 
1227 public:
1228  const value_vector *operator->() const { return &data; }
1229 
1230  Pointer() = delete;
1231  Pointer(const Pointer &) = delete;
1232  Pointer &operator=(const Pointer &) = delete;
1233  Pointer &operator=(Pointer &&) = delete;
1234 
1235  Pointer(Pointer &&) = default; // required for returning the Pointer
1236 
1237  Pointer(const T &it) : data(fromIterator<T, value_vector>(it)) {}
1238 
1239 private:
1240  value_vector data;
1241 };
1242 
1255 template <typename T, typename value_vector, Mutable M> class Reference;
1256 
1258 template <typename T, typename value_vector>
1259 class Reference<T, value_vector, Mutable::Yes> : public value_vector
1260 {
1261  static constexpr auto Size = value_vector::size();
1262 
1263  using reference = typename std::add_lvalue_reference<T>::type;
1264  reference scalar_it;
1265 
1266 public:
1269  Reference(reference first_it)
1270  : value_vector(fromIterator<T, value_vector>(first_it)), scalar_it(first_it)
1271  {
1272  }
1273 
1275  Reference(const Reference &) = delete;
1276  Reference(Reference &&) = default;
1277  Reference &operator=(const Reference &) = delete;
1278  Reference &operator=(Reference &&) = delete;
1279 
1285  void operator=(const value_vector &x)
1286  {
1287  static_cast<value_vector &>(*this) = x;
1288  auto it = scalar_it;
1289  for (size_t i = 0; i < Size; ++i, ++it) {
1290  *it = extract(x, i);
1291  }
1292  }
1293 };
1294 
1296 template <typename T, typename value_vector>
1297 class Reference<T, value_vector, Mutable::No> : public value_vector
1298 {
1299  static constexpr auto Size = value_vector::size();
1300 
1301 public:
1302  Reference(const T &it) : value_vector(fromIterator<T, value_vector>(it)) {}
1303 
1304  Reference(const Reference &) = delete;
1305  Reference(Reference &&) = default;
1306  Reference &operator=(const Reference &) = delete;
1307  Reference &operator=(Reference &&) = delete;
1308 
1310  void operator=(const value_vector &x) = delete;
1311 };
1312 
1313 template <typename T, size_t N,
1314  IteratorDetails::Mutable M =
1315  (Traits::is_output_iterator<T>::value ? Mutable::Yes : Mutable::No),
1316  typename V = simdize<typename std::iterator_traits<T>::value_type, N>,
1317  size_t Size = V::size(),
1318  typename = typename std::iterator_traits<T>::iterator_category>
1319 class Iterator;
1320 
1321 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1322 class Iterator<T, N, M, V, Size, std::forward_iterator_tag>
1323  : public std::iterator<typename std::iterator_traits<T>::iterator_category, V,
1324  typename std::iterator_traits<T>::difference_type,
1325  IteratorDetails::Pointer<T, V, M>,
1326  IteratorDetails::Reference<T, V, M>>
1327 {
1328 public:
1329  using pointer = IteratorDetails::Pointer<T, V, M>;
1330  using reference = IteratorDetails::Reference<T, V, M>;
1331  using const_pointer = IteratorDetails::Pointer<T, V, IteratorDetails::Mutable::No>;
1332  using const_reference =
1333  IteratorDetails::Reference<T, V, IteratorDetails::Mutable::No>;
1334 
1336  static constexpr std::size_t size() { return Size; }
1337 
1338  Iterator() = default;
1339 
1346  Iterator(const T &x) : scalar_it(x) {}
1350  Iterator(T &&x) : scalar_it(std::move(x)) {}
1354  Iterator &operator=(const T &x)
1355  {
1356  scalar_it = x;
1357  return *this;
1358  }
1362  Iterator &operator=(T &&x)
1363  {
1364  scalar_it = std::move(x);
1365  return *this;
1366  }
1367 
1369  Iterator(const Iterator &) = default;
1371  Iterator(Iterator &&) = default;
1373  Iterator &operator=(const Iterator &) = default;
1375  Iterator &operator=(Iterator &&) = default;
1376 
1378  Iterator &operator++()
1379  {
1380  std::advance(scalar_it, Size);
1381  return *this;
1382  }
1384  Iterator operator++(int)
1385  {
1386  Iterator copy(*this);
1387  operator++();
1388  return copy;
1389  }
1390 
1399  bool operator==(const Iterator &rhs) const
1400  {
1401  T it(scalar_it);
1402  for (size_t i = 1; i < Size; ++i) {
1403  Vc_ASSERT((++it != rhs.scalar_it));
1404  }
1405  return scalar_it == rhs.scalar_it;
1406  }
1415  bool operator!=(const Iterator &rhs) const
1416  {
1417  T it(scalar_it);
1418  for (size_t i = 1; i < Size; ++i) {
1419  Vc_ASSERT((++it != rhs.scalar_it));
1420  }
1421  return scalar_it != rhs.scalar_it;
1422  }
1423 
1424  pointer operator->() { return scalar_it; }
1425 
1432  reference operator*() { return scalar_it; }
1433 
1434  const_pointer operator->() const { return scalar_it; }
1435 
1443  const_reference operator*() const { return scalar_it; }
1444 
1458  operator const T &() const { return scalar_it; }
1459 
1460 protected:
1461  T scalar_it;
1462 };
1463 
1468 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1469 class Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1470  : public Iterator<T, N, M, V, Size, std::forward_iterator_tag>
1471 {
1472  using Base = Iterator<T, N, M, V, Size, std::forward_iterator_tag>;
1473 
1474 protected:
1475  using Base::scalar_it;
1476 
1477 public:
1478  using pointer = typename Base::pointer;
1479  using reference = typename Base::reference;
1480  using const_pointer = typename Base::const_pointer;
1481  using const_reference = typename Base::const_reference;
1482 
1483  using Iterator<T, N, M, V, Size,
1484  std::forward_iterator_tag>::Iterator; // in short: "using
1485  // Base::Iterator", but that
1486  // confuses ICC
1488  Iterator &operator--()
1489  {
1490  std::advance(scalar_it, -Size);
1491  return *this;
1492  }
1494  Iterator operator--(int)
1495  {
1496  Iterator copy(*this);
1497  operator--();
1498  return copy;
1499  }
1500 };
1501 
1506 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1507 class Iterator<T, N, M, V, Size, std::random_access_iterator_tag>
1508  : public Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1509 {
1511 
1512 protected:
1513  using Base::scalar_it;
1514 
1515 public:
1516  using pointer = typename Base::pointer;
1517  using reference = typename Base::reference;
1518  using const_pointer = typename Base::const_pointer;
1519  using const_reference = typename Base::const_reference;
1520  using difference_type = typename std::iterator_traits<T>::difference_type;
1521 
1523  Iterator; // in short: "using Base::Iterator", but that confuses ICC
1524 
1525  Iterator &operator+=(difference_type n)
1526  {
1527  scalar_it += n * Size;
1528  return *this;
1529  }
1530  Iterator operator+(difference_type n) const { return Iterator(*this) += n; }
1531 
1532  Iterator &operator-=(difference_type n)
1533  {
1534  scalar_it -= n * Size;
1535  return *this;
1536  }
1537  Iterator operator-(difference_type n) const { return Iterator(*this) -= n; }
1538 
1539  difference_type operator-(const Iterator &rhs) const
1540  {
1541  constexpr difference_type n = Size;
1542  Vc_ASSERT((scalar_it - rhs.scalar_it) % n ==
1543  0); // if this fails the two iterators are not a multiple of the vector
1544  // width apart. The distance would be fractional and that doesn't
1545  // make too much sense for iteration. Therefore, it is a
1546  // precondition for the distance of the two iterators to be a
1547  // multiple of Size.
1548  return (scalar_it - rhs.scalar_it) / n;
1549  }
1550 
1555  bool operator<(const Iterator &rhs) const
1556  {
1557  return scalar_it + Size <= rhs.scalar_it;
1558  }
1559 
1560  bool operator>(const Iterator &rhs) const
1561  {
1562  return scalar_it >= rhs.scalar_it + Size;
1563  }
1564 
1565  bool operator<=(const Iterator &rhs) const
1566  {
1567  return scalar_it + (Size - 1) <= rhs.scalar_it;
1568  }
1569 
1570  bool operator>=(const Iterator &rhs) const
1571  {
1572  return scalar_it >= rhs.scalar_it + (Size - 1);
1573  }
1574 
1575  reference operator[](difference_type i) { return *(*this + i); }
1576  const_reference operator[](difference_type i) const { return *(*this + i); }
1577 };
1578 
1579 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1580 Iterator<T, N, M, V, Size, std::random_access_iterator_tag> operator+(
1581  typename Iterator<T, N, M, V, Size, std::random_access_iterator_tag>::difference_type
1582  n,
1583  const Iterator<T, N, M, V, Size, std::random_access_iterator_tag> &i)
1584 {
1585  return i + n;
1586 }
1587 
1588 } // namespace IteratorDetails
1589 
1598 template <typename T, size_t N, typename MT>
1599 struct ReplaceTypes<T, N, MT, Category::ForwardIterator>
1600 {
1601  using type = IteratorDetails::Iterator<T, N>;
1602 };
1603 template <typename T, size_t N, typename MT>
1604 struct ReplaceTypes<T, N, MT, Category::BidirectionalIterator>
1605 {
1606  using type = IteratorDetails::Iterator<T, N>;
1607 };
1608 template <typename T, size_t N, typename MT>
1609 struct ReplaceTypes<T, N, MT, Category::RandomAccessIterator>
1610 {
1611  using type = IteratorDetails::Iterator<T, N>;
1612 };
1613 
1617 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1618  std::size_t Offset>
1619 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size<S>() && M::size() == N), void>
1620  conditional_assign(Adapter<S, T, N> &, const M &, const U &)
1621 {
1622 }
1623 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1624  std::size_t Offset = 0>
1625 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size<S>() && M::size() == N), void>
1626  conditional_assign(Adapter<S, T, N> &lhs, const M &mask, const U &rhs)
1627 {
1628  using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1629  using M2 = typename V::mask_type;
1630  conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask), get_dispatcher<Offset>(rhs));
1631  conditional_assign<Op, S, T, N, M, U, Offset + 1>(lhs, mask, rhs);
1632 }
1633 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1634  std::size_t Offset>
1635 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size<S>() && M::size() == N), void>
1636  conditional_assign(Adapter<S, T, N> &, const M &)
1637 {
1638 }
1639 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1640  std::size_t Offset = 0>
1641 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size<S>() && M::size() == N), void>
1642  conditional_assign(Adapter<S, T, N> &lhs, const M &mask)
1643 {
1644  using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1645  using M2 = typename V::mask_type;
1646  conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask));
1647  conditional_assign<Op, S, T, N, M, Offset + 1>(lhs, mask);
1648 }
1649 
1651 } // namespace SimdizeDetail
1652 
1671 template <typename T, size_t N = 0, typename MT = void>
1672 using simdize = SimdizeDetail::simdize<T, N, MT>;
1673 
1693 #define Vc_SIMDIZE_INTERFACE(MEMBERS_) \
1694  template <std::size_t N_> \
1695  inline auto vc_get_()->decltype(std::get<N_>(std::tie MEMBERS_)) \
1696  { \
1697  return std::get<N_>(std::tie MEMBERS_); \
1698  } \
1699  template <std::size_t N_> \
1700  inline auto vc_get_() const->decltype(std::get<N_>(std::tie MEMBERS_)) \
1701  { \
1702  return std::get<N_>(std::tie MEMBERS_); \
1703  } \
1704  enum : std::size_t { \
1705  tuple_size = std::tuple_size<decltype(std::tie MEMBERS_)>::value \
1706  }
1707 
1708 } // namespace Vc
1709 
1710 namespace std
1711 {
1712 using Vc::SimdizeDetail::swap;
1713 } // namespace std
1714 
1715 #endif // VC_COMMON_SIMDIZE_H_
1716 
1717 // 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:1555
Definition: vector.h:258
SimdizeDetail::simdize< T, N, MT > simdize
Definition: simdize.h:1672
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:967
An allocator that uses global new and supports over-aligned types, as per [C++11 20.6.9].
Definition: Allocator:129
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:938
Iterator & operator--()
Advances the iterator by one vector width, or respectively N scalar steps.
Definition: simdize.h:1488
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:999
Vector Classes Namespace.
Definition: cpuid.h:33
This is the iterator type created when applying simdize to a bidirectional iterator type...
Definition: simdize.h:1469