xutils.hpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134
  1. /***************************************************************************
  2. * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht *
  3. * Copyright (c) QuantStack *
  4. * *
  5. * Distributed under the terms of the BSD 3-Clause License. *
  6. * *
  7. * The full license is in the file LICENSE, distributed with this software. *
  8. ****************************************************************************/
  9. #ifndef XTENSOR_UTILS_HPP
  10. #define XTENSOR_UTILS_HPP
  11. #include <algorithm>
  12. #include <array>
  13. #include <cmath>
  14. #include <complex>
  15. #include <cstddef>
  16. #include <initializer_list>
  17. #include <iostream>
  18. #include <memory>
  19. #include <tuple>
  20. #include <type_traits>
  21. #include <utility>
  22. #include <vector>
  23. #include <xtl/xfunctional.hpp>
  24. #include <xtl/xmeta_utils.hpp>
  25. #include <xtl/xsequence.hpp>
  26. #include <xtl/xtype_traits.hpp>
  27. #include "xtensor_config.hpp"
  28. #if (_MSC_VER >= 1910)
  29. #define NOEXCEPT(T)
  30. #else
  31. #define NOEXCEPT(T) noexcept(T)
  32. #endif
  33. namespace xt
  34. {
  35. /****************
  36. * declarations *
  37. ****************/
  38. template <class T>
  39. struct remove_class;
  40. /*template <class F, class... T>
  41. void for_each(F&& f, std::tuple<T...>& t) noexcept(implementation_dependent);*/
  42. /*template <class F, class R, class... T>
  43. R accumulate(F&& f, R init, const std::tuple<T...>& t) noexcept(implementation_dependent);*/
  44. template <std::size_t I, class... Args>
  45. constexpr decltype(auto) argument(Args&&... args) noexcept;
  46. template <class R, class F, class... S>
  47. R apply(std::size_t index, F&& func, const std::tuple<S...>& s) NOEXCEPT(noexcept(func(std::get<0>(s))));
  48. template <class T, class S>
  49. void nested_copy(T&& iter, const S& s);
  50. template <class T, class S>
  51. void nested_copy(T&& iter, std::initializer_list<S> s);
  52. template <class C>
  53. bool resize_container(C& c, typename C::size_type size);
  54. template <class T, std::size_t N>
  55. bool resize_container(std::array<T, N>& a, typename std::array<T, N>::size_type size);
  56. template <std::size_t... I>
  57. class fixed_shape;
  58. template <std::size_t... I>
  59. bool resize_container(fixed_shape<I...>& a, std::size_t size);
  60. template <class X, class C>
  61. struct rebind_container;
  62. template <class X, class C>
  63. using rebind_container_t = typename rebind_container<X, C>::type;
  64. std::size_t normalize_axis(std::size_t dim, std::ptrdiff_t axis);
  65. // gcc 4.9 is affected by C++14 defect CGW 1558
  66. // see http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1558
  67. template <class... T>
  68. struct make_void
  69. {
  70. using type = void;
  71. };
  72. template <class... T>
  73. using void_t = typename make_void<T...>::type;
  74. // This is used for non existent types (e.g. storage for some expressions
  75. // like generators)
  76. struct invalid_type
  77. {
  78. };
  79. template <class... T>
  80. struct make_invalid_type
  81. {
  82. using type = invalid_type;
  83. };
  84. template <class T, class R>
  85. using disable_integral_t = std::enable_if_t<!xtl::is_integral<T>::value, R>;
  86. /********************************
  87. * meta identity implementation *
  88. ********************************/
  89. template <class T>
  90. struct meta_identity
  91. {
  92. using type = T;
  93. };
  94. /***************************************
  95. * is_specialization_of implementation *
  96. ***************************************/
  97. template <template <class...> class TT, class T>
  98. struct is_specialization_of : std::false_type
  99. {
  100. };
  101. template <template <class...> class TT, class... Ts>
  102. struct is_specialization_of<TT, TT<Ts...>> : std::true_type
  103. {
  104. };
  105. /*******************************
  106. * remove_class implementation *
  107. *******************************/
  108. template <class T>
  109. struct remove_class
  110. {
  111. };
  112. template <class C, class R, class... Args>
  113. struct remove_class<R (C::*)(Args...)>
  114. {
  115. typedef R type(Args...);
  116. };
  117. template <class C, class R, class... Args>
  118. struct remove_class<R (C::*)(Args...) const>
  119. {
  120. typedef R type(Args...);
  121. };
  122. template <class T>
  123. using remove_class_t = typename remove_class<T>::type;
  124. /***************************
  125. * for_each implementation *
  126. ***************************/
  127. namespace detail
  128. {
  129. template <std::size_t I, class F, class... T>
  130. inline typename std::enable_if<I == sizeof...(T), void>::type
  131. for_each_impl(F&& /*f*/, std::tuple<T...>& /*t*/) noexcept
  132. {
  133. }
  134. template <std::size_t I, class F, class... T>
  135. inline typename std::enable_if < I<sizeof...(T), void>::type
  136. for_each_impl(F&& f, std::tuple<T...>& t) noexcept(noexcept(f(std::get<I>(t))))
  137. {
  138. f(std::get<I>(t));
  139. for_each_impl<I + 1, F, T...>(std::forward<F>(f), t);
  140. }
  141. }
  142. template <class F, class... T>
  143. inline void for_each(F&& f, std::tuple<T...>& t) noexcept(
  144. noexcept(detail::for_each_impl<0, F, T...>(std::forward<F>(f), t))
  145. )
  146. {
  147. detail::for_each_impl<0, F, T...>(std::forward<F>(f), t);
  148. }
  149. namespace detail
  150. {
  151. template <std::size_t I, class F, class... T>
  152. inline typename std::enable_if<I == sizeof...(T), void>::type
  153. for_each_impl(F&& /*f*/, const std::tuple<T...>& /*t*/) noexcept
  154. {
  155. }
  156. template <std::size_t I, class F, class... T>
  157. inline typename std::enable_if < I<sizeof...(T), void>::type
  158. for_each_impl(F&& f, const std::tuple<T...>& t) noexcept(noexcept(f(std::get<I>(t))))
  159. {
  160. f(std::get<I>(t));
  161. for_each_impl<I + 1, F, T...>(std::forward<F>(f), t);
  162. }
  163. }
  164. template <class F, class... T>
  165. inline void for_each(F&& f, const std::tuple<T...>& t) noexcept(
  166. noexcept(detail::for_each_impl<0, F, T...>(std::forward<F>(f), t))
  167. )
  168. {
  169. detail::for_each_impl<0, F, T...>(std::forward<F>(f), t);
  170. }
  171. /*****************************
  172. * accumulate implementation *
  173. *****************************/
  174. /// @cond DOXYGEN_INCLUDE_NOEXCEPT
  175. namespace detail
  176. {
  177. template <std::size_t I, class F, class R, class... T>
  178. inline std::enable_if_t<I == sizeof...(T), R>
  179. accumulate_impl(F&& /*f*/, R init, const std::tuple<T...>& /*t*/) noexcept
  180. {
  181. return init;
  182. }
  183. template <std::size_t I, class F, class R, class... T>
  184. inline std::enable_if_t < I<sizeof...(T), R>
  185. accumulate_impl(F&& f, R init, const std::tuple<T...>& t) noexcept(noexcept(f(init, std::get<I>(t))))
  186. {
  187. R res = f(init, std::get<I>(t));
  188. return accumulate_impl<I + 1, F, R, T...>(std::forward<F>(f), res, t);
  189. }
  190. }
  191. template <class F, class R, class... T>
  192. inline R accumulate(F&& f, R init, const std::tuple<T...>& t) noexcept(
  193. noexcept(detail::accumulate_impl<0, F, R, T...>(std::forward<F>(f), init, t))
  194. )
  195. {
  196. return detail::accumulate_impl<0, F, R, T...>(std::forward<F>(f), init, t);
  197. }
  198. /// @endcond
  199. /***************************
  200. * argument implementation *
  201. ***************************/
  202. namespace detail
  203. {
  204. template <std::size_t I>
  205. struct getter
  206. {
  207. template <class Arg, class... Args>
  208. static constexpr decltype(auto) get(Arg&& /*arg*/, Args&&... args) noexcept
  209. {
  210. return getter<I - 1>::get(std::forward<Args>(args)...);
  211. }
  212. };
  213. template <>
  214. struct getter<0>
  215. {
  216. template <class Arg, class... Args>
  217. static constexpr Arg&& get(Arg&& arg, Args&&... /*args*/) noexcept
  218. {
  219. return std::forward<Arg>(arg);
  220. }
  221. };
  222. }
  223. template <std::size_t I, class... Args>
  224. constexpr decltype(auto) argument(Args&&... args) noexcept
  225. {
  226. static_assert(I < sizeof...(Args), "I should be lesser than sizeof...(Args)");
  227. return detail::getter<I>::get(std::forward<Args>(args)...);
  228. }
  229. /************************
  230. * apply implementation *
  231. ************************/
  232. namespace detail
  233. {
  234. template <class R, class F, std::size_t I, class... S>
  235. R apply_one(F&& func, const std::tuple<S...>& s) NOEXCEPT(noexcept(func(std::get<I>(s))))
  236. {
  237. return static_cast<R>(func(std::get<I>(s)));
  238. }
  239. template <class R, class F, std::size_t... I, class... S>
  240. R apply(std::size_t index, F&& func, std::index_sequence<I...> /*seq*/, const std::tuple<S...>& s)
  241. NOEXCEPT(noexcept(func(std::get<0>(s))))
  242. {
  243. using FT = std::add_pointer_t<R(F&&, const std::tuple<S...>&)>;
  244. static const std::array<FT, sizeof...(I)> ar = {{&apply_one<R, F, I, S...>...}};
  245. return ar[index](std::forward<F>(func), s);
  246. }
  247. }
  248. template <class R, class F, class... S>
  249. inline R apply(std::size_t index, F&& func, const std::tuple<S...>& s)
  250. NOEXCEPT(noexcept(func(std::get<0>(s))))
  251. {
  252. return detail::apply<R>(index, std::forward<F>(func), std::make_index_sequence<sizeof...(S)>(), s);
  253. }
  254. /***************************
  255. * nested_initializer_list *
  256. ***************************/
  257. template <class T, std::size_t I>
  258. struct nested_initializer_list
  259. {
  260. using type = std::initializer_list<typename nested_initializer_list<T, I - 1>::type>;
  261. };
  262. template <class T>
  263. struct nested_initializer_list<T, 0>
  264. {
  265. using type = T;
  266. };
  267. template <class T, std::size_t I>
  268. using nested_initializer_list_t = typename nested_initializer_list<T, I>::type;
  269. /******************************
  270. * nested_copy implementation *
  271. ******************************/
  272. template <class T, class S>
  273. inline void nested_copy(T&& iter, const S& s)
  274. {
  275. *iter++ = s;
  276. }
  277. template <class T, class S>
  278. inline void nested_copy(T&& iter, std::initializer_list<S> s)
  279. {
  280. for (auto it = s.begin(); it != s.end(); ++it)
  281. {
  282. nested_copy(std::forward<T>(iter), *it);
  283. }
  284. }
  285. /***********************************
  286. * resize_container implementation *
  287. ***********************************/
  288. template <class C>
  289. inline bool resize_container(C& c, typename C::size_type size)
  290. {
  291. c.resize(size);
  292. return true;
  293. }
  294. template <class T, std::size_t N>
  295. inline bool resize_container(std::array<T, N>& /*a*/, typename std::array<T, N>::size_type size)
  296. {
  297. return size == N;
  298. }
  299. template <std::size_t... I>
  300. inline bool resize_container(xt::fixed_shape<I...>&, std::size_t size)
  301. {
  302. return sizeof...(I) == size;
  303. }
  304. /*********************************
  305. * normalize_axis implementation *
  306. *********************************/
  307. // scalar normalize axis
  308. inline std::size_t normalize_axis(std::size_t dim, std::ptrdiff_t axis)
  309. {
  310. return axis < 0 ? static_cast<std::size_t>(static_cast<std::ptrdiff_t>(dim) + axis)
  311. : static_cast<std::size_t>(axis);
  312. }
  313. template <class E, class C>
  314. inline std::enable_if_t<
  315. !xtl::is_integral<std::decay_t<C>>::value && xtl::is_signed<typename std::decay_t<C>::value_type>::value,
  316. rebind_container_t<std::size_t, std::decay_t<C>>>
  317. normalize_axis(E& expr, C&& axes)
  318. {
  319. rebind_container_t<std::size_t, std::decay_t<C>> res;
  320. resize_container(res, axes.size());
  321. for (std::size_t i = 0; i < axes.size(); ++i)
  322. {
  323. res[i] = normalize_axis(expr.dimension(), axes[i]);
  324. }
  325. XTENSOR_ASSERT(std::all_of(
  326. res.begin(),
  327. res.end(),
  328. [&expr](auto ax_el)
  329. {
  330. return ax_el < expr.dimension();
  331. }
  332. ));
  333. return res;
  334. }
  335. template <class C, class E>
  336. inline std::enable_if_t<
  337. !xtl::is_integral<std::decay_t<C>>::value && std::is_unsigned<typename std::decay_t<C>::value_type>::value,
  338. C&&>
  339. normalize_axis(E& expr, C&& axes)
  340. {
  341. static_cast<void>(expr);
  342. XTENSOR_ASSERT(std::all_of(
  343. axes.begin(),
  344. axes.end(),
  345. [&expr](auto ax_el)
  346. {
  347. return ax_el < expr.dimension();
  348. }
  349. ));
  350. return std::forward<C>(axes);
  351. }
  352. template <class R, class E, class C>
  353. inline auto forward_normalize(E& expr, C&& axes)
  354. -> std::enable_if_t<xtl::is_signed<std::decay_t<decltype(*std::begin(axes))>>::value, R>
  355. {
  356. R res;
  357. xt::resize_container(res, xtl::sequence_size(axes));
  358. auto dim = expr.dimension();
  359. std::transform(
  360. std::begin(axes),
  361. std::end(axes),
  362. std::begin(res),
  363. [&dim](auto ax_el)
  364. {
  365. return normalize_axis(dim, ax_el);
  366. }
  367. );
  368. XTENSOR_ASSERT(std::all_of(
  369. res.begin(),
  370. res.end(),
  371. [&expr](auto ax_el)
  372. {
  373. return ax_el < expr.dimension();
  374. }
  375. ));
  376. return res;
  377. }
  378. template <class R, class E, class C>
  379. inline auto forward_normalize(E& expr, C&& axes) -> std::enable_if_t<
  380. !xtl::is_signed<std::decay_t<decltype(*std::begin(axes))>>::value && !std::is_same<R, std::decay_t<C>>::value,
  381. R>
  382. {
  383. static_cast<void>(expr);
  384. R res;
  385. xt::resize_container(res, xtl::sequence_size(axes));
  386. std::copy(std::begin(axes), std::end(axes), std::begin(res));
  387. XTENSOR_ASSERT(std::all_of(
  388. res.begin(),
  389. res.end(),
  390. [&expr](auto ax_el)
  391. {
  392. return ax_el < expr.dimension();
  393. }
  394. ));
  395. return res;
  396. }
  397. template <class R, class E, class C>
  398. inline auto forward_normalize(E& expr, C&& axes) -> std::enable_if_t<
  399. !xtl::is_signed<std::decay_t<decltype(*std::begin(axes))>>::value && std::is_same<R, std::decay_t<C>>::value,
  400. R&&>
  401. {
  402. static_cast<void>(expr);
  403. XTENSOR_ASSERT(std::all_of(
  404. std::begin(axes),
  405. std::end(axes),
  406. [&expr](auto ax_el)
  407. {
  408. return ax_el < expr.dimension();
  409. }
  410. ));
  411. return std::move(axes);
  412. }
  413. /******************
  414. * get_value_type *
  415. ******************/
  416. template <class T, class = void_t<>>
  417. struct get_value_type
  418. {
  419. using type = T;
  420. };
  421. template <class T>
  422. struct get_value_type<T, void_t<typename T::value_type>>
  423. {
  424. using type = typename T::value_type;
  425. };
  426. template <class T>
  427. using get_value_type_t = typename get_value_type<T>::type;
  428. /**********************
  429. * get implementation *
  430. **********************/
  431. // When subclassing from std::tuple not all compilers are able to correctly instantiate get
  432. // See here: https://stackoverflow.com/a/37188019/2528668
  433. template <std::size_t I, template <typename... Args> class T, typename... Args>
  434. decltype(auto) get(T<Args...>&& v)
  435. {
  436. return std::get<I>(static_cast<std::tuple<Args...>&&>(v));
  437. }
  438. template <std::size_t I, template <typename... Args> class T, typename... Args>
  439. decltype(auto) get(T<Args...>& v)
  440. {
  441. return std::get<I>(static_cast<std::tuple<Args...>&>(v));
  442. }
  443. template <std::size_t I, template <typename... Args> class T, typename... Args>
  444. decltype(auto) get(const T<Args...>& v)
  445. {
  446. return std::get<I>(static_cast<const std::tuple<Args...>&>(v));
  447. }
  448. /***************************
  449. * apply_cv implementation *
  450. ***************************/
  451. namespace detail
  452. {
  453. template <
  454. class T,
  455. class U,
  456. bool = std::is_const<std::remove_reference_t<T>>::value,
  457. bool = std::is_volatile<std::remove_reference_t<T>>::value>
  458. struct apply_cv_impl
  459. {
  460. using type = U;
  461. };
  462. template <class T, class U>
  463. struct apply_cv_impl<T, U, true, false>
  464. {
  465. using type = const U;
  466. };
  467. template <class T, class U>
  468. struct apply_cv_impl<T, U, false, true>
  469. {
  470. using type = volatile U;
  471. };
  472. template <class T, class U>
  473. struct apply_cv_impl<T, U, true, true>
  474. {
  475. using type = const volatile U;
  476. };
  477. template <class T, class U>
  478. struct apply_cv_impl<T&, U, false, false>
  479. {
  480. using type = U&;
  481. };
  482. template <class T, class U>
  483. struct apply_cv_impl<T&, U, true, false>
  484. {
  485. using type = const U&;
  486. };
  487. template <class T, class U>
  488. struct apply_cv_impl<T&, U, false, true>
  489. {
  490. using type = volatile U&;
  491. };
  492. template <class T, class U>
  493. struct apply_cv_impl<T&, U, true, true>
  494. {
  495. using type = const volatile U&;
  496. };
  497. }
  498. template <class T, class U>
  499. struct apply_cv
  500. {
  501. using type = typename detail::apply_cv_impl<T, U>::type;
  502. };
  503. template <class T, class U>
  504. using apply_cv_t = typename apply_cv<T, U>::type;
  505. /**************************
  506. * to_array implementation *
  507. ***************************/
  508. namespace detail
  509. {
  510. template <class T, std::size_t N, std::size_t... I>
  511. constexpr std::array<std::remove_cv_t<T>, N> to_array_impl(T (&a)[N], std::index_sequence<I...>)
  512. {
  513. return {{a[I]...}};
  514. }
  515. }
  516. template <class T, std::size_t N>
  517. constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&a)[N])
  518. {
  519. return detail::to_array_impl(a, std::make_index_sequence<N>{});
  520. }
  521. /********************************
  522. * sequence_size implementation *
  523. ********************************/
  524. // equivalent to std::size(c) in c++17
  525. template <class C>
  526. constexpr auto sequence_size(const C& c) -> decltype(c.size())
  527. {
  528. return c.size();
  529. }
  530. // equivalent to std::size(a) in c++17
  531. template <class T, std::size_t N>
  532. constexpr std::size_t sequence_size(const T (&)[N])
  533. {
  534. return N;
  535. }
  536. /***********************************
  537. * has_storage_type implementation *
  538. ***********************************/
  539. template <class T, class = void>
  540. struct has_storage_type : std::false_type
  541. {
  542. };
  543. template <class T>
  544. struct xcontainer_inner_types;
  545. template <class T>
  546. struct has_storage_type<T, void_t<typename xcontainer_inner_types<T>::storage_type>>
  547. : xtl::negation<
  548. std::is_same<typename std::remove_cv<typename xcontainer_inner_types<T>::storage_type>::type, invalid_type>>
  549. {
  550. };
  551. /*************************************
  552. * has_data_interface implementation *
  553. *************************************/
  554. template <class E, class = void>
  555. struct has_data_interface : std::false_type
  556. {
  557. };
  558. template <class E>
  559. struct has_data_interface<E, void_t<decltype(std::declval<E>().data())>> : std::true_type
  560. {
  561. };
  562. template <class E, class = void>
  563. struct has_strides : std::false_type
  564. {
  565. };
  566. template <class E>
  567. struct has_strides<E, void_t<decltype(std::declval<E>().strides())>> : std::true_type
  568. {
  569. };
  570. template <class E, class = void>
  571. struct has_iterator_interface : std::false_type
  572. {
  573. };
  574. template <class E>
  575. struct has_iterator_interface<E, void_t<decltype(std::declval<E>().begin())>> : std::true_type
  576. {
  577. };
  578. /******************************
  579. * is_iterator implementation *
  580. ******************************/
  581. template <class E, class = void>
  582. struct is_iterator : std::false_type
  583. {
  584. };
  585. template <class E>
  586. struct is_iterator<
  587. E,
  588. void_t<
  589. 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())>>
  590. : std::true_type
  591. {
  592. };
  593. /********************************************
  594. * xtrivial_default_construct implemenation *
  595. ********************************************/
  596. #if defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE >= 7
  597. // has_trivial_default_constructor has not been available since libstdc++-7.
  598. #define XTENSOR_GLIBCXX_USE_CXX11_ABI 1
  599. #else
  600. #if defined(_GLIBCXX_USE_CXX11_ABI)
  601. #if _GLIBCXX_USE_CXX11_ABI || (defined(_GLIBCXX_USE_DUAL_ABI) && !_GLIBCXX_USE_DUAL_ABI)
  602. #define XTENSOR_GLIBCXX_USE_CXX11_ABI 1
  603. #endif
  604. #endif
  605. #endif
  606. #if !defined(__GNUG__) || defined(_LIBCPP_VERSION) || defined(XTENSOR_GLIBCXX_USE_CXX11_ABI)
  607. template <class T>
  608. using xtrivially_default_constructible = std::is_trivially_default_constructible<T>;
  609. #else
  610. template <class T>
  611. using xtrivially_default_constructible = std::has_trivial_default_constructor<T>;
  612. #endif
  613. #undef XTENSOR_GLIBCXX_USE_CXX11_ABI
  614. /*************************
  615. * conditional type cast *
  616. *************************/
  617. template <bool condition, class T>
  618. struct conditional_cast_functor;
  619. template <class T>
  620. struct conditional_cast_functor<false, T> : public xtl::identity
  621. {
  622. };
  623. template <class T>
  624. struct conditional_cast_functor<true, T>
  625. {
  626. template <class U>
  627. inline auto operator()(U&& u) const
  628. {
  629. return static_cast<T>(std::forward<U>(u));
  630. }
  631. };
  632. /**
  633. * @brief Perform a type cast when a condition is true.
  634. * If <tt>condition</tt> is true, return <tt>static_cast<T>(u)</tt>,
  635. * otherwise return <tt>u</tt> unchanged. This is useful when an unconditional
  636. * static_cast would force undesired type conversions in some situations where
  637. * an error or warning would be desired. The condition determines when the
  638. * explicit cast is ok.
  639. */
  640. template <bool condition, class T, class U>
  641. inline auto conditional_cast(U&& u)
  642. {
  643. return conditional_cast_functor<condition, T>()(std::forward<U>(u));
  644. }
  645. /**********************
  646. * tracking allocator *
  647. **********************/
  648. namespace alloc_tracking
  649. {
  650. inline bool& enabled()
  651. {
  652. static bool enabled;
  653. return enabled;
  654. }
  655. inline void enable()
  656. {
  657. enabled() = true;
  658. }
  659. inline void disable()
  660. {
  661. enabled() = false;
  662. }
  663. enum policy
  664. {
  665. print,
  666. assert
  667. };
  668. }
  669. template <class T, class A, alloc_tracking::policy P>
  670. struct tracking_allocator : private A
  671. {
  672. using base_type = A;
  673. using value_type = typename A::value_type;
  674. using reference = typename A::reference;
  675. using const_reference = typename A::const_reference;
  676. using pointer = typename A::pointer;
  677. using const_pointer = typename A::const_pointer;
  678. using size_type = typename A::size_type;
  679. using difference_type = typename A::difference_type;
  680. tracking_allocator() = default;
  681. T* allocate(std::size_t n)
  682. {
  683. if (alloc_tracking::enabled())
  684. {
  685. if (P == alloc_tracking::print)
  686. {
  687. std::cout << "xtensor allocating: " << n << "" << std::endl;
  688. }
  689. else if (P == alloc_tracking::assert)
  690. {
  691. XTENSOR_THROW(
  692. std::runtime_error,
  693. "xtensor allocation of " + std::to_string(n) + " elements detected"
  694. );
  695. }
  696. }
  697. return base_type::allocate(n);
  698. }
  699. using base_type::construct;
  700. using base_type::deallocate;
  701. using base_type::destroy;
  702. template <class U>
  703. struct rebind
  704. {
  705. using traits = std::allocator_traits<A>;
  706. using other = tracking_allocator<U, typename traits::template rebind_alloc<U>, P>;
  707. };
  708. };
  709. template <class T, class AT, alloc_tracking::policy PT, class U, class AU, alloc_tracking::policy PU>
  710. inline bool operator==(const tracking_allocator<T, AT, PT>&, const tracking_allocator<U, AU, PU>&)
  711. {
  712. return std::is_same<AT, AU>::value;
  713. }
  714. template <class T, class AT, alloc_tracking::policy PT, class U, class AU, alloc_tracking::policy PU>
  715. inline bool operator!=(const tracking_allocator<T, AT, PT>& a, const tracking_allocator<U, AU, PU>& b)
  716. {
  717. return !(a == b);
  718. }
  719. /*****************
  720. * has_assign_to *
  721. *****************/
  722. template <class E1, class E2, class = void>
  723. struct has_assign_to : std::false_type
  724. {
  725. };
  726. template <class E1, class E2>
  727. struct has_assign_to<E1, E2, void_t<decltype(std::declval<const E2&>().assign_to(std::declval<E1&>()))>>
  728. : std::true_type
  729. {
  730. };
  731. /*************************************
  732. * overlapping_memory_checker_traits *
  733. *************************************/
  734. template <class T, class Enable = void>
  735. struct has_memory_address : std::false_type
  736. {
  737. };
  738. template <class T>
  739. struct has_memory_address<T, void_t<decltype(std::addressof(*std::declval<T>().begin()))>> : std::true_type
  740. {
  741. };
  742. struct memory_range
  743. {
  744. // Checking pointer overlap is more correct in integer values,
  745. // for more explanation check https://devblogs.microsoft.com/oldnewthing/20170927-00/?p=97095
  746. const uintptr_t m_first = 0;
  747. const uintptr_t m_last = 0;
  748. explicit memory_range() = default;
  749. template <class T>
  750. explicit memory_range(T* first, T* last)
  751. : m_first(reinterpret_cast<uintptr_t>(last < first ? last : first))
  752. , m_last(reinterpret_cast<uintptr_t>(last < first ? first : last))
  753. {
  754. }
  755. template <class T>
  756. bool overlaps(T* first, T* last) const
  757. {
  758. if (first <= last)
  759. {
  760. return reinterpret_cast<uintptr_t>(first) <= m_last
  761. && reinterpret_cast<uintptr_t>(last) >= m_first;
  762. }
  763. else
  764. {
  765. return reinterpret_cast<uintptr_t>(last) <= m_last
  766. && reinterpret_cast<uintptr_t>(first) >= m_first;
  767. }
  768. }
  769. };
  770. template <class E, class Enable = void>
  771. struct overlapping_memory_checker_traits
  772. {
  773. static bool check_overlap(const E&, const memory_range&)
  774. {
  775. return true;
  776. }
  777. };
  778. template <class E>
  779. struct overlapping_memory_checker_traits<E, std::enable_if_t<has_memory_address<E>::value>>
  780. {
  781. static bool check_overlap(const E& expr, const memory_range& dst_range)
  782. {
  783. if (expr.size() == 0)
  784. {
  785. return false;
  786. }
  787. else
  788. {
  789. return dst_range.overlaps(std::addressof(*expr.begin()), std::addressof(*expr.rbegin()));
  790. }
  791. }
  792. };
  793. struct overlapping_memory_checker_base
  794. {
  795. memory_range m_dst_range;
  796. explicit overlapping_memory_checker_base() = default;
  797. explicit overlapping_memory_checker_base(memory_range dst_memory_range)
  798. : m_dst_range(std::move(dst_memory_range))
  799. {
  800. }
  801. template <class E>
  802. bool check_overlap(const E& expr) const
  803. {
  804. if (!m_dst_range.m_first || !m_dst_range.m_last)
  805. {
  806. return false;
  807. }
  808. else
  809. {
  810. return overlapping_memory_checker_traits<E>::check_overlap(expr, m_dst_range);
  811. }
  812. }
  813. };
  814. template <class Dst, class Enable = void>
  815. struct overlapping_memory_checker : overlapping_memory_checker_base
  816. {
  817. explicit overlapping_memory_checker(const Dst&)
  818. : overlapping_memory_checker_base()
  819. {
  820. }
  821. };
  822. template <class Dst>
  823. struct overlapping_memory_checker<Dst, std::enable_if_t<has_memory_address<Dst>::value>>
  824. : overlapping_memory_checker_base
  825. {
  826. explicit overlapping_memory_checker(const Dst& aDst)
  827. : overlapping_memory_checker_base(
  828. [&]()
  829. {
  830. if (aDst.size() == 0)
  831. {
  832. return memory_range();
  833. }
  834. else
  835. {
  836. return memory_range(std::addressof(*aDst.begin()), std::addressof(*aDst.rbegin()));
  837. }
  838. }()
  839. )
  840. {
  841. }
  842. };
  843. template <class Dst>
  844. auto make_overlapping_memory_checker(const Dst& a_dst)
  845. {
  846. return overlapping_memory_checker<Dst>(a_dst);
  847. }
  848. /********************
  849. * rebind_container *
  850. ********************/
  851. template <class X, template <class, class> class C, class T, class A>
  852. struct rebind_container<X, C<T, A>>
  853. {
  854. using traits = std::allocator_traits<A>;
  855. using allocator = typename traits::template rebind_alloc<X>;
  856. using type = C<X, allocator>;
  857. };
  858. #if defined(__GNUC__) && __GNUC__ > 6 && !defined(__clang__) && __cplusplus >= 201703L
  859. template <class X, class T, std::size_t N>
  860. struct rebind_container<X, std::array<T, N>>
  861. {
  862. using type = std::array<X, N>;
  863. };
  864. #else
  865. template <class X, template <class, std::size_t> class C, class T, std::size_t N>
  866. struct rebind_container<X, C<T, N>>
  867. {
  868. using type = C<X, N>;
  869. };
  870. #endif
  871. /********************
  872. * get_strides_type *
  873. ********************/
  874. template <class S>
  875. struct get_strides_type
  876. {
  877. using type = typename rebind_container<std::ptrdiff_t, S>::type;
  878. };
  879. template <std::size_t... I>
  880. struct get_strides_type<fixed_shape<I...>>
  881. {
  882. // TODO we could compute the strides statically here.
  883. // But we'll need full constexpr support to have a
  884. // homogenous ``compute_strides`` method
  885. using type = std::array<std::ptrdiff_t, sizeof...(I)>;
  886. };
  887. template <class CP, class O, class A>
  888. class xbuffer_adaptor;
  889. template <class CP, class O, class A>
  890. struct get_strides_type<xbuffer_adaptor<CP, O, A>>
  891. {
  892. // In bindings this mapping is called by reshape_view with an inner shape of type
  893. // xbuffer_adaptor.
  894. // Since we cannot create a buffer adaptor holding data, we map it to an std::vector.
  895. using type = std::vector<
  896. typename xbuffer_adaptor<CP, O, A>::value_type,
  897. typename xbuffer_adaptor<CP, O, A>::allocator_type>;
  898. };
  899. template <class C>
  900. using get_strides_t = typename get_strides_type<C>::type;
  901. /*******************
  902. * inner_reference *
  903. *******************/
  904. template <class ST>
  905. struct inner_reference
  906. {
  907. using storage_type = std::decay_t<ST>;
  908. using type = std::conditional_t<
  909. std::is_const<std::remove_reference_t<ST>>::value,
  910. typename storage_type::const_reference,
  911. typename storage_type::reference>;
  912. };
  913. template <class ST>
  914. using inner_reference_t = typename inner_reference<ST>::type;
  915. /************
  916. * get_rank *
  917. ************/
  918. template <class E, typename = void>
  919. struct get_rank
  920. {
  921. static constexpr std::size_t value = SIZE_MAX;
  922. };
  923. template <class E>
  924. struct get_rank<E, decltype((void) E::rank, void())>
  925. {
  926. static constexpr std::size_t value = E::rank;
  927. };
  928. /******************
  929. * has_fixed_rank *
  930. ******************/
  931. template <class E>
  932. struct has_fixed_rank
  933. {
  934. using type = std::integral_constant<bool, get_rank<std::decay_t<E>>::value != SIZE_MAX>;
  935. };
  936. template <class E>
  937. using has_fixed_rank_t = typename has_fixed_rank<std::decay_t<E>>::type;
  938. /************
  939. * has_rank *
  940. ************/
  941. template <class E, size_t N>
  942. struct has_rank
  943. {
  944. using type = std::integral_constant<bool, get_rank<std::decay_t<E>>::value == N>;
  945. };
  946. template <class E, size_t N>
  947. using has_rank_t = typename has_rank<std::decay_t<E>, N>::type;
  948. }
  949. #endif