Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-08-28 09:11:40

0001 /***************************************************************************
0002  * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and         *
0003  * Martin Renou                                                             *
0004  * Copyright (c) QuantStack                                                 *
0005  * Copyright (c) Serge Guelton                                              *
0006  *                                                                          *
0007  * Distributed under the terms of the BSD 3-Clause License.                 *
0008  *                                                                          *
0009  * The full license is in the file LICENSE, distributed with this software. *
0010  ****************************************************************************/
0011 
0012 #ifndef XSIMD_UTILS_HPP
0013 #define XSIMD_UTILS_HPP
0014 
0015 #include <complex>
0016 #include <cstdint>
0017 #include <cstring>
0018 #include <tuple>
0019 #include <type_traits>
0020 
0021 #ifdef XSIMD_ENABLE_XTL_COMPLEX
0022 #include "xtl/xcomplex.hpp"
0023 #endif
0024 
0025 namespace xsimd
0026 {
0027 
0028     template <class T, class A>
0029     class batch;
0030 
0031     template <class T, class A>
0032     class batch_bool;
0033 
0034     /**************
0035      * index      *
0036      **************/
0037 
0038     template <size_t I>
0039     using index = std::integral_constant<size_t, I>;
0040 
0041     /**************
0042      * as_integer *
0043      **************/
0044 
0045     template <class T>
0046     struct as_integer : std::make_signed<T>
0047     {
0048     };
0049 
0050     template <>
0051     struct as_integer<float>
0052     {
0053         using type = int32_t;
0054     };
0055 
0056     template <>
0057     struct as_integer<double>
0058     {
0059         using type = int64_t;
0060     };
0061 
0062     template <class T, class A>
0063     struct as_integer<batch<T, A>>
0064     {
0065         using type = batch<typename as_integer<T>::type, A>;
0066     };
0067 
0068     template <class B>
0069     using as_integer_t = typename as_integer<B>::type;
0070 
0071     /***********************
0072      * as_unsigned_integer *
0073      ***********************/
0074 
0075     template <class T>
0076     struct as_unsigned_integer : std::make_unsigned<T>
0077     {
0078     };
0079 
0080     template <>
0081     struct as_unsigned_integer<float>
0082     {
0083         using type = uint32_t;
0084     };
0085 
0086     template <>
0087     struct as_unsigned_integer<double>
0088     {
0089         using type = uint64_t;
0090     };
0091 
0092     template <class T, class A>
0093     struct as_unsigned_integer<batch<T, A>>
0094     {
0095         using type = batch<typename as_unsigned_integer<T>::type, A>;
0096     };
0097 
0098     template <class T>
0099     using as_unsigned_integer_t = typename as_unsigned_integer<T>::type;
0100 
0101     /*********************
0102      * as_signed_integer *
0103      *********************/
0104 
0105     template <class T>
0106     struct as_signed_integer : std::make_signed<T>
0107     {
0108     };
0109 
0110     template <class T>
0111     using as_signed_integer_t = typename as_signed_integer<T>::type;
0112 
0113     /******************
0114      * flip_sign_type *
0115      ******************/
0116 
0117     namespace detail
0118     {
0119         template <class T, bool is_signed>
0120         struct flipped_sign_type_impl : std::make_signed<T>
0121         {
0122         };
0123 
0124         template <class T>
0125         struct flipped_sign_type_impl<T, true> : std::make_unsigned<T>
0126         {
0127         };
0128     }
0129 
0130     template <class T>
0131     struct flipped_sign_type
0132         : detail::flipped_sign_type_impl<T, std::is_signed<T>::value>
0133     {
0134     };
0135 
0136     template <class T>
0137     using flipped_sign_type_t = typename flipped_sign_type<T>::type;
0138 
0139     /***********
0140      * as_float *
0141      ************/
0142 
0143     template <class T>
0144     struct as_float;
0145 
0146     template <>
0147     struct as_float<int32_t>
0148     {
0149         using type = float;
0150     };
0151 
0152     template <>
0153     struct as_float<int64_t>
0154     {
0155         using type = double;
0156     };
0157 
0158     template <class T, class A>
0159     struct as_float<batch<T, A>>
0160     {
0161         using type = batch<typename as_float<T>::type, A>;
0162     };
0163 
0164     template <class T>
0165     using as_float_t = typename as_float<T>::type;
0166 
0167     /**************
0168      * as_logical *
0169      **************/
0170 
0171     template <class T>
0172     struct as_logical;
0173 
0174     template <class T, class A>
0175     struct as_logical<batch<T, A>>
0176     {
0177         using type = batch_bool<T, A>;
0178     };
0179 
0180     template <class T>
0181     using as_logical_t = typename as_logical<T>::type;
0182 
0183     /********************
0184      * bit_cast *
0185      ********************/
0186 
0187     template <class To, class From>
0188     inline To bit_cast(From val) noexcept
0189     {
0190         static_assert(sizeof(From) == sizeof(To), "casting between compatible layout");
0191         // FIXME: Some old version of GCC don't support that trait
0192         // static_assert(std::is_trivially_copyable<From>::value, "input type is trivially copyable");
0193         // static_assert(std::is_trivially_copyable<To>::value, "output type is trivially copyable");
0194         To res;
0195         std::memcpy(&res, &val, sizeof(val));
0196         return res;
0197     }
0198 
0199     namespace kernel
0200     {
0201         namespace detail
0202         {
0203             /**************************************
0204              * enabling / disabling metafunctions *
0205              **************************************/
0206 
0207             template <class T>
0208             using enable_integral_t = typename std::enable_if<std::is_integral<T>::value, int>::type;
0209 
0210             template <class T, size_t S>
0211             using enable_sized_signed_t = typename std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value && sizeof(T) == S, int>::type;
0212 
0213             template <class T, size_t S>
0214             using enable_sized_unsigned_t = typename std::enable_if<std::is_integral<T>::value && !std::is_signed<T>::value && sizeof(T) == S, int>::type;
0215 
0216             template <class T, size_t S>
0217             using enable_sized_integral_t = typename std::enable_if<std::is_integral<T>::value && sizeof(T) == S, int>::type;
0218 
0219             template <class T, size_t S>
0220             using enable_sized_t = typename std::enable_if<sizeof(T) == S, int>::type;
0221 
0222             template <class T, size_t S>
0223             using enable_max_sized_integral_t = typename std::enable_if<std::is_integral<T>::value && sizeof(T) <= S, int>::type;
0224 
0225             /********************************
0226              * Matching & mismatching sizes *
0227              ********************************/
0228 
0229             template <class T, class U, class B = int>
0230             using sizes_match_t = typename std::enable_if<sizeof(T) == sizeof(U), B>::type;
0231 
0232             template <class T, class U, class B = int>
0233             using sizes_mismatch_t = typename std::enable_if<sizeof(T) != sizeof(U), B>::type;
0234 
0235             template <class T, class U, class B = int>
0236             using stride_match_t = typename std::enable_if<!std::is_same<T, U>::value && sizeof(T) == sizeof(U), B>::type;
0237         } // namespace detail
0238     } // namespace kernel
0239 
0240     /*****************************************
0241      * Backport of index_sequence from c++14 *
0242      *****************************************/
0243 
0244     // TODO: Remove this once we drop C++11 support
0245     namespace detail
0246     {
0247         template <typename T>
0248         struct identity
0249         {
0250             using type = T;
0251         };
0252 
0253 #ifdef __cpp_lib_integer_sequence
0254         using std::index_sequence;
0255         using std::integer_sequence;
0256         using std::make_index_sequence;
0257         using std::make_integer_sequence;
0258 
0259         using std::index_sequence_for;
0260 #else
0261         template <typename T, T... Is>
0262         struct integer_sequence
0263         {
0264             using value_type = T;
0265             static constexpr std::size_t size() noexcept { return sizeof...(Is); }
0266         };
0267 
0268         template <typename Lhs, typename Rhs>
0269         struct make_integer_sequence_concat;
0270 
0271         template <typename T, T... Lhs, T... Rhs>
0272         struct make_integer_sequence_concat<integer_sequence<T, Lhs...>,
0273                                             integer_sequence<T, Rhs...>>
0274             : identity<integer_sequence<T, Lhs..., (sizeof...(Lhs) + Rhs)...>>
0275         {
0276         };
0277 
0278         template <typename T>
0279         struct make_integer_sequence_impl;
0280 
0281         template <typename T>
0282         struct make_integer_sequence_impl<std::integral_constant<T, (T)0>> : identity<integer_sequence<T>>
0283         {
0284         };
0285 
0286         template <typename T>
0287         struct make_integer_sequence_impl<std::integral_constant<T, (T)1>> : identity<integer_sequence<T, 0>>
0288         {
0289         };
0290 
0291         template <typename T, T N>
0292         struct make_integer_sequence_impl<std::integral_constant<T, N>>
0293             : make_integer_sequence_concat<typename make_integer_sequence_impl<std::integral_constant<T, N / 2>>::type,
0294                                            typename make_integer_sequence_impl<std::integral_constant<T, N - (N / 2)>>::type>
0295         {
0296         };
0297 
0298         template <typename T, T N>
0299         using make_integer_sequence = typename make_integer_sequence_impl<std::integral_constant<T, N>>::type;
0300 
0301         template <std::size_t... Is>
0302         using index_sequence = integer_sequence<std::size_t, Is...>;
0303 
0304         template <std::size_t N>
0305         using make_index_sequence = make_integer_sequence<std::size_t, N>;
0306 
0307         template <typename... Ts>
0308         using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
0309 
0310 #endif
0311 
0312         template <int... Is>
0313         using int_sequence = integer_sequence<int, Is...>;
0314 
0315         template <int N>
0316         using make_int_sequence = make_integer_sequence<int, N>;
0317 
0318         template <typename... Ts>
0319         using int_sequence_for = make_int_sequence<(int)sizeof...(Ts)>;
0320 
0321         // Type-casted index sequence.
0322         template <class P, size_t... Is>
0323         inline P indexes_from(index_sequence<Is...>) noexcept
0324         {
0325             return { static_cast<typename P::value_type>(Is)... };
0326         }
0327 
0328         template <class P>
0329         inline P make_sequence_as_batch() noexcept
0330         {
0331             return indexes_from<P>(make_index_sequence<P::size>());
0332         }
0333     }
0334 
0335     /***********************************
0336      * Backport of std::get from C++14 *
0337      ***********************************/
0338 
0339     namespace detail
0340     {
0341         template <class T, class... Types, size_t I, size_t... Is>
0342         inline const T& get_impl(const std::tuple<Types...>& t, std::is_same<T, T>, index_sequence<I, Is...>) noexcept
0343         {
0344             return std::get<I>(t);
0345         }
0346 
0347         template <class T, class U, class... Types, size_t I, size_t... Is>
0348         inline const T& get_impl(const std::tuple<Types...>& t, std::is_same<T, U>, index_sequence<I, Is...>) noexcept
0349         {
0350             using tuple_elem = typename std::tuple_element<I + 1, std::tuple<Types...>>::type;
0351             return get_impl<T>(t, std::is_same<T, tuple_elem>(), index_sequence<Is...>());
0352         }
0353 
0354         template <class T, class... Types>
0355         inline const T& get(const std::tuple<Types...>& t) noexcept
0356         {
0357             using tuple_elem = typename std::tuple_element<0, std::tuple<Types...>>::type;
0358             return get_impl<T>(t, std::is_same<T, tuple_elem>(), make_index_sequence<sizeof...(Types)>());
0359         }
0360     }
0361 
0362     /*********************************
0363      * Backport of void_t from C++17 *
0364      *********************************/
0365 
0366     namespace detail
0367     {
0368         template <class... T>
0369         struct make_void
0370         {
0371             using type = void;
0372         };
0373 
0374         template <class... T>
0375         using void_t = typename make_void<T...>::type;
0376     }
0377 
0378     /**************************************************
0379      * Equivalent of void_t but with size_t parameter *
0380      **************************************************/
0381 
0382     namespace detail
0383     {
0384         template <std::size_t>
0385         struct check_size
0386         {
0387             using type = void;
0388         };
0389 
0390         template <std::size_t S>
0391         using check_size_t = typename check_size<S>::type;
0392     }
0393 
0394     /*****************************************
0395      * Supplementary std::array constructors *
0396      *****************************************/
0397 
0398     namespace detail
0399     {
0400         // std::array constructor from scalar value ("broadcast")
0401         template <typename T, std::size_t... Is>
0402         inline constexpr std::array<T, sizeof...(Is)>
0403         array_from_scalar_impl(const T& scalar, index_sequence<Is...>) noexcept
0404         {
0405             // You can safely ignore this silly ternary, the "scalar" is all
0406             // that matters. The rest is just a dirty workaround...
0407             return std::array<T, sizeof...(Is)> { (Is + 1) ? scalar : T()... };
0408         }
0409 
0410         template <typename T, std::size_t N>
0411         inline constexpr std::array<T, N>
0412         array_from_scalar(const T& scalar) noexcept
0413         {
0414             return array_from_scalar_impl(scalar, make_index_sequence<N>());
0415         }
0416 
0417         // std::array constructor from C-style pointer (handled as an array)
0418         template <typename T, std::size_t... Is>
0419         inline constexpr std::array<T, sizeof...(Is)>
0420         array_from_pointer_impl(const T* c_array, index_sequence<Is...>) noexcept
0421         {
0422             return std::array<T, sizeof...(Is)> { c_array[Is]... };
0423         }
0424 
0425         template <typename T, std::size_t N>
0426         inline constexpr std::array<T, N>
0427         array_from_pointer(const T* c_array) noexcept
0428         {
0429             return array_from_pointer_impl(c_array, make_index_sequence<N>());
0430         }
0431     }
0432 
0433     /************************
0434      * is_array_initializer *
0435      ************************/
0436 
0437     namespace detail
0438     {
0439         template <bool...>
0440         struct bool_pack;
0441 
0442         template <bool... bs>
0443         using all_true = std::is_same<
0444             bool_pack<bs..., true>, bool_pack<true, bs...>>;
0445 
0446         template <typename T, typename... Args>
0447         using is_all_convertible = all_true<std::is_convertible<Args, T>::value...>;
0448 
0449         template <typename T, std::size_t N, typename... Args>
0450         using is_array_initializer = std::enable_if<
0451             (sizeof...(Args) == N) && is_all_convertible<T, Args...>::value>;
0452 
0453         // Check that a variadic argument pack is a list of N values of type T,
0454         // as usable for instantiating a value of type std::array<T, N>.
0455         template <typename T, std::size_t N, typename... Args>
0456         using is_array_initializer_t = typename is_array_initializer<T, N, Args...>::type;
0457     }
0458 
0459     /**************
0460      * is_complex *
0461      **************/
0462 
0463     // This is used in both xsimd_complex_base.hpp and xsimd_traits.hpp
0464     // However xsimd_traits.hpp indirectly includes xsimd_complex_base.hpp
0465     // so we cannot define is_complex in xsimd_traits.hpp. Besides, if
0466     // no file defining batches is included, we still need this definition
0467     // in xsimd_traits.hpp, so let's define it here.
0468 
0469     namespace detail
0470     {
0471         template <class T>
0472         struct is_complex : std::false_type
0473         {
0474         };
0475 
0476         template <class T>
0477         struct is_complex<std::complex<T>> : std::true_type
0478         {
0479         };
0480 
0481 #ifdef XSIMD_ENABLE_XTL_COMPLEX
0482         template <class T, bool i3ec>
0483         struct is_complex<xtl::xcomplex<T, T, i3ec>> : std::true_type
0484         {
0485         };
0486 #endif
0487     }
0488 
0489     /*******************
0490      * real_batch_type *
0491      *******************/
0492 
0493     template <class B>
0494     struct real_batch_type
0495     {
0496         using type = B;
0497     };
0498 
0499     template <class T, class A>
0500     struct real_batch_type<batch<std::complex<T>, A>>
0501     {
0502         using type = batch<T, A>;
0503     };
0504 
0505     template <class B>
0506     using real_batch_type_t = typename real_batch_type<B>::type;
0507 
0508     /**********************
0509      * complex_batch_type *
0510      **********************/
0511 
0512     template <class B>
0513     struct complex_batch_type
0514     {
0515         using real_value_type = typename B::value_type;
0516         using arch_type = typename B::arch_type;
0517         using type = batch<std::complex<real_value_type>, arch_type>;
0518     };
0519 
0520     template <class T, class A>
0521     struct complex_batch_type<batch<std::complex<T>, A>>
0522     {
0523         using type = batch<std::complex<T>, A>;
0524     };
0525 
0526     template <class B>
0527     using complex_batch_type_t = typename complex_batch_type<B>::type;
0528 }
0529 
0530 #endif