Vc 1.4.1
SIMD Vector Classes for C++
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 None,
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::None;
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::None;
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::None
229 ? iteratorCategories<T>(int())
230 : is_class_template<T>::value ? Category::ClassTemplate
231 : Category::None;
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::None>
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}
1354template <typename It, typename V>
1355Vc_INTRINSIC V fromIterator(enable_if<Traits::is_simd_vector<V>::value, It> it)
1356{
1357 V r;
1358 for (size_t j = 0; j < V::size(); ++j, ++it) {
1359 r[j] = *it;
1360 }
1361 return r;
1362}
1363
1364// Note: §13.5.6 says: “An expression x->m is interpreted as (x.operator->())->m for a
1365// class object x of type T if T::operator->() exists and if the operator is selected as
1366// the best match function by the overload resolution mechanism (13.3).”
1367template <typename T, typename value_vector, Mutable> class Pointer;
1368
1377template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::Yes>
1378{
1379 static constexpr auto Size = value_vector::size();
1380
1381public:
1383 value_vector *operator->() { return &data; }
1384
1389 Pointer() = delete;
1390 Pointer(const Pointer &) = delete;
1391 Pointer &operator=(const Pointer &) = delete;
1392 Pointer &operator=(Pointer &&) = delete;
1393
1395 Pointer(Pointer &&) = default;
1396
1402 ~Pointer()
1403 {
1404 // store data back to where it came from
1405 for (size_t i = 0; i < Size; ++i, ++begin_iterator) {
1406 *begin_iterator = extract(data, i);
1407 }
1408 }
1409
1411 Pointer(const T &it) : data(fromIterator<T, value_vector>(it)), begin_iterator(it) {}
1412
1413private:
1415 value_vector data;
1417 T begin_iterator;
1418};
1424template <typename T, typename value_vector> class Pointer<T, value_vector, Mutable::No>
1425{
1426 static constexpr auto Size = value_vector::size();
1427
1428public:
1429 const value_vector *operator->() const { return &data; }
1430
1431 Pointer() = delete;
1432 Pointer(const Pointer &) = delete;
1433 Pointer &operator=(const Pointer &) = delete;
1434 Pointer &operator=(Pointer &&) = delete;
1435
1436 Pointer(Pointer &&) = default; // required for returning the Pointer
1437
1438 Pointer(const T &it) : data(fromIterator<T, value_vector>(it)) {}
1439
1440private:
1441 value_vector data;
1442};
1443
1456template <typename T, typename value_vector, Mutable M> class Reference;
1457
1459template <typename T, typename value_vector>
1460class Reference<T, value_vector, Mutable::Yes> : public value_vector
1461{
1462 static constexpr auto Size = value_vector::size();
1463
1464 using reference = typename std::add_lvalue_reference<T>::type;
1465 reference scalar_it;
1466
1467public:
1470 Reference(reference first_it)
1471 : value_vector(fromIterator<T, value_vector>(first_it)), scalar_it(first_it)
1472 {
1473 }
1474
1476 Reference(const Reference &) = delete;
1477 Reference(Reference &&) = default;
1478 Reference &operator=(const Reference &) = delete;
1479 Reference &operator=(Reference &&) = delete;
1480
1486 void operator=(const value_vector &x)
1487 {
1488 static_cast<value_vector &>(*this) = x;
1489 auto it = scalar_it;
1490 for (size_t i = 0; i < Size; ++i, ++it) {
1491 *it = extract(x, i);
1492 }
1493 }
1494};
1495#define Vc_OP(op_) \
1496 template <typename T0, typename V0, typename T1, typename V1> \
1497 decltype(std::declval<const V0 &>() op_ std::declval<const V1 &>()) operator op_( \
1498 const Reference<T0, V0, Mutable::Yes> &x, \
1499 const Reference<T1, V1, Mutable::Yes> &y) \
1500 { \
1501 return static_cast<const V0 &>(x) op_ static_cast<const V1 &>(y); \
1502 }
1503Vc_ALL_COMPARES(Vc_OP);
1504Vc_ALL_ARITHMETICS(Vc_OP);
1505Vc_ALL_BINARY(Vc_OP);
1506Vc_ALL_LOGICAL(Vc_OP);
1507Vc_ALL_SHIFTS(Vc_OP);
1508#undef Vc_OP
1509
1511template <typename T, typename value_vector>
1512class Reference<T, value_vector, Mutable::No> : public value_vector
1513{
1514 static constexpr auto Size = value_vector::size();
1515
1516public:
1517 Reference(const T &it) : value_vector(fromIterator<T, value_vector>(it)) {}
1518
1519 Reference(const Reference &) = delete;
1520 Reference(Reference &&) = default;
1521 Reference &operator=(const Reference &) = delete;
1522 Reference &operator=(Reference &&) = delete;
1523
1525 void operator=(const value_vector &x) = delete;
1526};
1527
1528template <typename T, size_t N,
1529 IteratorDetails::Mutable M =
1530 (Traits::is_output_iterator<T>::value ? Mutable::Yes : Mutable::No),
1531 typename V = simdize<typename std::iterator_traits<T>::value_type, N>,
1532 size_t Size = V::Size,
1533 typename = typename std::iterator_traits<T>::iterator_category>
1534class Iterator;
1535
1536template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size_>
1537class Iterator<T, N, M, V, Size_, std::forward_iterator_tag>
1538 : public std::iterator<typename std::iterator_traits<T>::iterator_category, V,
1539 typename std::iterator_traits<T>::difference_type,
1540 IteratorDetails::Pointer<T, V, M>,
1541 IteratorDetails::Reference<T, V, M>>
1542{
1543public:
1544 using pointer = IteratorDetails::Pointer<T, V, M>;
1545 using reference = IteratorDetails::Reference<T, V, M>;
1546 using const_pointer = IteratorDetails::Pointer<T, V, IteratorDetails::Mutable::No>;
1547 using const_reference =
1548 IteratorDetails::Reference<T, V, IteratorDetails::Mutable::No>;
1549
1551 static constexpr std::size_t size() { return Size_; }
1552 static constexpr std::size_t Size = Size_;
1553
1554 Iterator() = default;
1555
1562 Iterator(const T &x) : scalar_it(x) {}
1566 Iterator(T &&x) : scalar_it(std::move(x)) {}
1570 Iterator &operator=(const T &x)
1571 {
1572 scalar_it = x;
1573 return *this;
1574 }
1578 Iterator &operator=(T &&x)
1579 {
1580 scalar_it = std::move(x);
1581 return *this;
1582 }
1583
1585 Iterator(const Iterator &) = default;
1587 Iterator(Iterator &&) = default;
1589 Iterator &operator=(const Iterator &) = default;
1591 Iterator &operator=(Iterator &&) = default;
1592
1594 Iterator &operator++()
1595 {
1596 std::advance(scalar_it, Size);
1597 return *this;
1598 }
1600 Iterator operator++(int)
1601 {
1602 Iterator copy(*this);
1603 operator++();
1604 return copy;
1605 }
1606
1615 bool operator==(const Iterator &rhs) const
1616 {
1617#ifndef NDEBUG
1618 if (scalar_it == rhs.scalar_it) {
1619 return true;
1620 } else {
1621 T it(scalar_it);
1622 for (size_t i = 1; i < Size; ++i) {
1623 Vc_ASSERT((++it != rhs.scalar_it));
1624 }
1625 return false;
1626 }
1627#else
1628 return scalar_it == rhs.scalar_it;
1629#endif
1630 }
1639 bool operator!=(const Iterator &rhs) const
1640 {
1641 return !operator==(rhs);
1642 }
1643
1644 pointer operator->() { return scalar_it; }
1645
1652 reference operator*() { return scalar_it; }
1653
1654 const_pointer operator->() const { return scalar_it; }
1655
1663 const_reference operator*() const { return scalar_it; }
1664
1678 operator const T &() const { return scalar_it; }
1679
1680protected:
1681 T scalar_it;
1682};
1683
1688template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1689class Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1690 : public Iterator<T, N, M, V, Size, std::forward_iterator_tag>
1691{
1692 using Base = Iterator<T, N, M, V, Size, std::forward_iterator_tag>;
1693
1694protected:
1695 using Base::scalar_it;
1696
1697public:
1698 using pointer = typename Base::pointer;
1699 using reference = typename Base::reference;
1700 using const_pointer = typename Base::const_pointer;
1701 using const_reference = typename Base::const_reference;
1702
1703 using Iterator<T, N, M, V, Size,
1704 std::forward_iterator_tag>::Iterator; // in short: "using
1705 // Base::Iterator", but that
1706 // confuses ICC
1708 Iterator &operator--()
1709 {
1710 std::advance(scalar_it, -Size);
1711 return *this;
1712 }
1714 Iterator operator--(int)
1715 {
1716 Iterator copy(*this);
1717 operator--();
1718 return copy;
1719 }
1720};
1721
1726template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1727class Iterator<T, N, M, V, Size, std::random_access_iterator_tag>
1728 : public Iterator<T, N, M, V, Size, std::bidirectional_iterator_tag>
1729{
1731
1732protected:
1733 using Base::scalar_it;
1734
1735public:
1736 using pointer = typename Base::pointer;
1737 using reference = typename Base::reference;
1738 using const_pointer = typename Base::const_pointer;
1739 using const_reference = typename Base::const_reference;
1740 using difference_type = typename std::iterator_traits<T>::difference_type;
1741
1743 Iterator; // in short: "using Base::Iterator", but that confuses ICC
1744
1745 Iterator &operator+=(difference_type n)
1746 {
1747 scalar_it += n * difference_type(Size);
1748 return *this;
1749 }
1750 Iterator operator+(difference_type n) const { return Iterator(*this) += n; }
1751
1752 Iterator &operator-=(difference_type n)
1753 {
1754 scalar_it -= n * difference_type(Size);
1755 return *this;
1756 }
1757 Iterator operator-(difference_type n) const { return Iterator(*this) -= n; }
1758
1759 difference_type operator-(const Iterator &rhs) const
1760 {
1761 constexpr difference_type n = Size;
1762 Vc_ASSERT((scalar_it - rhs.scalar_it) % n ==
1763 0); // if this fails the two iterators are not a multiple of the vector
1764 // width apart. The distance would be fractional and that doesn't
1765 // make too much sense for iteration. Therefore, it is a
1766 // precondition for the distance of the two iterators to be a
1767 // multiple of Size.
1768 return (scalar_it - rhs.scalar_it) / n;
1769 }
1770
1775 bool operator<(const Iterator &rhs) const
1776 {
1777 return rhs.scalar_it - scalar_it >= difference_type(Size);
1778 }
1779
1780 bool operator>(const Iterator &rhs) const
1781 {
1782 return scalar_it - rhs.scalar_it >= difference_type(Size);
1783 }
1784
1785 bool operator<=(const Iterator &rhs) const
1786 {
1787 return rhs.scalar_it - scalar_it >= difference_type(Size) - 1;
1788 }
1789
1790 bool operator>=(const Iterator &rhs) const
1791 {
1792 return scalar_it - rhs.scalar_it >= difference_type(Size) - 1;
1793 }
1794
1795 reference operator[](difference_type i) { return *(*this + i); }
1796 const_reference operator[](difference_type i) const { return *(*this + i); }
1797};
1798
1799template <typename T, size_t N, IteratorDetails::Mutable M, typename V, size_t Size>
1800Iterator<T, N, M, V, Size, std::random_access_iterator_tag> operator+(
1801 typename Iterator<T, N, M, V, Size, std::random_access_iterator_tag>::difference_type
1802 n,
1803 const Iterator<T, N, M, V, Size, std::random_access_iterator_tag> &i)
1804{
1805 return i + n;
1806}
1807
1808} // namespace IteratorDetails }}}
1809
1818template <typename T, size_t N, typename MT>
1819struct ReplaceTypes<T, N, MT, Category::ForwardIterator>
1820{
1821 using type = IteratorDetails::Iterator<T, N>;
1822};
1823template <typename T, size_t N, typename MT>
1824struct ReplaceTypes<T, N, MT, Category::BidirectionalIterator>
1825{
1826 using type = IteratorDetails::Iterator<T, N>;
1827};
1828template <typename T, size_t N, typename MT>
1829struct ReplaceTypes<T, N, MT, Category::RandomAccessIterator>
1830{
1831 using type = IteratorDetails::Iterator<T, N>;
1832};
1833
1837template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1838 std::size_t Offset>
1839Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size_<S>::value && M::Size == N), void>
1840 conditional_assign(Adapter<S, T, N> &, const M &, const U &)
1841{
1842}
1843template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M, typename U,
1844 std::size_t Offset = 0>
1845Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size_<S>::value && M::Size == N), void>
1846 conditional_assign(Adapter<S, T, N> &lhs, const M &mask, const U &rhs)
1847{
1848 using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1849 using M2 = typename V::mask_type;
1850 conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask), get_dispatcher<Offset>(rhs));
1851 conditional_assign<Op, S, T, N, M, U, Offset + 1>(lhs, mask, rhs);
1852}
1853template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1854 std::size_t Offset>
1855Vc_INTRINSIC Vc::enable_if<(Offset >= determine_tuple_size_<S>::value && M::Size == N), void>
1856 conditional_assign(Adapter<S, T, N> &, const M &)
1857{
1858}
1859template <Vc::Operator Op, typename S, typename T, std::size_t N, typename M,
1860 std::size_t Offset = 0>
1861Vc_INTRINSIC Vc::enable_if<(Offset < determine_tuple_size_<S>::value && M::Size == N), void>
1862 conditional_assign(Adapter<S, T, N> &lhs, const M &mask)
1863{
1864 using V = typename std::decay<decltype(get_dispatcher<Offset>(lhs))>::type;
1865 using M2 = typename V::mask_type;
1866 conditional_assign<Op>(get_dispatcher<Offset>(lhs), simd_cast<M2>(mask));
1867 conditional_assign<Op, S, T, N, M, Offset + 1>(lhs, mask);
1868}
1869
1871} // namespace SimdizeDetail
1872
1873// user API {{{
1892template <typename T, size_t N = 0, typename MT = void>
1893using simdize = SimdizeDetail::simdize<T, N, MT>;
1894
1914#define Vc_SIMDIZE_INTERFACE(MEMBERS_) \
1915 template <std::size_t N_> \
1916 inline auto vc_get_()->decltype(std::get<N_>(std::tie MEMBERS_)) \
1917 { \
1918 return std::get<N_>(std::tie MEMBERS_); \
1919 } \
1920 template <std::size_t N_> \
1921 inline auto vc_get_() const->decltype(std::get<N_>(std::tie MEMBERS_)) \
1922 { \
1923 return std::get<N_>(std::tie MEMBERS_); \
1924 } \
1925 enum : std::size_t { \
1926 tuple_size = std::tuple_size<decltype(std::make_tuple MEMBERS_)>::value \
1927 }
1928// }}}
1929} // namespace Vc
1930
1931namespace std // {{{
1932{
1934} // namespace std }}}
1935
1936#endif // VC_COMMON_SIMDIZE_H_
1937
1938// 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:1775
This is the iterator type created when applying simdize to a bidirectional iterator type.
Definition: simdize.h:1691
Iterator & operator--()
Advances the iterator by one vector width, or respectively N scalar steps.
Definition: simdize.h:1708
result_vector_type< L, R > operator*(L &&lhs, R &&rhs)
Applies * component-wise and concurrently.
Definition: simdarray.h:1721
result_vector_type< L, R > operator-(L &&lhs, R &&rhs)
Applies - component-wise and concurrently.
Definition: simdarray.h:1721
result_vector_type< L, R > operator+(L &&lhs, R &&rhs)
Applies + component-wise and concurrently.
Definition: simdarray.h:1721
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
SimdizeDetail::simdize< T, N, MT > simdize
Definition: simdize.h:1893
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
constexpr UnalignedTag Unaligned
Use this object for a flags parameter to request unaligned loads and stores.
void free(T *p)
Frees memory that was allocated with Vc::malloc.
Definition: malloc.h:163
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