Vc 1.4.5
SIMD Vector Classes for C++
 
Loading...
Searching...
No Matches
simdize.h
1/* This file is part of the Vc library. {{{
2Copyright © 2014-2015 Matthias Kretz <kretz@kde.org>
3
4Redistribution and use in source and binary forms, with or without
5modification, are permitted provided that the following conditions are met:
6 * Redistributions of source code must retain the above copyright
7 notice, this list of conditions and the following disclaimer.
8 * Redistributions in binary form must reproduce the above copyright
9 notice, this list of conditions and the following disclaimer in the
10 documentation and/or other materials provided with the distribution.
11 * Neither the names of contributing organizations nor the
12 names of its contributors may be used to endorse or promote products
13 derived from this software without specific prior written permission.
14
15THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
19DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26}}}*/
27
28#ifndef VC_COMMON_SIMDIZE_H_
29#define VC_COMMON_SIMDIZE_H_
30
31#include <tuple>
32#include <array>
33
34#include "../Allocator"
35#include "interleavedmemory.h"
36
122namespace Vc_VERSIONED_NAMESPACE
123{
130namespace SimdizeDetail // {{{
131{
136using std::is_same;
137using std::is_base_of;
138using std::false_type;
139using std::true_type;
140using std::iterator_traits;
141using std::conditional;
142using std::size_t;
143
148template <typename... Ts> struct Typelist;
149
153enum class Category {
155 NoTransformation,
157 ArithmeticVectorizable,
159 InputIterator,
161 OutputIterator,
163 ForwardIterator,
165 BidirectionalIterator,
167 RandomAccessIterator,
169 ClassTemplate
170};
171
176template <typename T, typename ItCat = typename T::iterator_category>
177constexpr Category iteratorCategories(int, ItCat * = nullptr)
178{
179 return is_base_of<std::random_access_iterator_tag, ItCat>::value
180 ? Category::RandomAccessIterator
181 : is_base_of<std::bidirectional_iterator_tag, ItCat>::value
182 ? Category::BidirectionalIterator
183 : is_base_of<std::forward_iterator_tag, ItCat>::value
184 ? Category::ForwardIterator
185 : is_base_of<std::output_iterator_tag, ItCat>::value
186 ? Category::OutputIterator
187 : is_base_of<std::input_iterator_tag, ItCat>::value
188 ? Category::InputIterator
189 : Category::NoTransformation;
190}
194template <typename T>
195constexpr enable_if<std::is_pointer<T>::value, Category> iteratorCategories(float)
196{
197 return Category::RandomAccessIterator;
198}
202template <typename T> constexpr Category iteratorCategories(...)
203{
204 return Category::NoTransformation;
205}
206
210template <typename T> struct is_class_template : public false_type
211{
212};
213template <template <typename...> class C, typename... Ts>
214struct is_class_template<C<Ts...>> : public true_type
215{
216};
217
221template <typename T> constexpr Category typeCategory()
222{
223 return (is_same<T, bool>::value || is_same<T, short>::value ||
224 is_same<T, unsigned short>::value || is_same<T, int>::value ||
225 is_same<T, unsigned int>::value || is_same<T, float>::value ||
226 is_same<T, double>::value)
227 ? Category::ArithmeticVectorizable
228 : iteratorCategories<T>(int()) != Category::NoTransformation
229 ? iteratorCategories<T>(int())
230 : is_class_template<T>::value ? Category::ClassTemplate
231 : Category::NoTransformation;
232}
233
239template <typename T, size_t TupleSize = std::tuple_size<T>::value>
240constexpr size_t determine_tuple_size()
241{
242 return TupleSize;
243}
244template <typename T, size_t TupleSize = T::tuple_size>
245constexpr size_t determine_tuple_size(size_t = T::tuple_size)
246{
247 return TupleSize;
248}
249
250// workaround for MSVC limitation: constexpr functions in template arguments
251// confuse the compiler
252template <typename T> struct determine_tuple_size_
253: public std::integral_constant<size_t, determine_tuple_size<T>()>
254{};
255
256namespace
257{
258template <typename T> struct The_simdization_for_the_requested_type_is_not_implemented;
259} // unnamed namespace
260
273template <typename T, size_t N, typename MT, Category = typeCategory<T>()>
274struct ReplaceTypes : public The_simdization_for_the_requested_type_is_not_implemented<T>
275{
276};
277
282template <typename T, size_t N, typename MT> struct ReplaceTypes<T, N, MT, Category::NoTransformation>
283{
284 typedef T type;
285};
286
291template <typename T, size_t N = 0, typename MT = void>
292using simdize = typename SimdizeDetail::ReplaceTypes<T, N, MT>::type;
293
294// Alias for Vector<T, Abi> with size() == N, or SimdArray<T, N> otherwise.
295template <class T, size_t N,
296 class Best = typename Common::select_best_vector_type<T, N>::type>
297using deduce_vector_t =
298 typename std::conditional<Best::size() == N, Best, SimdArray<T, N>>::type;
299
304template <typename T, size_t N, typename MT>
305struct ReplaceTypes<T, N, MT, Category::ArithmeticVectorizable>
306 : public conditional<N == 0, Vector<T>, deduce_vector_t<T, N>> {
307};
308
313template <size_t N, typename MT>
314struct ReplaceTypes<bool, N, MT, Category::ArithmeticVectorizable>
315 : public std::enable_if<true, typename ReplaceTypes<MT, N, MT>::type::mask_type> {
316};
320template <size_t N>
321struct ReplaceTypes<bool, N, void, Category::ArithmeticVectorizable>
322 : public ReplaceTypes<bool, N, float, Category::ArithmeticVectorizable>
323{
324};
325
332template <size_t N, typename MT, typename Replaced, typename... Remaining>
333struct SubstituteOneByOne;
334
339template <size_t N, typename MT, typename... Replaced, typename T,
340 typename... Remaining>
341struct SubstituteOneByOne<N, MT, Typelist<Replaced...>, T, Remaining...>
342{
343private:
348 template <typename U, size_t M = U::Size>
349 static std::integral_constant<size_t, M> size_or_0(int);
350 template <typename U> static std::integral_constant<size_t, 0> size_or_0(...);
351
353 using V = simdize<T, N, MT>;
354
359 static constexpr auto NewN = N != 0 ? N : decltype(size_or_0<V>(int()))::value;
360
366 typedef conditional_t<(N != NewN && is_same<MT, void>::value),
367 conditional_t<is_same<T, bool>::value, float, T>, MT> NewMT;
368
369public:
373 using type = typename SubstituteOneByOne<NewN, NewMT, Typelist<Replaced..., V>,
374 Remaining...>::type;
375};
376
379template <size_t Size, typename... Replaced> struct SubstitutedBase;
381template <typename Replaced> struct SubstitutedBase<1, Replaced> {
382 template <typename ValueT, template <typename, ValueT...> class C, ValueT... Values>
383 using SubstitutedWithValues = C<Replaced, Values...>;
384};
386template <typename R0, typename R1> struct SubstitutedBase<2, R0, R1>
387{
388 template <typename ValueT, template <typename, typename, ValueT...> class C,
389 ValueT... Values>
390 using SubstitutedWithValues = C<R0, R1, Values...>;
391};
393template <typename R0, typename R1, typename R2> struct SubstitutedBase<3, R0, R1, R2>
394{
395 template <typename ValueT, template <typename, typename, typename, ValueT...> class C,
396 ValueT... Values>
397 using SubstitutedWithValues = C<R0, R1, R2, Values...>;
398};
399#if defined Vc_ICC || defined Vc_MSVC
400#define Vc_VALUE_PACK_EXPANSION_IS_BROKEN 1
401#endif
403template <typename... Replaced> struct SubstitutedBase<4, Replaced...> {
404#ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
405 template <typename ValueT,
406 template <typename, typename, typename, typename, ValueT...> class C,
407 ValueT... Values>
408 using SubstitutedWithValues = C<Replaced..., Values...>;
409#endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
410};
412template <typename... Replaced> struct SubstitutedBase<5, Replaced...> {
413#ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
414 template <typename ValueT, template <typename, typename, typename, typename, typename,
415 ValueT...> class C,
416 ValueT... Values>
417 using SubstitutedWithValues = C<Replaced..., Values...>;
418#endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
419};
421template <typename... Replaced> struct SubstitutedBase<6, Replaced...> {
422#ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
423 template <typename ValueT, template <typename, typename, typename, typename, typename,
424 typename, ValueT...> class C,
425 ValueT... Values>
426 using SubstitutedWithValues = C<Replaced..., Values...>;
427#endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
428};
430template <typename... Replaced> struct SubstitutedBase<7, Replaced...> {
431#ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
432 template <typename ValueT, template <typename, typename, typename, typename, typename,
433 typename, typename, ValueT...> class C,
434 ValueT... Values>
435 using SubstitutedWithValues = C<Replaced..., Values...>;
436#endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
437};
439template <typename... Replaced> struct SubstitutedBase<8, Replaced...> {
440#ifndef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
441 template <typename ValueT, template <typename, typename, typename, typename, typename,
442 typename, typename, typename, ValueT...> class C,
443 ValueT... Values>
444 using SubstitutedWithValues = C<Replaced..., Values...>;
445#endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
446};
447
453template <size_t N_, typename MT, typename Replaced0, typename... Replaced>
454struct SubstituteOneByOne<N_, MT, Typelist<Replaced0, Replaced...>>
455{
459 struct type
460 : public SubstitutedBase<sizeof...(Replaced) + 1, Replaced0, Replaced...> {
461 static constexpr auto N = N_;
466 template <template <typename...> class C>
467 using Substituted = C<Replaced0, Replaced...>;
468 };
469};
470
487template <typename Scalar, typename Base, size_t N> class Adapter;
488
493template <template <typename...> class C, typename... Ts, size_t N, typename MT>
494struct ReplaceTypes<C<Ts...>, N, MT, Category::ClassTemplate>
495{
497 using SubstitutionResult =
498 typename SubstituteOneByOne<N, MT, Typelist<>, Ts...>::type;
504 using Vectorized = typename SubstitutionResult::template Substituted<C>;
510 using type = conditional_t<is_same<C<Ts...>, Vectorized>::value, C<Ts...>,
511 Adapter<C<Ts...>, Vectorized, SubstitutionResult::N>>;
512};
513
519#ifdef Vc_VALUE_PACK_EXPANSION_IS_BROKEN
520// ICC barfs on packs of values
521#define Vc_DEFINE_NONTYPE_REPLACETYPES_(ValueType_) \
522 template <template <typename, ValueType_...> class C, typename T, ValueType_ Value0, \
523 ValueType_... Values> \
524 struct is_class_template<C<T, Value0, Values...>> : public true_type { \
525 }; \
526 template <template <typename, typename, ValueType_...> class C, typename T0, \
527 typename T1, ValueType_ Value0, ValueType_... Values> \
528 struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type { \
529 }; \
530 template <template <typename, typename, typename, ValueType_...> class C, \
531 typename T0, typename T1, typename T2, ValueType_ Value0, \
532 ValueType_... Values> \
533 struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type { \
534 }; \
535 template <template <typename, typename, typename, typename, ValueType_...> class C, \
536 typename T0, typename T1, typename T2, typename T3, ValueType_ Value0, \
537 ValueType_... Values> \
538 struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type { \
539 }; \
540 template <template <typename, typename, typename, typename, typename, ValueType_...> \
541 class C, \
542 typename T0, typename T1, typename T2, typename T3, typename T4, \
543 ValueType_ Value0, ValueType_... Values> \
544 struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
545 : public true_type { \
546 }; \
547 template <template <typename, typename, typename, typename, typename, typename, \
548 ValueType_...> class C, \
549 typename T0, typename T1, typename T2, typename T3, typename T4, \
550 typename T5, ValueType_ Value0, ValueType_... Values> \
551 struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
552 : public true_type { \
553 }; \
554 template <template <typename, typename, typename, typename, typename, typename, \
555 typename, ValueType_...> class C, \
556 typename T0, typename T1, typename T2, typename T3, typename T4, \
557 typename T5, typename T6, ValueType_ Value0, ValueType_... Values> \
558 struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
559 : public true_type { \
560 }; \
561 template <template <typename, ValueType_> class C, typename T0, ValueType_ Value0, \
562 size_t N, typename MT> \
563 struct ReplaceTypes<C<T0, Value0>, N, MT, Category::ClassTemplate> { \
564 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
565 typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
566 Substituted; \
567 static constexpr auto NN = tmp::N; \
568 typedef conditional_t<is_same<C<T0, Value0>, Substituted>::value, C<T0, Value0>, \
569 Adapter<C<T0, Value0>, Substituted, NN>> type; \
570 }; \
571 template <template <typename, typename, ValueType_> class C, typename T0, \
572 typename T1, ValueType_ Value0, size_t N, typename MT> \
573 struct ReplaceTypes<C<T0, T1, Value0>, N, MT, Category::ClassTemplate> { \
574 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
575 typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
576 Substituted; \
577 static constexpr auto NN = tmp::N; \
578 typedef conditional_t<is_same<C<T0, T1, Value0>, Substituted>::value, \
579 C<T0, T1, Value0>, \
580 Adapter<C<T0, T1, Value0>, Substituted, NN>> type; \
581 }; \
582 template <template <typename, typename, typename, ValueType_> class C, typename T0, \
583 typename T1, typename T2, ValueType_ Value0, size_t N, typename MT> \
584 struct ReplaceTypes<C<T0, T1, T2, Value0>, N, MT, Category::ClassTemplate> { \
585 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
586 typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0> \
587 Substituted; \
588 static constexpr auto NN = tmp::N; \
589 typedef conditional_t<is_same<C<T0, T1, T2, Value0>, Substituted>::value, \
590 C<T0, T1, T2, Value0>, \
591 Adapter<C<T0, T1, T2, Value0>, Substituted, NN>> type; \
592 }
593#else
594#define Vc_DEFINE_NONTYPE_REPLACETYPES_(ValueType_) \
595 template <template <typename, ValueType_...> class C, typename T, ValueType_ Value0, \
596 ValueType_... Values> \
597 struct is_class_template<C<T, Value0, Values...>> : public true_type { \
598 }; \
599 template <template <typename, typename, ValueType_...> class C, typename T0, \
600 typename T1, ValueType_ Value0, ValueType_... Values> \
601 struct is_class_template<C<T0, T1, Value0, Values...>> : public true_type { \
602 }; \
603 template <template <typename, typename, typename, ValueType_...> class C, \
604 typename T0, typename T1, typename T2, ValueType_ Value0, \
605 ValueType_... Values> \
606 struct is_class_template<C<T0, T1, T2, Value0, Values...>> : public true_type { \
607 }; \
608 template <template <typename, typename, typename, typename, ValueType_...> class C, \
609 typename T0, typename T1, typename T2, typename T3, ValueType_ Value0, \
610 ValueType_... Values> \
611 struct is_class_template<C<T0, T1, T2, T3, Value0, Values...>> : public true_type { \
612 }; \
613 template <template <typename, typename, typename, typename, typename, ValueType_...> \
614 class C, \
615 typename T0, typename T1, typename T2, typename T3, typename T4, \
616 ValueType_ Value0, ValueType_... Values> \
617 struct is_class_template<C<T0, T1, T2, T3, T4, Value0, Values...>> \
618 : public true_type { \
619 }; \
620 template <template <typename, typename, typename, typename, typename, typename, \
621 ValueType_...> class C, \
622 typename T0, typename T1, typename T2, typename T3, typename T4, \
623 typename T5, ValueType_ Value0, ValueType_... Values> \
624 struct is_class_template<C<T0, T1, T2, T3, T4, T5, Value0, Values...>> \
625 : public true_type { \
626 }; \
627 template <template <typename, typename, typename, typename, typename, typename, \
628 typename, ValueType_...> class C, \
629 typename T0, typename T1, typename T2, typename T3, typename T4, \
630 typename T5, typename T6, ValueType_ Value0, ValueType_... Values> \
631 struct is_class_template<C<T0, T1, T2, T3, T4, T5, T6, Value0, Values...>> \
632 : public true_type { \
633 }; \
634 template <template <typename, ValueType_...> class C, typename T0, \
635 ValueType_ Value0, ValueType_... Values, size_t N, typename MT> \
636 struct ReplaceTypes<C<T0, Value0, Values...>, N, MT, Category::ClassTemplate> { \
637 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0>::type tmp; \
638 typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
639 Values...> Substituted; \
640 static constexpr auto NN = tmp::N; \
641 typedef conditional_t<is_same<C<T0, Value0, Values...>, Substituted>::value, \
642 C<T0, Value0, Values...>, \
643 Adapter<C<T0, Value0, Values...>, Substituted, NN>> type; \
644 }; \
645 template <template <typename, typename, ValueType_...> class C, typename T0, \
646 typename T1, ValueType_ Value0, ValueType_... Values, size_t N, \
647 typename MT> \
648 struct ReplaceTypes<C<T0, T1, Value0, Values...>, N, MT, Category::ClassTemplate> { \
649 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1>::type tmp; \
650 typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
651 Values...> Substituted; \
652 static constexpr auto NN = tmp::N; \
653 typedef conditional_t<is_same<C<T0, T1, Value0, Values...>, Substituted>::value, \
654 C<T0, T1, Value0, Values...>, \
655 Adapter<C<T0, T1, Value0, Values...>, Substituted, NN>> \
656 type; \
657 }; \
658 template <template <typename, typename, typename, ValueType_...> class C, \
659 typename T0, typename T1, typename T2, ValueType_ Value0, \
660 ValueType_... Values, size_t N, typename MT> \
661 struct ReplaceTypes<C<T0, T1, T2, Value0, Values...>, N, MT, \
662 Category::ClassTemplate> { \
663 typedef typename SubstituteOneByOne<N, MT, Typelist<>, T0, T1, T2>::type tmp; \
664 typedef typename tmp::template SubstitutedWithValues<ValueType_, C, Value0, \
665 Values...> Substituted; \
666 static constexpr auto NN = tmp::N; \
667 typedef conditional_t< \
668 is_same<C<T0, T1, T2, Value0, Values...>, Substituted>::value, \
669 C<T0, T1, T2, Value0, Values...>, \
670 Adapter<C<T0, T1, T2, Value0, Values...>, Substituted, NN>> type; \
671 }
672#endif // Vc_VALUE_PACK_EXPANSION_IS_BROKEN
673Vc_DEFINE_NONTYPE_REPLACETYPES_(bool);
674Vc_DEFINE_NONTYPE_REPLACETYPES_(wchar_t);
675Vc_DEFINE_NONTYPE_REPLACETYPES_(char);
676Vc_DEFINE_NONTYPE_REPLACETYPES_( signed char);
677Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned char);
678Vc_DEFINE_NONTYPE_REPLACETYPES_( signed short);
679Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned short);
680Vc_DEFINE_NONTYPE_REPLACETYPES_( signed int);
681Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned int);
682Vc_DEFINE_NONTYPE_REPLACETYPES_( signed long);
683Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned long);
684Vc_DEFINE_NONTYPE_REPLACETYPES_( signed long long);
685Vc_DEFINE_NONTYPE_REPLACETYPES_(unsigned long long);
686#undef Vc_DEFINE_NONTYPE_REPLACETYPES_
687
688// preferred_construction {{{
689namespace preferred_construction_impl
690{
691template <typename T> T create();
692// 0: paren init
693template <class Type, class... Init, class = decltype(Type(create<Init>()...))>
694constexpr std::integral_constant<int, 0> test(int);
695// 1: 1-brace init
696template <class Type, class... Init, class = decltype(Type{create<Init>()...})>
697constexpr std::integral_constant<int, 1> test(float);
698// 2: 2-brace init
699template <class Type, class... Init, class T, class = decltype(Type{{create<Init>()...}})>
700constexpr std::integral_constant<int, 2> test(T);
701// 3: no init at all
702template <class Type, class... Init> constexpr std::integral_constant<int, 3> test(...);
703} // namespace preferred_construction_impl
704
705template <class Type, class... Init>
706constexpr inline decltype(preferred_construction_impl::test<Type, Init...>(0))
707preferred_construction()
708{
709 return {};
710}
711
712// }}}
713// get_dispatcher {{{
718template <size_t I, typename T,
719 typename R = decltype(std::declval<T &>().template vc_get_<I>())>
720R get_dispatcher(T &x, void * = nullptr)
721{
722 return x.template vc_get_<I>();
723}
724template <size_t I, typename T,
725 typename R = decltype(std::declval<const T &>().template vc_get_<I>())>
726R get_dispatcher(const T &x, void * = nullptr)
727{
728 return x.template vc_get_<I>();
729}
730template <size_t I, typename T, typename R = decltype(std::get<I>(std::declval<T &>()))>
731R get_dispatcher(T &x, int = 0)
732{
733 return std::get<I>(x);
734}
735template <size_t I, typename T,
736 typename R = decltype(std::get<I>(std::declval<const T &>()))>
737R get_dispatcher(const T &x, int = 0)
738{
739 return std::get<I>(x);
740}
741
742// }}}
743// my_tuple_element {{{
744template <size_t I, class T, class = void>
745struct my_tuple_element : std::tuple_element<I, T> {
746};
747
748template <size_t I, class T>
749struct my_tuple_element<
750 I, T, typename std::conditional<
751 true, void, decltype(std::declval<T>().template vc_get_<I>())>::type> {
752 using type =
753 typename std::decay<decltype(std::declval<T>().template vc_get_<I>())>::type;
754};
755
756// }}}
757// homogeneous_sizeof {{{
763template <class... Ts> struct homogeneous_sizeof;
764template <class T, class = void> struct homogeneous_sizeof_one;
765template <class T>
766struct homogeneous_sizeof_one<T,
767 typename std::enable_if<std::is_arithmetic<T>::value>::type>
768 : std::integral_constant<size_t, sizeof(T)> {
769};
770template <class T0> struct homogeneous_sizeof<T0> : homogeneous_sizeof_one<T0> {
771};
772
773template <class T0, class... Ts>
774struct homogeneous_sizeof<T0, Ts...>
775 : std::integral_constant<size_t, homogeneous_sizeof<T0>::value ==
776 homogeneous_sizeof<Ts...>::value
777 ? homogeneous_sizeof<T0>::value
778 : 0> {
779};
780
781template <class T, size_t... Is>
782std::integral_constant<
783 size_t, homogeneous_sizeof<typename my_tuple_element<Is, T>::type...>::value>
784 homogeneous_sizeof_helper(index_sequence<Is...>);
785
786template <class T>
787struct homogeneous_sizeof_one<T, typename std::enable_if<std::is_class<T>::value>::type>
788 : decltype(homogeneous_sizeof_helper<T>(
789 make_index_sequence<determine_tuple_size_<T>::value>())) {
790};
791
792// }}}
793// class Adapter {{{
794template <typename Scalar, typename Base, size_t N> class Adapter : public Base
795{
796private:
798 template <std::size_t... Indexes, int X>
799 Adapter(Vc::index_sequence<Indexes...>, const Scalar,
800 std::integral_constant<int, X>)
801 {
802 static_assert(
803 X < 3, "Failed to construct an object of type Base. Neither via "
804 "parenthesis-init, brace-init, nor double-brace init appear to work.");
805 }
806
808 template <std::size_t... Indexes>
809 Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_,
810 std::integral_constant<int, 2>)
811 : Base{{get_dispatcher<Indexes>(x_)...}}
812 {
813 }
814
816 template <std::size_t... Indexes>
817 Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_,
818 std::integral_constant<int, 1>)
819 : Base{get_dispatcher<Indexes>(x_)...}
820 {
821 }
822
824 template <std::size_t... Indexes>
825 Adapter(Vc::index_sequence<Indexes...>, const Scalar &x_,
826 std::integral_constant<int, 0>)
827 : Base(get_dispatcher<Indexes>(x_)...)
828 {
829 }
830
831 template <std::size_t... Indexes>
832 Adapter(Vc::index_sequence<Indexes...> seq_, const Scalar &x_)
833 : Adapter(seq_, x_,
834 preferred_construction<Base, decltype(get_dispatcher<Indexes>(
835 std::declval<const Scalar &>()))...>())
836 {
837 }
838
839public:
841 static constexpr size_t size() { return N; }
842 static constexpr size_t Size = N;
843
845 using base_type = Base;
848 using scalar_type = Scalar;
849
852 Adapter() = default;
853
855#if defined Vc_CLANG && Vc_CLANG < 0x30700
856 Vc_INTRINSIC Adapter(const Adapter &x) : Base(x) {}
857#else
858 Adapter(const Adapter &) = default;
859#endif
861 Adapter(Adapter &&) = default;
863 Adapter &operator=(const Adapter &) = default;
865 Adapter &operator=(Adapter &&) = default;
866
868 template <typename U, size_t TupleSize = determine_tuple_size_<Scalar>::value,
869 typename Seq = Vc::make_index_sequence<TupleSize>,
870 typename = enable_if<std::is_convertible<U, Scalar>::value>>
871 Adapter(U &&x_)
872 : Adapter(Seq(), static_cast<const Scalar &>(x_))
873 {
874 }
875
877 template <class F,
878 class = decltype(static_cast<Scalar>(std::declval<F>()(
879 size_t())))> // F returns objects that are convertible to S
880 Adapter(F &&fun); // implementation below
881
882 // }}}
884 template <typename A0, typename... Args,
885 typename = typename std::enable_if<
886 !Traits::is_index_sequence<A0>::value &&
887 (sizeof...(Args) > 0 || !std::is_convertible<A0, Scalar>::value)>::type>
888 Adapter(A0 &&arg0_, Args &&... arguments_)
889 : Base(std::forward<A0>(arg0_), std::forward<Args>(arguments_)...)
890 {
891 }
892
894 template <typename T,
895 typename = decltype(Base(std::declval<const std::initializer_list<T> &>()))>
896 Adapter(const std::initializer_list<T> &l_)
897 : Base(l_)
898 {
899 }
900
903 void *operator new(size_t size)
904 {
905 return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
906 }
907 void *operator new(size_t, void *p_) { return p_; }
908 void *operator new[](size_t size)
909 {
910 return Vc::Common::aligned_malloc<alignof(Adapter)>(size);
911 }
912 void *operator new[](size_t , void *p_) { return p_; }
913 void operator delete(void *ptr_, size_t) { Vc::Common::free(ptr_); }
914 void operator delete(void *, void *) {}
915 void operator delete[](void *ptr_, size_t) { Vc::Common::free(ptr_); }
916 void operator delete[](void *, void *) {}
917}; // }}}
918// delete compare operators for Adapter {{{
923template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
924inline void operator==(
925 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
926 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
927template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
928inline void operator!=(
929 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
930 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
931template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
932inline void operator<=(
933 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
934 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
935template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
936inline void operator>=(
937 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
938 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
939template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
940inline void operator<(
941 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
942 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
943template <class... TTypes, class... TTypesV, class... UTypes, class... UTypesV, size_t N>
944inline void operator>(
945 const Adapter<std::tuple<TTypes...>, std::tuple<TTypesV...>, N> &t,
946 const Adapter<std::tuple<UTypes...>, std::tuple<UTypesV...>, N> &u) = delete;
947// }}}
949} // namespace SimdizeDetail }}}
950} // namespace Vc
951
952namespace std // {{{
953{
957template <typename Scalar, typename Base, size_t N>
958class tuple_size<Vc::SimdizeDetail::Adapter<Scalar, Base, N>> : public tuple_size<Base>
959{
960};
964template <size_t I, typename Scalar, typename Base, size_t N>
965class tuple_element<I, Vc::SimdizeDetail::Adapter<Scalar, Base, N>>
966 : public tuple_element<I, Base>
967{
968};
969// std::get does not need additional work because Vc::Adapter derives from
970// C<Ts...> and therefore if get<N>(C<Ts...>) works it works for Adapter as well.
971
976template <typename S, typename T, size_t N>
977class allocator<Vc::SimdizeDetail::Adapter<S, T, N>>
978 : public Vc::Allocator<Vc::SimdizeDetail::Adapter<S, T, N>>
979{
980public:
981 template <typename U> struct rebind
982 {
983 typedef std::allocator<U> other;
984 };
985};
986} // namespace std }}}
987
988namespace Vc_VERSIONED_NAMESPACE
989{
990namespace SimdizeDetail
991{
1000template <typename T> static inline T decay_workaround(const T &x) { return x; }
1001
1002// assign_impl {{{
1006template <typename S, typename T, size_t N, size_t... Indexes>
1007inline void assign_impl(Adapter<S, T, N> &a, size_t i, const S &x,
1008 Vc::index_sequence<Indexes...>)
1009{
1010 const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(x)))...> tmp(
1011 decay_workaround(get_dispatcher<Indexes>(x))...);
1012 auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(tmp), 0)...};
1013 if (&unused == &unused) {}
1014} // }}}
1015// construct (parens, braces, double-braces) {{{
1016template <class S, class... Args>
1017S construct(std::integral_constant<int, 0>, Args &&... args)
1018{
1019 return S(std::forward<Args>(args)...);
1020}
1021template <class S, class... Args>
1022S construct(std::integral_constant<int, 1>, Args &&... args)
1023{
1024 return S{std::forward<Args>(args)...};
1025}
1026template <class S, class... Args>
1027S construct(std::integral_constant<int, 2>, Args &&... args)
1028{
1029 return S{{std::forward<Args>(args)...}};
1030}
1031// }}}
1032// extract_impl {{{
1036template <typename S, typename T, size_t N, size_t... Indexes>
1037inline S extract_impl(const Adapter<S, T, N> &a, size_t i, Vc::index_sequence<Indexes...>)
1038{
1039 const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a)[i]))...> tmp(
1040 decay_workaround(get_dispatcher<Indexes>(a)[i])...);
1041 return construct<S>(
1042 preferred_construction<S, decltype(decay_workaround(
1043 get_dispatcher<Indexes>(a)[i]))...>(),
1044 decay_workaround(get_dispatcher<Indexes>(a)[i])...);
1045 //return S(get_dispatcher<Indexes>(tmp)...);
1046}
1047// }}}
1048// shifted_impl {{{
1049template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1050inline Adapter<S, T, N> shifted_impl(const Adapter<S, T, N> &a, int shift,
1051 Vc::index_sequence<Indexes...>)
1052{
1053 Adapter<S, T, N> r;
1054 auto &&unused = {(get_dispatcher<Indexes>(r) = get_dispatcher<Indexes>(a).shifted(shift), 0)...};
1055 if (&unused == &unused) {}
1056 return r;
1057}
1058// }}}
1059// shifted(Adapter) {{{
1068template <typename S, typename T, size_t N>
1069inline Adapter<S, T, N> shifted(const Adapter<S, T, N> &a, int shift)
1070{
1071 return shifted_impl(a, shift, Vc::make_index_sequence<determine_tuple_size<T>()>());
1072}
1073// }}}
1074// swap_impl {{{
1078template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1079inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, S &x,
1080 Vc::index_sequence<Indexes...>)
1081{
1082 const auto &a_const = a;
1083 const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a_const)[0]))...>
1084 tmp{decay_workaround(get_dispatcher<Indexes>(a_const)[i])...};
1085 auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(x), 0)...};
1086 auto &&unused2 = {(get_dispatcher<Indexes>(x) = get_dispatcher<Indexes>(tmp), 0)...};
1087 if (&unused == &unused2) {}
1088}
1089template <typename S, typename T, std::size_t N, std::size_t... Indexes>
1090inline void swap_impl(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b,
1091 std::size_t j, Vc::index_sequence<Indexes...>)
1092{
1093 const auto &a_const = a;
1094 const auto &b_const = b;
1095 const std::tuple<decltype(decay_workaround(get_dispatcher<Indexes>(a_const)[0]))...>
1096 tmp{decay_workaround(get_dispatcher<Indexes>(a_const)[i])...};
1097 auto &&unused = {(get_dispatcher<Indexes>(a)[i] = get_dispatcher<Indexes>(b_const)[j], 0)...};
1098 auto &&unused2 = {(get_dispatcher<Indexes>(b)[j] = get_dispatcher<Indexes>(tmp), 0)...};
1099 if (&unused == &unused2) {}
1100}
1101// }}}
1102// swap(Adapter) {{{
1107template <typename S, typename T, std::size_t N>
1108inline void swap(Adapter<S, T, N> &a, std::size_t i, S &x)
1109{
1110 swap_impl(a, i, x, Vc::make_index_sequence<determine_tuple_size<T>()>());
1111}
1112template <typename S, typename T, std::size_t N>
1113inline void swap(Adapter<S, T, N> &a, std::size_t i, Adapter<S, T, N> &b, std::size_t j)
1114{
1115 swap_impl(a, i, b, j, Vc::make_index_sequence<determine_tuple_size<T>()>());
1116}
1117// }}}
1118template <typename A> class Scalar // {{{
1119{
1120 using reference = typename std::add_lvalue_reference<A>::type;
1121 using S = typename A::scalar_type;
1122 using IndexSeq = Vc::make_index_sequence<determine_tuple_size<S>()>;
1123
1124public:
1125 Scalar(reference aa, size_t ii) : a(aa), i(ii) {}
1126
1127 // delete copy and move to keep the type a pure proxy temporary object.
1128 Scalar(const Scalar &) = delete;
1129 Scalar(Scalar &&) = delete;
1130 Scalar &operator=(const Scalar &) = delete;
1131 Scalar &operator=(Scalar &&) = delete;
1132
1133 void operator=(const S &x) { assign_impl(a, i, x, IndexSeq()); }
1134 operator S() const { return extract_impl(a, i, IndexSeq()); }
1135
1136 template <typename AA>
1137 friend inline void swap(Scalar<AA> &&a, typename AA::scalar_type &b);
1138 template <typename AA>
1139 friend inline void swap(typename AA::scalar_type &b, Scalar<AA> &&a);
1140 template <typename AA> friend inline void swap(Scalar<AA> &&a, Scalar<AA> &&b);
1141
1142private:
1143 reference a;
1144 size_t i;
1145}; // }}}
1146// swap(Scalar) {{{
1149template <typename A> inline void swap(Scalar<A> &&a, typename A::scalar_type &b)
1150{
1151 swap_impl(a.a, a.i, b, typename Scalar<A>::IndexSeq());
1152}
1155template <typename A> inline void swap(typename A::scalar_type &b, Scalar<A> &&a)
1156{
1157 swap_impl(a.a, a.i, b, typename Scalar<A>::IndexSeq());
1158}
1159
1160template <typename A> inline void swap(Scalar<A> &&a, Scalar<A> &&b)
1161{
1162 swap_impl(a.a, a.i, b.a, b.i, typename Scalar<A>::IndexSeq());
1163}
1164// }}}
1165// load_interleaved_impl {{{
1166template <class S, class T, size_t N, size_t... I>
1167inline void load_interleaved_impl(Vc::index_sequence<I...>, Adapter<S, T, N> &a,
1168 const S *mem)
1169{
1170 const InterleavedMemoryWrapper<S, decltype(decay_workaround(get_dispatcher<0>(a)))>
1171 wrapper(const_cast<S *>(mem));
1172 Vc::tie(get_dispatcher<I>(a)...) = wrapper[0];
1173}
1174// }}}
1175// store_interleaved_impl {{{
1176template <class S, class T, size_t N, size_t... I>
1177inline void store_interleaved_impl(Vc::index_sequence<I...>, const Adapter<S, T, N> &a,
1178 S *mem)
1179{
1180 InterleavedMemoryWrapper<S, decltype(decay_workaround(get_dispatcher<0>(a)))> wrapper(
1181 mem);
1182 wrapper[0] = Vc::tie(get_dispatcher<I>(a)...);
1183}
1184// }}}
1185template <typename A> class Interface // {{{
1186{
1187 using reference = typename std::add_lvalue_reference<A>::type;
1188 using IndexSeq =
1189 Vc::make_index_sequence<determine_tuple_size<typename A::scalar_type>()>;
1190
1191public:
1192 Interface(reference aa) : a(aa) {}
1193
1194 Scalar<A> operator[](size_t i)
1195 {
1196 return {a, i};
1197 }
1198 typename A::scalar_type operator[](size_t i) const
1199 {
1200 return extract_impl(a, i, IndexSeq());
1201 }
1202
1203 A shifted(int amount) const
1204 {
1205 return shifted_impl(a, amount, IndexSeq());
1206 }
1207
1208 void load(const typename A::scalar_type *mem) { load_interleaved(*this, mem); }
1209 void store(typename A::scalar_type *mem) { store_interleaved(*this, mem); }
1210
1211private:
1212 reference a;
1213}; // }}}
1214} // namespace SimdizeDetail
1215// assign {{{
1220template <typename S, typename T, size_t N>
1221inline void assign(SimdizeDetail::Adapter<S, T, N> &a, size_t i, const S &x)
1222{
1223 SimdizeDetail::assign_impl(
1224 a, i, x, Vc::make_index_sequence<SimdizeDetail::determine_tuple_size<T>()>());
1225}
1229template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
1230Vc_INTRINSIC void assign(V &v, size_t i, typename V::EntryType x)
1231{
1232 v[i] = x;
1233}
1234// }}}
1235// extract {{{
1240template <typename S, typename T, size_t N>
1241inline S extract(const SimdizeDetail::Adapter<S, T, N> &a, size_t i)
1242{
1243 return SimdizeDetail::extract_impl(
1244 a, i, Vc::make_index_sequence<SimdizeDetail::determine_tuple_size<S>()>());
1245}
1249template <typename V, typename = enable_if<Traits::is_simd_vector<V>::value>>
1250Vc_INTRINSIC typename V::EntryType extract(const V &v, size_t i)
1251{
1252 return v[i];
1253}
1254// }}}
1255// load_interleaved {{{
1256template <class S, class T, size_t N>
1257inline void load_interleaved(SimdizeDetail::Adapter<S, T, N> &a, const S *mem)
1258{
1259 if (SimdizeDetail::homogeneous_sizeof<S>::value == 0) {
1260 Common::unrolled_loop<std::size_t, 0, N>(
1261 [&](std::size_t i) { assign(a, i, mem[i]); });
1262 } else {
1263 constexpr size_t TupleSize = SimdizeDetail::determine_tuple_size_<S>::value;
1264 SimdizeDetail::load_interleaved_impl(Vc::make_index_sequence<TupleSize>(), a,
1265 mem);
1266 }
1267}
1268template <
1269 class V, class T,
1270 class = enable_if<Traits::is_simd_vector<V>::value && std::is_arithmetic<T>::value>>
1271Vc_INTRINSIC void load_interleaved(V &a, const T *mem)
1272{
1273 a.load(mem, Vc::Unaligned);
1274}
1275// }}}
1276// store_interleaved {{{
1277template <class S, class T, size_t N>
1278inline void store_interleaved(const SimdizeDetail::Adapter<S, T, N> &a, S *mem)
1279{
1280 if (SimdizeDetail::homogeneous_sizeof<S>::value == 0) {
1281 Common::unrolled_loop<std::size_t, 0, N>(
1282 [&](std::size_t i) { mem[i] = extract(a, i); });
1283 } else {
1284 constexpr size_t TupleSize = SimdizeDetail::determine_tuple_size_<S>::value;
1285 SimdizeDetail::store_interleaved_impl(Vc::make_index_sequence<TupleSize>(), a,
1286 mem);
1287 }
1288}
1289template <
1290 class V, class T,
1291 class = enable_if<Traits::is_simd_vector<V>::value && std::is_arithmetic<T>::value>>
1292Vc_INTRINSIC void store_interleaved(const V &a, T *mem)
1293{
1294 a.store(mem, Vc::Unaligned);
1295}
1296// }}}
1297// decorate(Adapter) {{{
1298template <typename S, typename T, size_t N>
1299SimdizeDetail::Interface<SimdizeDetail::Adapter<S, T, N>> decorate(
1300 SimdizeDetail::Adapter<S, T, N> &a)
1301{
1302 return {a};
1303}
1304template <typename S, typename T, size_t N>
1305const SimdizeDetail::Interface<const SimdizeDetail::Adapter<S, T, N>> decorate(
1306 const SimdizeDetail::Adapter<S, T, N> &a)
1307{
1308 return {a};
1309}
1310template <class V, class = typename std::enable_if<
1311 Traits::is_simd_vector<typename std::decay<V>::type>::value>>
1312V &&decorate(V &&v)
1313{
1314 return std::forward<V>(v);
1315}
1316// }}}
1317namespace SimdizeDetail
1318{
1319// Adapter::Adapter(F) Generator {{{
1320template <typename Scalar, typename Base, size_t N>
1321template <class F, class>
1322Adapter<Scalar, Base, N>::Adapter(F &&fun)
1323{
1324 for (size_t i = 0; i < N; ++i) {
1325 Vc::assign(*this, i, fun(i));
1326 }
1327}
1328// }}}
1329namespace IteratorDetails // {{{
1330{
1331enum class Mutable { Yes, No };
1332
1333template <typename It, typename V, size_t I, size_t End>
1334Vc_INTRINSIC V fromIteratorImpl(enable_if<(I == End), It>)
1335{
1336 return {};
1337}
1338template <typename It, typename V, size_t I, size_t End>
1339Vc_INTRINSIC V fromIteratorImpl(enable_if<(I < End), It> it)
1340{
1341 V r = fromIteratorImpl<It, V, I + 1, End>(it);
1342 Traits::decay<decltype(get_dispatcher<I>(r))> tmp;
1343 for (size_t j = 0; j < V::size(); ++j, ++it) {
1344 tmp[j] = get_dispatcher<I>(*it);
1345 }
1346 get_dispatcher<I>(r) = tmp;
1347 return r;
1348}
1349template <typename It, typename V>
1350Vc_INTRINSIC V fromIterator(enable_if<!Traits::is_simd_vector<V>::value, const It &> it)
1351{
1352 return fromIteratorImpl<It, V, 0, determine_tuple_size<V>()>(it);
1353}
1354
1355template <typename It, typename V>
1356Vc_INTRINSIC V fromIterator(
1357 enable_if<
1358 Traits::is_simd_vector<V>::value && Traits::has_contiguous_storage<It>::value, It>
1359 it)
1360{
1361#ifndef _MSC_VER
1362 // this check potentially moves it past the end of a container, which is UB. Some STL
1363 // implementations, like MS STL, trap this.
1364 Vc_ASSERT(&*it + 1 == &*(it + 1));
1365#endif
1366 return V(&*it, Vc::Unaligned);
1367}
1368
1369template <typename It, typename V>
1370Vc_INTRINSIC V fromIterator(enable_if<Traits::is_simd_vector<V>::value &&
1371 !Traits::has_contiguous_storage<It>::value,
1372 It>
1373 it)
1374{
1375 V r;
1376 for (size_t j = 0; j < V::size(); ++j, ++it) {
1377 r[j] = *it;
1378 }
1379 return r;
1380}
1381
1382// Note: §13.5.6 says: “An expression x->m is interpreted as (x.operator->())->m for a
1383// class object x of type T if T::operator->() exists and if the operator is selected as
1384// the best match function by the overload resolution mechanism (13.3).”
1385template <typename T, typename value_vector, Mutable> class Pointer;
1386
1395template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::Yes>
1396{
1397 static constexpr auto Size = value_vector::size();
1398
1399public:
1401 value_vector *operator->() { return &data; }
1402
1407 Pointer() = delete;
1408 Pointer(const Pointer &) = delete;
1409 Pointer &operator=(const Pointer &) = delete;
1410 Pointer &operator=(Pointer &&) = delete;
1411
1413 Pointer(Pointer &&) = default;
1414
1420 ~Pointer()
1421 {
1422 // store data back to where it came from
1423 for (size_t i = 0; i < Size; ++i, ++begin_iterator) {
1424 *begin_iterator = extract(data, i);
1425 }
1426 }
1427
1429 Pointer(const T &it) : data(fromIterator<T, value_vector>(it)), begin_iterator(it) {}
1430
1431private:
1433 value_vector data;
1435 T begin_iterator;
1436};
1442template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::No>
1443{
1444 static constexpr auto Size = value_vector::size();
1445
1446public:
1447 const value_vector *operator->() const { return &data; }
1448
1449 Pointer() = delete;
1450 Pointer(const Pointer &) = delete;
1451 Pointer &operator=(const Pointer &) = delete;
1452 Pointer &operator=(Pointer &&) = delete;
1453
1454 Pointer(Pointer &&) = default; // required for returning the Pointer
1455
1456 Pointer(const T &it) : data(fromIterator<T, value_vector>(it)) {}
1457
1458private:
1459 value_vector data;
1460};
1461
1474template <typename T, typename value_vector, Mutable M> class Reference;
1475
1477template <typename T, typename value_vector>
1478class Reference<T, value_vector, Mutable::Yes> : public value_vector
1479{
1480 static constexpr auto Size = value_vector::size();
1481
1482 using reference = typename std::add_lvalue_reference<T>::type;
1483 reference scalar_it;
1484
1485public:
1488 Reference(reference first_it)
1489 : value_vector(fromIterator<T, value_vector>(first_it)), scalar_it(first_it)
1490 {
1491 }
1492
1494 Reference(const Reference &) = delete;
1495 Reference(Reference &&) = default;
1496 Reference &operator=(const Reference &) = delete;
1497 Reference &operator=(Reference &&) = delete;
1498
1504 void operator=(const value_vector &x)
1505 {
1506 static_cast<value_vector &>(*this) = x;
1507 auto it = scalar_it;
1508 for (size_t i = 0; i < Size; ++i, ++it) {
1509 *it = extract(x, i);
1510 }
1511 }
1512};
1513#define Vc_OP(op_) \
1514 template <typename T0, typename V0, typename T1, typename V1> \
1515 decltype(std::declval<const V0 &>() op_ std::declval<const V1 &>()) operator op_( \
1516 const Reference<T0, V0, Mutable::Yes> &x, \
1517 const Reference<T1, V1, Mutable::Yes> &y) \
1518 { \
1519 return static_cast<const V0 &>(x) op_ static_cast<const V1 &>(y); \
1520 }
1521Vc_ALL_COMPARES(Vc_OP);
1522Vc_ALL_ARITHMETICS(Vc_OP);
1523Vc_ALL_BINARY(Vc_OP);
1524Vc_ALL_LOGICAL(Vc_OP);
1525Vc_ALL_SHIFTS(Vc_OP);
1526#undef Vc_OP
1527
1529template <typename T, typename value_vector>
1530class Reference<T, value_vector, Mutable::No> : public value_vector
1531{
1532 static constexpr auto Size = value_vector::size();
1533
1534public:
1535 Reference(const T &it) : value_vector(fromIterator<T, value_vector>(it)) {}
1536
1537 Reference(const Reference &) = delete;
1538 Reference(Reference &&) = default;
1539 Reference &operator=(const Reference &) = delete;
1540 Reference &operator=(Reference &&) = delete;
1541
1543 void operator=(const value_vector &x) = delete;
1544};
1545
1546template <typename T, size_t N,
1547 IteratorDetails::Mutable M =
1548 (Traits::is_output_iterator<T>::value ? Mutable::Yes : Mutable::No),
1549 typename V = simdize<typename std::iterator_traits<T>::value_type, N>,
1550 size_t Size = V::Size,
1551 typename = typename std::iterator_traits<T>::iterator_category>
1552class Iterator;
1553
1554template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size_>
1555class Iterator<T, N, M, V, Size_, std::forward_iterator_tag>
1556{
1557public:
1558 using iterator_category = typename std::iterator_traits<T>::iterator_category;
1559 using difference_type = typename std::iterator_traits<T>::difference_type;
1560 using value_type = V;
1561 using pointer = IteratorDetails::Pointer<T, V, M>;
1562 using reference = IteratorDetails::Reference<T, V, M>;
1563 using const_pointer = IteratorDetails::Pointer<T, V, IteratorDetails::Mutable::No>;
1564 using const_reference =
1565 IteratorDetails::Reference<T, V, IteratorDetails::Mutable::No>;
1566
1568 static constexpr std::size_t size() { return Size_; }
1569 static constexpr std::size_t Size = Size_;
1570
1571 Iterator() = default;
1572
1579 Iterator(const T &x) : scalar_it(x) {}
1583 Iterator(T &&x) : scalar_it(std::move(x)) {}
1587 Iterator &operator=(const T &x)
1588 {
1589 scalar_it = x;
1590 return *this;
1591 }
1595 Iterator &operator=(T &&x)
1596 {
1597 scalar_it = std::move(x);
1598 return *this;
1599 }
1600
1602 Iterator(const Iterator &) = default;
1604 Iterator(Iterator &&) = default;
1606 Iterator &operator=(const Iterator &) = default;
1608 Iterator &operator=(Iterator &&) = default;
1609
1611 Iterator &operator++()
1612 {
1613 std::advance(scalar_it, Size);
1614 return *this;
1615 }
1617 Iterator operator++(int)
1618 {
1619 Iterator copy(*this);
1620 operator++();
1621 return copy;
1622 }
1623
1632 bool operator==(const Iterator &rhs) const
1633 {
1634#ifndef NDEBUG
1635 if (scalar_it == rhs.scalar_it) {
1636 return true;
1637 } else {
1638 T it(scalar_it);
1639 for (size_t i = 1; i < Size; ++i) {
1640 Vc_ASSERT((++it != rhs.scalar_it));
1641 }
1642 return false;
1643 }
1644#else
1645 return scalar_it == rhs.scalar_it;
1646#endif
1647 }
1656 bool operator!=(const Iterator &rhs) const
1657 {
1658 return !operator==(rhs);
1659 }
1660
1661 pointer operator->() { return scalar_it; }
1662
1669 reference operator*() { return scalar_it; }
1670
1671 const_pointer operator->() const { return scalar_it; }
1672
1680 const_reference operator*() const { return scalar_it; }
1681
1695 operator const T &() const { return scalar_it; }
1696
1697protected:
1698 T scalar_it;
1699};
1700
1705template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1706class Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1707 : public Iterator<T, N, M, V, Size, std::forward_iterator_tag>
1708{
1709 using Base = Iterator<T, N, M, V, Size, std::forward_iterator_tag>;
1710
1711protected:
1712 using Base::scalar_it;
1713
1714public:
1715 using pointer = typename Base::pointer;
1716 using reference = typename Base::reference;
1717 using const_pointer = typename Base::const_pointer;
1718 using const_reference = typename Base::const_reference;
1719
1720 using Iterator<T, N, M, V, Size,
1721 std::forward_iterator_tag>::Iterator; // in short: "using
1722 // Base::Iterator", but that
1723 // confuses ICC
1725 Iterator &operator--()
1726 {
1727 std::advance(scalar_it, -Size);
1728 return *this;
1729 }
1731 Iterator operator--(int)
1732 {
1733 Iterator copy(*this);
1734 operator--();
1735 return copy;
1736 }
1737};
1738
1743template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1744class Iterator<T, N, M, V, Size, std::random_access_iterator_tag>
1745 : public Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1746{
1747 using Base = Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>;
1748
1749protected:
1750 using Base::scalar_it;
1751
1752public:
1753 using pointer = typename Base::pointer;
1754 using reference = typename Base::reference;
1755 using const_pointer = typename Base::const_pointer;
1756 using const_reference = typename Base::const_reference;
1757 using difference_type = typename std::iterator_traits<T>::difference_type;
1758
1759 using Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>::
1760 Iterator; // in short: "using Base::Iterator", but that confuses ICC
1761
1762 Iterator &operator+=(difference_type n)
1763 {
1764 scalar_it += n * difference_type(Size);
1765 return *this;
1766 }
1767 Iterator operator+(difference_type n) const { return Iterator(*this) += n; }
1768
1769 Iterator &operator-=(difference_type n)
1770 {
1771 scalar_it -= n * difference_type(Size);
1772 return *this;
1773 }
1774 Iterator operator-(difference_type n) const { return Iterator(*this) -= n; }
1775
1776 difference_type operator-(const Iterator &rhs) const
1777 {
1778 constexpr difference_type n = Size;
1779 Vc_ASSERT((scalar_it - rhs.scalar_it) % n ==
1780 0); // if this fails the two iterators are not a multiple of the vector
1781 // width apart. The distance would be fractional and that doesn't
1782 // make too much sense for iteration. Therefore, it is a
1783 // precondition for the distance of the two iterators to be a
1784 // multiple of Size.
1785 return (scalar_it - rhs.scalar_it) / n;
1786 }
1787
1792 bool operator<(const Iterator &rhs) const
1793 {
1794 return rhs.scalar_it - scalar_it >= difference_type(Size);
1795 }
1796
1797 bool operator>(const Iterator &rhs) const
1798 {
1799 return scalar_it - rhs.scalar_it >= difference_type(Size);
1800 }
1801
1802 bool operator<=(const Iterator &rhs) const
1803 {
1804 return rhs.scalar_it - scalar_it >= difference_type(Size) - 1;
1805 }
1806
1807 bool operator>=(const Iterator &rhs) const
1808 {
1809 return scalar_it - rhs.scalar_it >= difference_type(Size) - 1;
1810 }
1811
1812 reference operator[](difference_type i) { return *(*this + i); }
1813 const_reference operator[](difference_type i) const { return *(*this + i); }
1814};
1815
1816template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1817Iterator<T, N, M, V, Size, std::random_access_iterator_tag> operator+(
1818 typename Iterator<T, N, M, V, Size, std::random_access_iterator_tag>::difference_type
1819 n,
1820 const Iterator<T, N, M, V, Size, std::random_access_iterator_tag> &i)
1821{
1822 return i + n;
1823}
1824
1825} // namespace IteratorDetails }}}
1826
1835template <typename T, size_t N, typename MT>
1836struct ReplaceTypes<T, N, MT, Category::ForwardIterator>
1837{
1838 using type = IteratorDetails::Iterator<T, N>;
1839};
1840template <typename T, size_t N, typename MT>
1841struct ReplaceTypes<T, N, MT, Category::BidirectionalIterator>
1842{
1843 using type = IteratorDetails::Iterator<T, N>;
1844};
1845template <typename T, size_t N, typename MT>
1846struct ReplaceTypes<T, N, MT, Category::RandomAccessIterator>
1847{
1848 using type = IteratorDetails::Iterator<T, N>;
1849};
1850
1854template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1855 std::size_t Offset>
1856Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size_<S>::value && M::Size == N), void>
1857 conditional_assign(Adapter<S, T, N> &, const M &, const U &)
1858{
1859}
1860template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1861 std::size_t Offset = 0>
1862Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size_<S>::value && M::Size == N), void>
1863 conditional_assign(Adapter<S, T, N> &lhs, const M &mask, const U &rhs)
1864{
1865 using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1866 using M2 = typename V::mask_type;
1867 conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask), get_dispatcher<Offset>(rhs));
1868 conditional_assign<Op, S, T, N, M, U, Offset + 1>(lhs, mask, rhs);
1869}
1870template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1871 std::size_t Offset>
1872Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size_<S>::value && M::Size == N), void>
1873 conditional_assign(Adapter<S, T, N> &, const M &)
1874{
1875}
1876template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1877 std::size_t Offset = 0>
1878Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size_<S>::value && M::Size == N), void>
1879 conditional_assign(Adapter<S, T, N> &lhs, const M &mask)
1880{
1881 using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1882 using M2 = typename V::mask_type;
1883 conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask));
1884 conditional_assign<Op, S, T, N, M, Offset + 1>(lhs, mask);
1885}
1886
1888} // namespace SimdizeDetail
1889
1890// user API {{{
1909template <typename T, size_t N = 0, typename MT = void>
1910using simdize = SimdizeDetail::simdize<T, N, MT>;
1911
1931#define Vc_SIMDIZE_INTERFACE(MEMBERS_) \
1932 template <std::size_t N_> \
1933 inline auto vc_get_()->decltype(std::get<N_>(std::tie MEMBERS_)) \
1934 { \
1935 return std::get<N_>(std::tie MEMBERS_); \
1936 } \
1937 template <std::size_t N_> \
1938 inline auto vc_get_() const->decltype(std::get<N_>(std::tie MEMBERS_)) \
1939 { \
1940 return std::get<N_>(std::tie MEMBERS_); \
1941 } \
1942 enum : std::size_t { \
1943 tuple_size = std::tuple_size<decltype(std::make_tuple MEMBERS_)>::value \
1944 }
1945// }}}
1946} // namespace Vc
1947
1948namespace std // {{{
1949{
1951} // namespace std }}}
1952
1953#endif // VC_COMMON_SIMDIZE_H_
1954
1955// vim: foldmethod=marker
An allocator that uses global new and supports over-aligned types, as per [C++11 20....
Definition Allocator:129
bool operator<(const Iterator &rhs) const
Returns whether all entries accessed via iterator dereferencing come before the iterator rhs.
Definition simdize.h:1792
This is the iterator type created when applying simdize to a bidirectional iterator type.
Definition simdize.h:1708
Iterator & operator--()
Advances the iterator by one vector width, or respectively N scalar steps.
Definition simdize.h:1725
SimdizeDetail::simdize< T, N, MT > simdize
Definition simdize.h:1910
Adapter< S, T, N > shifted(const Adapter< S, T, N > &a, int shift)
Returns a new vectorized object where each entry is shifted by shift.
Definition simdize.h:1069
void swap(Adapter< S, T, N > &a, std::size_t i, S &x)
Swaps one scalar object x with a SIMD slot at offset i in the simdized object a.
Definition simdize.h:1108
constexpr UnalignedTag Unaligned
Use this object for a flags parameter to request unaligned loads and stores.
Vector Classes Namespace.
Definition dox.h:585
S extract(const SimdizeDetail::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:1241
void assign(SimdizeDetail::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:1221