| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134 |
- /***************************************************************************
- * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht *
- * Copyright (c) QuantStack *
- * *
- * Distributed under the terms of the BSD 3-Clause License. *
- * *
- * The full license is in the file LICENSE, distributed with this software. *
- ****************************************************************************/
- #ifndef XTENSOR_UTILS_HPP
- #define XTENSOR_UTILS_HPP
- #include <algorithm>
- #include <array>
- #include <cmath>
- #include <complex>
- #include <cstddef>
- #include <initializer_list>
- #include <iostream>
- #include <memory>
- #include <tuple>
- #include <type_traits>
- #include <utility>
- #include <vector>
- #include <xtl/xfunctional.hpp>
- #include <xtl/xmeta_utils.hpp>
- #include <xtl/xsequence.hpp>
- #include <xtl/xtype_traits.hpp>
- #include "xtensor_config.hpp"
- #if (_MSC_VER >= 1910)
- #define NOEXCEPT(T)
- #else
- #define NOEXCEPT(T) noexcept(T)
- #endif
- namespace xt
- {
- /****************
- * declarations *
- ****************/
- template <class T>
- struct remove_class;
- /*template <class F, class... T>
- void for_each(F&& f, std::tuple<T...>& t) noexcept(implementation_dependent);*/
- /*template <class F, class R, class... T>
- R accumulate(F&& f, R init, const std::tuple<T...>& t) noexcept(implementation_dependent);*/
- template <std::size_t I, class... Args>
- constexpr decltype(auto) argument(Args&&... args) noexcept;
- template <class R, class F, class... S>
- R apply(std::size_t index, F&& func, const std::tuple<S...>& s) NOEXCEPT(noexcept(func(std::get<0>(s))));
- template <class T, class S>
- void nested_copy(T&& iter, const S& s);
- template <class T, class S>
- void nested_copy(T&& iter, std::initializer_list<S> s);
- template <class C>
- bool resize_container(C& c, typename C::size_type size);
- template <class T, std::size_t N>
- bool resize_container(std::array<T, N>& a, typename std::array<T, N>::size_type size);
- template <std::size_t... I>
- class fixed_shape;
- template <std::size_t... I>
- bool resize_container(fixed_shape<I...>& a, std::size_t size);
- template <class X, class C>
- struct rebind_container;
- template <class X, class C>
- using rebind_container_t = typename rebind_container<X, C>::type;
- std::size_t normalize_axis(std::size_t dim, std::ptrdiff_t axis);
- // gcc 4.9 is affected by C++14 defect CGW 1558
- // see http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1558
- template <class... T>
- struct make_void
- {
- using type = void;
- };
- template <class... T>
- using void_t = typename make_void<T...>::type;
- // This is used for non existent types (e.g. storage for some expressions
- // like generators)
- struct invalid_type
- {
- };
- template <class... T>
- struct make_invalid_type
- {
- using type = invalid_type;
- };
- template <class T, class R>
- using disable_integral_t = std::enable_if_t<!xtl::is_integral<T>::value, R>;
- /********************************
- * meta identity implementation *
- ********************************/
- template <class T>
- struct meta_identity
- {
- using type = T;
- };
- /***************************************
- * is_specialization_of implementation *
- ***************************************/
- template <template <class...> class TT, class T>
- struct is_specialization_of : std::false_type
- {
- };
- template <template <class...> class TT, class... Ts>
- struct is_specialization_of<TT, TT<Ts...>> : std::true_type
- {
- };
- /*******************************
- * remove_class implementation *
- *******************************/
- template <class T>
- struct remove_class
- {
- };
- template <class C, class R, class... Args>
- struct remove_class<R (C::*)(Args...)>
- {
- typedef R type(Args...);
- };
- template <class C, class R, class... Args>
- struct remove_class<R (C::*)(Args...) const>
- {
- typedef R type(Args...);
- };
- template <class T>
- using remove_class_t = typename remove_class<T>::type;
- /***************************
- * for_each implementation *
- ***************************/
- namespace detail
- {
- template <std::size_t I, class F, class... T>
- inline typename std::enable_if<I == sizeof...(T), void>::type
- for_each_impl(F&& /*f*/, std::tuple<T...>& /*t*/) noexcept
- {
- }
- template <std::size_t I, class F, class... T>
- inline typename std::enable_if < I<sizeof...(T), void>::type
- for_each_impl(F&& f, std::tuple<T...>& t) noexcept(noexcept(f(std::get<I>(t))))
- {
- f(std::get<I>(t));
- for_each_impl<I + 1, F, T...>(std::forward<F>(f), t);
- }
- }
- template <class F, class... T>
- inline void for_each(F&& f, std::tuple<T...>& t) noexcept(
- noexcept(detail::for_each_impl<0, F, T...>(std::forward<F>(f), t))
- )
- {
- detail::for_each_impl<0, F, T...>(std::forward<F>(f), t);
- }
- namespace detail
- {
- template <std::size_t I, class F, class... T>
- inline typename std::enable_if<I == sizeof...(T), void>::type
- for_each_impl(F&& /*f*/, const std::tuple<T...>& /*t*/) noexcept
- {
- }
- template <std::size_t I, class F, class... T>
- inline typename std::enable_if < I<sizeof...(T), void>::type
- for_each_impl(F&& f, const std::tuple<T...>& t) noexcept(noexcept(f(std::get<I>(t))))
- {
- f(std::get<I>(t));
- for_each_impl<I + 1, F, T...>(std::forward<F>(f), t);
- }
- }
- template <class F, class... T>
- inline void for_each(F&& f, const std::tuple<T...>& t) noexcept(
- noexcept(detail::for_each_impl<0, F, T...>(std::forward<F>(f), t))
- )
- {
- detail::for_each_impl<0, F, T...>(std::forward<F>(f), t);
- }
- /*****************************
- * accumulate implementation *
- *****************************/
- /// @cond DOXYGEN_INCLUDE_NOEXCEPT
- namespace detail
- {
- template <std::size_t I, class F, class R, class... T>
- inline std::enable_if_t<I == sizeof...(T), R>
- accumulate_impl(F&& /*f*/, R init, const std::tuple<T...>& /*t*/) noexcept
- {
- return init;
- }
- template <std::size_t I, class F, class R, class... T>
- inline std::enable_if_t < I<sizeof...(T), R>
- accumulate_impl(F&& f, R init, const std::tuple<T...>& t) noexcept(noexcept(f(init, std::get<I>(t))))
- {
- R res = f(init, std::get<I>(t));
- return accumulate_impl<I + 1, F, R, T...>(std::forward<F>(f), res, t);
- }
- }
- template <class F, class R, class... T>
- inline R accumulate(F&& f, R init, const std::tuple<T...>& t) noexcept(
- noexcept(detail::accumulate_impl<0, F, R, T...>(std::forward<F>(f), init, t))
- )
- {
- return detail::accumulate_impl<0, F, R, T...>(std::forward<F>(f), init, t);
- }
- /// @endcond
- /***************************
- * argument implementation *
- ***************************/
- namespace detail
- {
- template <std::size_t I>
- struct getter
- {
- template <class Arg, class... Args>
- static constexpr decltype(auto) get(Arg&& /*arg*/, Args&&... args) noexcept
- {
- return getter<I - 1>::get(std::forward<Args>(args)...);
- }
- };
- template <>
- struct getter<0>
- {
- template <class Arg, class... Args>
- static constexpr Arg&& get(Arg&& arg, Args&&... /*args*/) noexcept
- {
- return std::forward<Arg>(arg);
- }
- };
- }
- template <std::size_t I, class... Args>
- constexpr decltype(auto) argument(Args&&... args) noexcept
- {
- static_assert(I < sizeof...(Args), "I should be lesser than sizeof...(Args)");
- return detail::getter<I>::get(std::forward<Args>(args)...);
- }
- /************************
- * apply implementation *
- ************************/
- namespace detail
- {
- template <class R, class F, std::size_t I, class... S>
- R apply_one(F&& func, const std::tuple<S...>& s) NOEXCEPT(noexcept(func(std::get<I>(s))))
- {
- return static_cast<R>(func(std::get<I>(s)));
- }
- template <class R, class F, std::size_t... I, class... S>
- R apply(std::size_t index, F&& func, std::index_sequence<I...> /*seq*/, const std::tuple<S...>& s)
- NOEXCEPT(noexcept(func(std::get<0>(s))))
- {
- using FT = std::add_pointer_t<R(F&&, const std::tuple<S...>&)>;
- static const std::array<FT, sizeof...(I)> ar = {{&apply_one<R, F, I, S...>...}};
- return ar[index](std::forward<F>(func), s);
- }
- }
- template <class R, class F, class... S>
- inline R apply(std::size_t index, F&& func, const std::tuple<S...>& s)
- NOEXCEPT(noexcept(func(std::get<0>(s))))
- {
- return detail::apply<R>(index, std::forward<F>(func), std::make_index_sequence<sizeof...(S)>(), s);
- }
- /***************************
- * nested_initializer_list *
- ***************************/
- template <class T, std::size_t I>
- struct nested_initializer_list
- {
- using type = std::initializer_list<typename nested_initializer_list<T, I - 1>::type>;
- };
- template <class T>
- struct nested_initializer_list<T, 0>
- {
- using type = T;
- };
- template <class T, std::size_t I>
- using nested_initializer_list_t = typename nested_initializer_list<T, I>::type;
- /******************************
- * nested_copy implementation *
- ******************************/
- template <class T, class S>
- inline void nested_copy(T&& iter, const S& s)
- {
- *iter++ = s;
- }
- template <class T, class S>
- inline void nested_copy(T&& iter, std::initializer_list<S> s)
- {
- for (auto it = s.begin(); it != s.end(); ++it)
- {
- nested_copy(std::forward<T>(iter), *it);
- }
- }
- /***********************************
- * resize_container implementation *
- ***********************************/
- template <class C>
- inline bool resize_container(C& c, typename C::size_type size)
- {
- c.resize(size);
- return true;
- }
- template <class T, std::size_t N>
- inline bool resize_container(std::array<T, N>& /*a*/, typename std::array<T, N>::size_type size)
- {
- return size == N;
- }
- template <std::size_t... I>
- inline bool resize_container(xt::fixed_shape<I...>&, std::size_t size)
- {
- return sizeof...(I) == size;
- }
- /*********************************
- * normalize_axis implementation *
- *********************************/
- // scalar normalize axis
- inline std::size_t normalize_axis(std::size_t dim, std::ptrdiff_t axis)
- {
- return axis < 0 ? static_cast<std::size_t>(static_cast<std::ptrdiff_t>(dim) + axis)
- : static_cast<std::size_t>(axis);
- }
- template <class E, class C>
- inline std::enable_if_t<
- !xtl::is_integral<std::decay_t<C>>::value && xtl::is_signed<typename std::decay_t<C>::value_type>::value,
- rebind_container_t<std::size_t, std::decay_t<C>>>
- normalize_axis(E& expr, C&& axes)
- {
- rebind_container_t<std::size_t, std::decay_t<C>> res;
- resize_container(res, axes.size());
- for (std::size_t i = 0; i < axes.size(); ++i)
- {
- res[i] = normalize_axis(expr.dimension(), axes[i]);
- }
- XTENSOR_ASSERT(std::all_of(
- res.begin(),
- res.end(),
- [&expr](auto ax_el)
- {
- return ax_el < expr.dimension();
- }
- ));
- return res;
- }
- template <class C, class E>
- inline std::enable_if_t<
- !xtl::is_integral<std::decay_t<C>>::value && std::is_unsigned<typename std::decay_t<C>::value_type>::value,
- C&&>
- normalize_axis(E& expr, C&& axes)
- {
- static_cast<void>(expr);
- XTENSOR_ASSERT(std::all_of(
- axes.begin(),
- axes.end(),
- [&expr](auto ax_el)
- {
- return ax_el < expr.dimension();
- }
- ));
- return std::forward<C>(axes);
- }
- template <class R, class E, class C>
- inline auto forward_normalize(E& expr, C&& axes)
- -> std::enable_if_t<xtl::is_signed<std::decay_t<decltype(*std::begin(axes))>>::value, R>
- {
- R res;
- xt::resize_container(res, xtl::sequence_size(axes));
- auto dim = expr.dimension();
- std::transform(
- std::begin(axes),
- std::end(axes),
- std::begin(res),
- [&dim](auto ax_el)
- {
- return normalize_axis(dim, ax_el);
- }
- );
- XTENSOR_ASSERT(std::all_of(
- res.begin(),
- res.end(),
- [&expr](auto ax_el)
- {
- return ax_el < expr.dimension();
- }
- ));
- return res;
- }
- template <class R, class E, class C>
- inline auto forward_normalize(E& expr, C&& axes) -> std::enable_if_t<
- !xtl::is_signed<std::decay_t<decltype(*std::begin(axes))>>::value && !std::is_same<R, std::decay_t<C>>::value,
- R>
- {
- static_cast<void>(expr);
- R res;
- xt::resize_container(res, xtl::sequence_size(axes));
- std::copy(std::begin(axes), std::end(axes), std::begin(res));
- XTENSOR_ASSERT(std::all_of(
- res.begin(),
- res.end(),
- [&expr](auto ax_el)
- {
- return ax_el < expr.dimension();
- }
- ));
- return res;
- }
- template <class R, class E, class C>
- inline auto forward_normalize(E& expr, C&& axes) -> std::enable_if_t<
- !xtl::is_signed<std::decay_t<decltype(*std::begin(axes))>>::value && std::is_same<R, std::decay_t<C>>::value,
- R&&>
- {
- static_cast<void>(expr);
- XTENSOR_ASSERT(std::all_of(
- std::begin(axes),
- std::end(axes),
- [&expr](auto ax_el)
- {
- return ax_el < expr.dimension();
- }
- ));
- return std::move(axes);
- }
- /******************
- * get_value_type *
- ******************/
- template <class T, class = void_t<>>
- struct get_value_type
- {
- using type = T;
- };
- template <class T>
- struct get_value_type<T, void_t<typename T::value_type>>
- {
- using type = typename T::value_type;
- };
- template <class T>
- using get_value_type_t = typename get_value_type<T>::type;
- /**********************
- * get implementation *
- **********************/
- // When subclassing from std::tuple not all compilers are able to correctly instantiate get
- // See here: https://stackoverflow.com/a/37188019/2528668
- template <std::size_t I, template <typename... Args> class T, typename... Args>
- decltype(auto) get(T<Args...>&& v)
- {
- return std::get<I>(static_cast<std::tuple<Args...>&&>(v));
- }
- template <std::size_t I, template <typename... Args> class T, typename... Args>
- decltype(auto) get(T<Args...>& v)
- {
- return std::get<I>(static_cast<std::tuple<Args...>&>(v));
- }
- template <std::size_t I, template <typename... Args> class T, typename... Args>
- decltype(auto) get(const T<Args...>& v)
- {
- return std::get<I>(static_cast<const std::tuple<Args...>&>(v));
- }
- /***************************
- * apply_cv implementation *
- ***************************/
- namespace detail
- {
- template <
- class T,
- class U,
- bool = std::is_const<std::remove_reference_t<T>>::value,
- bool = std::is_volatile<std::remove_reference_t<T>>::value>
- struct apply_cv_impl
- {
- using type = U;
- };
- template <class T, class U>
- struct apply_cv_impl<T, U, true, false>
- {
- using type = const U;
- };
- template <class T, class U>
- struct apply_cv_impl<T, U, false, true>
- {
- using type = volatile U;
- };
- template <class T, class U>
- struct apply_cv_impl<T, U, true, true>
- {
- using type = const volatile U;
- };
- template <class T, class U>
- struct apply_cv_impl<T&, U, false, false>
- {
- using type = U&;
- };
- template <class T, class U>
- struct apply_cv_impl<T&, U, true, false>
- {
- using type = const U&;
- };
- template <class T, class U>
- struct apply_cv_impl<T&, U, false, true>
- {
- using type = volatile U&;
- };
- template <class T, class U>
- struct apply_cv_impl<T&, U, true, true>
- {
- using type = const volatile U&;
- };
- }
- template <class T, class U>
- struct apply_cv
- {
- using type = typename detail::apply_cv_impl<T, U>::type;
- };
- template <class T, class U>
- using apply_cv_t = typename apply_cv<T, U>::type;
- /**************************
- * to_array implementation *
- ***************************/
- namespace detail
- {
- template <class T, std::size_t N, std::size_t... I>
- constexpr std::array<std::remove_cv_t<T>, N> to_array_impl(T (&a)[N], std::index_sequence<I...>)
- {
- return {{a[I]...}};
- }
- }
- template <class T, std::size_t N>
- constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&a)[N])
- {
- return detail::to_array_impl(a, std::make_index_sequence<N>{});
- }
- /********************************
- * sequence_size implementation *
- ********************************/
- // equivalent to std::size(c) in c++17
- template <class C>
- constexpr auto sequence_size(const C& c) -> decltype(c.size())
- {
- return c.size();
- }
- // equivalent to std::size(a) in c++17
- template <class T, std::size_t N>
- constexpr std::size_t sequence_size(const T (&)[N])
- {
- return N;
- }
- /***********************************
- * has_storage_type implementation *
- ***********************************/
- template <class T, class = void>
- struct has_storage_type : std::false_type
- {
- };
- template <class T>
- struct xcontainer_inner_types;
- template <class T>
- struct has_storage_type<T, void_t<typename xcontainer_inner_types<T>::storage_type>>
- : xtl::negation<
- std::is_same<typename std::remove_cv<typename xcontainer_inner_types<T>::storage_type>::type, invalid_type>>
- {
- };
- /*************************************
- * has_data_interface implementation *
- *************************************/
- template <class E, class = void>
- struct has_data_interface : std::false_type
- {
- };
- template <class E>
- struct has_data_interface<E, void_t<decltype(std::declval<E>().data())>> : std::true_type
- {
- };
- template <class E, class = void>
- struct has_strides : std::false_type
- {
- };
- template <class E>
- struct has_strides<E, void_t<decltype(std::declval<E>().strides())>> : std::true_type
- {
- };
- template <class E, class = void>
- struct has_iterator_interface : std::false_type
- {
- };
- template <class E>
- struct has_iterator_interface<E, void_t<decltype(std::declval<E>().begin())>> : std::true_type
- {
- };
- /******************************
- * is_iterator implementation *
- ******************************/
- template <class E, class = void>
- struct is_iterator : std::false_type
- {
- };
- template <class E>
- struct is_iterator<
- E,
- void_t<
- decltype(*std::declval<const E>(), std::declval<const E>() == std::declval<const E>(), std::declval<const E>() != std::declval<const E>(), ++(*std::declval<E*>()), (*std::declval<E*>())++, std::true_type())>>
- : std::true_type
- {
- };
- /********************************************
- * xtrivial_default_construct implemenation *
- ********************************************/
- #if defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE >= 7
- // has_trivial_default_constructor has not been available since libstdc++-7.
- #define XTENSOR_GLIBCXX_USE_CXX11_ABI 1
- #else
- #if defined(_GLIBCXX_USE_CXX11_ABI)
- #if _GLIBCXX_USE_CXX11_ABI || (defined(_GLIBCXX_USE_DUAL_ABI) && !_GLIBCXX_USE_DUAL_ABI)
- #define XTENSOR_GLIBCXX_USE_CXX11_ABI 1
- #endif
- #endif
- #endif
- #if !defined(__GNUG__) || defined(_LIBCPP_VERSION) || defined(XTENSOR_GLIBCXX_USE_CXX11_ABI)
- template <class T>
- using xtrivially_default_constructible = std::is_trivially_default_constructible<T>;
- #else
- template <class T>
- using xtrivially_default_constructible = std::has_trivial_default_constructor<T>;
- #endif
- #undef XTENSOR_GLIBCXX_USE_CXX11_ABI
- /*************************
- * conditional type cast *
- *************************/
- template <bool condition, class T>
- struct conditional_cast_functor;
- template <class T>
- struct conditional_cast_functor<false, T> : public xtl::identity
- {
- };
- template <class T>
- struct conditional_cast_functor<true, T>
- {
- template <class U>
- inline auto operator()(U&& u) const
- {
- return static_cast<T>(std::forward<U>(u));
- }
- };
- /**
- * @brief Perform a type cast when a condition is true.
- * If <tt>condition</tt> is true, return <tt>static_cast<T>(u)</tt>,
- * otherwise return <tt>u</tt> unchanged. This is useful when an unconditional
- * static_cast would force undesired type conversions in some situations where
- * an error or warning would be desired. The condition determines when the
- * explicit cast is ok.
- */
- template <bool condition, class T, class U>
- inline auto conditional_cast(U&& u)
- {
- return conditional_cast_functor<condition, T>()(std::forward<U>(u));
- }
- /**********************
- * tracking allocator *
- **********************/
- namespace alloc_tracking
- {
- inline bool& enabled()
- {
- static bool enabled;
- return enabled;
- }
- inline void enable()
- {
- enabled() = true;
- }
- inline void disable()
- {
- enabled() = false;
- }
- enum policy
- {
- print,
- assert
- };
- }
- template <class T, class A, alloc_tracking::policy P>
- struct tracking_allocator : private A
- {
- using base_type = A;
- using value_type = typename A::value_type;
- using reference = typename A::reference;
- using const_reference = typename A::const_reference;
- using pointer = typename A::pointer;
- using const_pointer = typename A::const_pointer;
- using size_type = typename A::size_type;
- using difference_type = typename A::difference_type;
- tracking_allocator() = default;
- T* allocate(std::size_t n)
- {
- if (alloc_tracking::enabled())
- {
- if (P == alloc_tracking::print)
- {
- std::cout << "xtensor allocating: " << n << "" << std::endl;
- }
- else if (P == alloc_tracking::assert)
- {
- XTENSOR_THROW(
- std::runtime_error,
- "xtensor allocation of " + std::to_string(n) + " elements detected"
- );
- }
- }
- return base_type::allocate(n);
- }
- using base_type::construct;
- using base_type::deallocate;
- using base_type::destroy;
- template <class U>
- struct rebind
- {
- using traits = std::allocator_traits<A>;
- using other = tracking_allocator<U, typename traits::template rebind_alloc<U>, P>;
- };
- };
- template <class T, class AT, alloc_tracking::policy PT, class U, class AU, alloc_tracking::policy PU>
- inline bool operator==(const tracking_allocator<T, AT, PT>&, const tracking_allocator<U, AU, PU>&)
- {
- return std::is_same<AT, AU>::value;
- }
- template <class T, class AT, alloc_tracking::policy PT, class U, class AU, alloc_tracking::policy PU>
- inline bool operator!=(const tracking_allocator<T, AT, PT>& a, const tracking_allocator<U, AU, PU>& b)
- {
- return !(a == b);
- }
- /*****************
- * has_assign_to *
- *****************/
- template <class E1, class E2, class = void>
- struct has_assign_to : std::false_type
- {
- };
- template <class E1, class E2>
- struct has_assign_to<E1, E2, void_t<decltype(std::declval<const E2&>().assign_to(std::declval<E1&>()))>>
- : std::true_type
- {
- };
- /*************************************
- * overlapping_memory_checker_traits *
- *************************************/
- template <class T, class Enable = void>
- struct has_memory_address : std::false_type
- {
- };
- template <class T>
- struct has_memory_address<T, void_t<decltype(std::addressof(*std::declval<T>().begin()))>> : std::true_type
- {
- };
- struct memory_range
- {
- // Checking pointer overlap is more correct in integer values,
- // for more explanation check https://devblogs.microsoft.com/oldnewthing/20170927-00/?p=97095
- const uintptr_t m_first = 0;
- const uintptr_t m_last = 0;
- explicit memory_range() = default;
- template <class T>
- explicit memory_range(T* first, T* last)
- : m_first(reinterpret_cast<uintptr_t>(last < first ? last : first))
- , m_last(reinterpret_cast<uintptr_t>(last < first ? first : last))
- {
- }
- template <class T>
- bool overlaps(T* first, T* last) const
- {
- if (first <= last)
- {
- return reinterpret_cast<uintptr_t>(first) <= m_last
- && reinterpret_cast<uintptr_t>(last) >= m_first;
- }
- else
- {
- return reinterpret_cast<uintptr_t>(last) <= m_last
- && reinterpret_cast<uintptr_t>(first) >= m_first;
- }
- }
- };
- template <class E, class Enable = void>
- struct overlapping_memory_checker_traits
- {
- static bool check_overlap(const E&, const memory_range&)
- {
- return true;
- }
- };
- template <class E>
- struct overlapping_memory_checker_traits<E, std::enable_if_t<has_memory_address<E>::value>>
- {
- static bool check_overlap(const E& expr, const memory_range& dst_range)
- {
- if (expr.size() == 0)
- {
- return false;
- }
- else
- {
- return dst_range.overlaps(std::addressof(*expr.begin()), std::addressof(*expr.rbegin()));
- }
- }
- };
- struct overlapping_memory_checker_base
- {
- memory_range m_dst_range;
- explicit overlapping_memory_checker_base() = default;
- explicit overlapping_memory_checker_base(memory_range dst_memory_range)
- : m_dst_range(std::move(dst_memory_range))
- {
- }
- template <class E>
- bool check_overlap(const E& expr) const
- {
- if (!m_dst_range.m_first || !m_dst_range.m_last)
- {
- return false;
- }
- else
- {
- return overlapping_memory_checker_traits<E>::check_overlap(expr, m_dst_range);
- }
- }
- };
- template <class Dst, class Enable = void>
- struct overlapping_memory_checker : overlapping_memory_checker_base
- {
- explicit overlapping_memory_checker(const Dst&)
- : overlapping_memory_checker_base()
- {
- }
- };
- template <class Dst>
- struct overlapping_memory_checker<Dst, std::enable_if_t<has_memory_address<Dst>::value>>
- : overlapping_memory_checker_base
- {
- explicit overlapping_memory_checker(const Dst& aDst)
- : overlapping_memory_checker_base(
- [&]()
- {
- if (aDst.size() == 0)
- {
- return memory_range();
- }
- else
- {
- return memory_range(std::addressof(*aDst.begin()), std::addressof(*aDst.rbegin()));
- }
- }()
- )
- {
- }
- };
- template <class Dst>
- auto make_overlapping_memory_checker(const Dst& a_dst)
- {
- return overlapping_memory_checker<Dst>(a_dst);
- }
- /********************
- * rebind_container *
- ********************/
- template <class X, template <class, class> class C, class T, class A>
- struct rebind_container<X, C<T, A>>
- {
- using traits = std::allocator_traits<A>;
- using allocator = typename traits::template rebind_alloc<X>;
- using type = C<X, allocator>;
- };
- #if defined(__GNUC__) && __GNUC__ > 6 && !defined(__clang__) && __cplusplus >= 201703L
- template <class X, class T, std::size_t N>
- struct rebind_container<X, std::array<T, N>>
- {
- using type = std::array<X, N>;
- };
- #else
- template <class X, template <class, std::size_t> class C, class T, std::size_t N>
- struct rebind_container<X, C<T, N>>
- {
- using type = C<X, N>;
- };
- #endif
- /********************
- * get_strides_type *
- ********************/
- template <class S>
- struct get_strides_type
- {
- using type = typename rebind_container<std::ptrdiff_t, S>::type;
- };
- template <std::size_t... I>
- struct get_strides_type<fixed_shape<I...>>
- {
- // TODO we could compute the strides statically here.
- // But we'll need full constexpr support to have a
- // homogenous ``compute_strides`` method
- using type = std::array<std::ptrdiff_t, sizeof...(I)>;
- };
- template <class CP, class O, class A>
- class xbuffer_adaptor;
- template <class CP, class O, class A>
- struct get_strides_type<xbuffer_adaptor<CP, O, A>>
- {
- // In bindings this mapping is called by reshape_view with an inner shape of type
- // xbuffer_adaptor.
- // Since we cannot create a buffer adaptor holding data, we map it to an std::vector.
- using type = std::vector<
- typename xbuffer_adaptor<CP, O, A>::value_type,
- typename xbuffer_adaptor<CP, O, A>::allocator_type>;
- };
- template <class C>
- using get_strides_t = typename get_strides_type<C>::type;
- /*******************
- * inner_reference *
- *******************/
- template <class ST>
- struct inner_reference
- {
- using storage_type = std::decay_t<ST>;
- using type = std::conditional_t<
- std::is_const<std::remove_reference_t<ST>>::value,
- typename storage_type::const_reference,
- typename storage_type::reference>;
- };
- template <class ST>
- using inner_reference_t = typename inner_reference<ST>::type;
- /************
- * get_rank *
- ************/
- template <class E, typename = void>
- struct get_rank
- {
- static constexpr std::size_t value = SIZE_MAX;
- };
- template <class E>
- struct get_rank<E, decltype((void) E::rank, void())>
- {
- static constexpr std::size_t value = E::rank;
- };
- /******************
- * has_fixed_rank *
- ******************/
- template <class E>
- struct has_fixed_rank
- {
- using type = std::integral_constant<bool, get_rank<std::decay_t<E>>::value != SIZE_MAX>;
- };
- template <class E>
- using has_fixed_rank_t = typename has_fixed_rank<std::decay_t<E>>::type;
- /************
- * has_rank *
- ************/
- template <class E, size_t N>
- struct has_rank
- {
- using type = std::integral_constant<bool, get_rank<std::decay_t<E>>::value == N>;
- };
- template <class E, size_t N>
- using has_rank_t = typename has_rank<std::decay_t<E>, N>::type;
- }
- #endif
|