Vc  1.0.0-dev
SIMD Vector Classes for C++
simdize.h
1 /* This file is part of the Vc library. {{{
2 Copyright © 2014-2015 Matthias Kretz <kretz@kde.org>
3 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, \
480  ValueType__ Value0, ValueType__... Values> \
481  struct is_class_template<C<T, Value0, Values...>> : public true_type \
482  { \
483  }; \
484  template <template <typename, typename, ValueType__...> class C, typename T0, \
485  typename T1, ValueType__ Value0, ValueType__... Values> \
486  struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type \
487  { \
488  }; \
489  template <template <typename, typename, typename, ValueType__...> class C, \
490  typename T0, typename T1, typename T2, ValueType__ Value0, \
491  ValueType__... Values> \
492  struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type \
493  { \
494  }; \
495  template <template <typename, typename, typename, typename, ValueType__...> class C, \
496  typename T0, typename T1, typename T2, typename T3, ValueType__ Value0, \
497  ValueType__... Values> \
498  struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type \
499  { \
500  }; \
501  template < \
502  template <typename, typename, typename, typename, typename, ValueType__...> \
503  class C, typename T0, typename T1, typename T2, typename T3, typename T4, \
504  ValueType__ Value0, ValueType__... Values> \
505  struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
506  : public true_type \
507  { \
508  }; \
509  template <template <typename, typename, typename, typename, typename, typename, \
510  ValueType__...> class C, \
511  typename T0, typename T1, typename T2, typename T3, typename T4, \
512  typename T5, ValueType__ Value0, ValueType__... Values> \
513  struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
514  : public true_type \
515  { \
516  }; \
517  template <template <typename, typename, typename, typename, typename, typename, \
518  typename, ValueType__...> class C, \
519  typename T0, typename T1, typename T2, typename T3, typename T4, \
520  typename T5, typename T6, ValueType__ Value0, ValueType__... Values> \
521  struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
522  : public true_type \
523  { \
524  }; \
525  template <template <typename, ValueType__> class C, typename T0, ValueType__ Value0, \
526  size_t N, typename MT> \
527  struct ReplaceTypes<C<T0, Value0>, N, MT, Category::ClassTemplate> \
528  { \
529  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
530  typedef typename tmp::template SubstitutedWithValues<ValueType__, C, Value0> \
531  Substituted; \
532  static constexpr auto NN = tmp::N; \
533  typedef conditional_t<is_same<C<T0, Value0>, Substituted>::value, C<T0, Value0>, \
534  Adapter<C<T0, Value0>, Substituted, NN>> type; \
535  }; \
536  template <template <typename, typename, ValueType__> class C, typename T0, \
537  typename T1, ValueType__ Value0, size_t N, typename MT> \
538  struct ReplaceTypes<C<T0, T1, Value0>, N, MT, Category::ClassTemplate> \
539  { \
540  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
541  typedef typename tmp::template SubstitutedWithValues<ValueType__, C, Value0> \
542  Substituted; \
543  static constexpr auto NN = tmp::N; \
544  typedef conditional_t<is_same<C<T0, T1, Value0>, Substituted>::value, \
545  C<T0, T1, Value0>, \
546  Adapter<C<T0, T1, Value0>, Substituted, NN>> type; \
547  }; \
548  template <template <typename, typename, typename, ValueType__> class C, typename T0, \
549  typename T1, typename T2, ValueType__ Value0, size_t N, typename MT> \
550  struct ReplaceTypes<C<T0, T1, T2, Value0>, N, MT, Category::ClassTemplate> \
551  { \
552  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
553  typedef typename tmp::template SubstitutedWithValues<ValueType__, C, Value0> \
554  Substituted; \
555  static constexpr auto NN = tmp::N; \
556  typedef conditional_t<is_same<C<T0, T1, T2, Value0>, Substituted>::value, \
557  C<T0, T1, T2, Value0>, \
558  Adapter<C<T0, T1, T2, Value0>, Substituted, NN>> type; \
559  }
560 #else
561 #define Vc_DEFINE_NONTYPE_REPLACETYPES__(ValueType__) \
562  template <template <typename, ValueType__...> class C, typename T, \
563  ValueType__ Value0, ValueType__... Values> \
564  struct is_class_template<C<T, Value0, Values...>> : public true_type { \
565  }; \
566  template <template <typename, typename, ValueType__...> class C, typename T0, \
567  typename T1, ValueType__ Value0, ValueType__... Values> \
568  struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type { \
569  }; \
570  template <template <typename, typename, typename, ValueType__...> class C, \
571  typename T0, typename T1, typename T2, ValueType__ Value0, \
572  ValueType__... Values> \
573  struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type { \
574  }; \
575  template <template <typename, typename, typename, typename, ValueType__...> class C, \
576  typename T0, typename T1, typename T2, typename T3, ValueType__ Value0, \
577  ValueType__... Values> \
578  struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type { \
579  }; \
580  template <template <typename, typename, typename, typename, typename, \
581  ValueType__...> class C, \
582  typename T0, typename T1, typename T2, typename T3, typename T4, \
583  ValueType__ Value0, ValueType__... Values> \
584  struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
585  : public true_type { \
586  }; \
587  template <template <typename, typename, typename, typename, typename, typename, \
588  ValueType__...> class C, \
589  typename T0, typename T1, typename T2, typename T3, typename T4, \
590  typename T5, ValueType__ Value0, ValueType__... Values> \
591  struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
592  : public true_type { \
593  }; \
594  template <template <typename, typename, typename, typename, typename, typename, \
595  typename, ValueType__...> class C, \
596  typename T0, typename T1, typename T2, typename T3, typename T4, \
597  typename T5, typename T6, ValueType__ Value0, ValueType__... Values> \
598  struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
599  : public true_type { \
600  }; \
601  template <template <typename, ValueType__...> class C, typename T0, \
602  ValueType__ Value0, ValueType__... Values, size_t N, typename MT> \
603  struct ReplaceTypes<C<T0, Value0, Values...>, N, MT, Category::ClassTemplate> { \
604  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
605  typedef typename tmp::template SubstitutedWithValues<ValueType__, C, Value0, \
606  Values...> Substituted; \
607  static constexpr auto NN = tmp::N; \
608  typedef conditional_t<is_same<C<T0, Value0, Values...>, Substituted>::value, \
609  C<T0, Value0, Values...>, \
610  Adapter<C<T0, Value0, Values...>, Substituted, NN>> type; \
611  }; \
612  template <template <typename, typename, ValueType__...> class C, typename T0, \
613  typename T1, ValueType__ Value0, ValueType__... Values, size_t N, \
614  typename MT> \
615  struct ReplaceTypes<C<T0, T1, Value0, Values...>, N, MT, Category::ClassTemplate> { \
616  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
617  typedef typename tmp::template SubstitutedWithValues<ValueType__, C, Value0, \
618  Values...> Substituted; \
619  static constexpr auto NN = tmp::N; \
620  typedef conditional_t<is_same<C<T0, T1, Value0, Values...>, Substituted>::value, \
621  C<T0, T1, Value0, Values...>, \
622  Adapter<C<T0, T1, Value0, Values...>, Substituted, NN>> \
623  type; \
624  }; \
625  template <template <typename, typename, typename, ValueType__...> class C, \
626  typename T0, typename T1, typename T2, ValueType__ Value0, \
627  ValueType__... Values, size_t N, typename MT> \
628  struct ReplaceTypes<C<T0, T1, T2, Value0, Values...>, N, MT, \
629  Category::ClassTemplate> { \
630  typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
631  typedef typename tmp::template SubstitutedWithValues<ValueType__, C, Value0, \
632  Values...> Substituted; \
633  static constexpr auto NN = tmp::N; \
634  typedef conditional_t< \
635  is_same<C<T0, T1, T2, Value0, Values...>, Substituted>::value, \
636  C<T0, T1, T2, Value0, Values...>, \
637  Adapter<C<T0, T1, T2, Value0, Values...>, Substituted, NN>> type; \
638  }
639 #endif // Vc_ICC
640 Vc_DEFINE_NONTYPE_REPLACETYPES__(bool);
641 Vc_DEFINE_NONTYPE_REPLACETYPES__(wchar_t);
642 Vc_DEFINE_NONTYPE_REPLACETYPES__(char);
643 Vc_DEFINE_NONTYPE_REPLACETYPES__( signed char);
644 Vc_DEFINE_NONTYPE_REPLACETYPES__(unsigned char);
645 Vc_DEFINE_NONTYPE_REPLACETYPES__( signed short);
646 Vc_DEFINE_NONTYPE_REPLACETYPES__(unsigned short);
647 Vc_DEFINE_NONTYPE_REPLACETYPES__( signed int);
648 Vc_DEFINE_NONTYPE_REPLACETYPES__(unsigned int);
649 Vc_DEFINE_NONTYPE_REPLACETYPES__( signed long);
650 Vc_DEFINE_NONTYPE_REPLACETYPES__(unsigned long);
651 Vc_DEFINE_NONTYPE_REPLACETYPES__( signed long long);
652 Vc_DEFINE_NONTYPE_REPLACETYPES__(unsigned long long);
653 #undef Vc_DEFINE_NONTYPE_REPLACETYPES__
654 
655 #ifdef Vc_ICC
656 // FIXME: find a proper workaround implementation for ICC
657 template <typename Class, typename... Args>
658 constexpr bool is_constructible_with_single_brace()
659 {
660  return true;
661 }
662 template <typename Class, typename... Args>
663 constexpr bool is_constructible_with_double_brace()
664 {
665  return false;
666 }
667 #else
668 namespace is_constructible_with_single_brace_impl
669 {
670 template <typename T> T create();
671 template <typename Class, typename... Args,
672  typename = decltype((Class{create<Args>()...}))>
673 std::true_type test(int);
674 template <typename Class, typename... Args> std::false_type test(...);
675 } // namespace is_constructible_with_single_brace_impl
676 
677 template <typename Class, typename... Args>
678 constexpr bool is_constructible_with_single_brace()
679 {
680  return decltype(
681  is_constructible_with_single_brace_impl::test<Class, Args...>(1))::value;
682 }
683 static_assert(
684  is_constructible_with_single_brace<std::tuple<int, int, int>, int, int, int>(), "");
685 static_assert(is_constructible_with_single_brace<std::array<int, 3>, int, int, int>(),
686  "");
687 
688 namespace is_constructible_with_double_brace_impl
689 {
690 template <typename T> T create();
691 template <typename Class, typename... Args,
692  typename = decltype(Class{{create<Args>()...}})>
693 std::true_type test(int);
694 template <typename Class, typename... Args> std::false_type test(...);
695 } // namespace is_constructible_with_double_brace_impl
696 
697 template <typename Class, typename... Args>
698 constexpr bool is_constructible_with_double_brace()
699 {
700  return decltype(
701  is_constructible_with_double_brace_impl::test<Class, Args...>(1))::value;
702 }
703 static_assert(
704  !is_constructible_with_double_brace<std::tuple<int, int, int>, int, int, int>(), "");
705 static_assert(is_constructible_with_double_brace<std::array<int, 3>, int, int, int>(),
706  "");
707 #endif
708 
709 template <size_t I, typename T,
710  typename R = decltype(std::declval<T &>().template vc_get__<I>())>
711 R get_dispatcher(T &x, void * = nullptr)
712 {
713  return x.template vc_get__<I>();
714 }
715 template <size_t I, typename T,
716  typename R = decltype(std::declval<const T &>().template vc_get__<I>())>
717 R get_dispatcher(const T &x, void * = nullptr)
718 {
719  return x.template vc_get__<I>();
720 }
721 template <size_t I, typename T, typename R = decltype(std::get<I>(std::declval<T &>()))>
722 R get_dispatcher(T &x, int = 0)
723 {
724  return std::get<I>(x);
725 }
726 template <size_t I, typename T,
727  typename R = decltype(std::get<I>(std::declval<const T &>()))>
728 R get_dispatcher(const T &x, int = 0)
729 {
730  return std::get<I>(x);
731 }
732 
733 
734 // see above
735 template <typename Scalar, typename Base, size_t N> class Adapter : public Base
736 {
737 private:
739  template <std::size_t... Indexes, typename T>
740  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x__, T, std::true_type)
741  : Base{{get_dispatcher<Indexes>(x__)...}}
742  {
743  }
744 
746  template <std::size_t... Indexes>
747  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x__, std::true_type,
748  std::false_type)
749  : Base{get_dispatcher<Indexes>(x__)...}
750  {
751  }
752 
754  template <std::size_t... Indexes>
755  Adapter(Vc::index_sequence<Indexes...>, const Scalar &x__, std::false_type,
756  std::false_type)
757  : Base(get_dispatcher<Indexes>(x__)...)
758  {
759  }
760 
761  template <std::size_t... Indexes>
762  Adapter(Vc::index_sequence<Indexes...> seq__, const Scalar &x__)
763  : Adapter(
764  seq__, x__,
765  std::integral_constant<bool, is_constructible_with_single_brace<
766  Base, decltype(get_dispatcher<Indexes>(std::declval<
767  const Scalar &>()))...>()>(),
768  std::integral_constant<bool, is_constructible_with_double_brace<
769  Base, decltype(get_dispatcher<Indexes>(std::declval<
770  const Scalar &>()))...>()>())
771  {
772  }
773 
774 public:
776  static constexpr size_t size() { return N; }
777 
779  using base_type = Base;
782  using scalar_type = Scalar;
783 
786  Adapter() = default;
787 
789 #if defined Vc_CLANG && Vc_CLANG < 0x30700
790  Vc_INTRINSIC Adapter(const Adapter &x) : Base(x) {}
791 #else
792  Adapter(const Adapter &) = default;
793 #endif
794  Adapter(Adapter &&) = default;
797  Adapter &operator=(const Adapter &) = default;
799  Adapter &operator=(Adapter &&) = default;
800 
802  template <typename U, size_t TupleSize = determine_tuple_size<Scalar>(),
803  typename Seq = Vc::make_index_sequence<TupleSize>,
804  typename = enable_if<std::is_convertible<U, Scalar>::value>>
805  Adapter(U &&x__)
806  : Adapter(Seq(), static_cast<const Scalar &>(x__))
807  {
808  }
809 
811  template <typename A0, typename... Args,
812  typename = typename std::enable_if<
813  !Traits::is_index_sequence<A0>::value &&
814  (sizeof...(Args) > 0 || !std::is_convertible<A0, Scalar>::value)>::type>
815  Adapter(A0 &&arg0__, Args &&... arguments__)
816  : Base(std::forward<A0>(arg0__), std::forward<Args>(arguments__)...)
817  {
818  }
819 
821  template <typename T,
822  typename = decltype(Base(std::declval<const std::initializer_list<T> &>()))>
823  Adapter(const std::initializer_list<T> &l__)
824  : Base(l__)
825  {
826  }
827 
830  void *operator new(size_t size) { return Vc::Common::aligned_malloc<alignof(Adapter)>(size); }
831  void *operator new(size_t, void *p__) { return p__; }
832  void *operator new[](size_t size) { return Vc::Common::aligned_malloc<alignof(Adapter)>(size); }
833  void *operator new[](size_t , void *p__) { return p__; }
834  void operator delete(void *ptr__, size_t) { Vc::Common::free(ptr__); }
835  void operator delete(void *, void *) {}
836  void operator delete[](void *ptr__, size_t) { Vc::Common::free(ptr__); }
837  void operator delete[](void *, void *) {}
838 };
839 
844 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
845 inline bool operator==(
846  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
847  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
848 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
849 inline bool operator!=(
850  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
851  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
852 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
853 inline bool operator<=(
854  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
855  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
856 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
857 inline bool operator>=(
858  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
859  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
860 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
861 inline bool operator<(
862  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
863  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
864 template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
865 inline bool operator>(
866  const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
867  const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
868 
870 } // namespace SimdizeDetail
871 } // namespace Vc
872 
873 namespace std
874 {
878 template <typename Scalar, typename Base, size_t N>
879 class tuple_size<Vc::SimdizeDetail::Adapter<Scalar, Base, N>> : public tuple_size<Base>
880 {
881 };
885 template <size_t I, typename Scalar, typename Base, size_t N>
886 class tuple_element<I, Vc::SimdizeDetail::Adapter<Scalar, Base, N>>
887  : public tuple_element<I, Base>
888 {
889 };
890 // std::get does not need additional work because Vc::Adapter derives from
891 // C<Ts...> and therefore if get<N>(C<Ts...>) works it works for Adapter as well.
892 
897 template <typename S, typename T, size_t N>
898 class allocator<Vc::SimdizeDetail::Adapter<S, T, N>>
899  : public Vc::Allocator<Vc::SimdizeDetail::Adapter<S, T, N>>
900 {
901 public:
902  template <typename U> struct rebind
903  {
904  typedef std::allocator<U> other;
905  };
906 };
907 } // namespace std
908 
909 namespace Vc_VERSIONED_NAMESPACE
910 {
911 namespace SimdizeDetail
912 {
921 template <typename T> static inline T decay_workaround(const T &x) { return x; }
922 
926 template <typename S, typename T, size_t N, size_t... Indexes>
927 inline void assign_impl(Adapter<S, T, N> &a, size_t i, const S &x,
928  Vc::index_sequence<Indexes...>)
929 {
930  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(x)))...> tmp(
931  decay_workaround(get_dispatcher<Indexes>(x))...);
932  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(tmp), 0)...};
933  if (&unused == &unused) {}
934 }
935 
940 template <typename S, typename T, size_t N>
941 inline void assign(Adapter<S, T, N> &a, size_t i, const S &x)
942 {
943  assign_impl(a, i, x, Vc::make_index_sequence<determine_tuple_size<T>()>());
944 }
948 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
949 Vc_INTRINSIC void assign(V &v, size_t i, typename V::EntryType x)
950 {
951  v[i] = x;
952 }
953 
957 template <typename S, typename T, size_t N, size_t... Indexes>
958 inline S extract_impl(const Adapter<S, T, N> &a, size_t i, Vc::index_sequence<Indexes...>)
959 {
960  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[i]))...> tmp(
961  decay_workaround(get_dispatcher<Indexes>(a)[i])...);
962  return S(get_dispatcher<Indexes>(tmp)...);
963 }
964 
969 template <typename S, typename T, size_t N>
970 inline S extract(const Adapter<S, T, N> &a, size_t i)
971 {
972  return extract_impl(a, i, Vc::make_index_sequence<determine_tuple_size<S>()>());
973 }
977 template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
978 Vc_INTRINSIC typename V::EntryType extract(const V &v, size_t i)
979 {
980  return v[i];
981 }
982 
983 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
984 inline Adapter<S, T, N> shifted_impl(const Adapter<S, T, N> &a, int shift,
985  Vc::index_sequence<Indexes...>)
986 {
987  Adapter<S, T, N> r;
988  auto &&unused = {(get_dispatcher<Indexes>(r) = get_dispatcher<Indexes>(a).shifted(shift), 0)...};
989  if (&unused == &unused) {}
990  return r;
991 }
992 
1001 template <typename S, typename T, size_t N>
1002 inline Adapter<S, T, N> shifted(const Adapter<S, T, N> &a, int shift)
1003 {
1004  return shifted_impl(a, shift, Vc::make_index_sequence<determine_tuple_size<T>()>());
1005 }
1006 
1010 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1011 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, S &x,
1012  Vc::index_sequence<Indexes...>)
1013 {
1014  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[0]))...> tmp{
1015  decay_workaround(get_dispatcher<Indexes>(a)[i])...};
1016  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(x), 0)...};
1017  auto &&unused2 = {(get_dispatcher<Indexes>(x) = get_dispatcher<Indexes>(tmp), 0)...};
1018  if (&unused == &unused2) {}
1019 }
1020 template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1021 inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b,
1022  std::size_t j, Vc::index_sequence<Indexes...>)
1023 {
1024  const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[0]))...> tmp{
1025  decay_workaround(get_dispatcher<Indexes>(a)[i])...};
1026  auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(b)[j], 0)...};
1027  auto &&unused2 = {(get_dispatcher<Indexes>(b)[j] = get_dispatcher<Indexes>(tmp), 0)...};
1028  if (&unused == &unused2) {}
1029 }
1030 
1035 template <typename S, typename T, std::size_t N>
1036 inline void swap(Adapter<S, T, N> &a, std::size_t i, S &x)
1037 {
1038  swap_impl(a, i, x, Vc::make_index_sequence<determine_tuple_size<T>()>());
1039 }
1040 template <typename S, typename T, std::size_t N>
1041 inline void swap(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b, std::size_t j)
1042 {
1043  swap_impl(a, i, b, j, Vc::make_index_sequence<determine_tuple_size<T>()>());
1044 }
1045 
1046 template <typename A> class Scalar
1047 {
1048  using reference = typename std::add_lvalue_reference<A>::type;
1049  using S = typename A::scalar_type;
1050  using IndexSeq = Vc::make_index_sequence<determine_tuple_size<S>()>;
1051 
1052 public:
1053  Scalar(reference aa, size_t ii) : a(aa), i(ii) {}
1054 
1055  // delete copy and move to keep the type a pure proxy temporary object.
1056  Scalar(const Scalar &) = delete;
1057  Scalar(Scalar &&) = delete;
1058  Scalar &operator=(const Scalar &) = delete;
1059  Scalar &operator=(Scalar &&) = delete;
1060 
1061  void operator=(const S &x) { assign_impl(a, i, x, IndexSeq()); }
1062  operator S() const { return extract_impl(a, i, IndexSeq()); }
1063 
1064  template <typename AA>
1065  friend inline void swap(Scalar<AA> &&a, typename AA::scalar_type &b);
1066  template <typename AA>
1067  friend inline void swap(typename AA::scalar_type &b, Scalar<AA> &&a);
1068  template <typename AA> friend inline void swap(Scalar<AA> &&a, Scalar<AA> &&b);
1069 
1070 private:
1071  reference a;
1072  size_t i;
1073 };
1074 
1077 template <typename A> inline void swap(Scalar<A> &&a, typename A::scalar_type &b)
1078 {
1079  swap_impl(a.a, a.i, b, typename Scalar<A>::IndexSeq());
1080 }
1083 template <typename A> inline void swap(typename A::scalar_type &b, Scalar<A> &&a)
1084 {
1085  swap_impl(a.a, a.i, b, typename Scalar<A>::IndexSeq());
1086 }
1087 
1088 template <typename A> inline void swap(Scalar<A> &&a, Scalar<A> &&b)
1089 {
1090  swap_impl(a.a, a.i, b.a, b.i, typename Scalar<A>::IndexSeq());
1091 }
1092 
1093 template <typename A> class Interface
1094 {
1095  using reference = typename std::add_lvalue_reference<A>::type;
1096  using IndexSeq =
1097  Vc::make_index_sequence<determine_tuple_size<typename A::scalar_type>()>;
1098 
1099 public:
1100  Interface(reference aa) : a(aa) {}
1101 
1102  Scalar<A> operator[](size_t i)
1103  {
1104  return {a, i};
1105  }
1106  typename A::scalar_type operator[](size_t i) const
1107  {
1108  return extract_impl(a, i, IndexSeq());
1109  }
1110 
1111  A shifted(int amount) const
1112  {
1113  return shifted_impl(a, amount, IndexSeq());
1114  }
1115 
1116 private:
1117  reference a;
1118 };
1119 
1120 template <typename S, typename T, size_t N>
1121 Interface<Adapter<S, T, N>> decorate(Adapter<S, T, N> &a)
1122 {
1123  return {a};
1124 }
1125 template <typename S, typename T, size_t N>
1126 const Interface<const Adapter<S, T, N>> decorate(const Adapter<S, T, N> &a)
1127 {
1128  return {a};
1129 }
1130 
1131 namespace IteratorDetails
1132 {
1133 enum class Mutable { Yes, No };
1134 
1135 template <typename It, typename V, size_t I, size_t End>
1136 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I == End), It>)
1137 {
1138  return {};
1139 }
1140 template <typename It, typename V, size_t I, size_t End>
1141 Vc_INTRINSIC V fromIteratorImpl(enable_if<(I < End), It> it)
1142 {
1143  V r = fromIteratorImpl<It, V, I + 1, End>(it);
1144  Traits::decay<decltype(get_dispatcher<I>(r))> tmp;
1145  for (size_t j = 0; j < V::size(); ++j, ++it) {
1146  tmp[j] = get_dispatcher<I>(*it);
1147  }
1148  get_dispatcher<I>(r) = tmp;
1149  return r;
1150 }
1151 template <typename It, typename V>
1152 Vc_INTRINSIC V fromIterator(enable_if<!Traits::is_simd_vector<V>::value, const It &> it)
1153 {
1154  return fromIteratorImpl<It, V, 0, determine_tuple_size<V>()>(it);
1155 }
1156 template <typename It, typename V>
1157 Vc_INTRINSIC V fromIterator(enable_if<Traits::is_simd_vector<V>::value, It> it)
1158 {
1159  V r;
1160  for (size_t j = 0; j < V::size(); ++j, ++it) {
1161  r[j] = *it;
1162  }
1163  return r;
1164 }
1165 
1166 // Note: §13.5.6 says: “An expression x->m is interpreted as (x.operator->())->m for a
1167 // class object x of type T if T::operator->() exists and if the operator is selected as
1168 // the best match function by the overload resolution mechanism (13.3).”
1169 template <typename T, typename value_vector, Mutable> class Pointer;
1170 
1179 template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::Yes>
1180 {
1181  static constexpr auto Size = value_vector::size();
1182 
1183 public:
1185  value_vector *operator->() { return &data; }
1186 
1191  Pointer() = delete;
1192  Pointer(const Pointer &) = delete;
1193  Pointer &operator=(const Pointer &) = delete;
1194  Pointer &operator=(Pointer &&) = delete;
1195 
1197  Pointer(Pointer &&) = default;
1198 
1204  ~Pointer()
1205  {
1206  // store data back to where it came from
1207  for (size_t i = 0; i < Size; ++i, ++begin_iterator) {
1208  *begin_iterator = extract(data, i);
1209  }
1210  }
1211 
1213  Pointer(const T &it) : data(fromIterator<T, value_vector>(it)), begin_iterator(it) {}
1214 
1215 private:
1217  value_vector data;
1219  T begin_iterator;
1220 };
1226 template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::No>
1227 {
1228  static constexpr auto Size = value_vector::size();
1229 
1230 public:
1231  const value_vector *operator->() const { return &data; }
1232 
1233  Pointer() = delete;
1234  Pointer(const Pointer &) = delete;
1235  Pointer &operator=(const Pointer &) = delete;
1236  Pointer &operator=(Pointer &&) = delete;
1237 
1238  Pointer(Pointer &&) = default; // required for returning the Pointer
1239 
1240  Pointer(const T &it) : data(fromIterator<T, value_vector>(it)) {}
1241 
1242 private:
1243  value_vector data;
1244 };
1245 
1258 template <typename T, typename value_vector, Mutable M> class Reference;
1259 
1261 template <typename T, typename value_vector>
1262 class Reference<T, value_vector, Mutable::Yes> : public value_vector
1263 {
1264  static constexpr auto Size = value_vector::size();
1265 
1266  using reference = typename std::add_lvalue_reference<T>::type;
1267  reference scalar_it;
1268 
1269 public:
1272  Reference(reference first_it)
1273  : value_vector(fromIterator<T, value_vector>(first_it)), scalar_it(first_it)
1274  {
1275  }
1276 
1278  Reference(const Reference &) = delete;
1279  Reference(Reference &&) = default;
1280  Reference &operator=(const Reference &) = delete;
1281  Reference &operator=(Reference &&) = delete;
1282 
1288  void operator=(const value_vector &x)
1289  {
1290  static_cast<value_vector &>(*this) = x;
1291  auto it = scalar_it;
1292  for (size_t i = 0; i < Size; ++i, ++it) {
1293  *it = extract(x, i);
1294  }
1295  }
1296 };
1297 
1299 template <typename T, typename value_vector>
1300 class Reference<T, value_vector, Mutable::No> : public value_vector
1301 {
1302  static constexpr auto Size = value_vector::size();
1303 
1304 public:
1305  Reference(const T &it) : value_vector(fromIterator<T, value_vector>(it)) {}
1306 
1307  Reference(const Reference &) = delete;
1308  Reference(Reference &&) = default;
1309  Reference &operator=(const Reference &) = delete;
1310  Reference &operator=(Reference &&) = delete;
1311 
1313  void operator=(const value_vector &x) = delete;
1314 };
1315 
1316 template <typename T, size_t N,
1317  IteratorDetails::Mutable M =
1318  (Traits::is_output_iterator<T>::value ? Mutable::Yes : Mutable::No),
1319  typename V = simdize<typename std::iterator_traits<T>::value_type, N>,
1320  size_t Size = V::size(),
1321  typename = typename std::iterator_traits<T>::iterator_category>
1322 class Iterator;
1323 
1324 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1325 class Iterator<T, N, M, V, Size, std::forward_iterator_tag>
1326  : public std::iterator<typename std::iterator_traits<T>::iterator_category, V,
1327  typename std::iterator_traits<T>::difference_type,
1328  IteratorDetails::Pointer<T, V, M>,
1329  IteratorDetails::Reference<T, V, M>>
1330 {
1331 public:
1332  using pointer = IteratorDetails::Pointer<T, V, M>;
1333  using reference = IteratorDetails::Reference<T, V, M>;
1334  using const_pointer = IteratorDetails::Pointer<T, V, IteratorDetails::Mutable::No>;
1335  using const_reference =
1336  IteratorDetails::Reference<T, V, IteratorDetails::Mutable::No>;
1337 
1339  static constexpr std::size_t size() { return Size; }
1340 
1341  Iterator() = default;
1342 
1349  Iterator(const T &x) : scalar_it(x) {}
1353  Iterator(T &&x) : scalar_it(std::move(x)) {}
1357  Iterator &operator=(const T &x)
1358  {
1359  scalar_it = x;
1360  return *this;
1361  }
1365  Iterator &operator=(T &&x)
1366  {
1367  scalar_it = std::move(x);
1368  return *this;
1369  }
1370 
1372  Iterator(const Iterator &) = default;
1374  Iterator(Iterator &&) = default;
1376  Iterator &operator=(const Iterator &) = default;
1378  Iterator &operator=(Iterator &&) = default;
1379 
1381  Iterator &operator++()
1382  {
1383  std::advance(scalar_it, Size);
1384  return *this;
1385  }
1387  Iterator operator++(int)
1388  {
1389  Iterator copy(*this);
1390  operator++();
1391  return copy;
1392  }
1393 
1402  bool operator==(const Iterator &rhs) const
1403  {
1404  T it(scalar_it);
1405  for (size_t i = 1; i < Size; ++i) {
1406  Vc_ASSERT((++it != rhs.scalar_it));
1407  }
1408  return scalar_it == rhs.scalar_it;
1409  }
1418  bool operator!=(const Iterator &rhs) const
1419  {
1420  T it(scalar_it);
1421  for (size_t i = 1; i < Size; ++i) {
1422  Vc_ASSERT((++it != rhs.scalar_it));
1423  }
1424  return scalar_it != rhs.scalar_it;
1425  }
1426 
1427  pointer operator->() { return scalar_it; }
1428 
1435  reference operator*() { return scalar_it; }
1436 
1437  const_pointer operator->() const { return scalar_it; }
1438 
1446  const_reference operator*() const { return scalar_it; }
1447 
1461  operator const T &() const { return scalar_it; }
1462 
1463 protected:
1464  T scalar_it;
1465 };
1466 
1471 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1472 class Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1473  : public Iterator<T, N, M, V, Size, std::forward_iterator_tag>
1474 {
1475  using Base = Iterator<T, N, M, V, Size, std::forward_iterator_tag>;
1476 
1477 protected:
1478  using Base::scalar_it;
1479 
1480 public:
1481  using pointer = typename Base::pointer;
1482  using reference = typename Base::reference;
1483  using const_pointer = typename Base::const_pointer;
1484  using const_reference = typename Base::const_reference;
1485 
1486  using Iterator<T, N, M, V, Size,
1487  std::forward_iterator_tag>::Iterator; // in short: "using
1488  // Base::Iterator", but that
1489  // confuses ICC
1491  Iterator &operator--()
1492  {
1493  std::advance(scalar_it, -Size);
1494  return *this;
1495  }
1497  Iterator operator--(int)
1498  {
1499  Iterator copy(*this);
1500  operator--();
1501  return copy;
1502  }
1503 };
1504 
1509 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1510 class Iterator<T, N, M, V, Size, std::random_access_iterator_tag>
1511  : public Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1512 {
1514 
1515 protected:
1516  using Base::scalar_it;
1517 
1518 public:
1519  using pointer = typename Base::pointer;
1520  using reference = typename Base::reference;
1521  using const_pointer = typename Base::const_pointer;
1522  using const_reference = typename Base::const_reference;
1523  using difference_type = typename std::iterator_traits<T>::difference_type;
1524 
1526  Iterator; // in short: "using Base::Iterator", but that confuses ICC
1527 
1528  Iterator &operator+=(difference_type n)
1529  {
1530  scalar_it += n * Size;
1531  return *this;
1532  }
1533  Iterator operator+(difference_type n) const { return Iterator(*this) += n; }
1534 
1535  Iterator &operator-=(difference_type n)
1536  {
1537  scalar_it -= n * Size;
1538  return *this;
1539  }
1540  Iterator operator-(difference_type n) const { return Iterator(*this) -= n; }
1541 
1542  difference_type operator-(const Iterator &rhs) const
1543  {
1544  constexpr difference_type n = Size;
1545  Vc_ASSERT((scalar_it - rhs.scalar_it) % n ==
1546  0); // if this fails the two iterators are not a multiple of the vector
1547  // width apart. The distance would be fractional and that doesn't
1548  // make too much sense for iteration. Therefore, it is a
1549  // precondition for the distance of the two iterators to be a
1550  // multiple of Size.
1551  return (scalar_it - rhs.scalar_it) / n;
1552  }
1553 
1558  bool operator<(const Iterator &rhs) const
1559  {
1560  return scalar_it + Size <= rhs.scalar_it;
1561  }
1562 
1563  bool operator>(const Iterator &rhs) const
1564  {
1565  return scalar_it >= rhs.scalar_it + Size;
1566  }
1567 
1568  bool operator<=(const Iterator &rhs) const
1569  {
1570  return scalar_it + (Size - 1) <= rhs.scalar_it;
1571  }
1572 
1573  bool operator>=(const Iterator &rhs) const
1574  {
1575  return scalar_it >= rhs.scalar_it + (Size - 1);
1576  }
1577 
1578  reference operator[](difference_type i) { return *(*this + i); }
1579  const_reference operator[](difference_type i) const { return *(*this + i); }
1580 };
1581 
1582 template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1583 Iterator<T, N, M, V, Size, std::random_access_iterator_tag> operator+(
1584  typename Iterator<T, N, M, V, Size, std::random_access_iterator_tag>::difference_type
1585  n,
1586  const Iterator<T, N, M, V, Size, std::random_access_iterator_tag> &i)
1587 {
1588  return i + n;
1589 }
1590 
1591 } // namespace IteratorDetails
1592 
1601 template <typename T, size_t N, typename MT>
1602 struct ReplaceTypes<T, N, MT, Category::ForwardIterator>
1603 {
1604  using type = IteratorDetails::Iterator<T, N>;
1605 };
1606 template <typename T, size_t N, typename MT>
1607 struct ReplaceTypes<T, N, MT, Category::BidirectionalIterator>
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::RandomAccessIterator>
1613 {
1614  using type = IteratorDetails::Iterator<T, N>;
1615 };
1616 
1620 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1621  std::size_t Offset>
1622 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size<S>() && M::size() == N), void>
1623  conditional_assign(Adapter<S, T, N> &, const M &, const U &)
1624 {
1625 }
1626 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1627  std::size_t Offset = 0>
1628 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size<S>() && M::size() == N), void>
1629  conditional_assign(Adapter<S, T, N> &lhs, const M &mask, const U &rhs)
1630 {
1631  using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1632  using M2 = typename V::mask_type;
1633  conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask), get_dispatcher<Offset>(rhs));
1634  conditional_assign<Op, S, T, N, M, U, Offset + 1>(lhs, mask, rhs);
1635 }
1636 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1637  std::size_t Offset>
1638 Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size<S>() && M::size() == N), void>
1639  conditional_assign(Adapter<S, T, N> &, const M &)
1640 {
1641 }
1642 template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1643  std::size_t Offset = 0>
1644 Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size<S>() && M::size() == N), void>
1645  conditional_assign(Adapter<S, T, N> &lhs, const M &mask)
1646 {
1647  using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1648  using M2 = typename V::mask_type;
1649  conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask));
1650  conditional_assign<Op, S, T, N, M, Offset + 1>(lhs, mask);
1651 }
1652 
1654 } // namespace SimdizeDetail
1655 
1674 template <typename T, size_t N = 0, typename MT = void>
1675 using simdize = SimdizeDetail::simdize<T, N, MT>;
1676 
1696 #define Vc_SIMDIZE_INTERFACE(MEMBERS__) \
1697  template <std::size_t N__> \
1698  inline auto vc_get__()->decltype(std::get<N__>(std::tie MEMBERS__)) \
1699  { \
1700  return std::get<N__>(std::tie MEMBERS__); \
1701  } \
1702  template <std::size_t N__> \
1703  inline auto vc_get__() const->decltype(std::get<N__>(std::tie MEMBERS__)) \
1704  { \
1705  return std::get<N__>(std::tie MEMBERS__); \
1706  } \
1707  enum : std::size_t { \
1708  tuple_size = std::tuple_size<decltype(std::tie MEMBERS__)>::value \
1709  }
1710 
1711 } // namespace Vc
1712 
1713 namespace std
1714 {
1715 using Vc::SimdizeDetail::swap;
1716 } // namespace std
1717 
1718 #endif // VC_COMMON_SIMDIZE_H_
1719 
1720 // 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:1558
Definition: vector.h:258
SimdizeDetail::simdize< T, N, MT > simdize
Definition: simdize.h:1675
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:970
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:941
Iterator & operator--()
Advances the iterator by one vector width, or respectively N scalar steps.
Definition: simdize.h:1491
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:1002
Vector Classes Namespace.
Definition: cpuid.h:33
This is the iterator type created when applying simdize to a bidirectional iterator type...
Definition: simdize.h:1472