xexpression.hpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769
  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_EXPRESSION_HPP
  10. #define XTENSOR_EXPRESSION_HPP
  11. #include <cstddef>
  12. #include <type_traits>
  13. #include <vector>
  14. #include <xtl/xclosure.hpp>
  15. #include <xtl/xmeta_utils.hpp>
  16. #include <xtl/xtype_traits.hpp>
  17. #include "xlayout.hpp"
  18. #include "xshape.hpp"
  19. #include "xtensor_forward.hpp"
  20. #include "xutils.hpp"
  21. namespace xt
  22. {
  23. /***************************
  24. * xexpression declaration *
  25. ***************************/
  26. /**
  27. * @class xexpression
  28. * @brief Base class for xexpressions
  29. *
  30. * The xexpression class is the base class for all classes representing an expression
  31. * that can be evaluated to a multidimensional container with tensor semantic.
  32. * Functions that can apply to any xexpression regardless of its specific type should take a
  33. * xexpression argument.
  34. *
  35. * @tparam E The derived type.
  36. *
  37. */
  38. template <class D>
  39. class xexpression
  40. {
  41. public:
  42. using derived_type = D;
  43. derived_type& derived_cast() & noexcept;
  44. const derived_type& derived_cast() const& noexcept;
  45. derived_type derived_cast() && noexcept;
  46. protected:
  47. xexpression() = default;
  48. ~xexpression() = default;
  49. xexpression(const xexpression&) = default;
  50. xexpression& operator=(const xexpression&) = default;
  51. xexpression(xexpression&&) = default;
  52. xexpression& operator=(xexpression&&) = default;
  53. };
  54. /************************************
  55. * xsharable_expression declaration *
  56. ************************************/
  57. template <class E>
  58. class xshared_expression;
  59. template <class E>
  60. class xsharable_expression;
  61. namespace detail
  62. {
  63. template <class E>
  64. xshared_expression<E> make_xshared_impl(xsharable_expression<E>&&);
  65. }
  66. template <class D>
  67. class xsharable_expression : public xexpression<D>
  68. {
  69. protected:
  70. xsharable_expression();
  71. ~xsharable_expression() = default;
  72. xsharable_expression(const xsharable_expression&) = default;
  73. xsharable_expression& operator=(const xsharable_expression&) = default;
  74. xsharable_expression(xsharable_expression&&) = default;
  75. xsharable_expression& operator=(xsharable_expression&&) = default;
  76. private:
  77. std::shared_ptr<D> p_shared;
  78. friend xshared_expression<D> detail::make_xshared_impl<D>(xsharable_expression<D>&&);
  79. };
  80. /******************************
  81. * xexpression implementation *
  82. ******************************/
  83. /**
  84. * @name Downcast functions
  85. */
  86. //@{
  87. /**
  88. * Returns a reference to the actual derived type of the xexpression.
  89. */
  90. template <class D>
  91. inline auto xexpression<D>::derived_cast() & noexcept -> derived_type&
  92. {
  93. return *static_cast<derived_type*>(this);
  94. }
  95. /**
  96. * Returns a constant reference to the actual derived type of the xexpression.
  97. */
  98. template <class D>
  99. inline auto xexpression<D>::derived_cast() const& noexcept -> const derived_type&
  100. {
  101. return *static_cast<const derived_type*>(this);
  102. }
  103. /**
  104. * Returns a constant reference to the actual derived type of the xexpression.
  105. */
  106. template <class D>
  107. inline auto xexpression<D>::derived_cast() && noexcept -> derived_type
  108. {
  109. return *static_cast<derived_type*>(this);
  110. }
  111. //@}
  112. /***************************************
  113. * xsharable_expression implementation *
  114. ***************************************/
  115. template <class D>
  116. inline xsharable_expression<D>::xsharable_expression()
  117. : p_shared(nullptr)
  118. {
  119. }
  120. /**
  121. * is_crtp_base_of<B, E>
  122. * Resembles std::is_base_of, but adresses the problem of whether _some_ instantiation
  123. * of a CRTP templated class B is a base of class E. A CRTP templated class is correctly
  124. * templated with the most derived type in the CRTP hierarchy. Using this assumption,
  125. * this implementation deals with either CRTP final classes (checks for inheritance
  126. * with E as the CRTP parameter of B) or CRTP base classes (which are singly templated
  127. * by the most derived class, and that's pulled out to use as a templete parameter for B).
  128. */
  129. namespace detail
  130. {
  131. template <template <class> class B, class E>
  132. struct is_crtp_base_of_impl : std::is_base_of<B<E>, E>
  133. {
  134. };
  135. template <template <class> class B, class E, template <class> class F>
  136. struct is_crtp_base_of_impl<B, F<E>>
  137. : xtl::disjunction<std::is_base_of<B<E>, F<E>>, std::is_base_of<B<F<E>>, F<E>>>
  138. {
  139. };
  140. }
  141. template <template <class> class B, class E>
  142. using is_crtp_base_of = detail::is_crtp_base_of_impl<B, std::decay_t<E>>;
  143. template <class E>
  144. using is_xexpression = is_crtp_base_of<xexpression, E>;
  145. template <class E, class R = void>
  146. using enable_xexpression = typename std::enable_if<is_xexpression<E>::value, R>::type;
  147. template <class E, class R = void>
  148. using disable_xexpression = typename std::enable_if<!is_xexpression<E>::value, R>::type;
  149. template <class... E>
  150. using has_xexpression = xtl::disjunction<is_xexpression<E>...>;
  151. template <class E>
  152. using is_xsharable_expression = is_crtp_base_of<xsharable_expression, E>;
  153. template <class E, class R = void>
  154. using enable_xsharable_expression = typename std::enable_if<is_xsharable_expression<E>::value, R>::type;
  155. template <class E, class R = void>
  156. using disable_xsharable_expression = typename std::enable_if<!is_xsharable_expression<E>::value, R>::type;
  157. template <class LHS, class RHS>
  158. struct can_assign : std::is_assignable<LHS, RHS>
  159. {
  160. };
  161. template <class LHS, class RHS, class R = void>
  162. using enable_assignable_expression = typename std::enable_if<can_assign<LHS, RHS>::value, R>::type;
  163. template <class LHS, class RHS, class R = void>
  164. using enable_not_assignable_expression = typename std::enable_if<!can_assign<LHS, RHS>::value, R>::type;
  165. /***********************
  166. * evaluation_strategy *
  167. ***********************/
  168. namespace detail
  169. {
  170. struct option_base
  171. {
  172. };
  173. }
  174. namespace evaluation_strategy
  175. {
  176. struct immediate_type : xt::detail::option_base
  177. {
  178. };
  179. constexpr auto immediate = std::tuple<immediate_type>{};
  180. struct lazy_type : xt::detail::option_base
  181. {
  182. };
  183. constexpr auto lazy = std::tuple<lazy_type>{};
  184. /*
  185. struct cached {};
  186. */
  187. }
  188. template <class T>
  189. struct is_evaluation_strategy : std::is_base_of<detail::option_base, std::decay_t<T>>
  190. {
  191. };
  192. /************
  193. * xclosure *
  194. ************/
  195. template <class T>
  196. class xscalar;
  197. template <class E, class EN = void>
  198. struct xclosure
  199. {
  200. using type = xtl::closure_type_t<E>;
  201. };
  202. template <class E>
  203. struct xclosure<xshared_expression<E>, std::enable_if_t<true>>
  204. {
  205. using type = xshared_expression<E>; // force copy
  206. };
  207. template <class E>
  208. struct xclosure<E, disable_xexpression<std::decay_t<E>>>
  209. {
  210. using type = xscalar<xtl::closure_type_t<E>>;
  211. };
  212. template <class E>
  213. using xclosure_t = typename xclosure<E>::type;
  214. template <class E, class EN = void>
  215. struct const_xclosure
  216. {
  217. using type = xtl::const_closure_type_t<E>;
  218. };
  219. template <class E>
  220. struct const_xclosure<E, disable_xexpression<std::decay_t<E>>>
  221. {
  222. using type = xscalar<xtl::const_closure_type_t<E>>;
  223. };
  224. template <class E>
  225. struct const_xclosure<xshared_expression<E>&, std::enable_if_t<true>>
  226. {
  227. using type = xshared_expression<E>; // force copy
  228. };
  229. template <class E>
  230. using const_xclosure_t = typename const_xclosure<E>::type;
  231. /*************************
  232. * expression tag system *
  233. *************************/
  234. struct xtensor_expression_tag
  235. {
  236. };
  237. struct xoptional_expression_tag
  238. {
  239. };
  240. namespace extension
  241. {
  242. template <class E, class = void_t<int>>
  243. struct get_expression_tag_impl
  244. {
  245. using type = xtensor_expression_tag;
  246. };
  247. template <class E>
  248. struct get_expression_tag_impl<E, void_t<typename std::decay_t<E>::expression_tag>>
  249. {
  250. using type = typename std::decay_t<E>::expression_tag;
  251. };
  252. template <class E>
  253. struct get_expression_tag : get_expression_tag_impl<E>
  254. {
  255. };
  256. template <class E>
  257. using get_expression_tag_t = typename get_expression_tag<E>::type;
  258. template <class... T>
  259. struct expression_tag_and;
  260. template <>
  261. struct expression_tag_and<>
  262. {
  263. using type = xtensor_expression_tag;
  264. };
  265. template <class T>
  266. struct expression_tag_and<T>
  267. {
  268. using type = T;
  269. };
  270. template <class T>
  271. struct expression_tag_and<T, T>
  272. {
  273. using type = T;
  274. };
  275. template <class T>
  276. struct expression_tag_and<xtensor_expression_tag, T>
  277. {
  278. using type = T;
  279. };
  280. template <class T>
  281. struct expression_tag_and<T, xtensor_expression_tag> : expression_tag_and<xtensor_expression_tag, T>
  282. {
  283. };
  284. template <>
  285. struct expression_tag_and<xtensor_expression_tag, xtensor_expression_tag>
  286. {
  287. using type = xtensor_expression_tag;
  288. };
  289. template <class T1, class... T>
  290. struct expression_tag_and<T1, T...> : expression_tag_and<T1, typename expression_tag_and<T...>::type>
  291. {
  292. };
  293. template <class... T>
  294. using expression_tag_and_t = typename expression_tag_and<T...>::type;
  295. struct xtensor_empty_base
  296. {
  297. using expression_tag = xtensor_expression_tag;
  298. };
  299. }
  300. template <class... T>
  301. struct xexpression_tag
  302. {
  303. using type = extension::expression_tag_and_t<
  304. extension::get_expression_tag_t<std::decay_t<const_xclosure_t<T>>>...>;
  305. };
  306. template <class... T>
  307. using xexpression_tag_t = typename xexpression_tag<T...>::type;
  308. template <class E>
  309. struct is_xtensor_expression : std::is_same<xexpression_tag_t<E>, xtensor_expression_tag>
  310. {
  311. };
  312. template <class E>
  313. struct is_xoptional_expression : std::is_same<xexpression_tag_t<E>, xoptional_expression_tag>
  314. {
  315. };
  316. /********************************
  317. * xoptional_comparable concept *
  318. ********************************/
  319. template <class... E>
  320. struct xoptional_comparable
  321. : xtl::conjunction<xtl::disjunction<is_xtensor_expression<E>, is_xoptional_expression<E>>...>
  322. {
  323. };
  324. #define XTENSOR_FORWARD_CONST_METHOD(name) \
  325. auto name() const -> decltype(std::declval<xtl::constify_t<E>>().name()) \
  326. { \
  327. return m_ptr->name(); \
  328. }
  329. #define XTENSOR_FORWARD_METHOD(name) \
  330. auto name() -> decltype(std::declval<E>().name()) \
  331. { \
  332. return m_ptr->name(); \
  333. }
  334. #define XTENSOR_FORWARD_CONST_ITERATOR_METHOD(name) \
  335. template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL> \
  336. auto name() const noexcept -> decltype(std::declval<xtl::constify_t<E>>().template name<L>()) \
  337. { \
  338. return m_ptr->template name<L>(); \
  339. } \
  340. template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S> \
  341. auto name(const S& shape) const noexcept \
  342. -> decltype(std::declval<xtl::constify_t<E>>().template name<L>(shape)) \
  343. { \
  344. return m_ptr->template name<L>(); \
  345. }
  346. #define XTENSOR_FORWARD_ITERATOR_METHOD(name) \
  347. template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL, class S> \
  348. auto name(const S& shape) noexcept -> decltype(std::declval<E>().template name<L>(shape)) \
  349. { \
  350. return m_ptr->template name<L>(); \
  351. } \
  352. template <layout_type L = XTENSOR_DEFAULT_TRAVERSAL> \
  353. auto name() noexcept -> decltype(std::declval<E>().template name<L>()) \
  354. { \
  355. return m_ptr->template name<L>(); \
  356. }
  357. namespace detail
  358. {
  359. template <class E>
  360. struct expr_strides_type
  361. {
  362. using type = typename E::strides_type;
  363. };
  364. template <class E>
  365. struct expr_inner_strides_type
  366. {
  367. using type = typename E::inner_strides_type;
  368. };
  369. template <class E>
  370. struct expr_backstrides_type
  371. {
  372. using type = typename E::backstrides_type;
  373. };
  374. template <class E>
  375. struct expr_inner_backstrides_type
  376. {
  377. using type = typename E::inner_backstrides_type;
  378. };
  379. template <class E>
  380. struct expr_storage_type
  381. {
  382. using type = typename E::storage_type;
  383. };
  384. }
  385. /**
  386. * @class xshared_expression
  387. * @brief Shared xexpressions
  388. *
  389. * Due to C++ lifetime constraints it's sometimes necessary to create shared
  390. * expressions (akin to a shared pointer).
  391. *
  392. * For example, when a temporary expression needs to be used twice in another
  393. * expression, shared expressions can come to the rescue:
  394. *
  395. * @code{.cpp}
  396. * template <class E>
  397. * auto cos_plus_sin(xexpression<E>&& expr)
  398. * {
  399. * // THIS IS WRONG: forwarding rvalue twice not permitted!
  400. * // return xt::sin(std::forward<E>(expr)) + xt::cos(std::forward<E>(expr));
  401. * // THIS IS WRONG TOO: because second `expr` is taken as reference (which will be invalid)
  402. * // return xt::sin(std::forward<E>(expr)) + xt::cos(expr)
  403. * auto shared_expr = xt::make_xshared(std::forward<E>(expr));
  404. * auto result = xt::sin(shared_expr) + xt::cos(shared_expr);
  405. * std::cout << shared_expr.use_count() << std::endl; // Will print 3 because used twice in expression
  406. * return result; // all valid because expr lifetime managed by xshared_expression / shared_ptr.
  407. * }
  408. * @endcode
  409. */
  410. template <class E>
  411. class xshared_expression : public xexpression<xshared_expression<E>>
  412. {
  413. public:
  414. using base_class = xexpression<xshared_expression<E>>;
  415. using value_type = typename E::value_type;
  416. using reference = typename E::reference;
  417. using const_reference = typename E::const_reference;
  418. using pointer = typename E::pointer;
  419. using const_pointer = typename E::const_pointer;
  420. using size_type = typename E::size_type;
  421. using difference_type = typename E::difference_type;
  422. using inner_shape_type = typename E::inner_shape_type;
  423. using shape_type = typename E::shape_type;
  424. using strides_type = xtl::mpl::
  425. eval_if_t<has_strides<E>, detail::expr_strides_type<E>, get_strides_type<shape_type>>;
  426. using backstrides_type = xtl::mpl::
  427. eval_if_t<has_strides<E>, detail::expr_backstrides_type<E>, get_strides_type<shape_type>>;
  428. using inner_strides_type = xtl::mpl::
  429. eval_if_t<has_strides<E>, detail::expr_inner_strides_type<E>, get_strides_type<shape_type>>;
  430. using inner_backstrides_type = xtl::mpl::
  431. eval_if_t<has_strides<E>, detail::expr_inner_backstrides_type<E>, get_strides_type<shape_type>>;
  432. using storage_type = xtl::mpl::eval_if_t<has_storage_type<E>, detail::expr_storage_type<E>, make_invalid_type<>>;
  433. using stepper = typename E::stepper;
  434. using const_stepper = typename E::const_stepper;
  435. using linear_iterator = typename E::linear_iterator;
  436. using const_linear_iterator = typename E::const_linear_iterator;
  437. using bool_load_type = typename E::bool_load_type;
  438. static constexpr layout_type static_layout = E::static_layout;
  439. static constexpr bool contiguous_layout = static_layout != layout_type::dynamic;
  440. explicit xshared_expression(const std::shared_ptr<E>& ptr);
  441. long use_count() const noexcept;
  442. template <class... Args>
  443. auto operator()(Args... args) -> decltype(std::declval<E>()(args...))
  444. {
  445. return m_ptr->operator()(args...);
  446. }
  447. XTENSOR_FORWARD_CONST_METHOD(shape)
  448. XTENSOR_FORWARD_CONST_METHOD(dimension)
  449. XTENSOR_FORWARD_CONST_METHOD(size)
  450. XTENSOR_FORWARD_CONST_METHOD(layout)
  451. XTENSOR_FORWARD_CONST_METHOD(is_contiguous)
  452. XTENSOR_FORWARD_ITERATOR_METHOD(begin)
  453. XTENSOR_FORWARD_ITERATOR_METHOD(end)
  454. XTENSOR_FORWARD_CONST_ITERATOR_METHOD(begin)
  455. XTENSOR_FORWARD_CONST_ITERATOR_METHOD(end)
  456. XTENSOR_FORWARD_CONST_ITERATOR_METHOD(cbegin)
  457. XTENSOR_FORWARD_CONST_ITERATOR_METHOD(cend)
  458. XTENSOR_FORWARD_ITERATOR_METHOD(rbegin)
  459. XTENSOR_FORWARD_ITERATOR_METHOD(rend)
  460. XTENSOR_FORWARD_CONST_ITERATOR_METHOD(rbegin)
  461. XTENSOR_FORWARD_CONST_ITERATOR_METHOD(rend)
  462. XTENSOR_FORWARD_CONST_ITERATOR_METHOD(crbegin)
  463. XTENSOR_FORWARD_CONST_ITERATOR_METHOD(crend)
  464. XTENSOR_FORWARD_METHOD(linear_begin)
  465. XTENSOR_FORWARD_METHOD(linear_end)
  466. XTENSOR_FORWARD_CONST_METHOD(linear_begin)
  467. XTENSOR_FORWARD_CONST_METHOD(linear_end)
  468. XTENSOR_FORWARD_CONST_METHOD(linear_cbegin)
  469. XTENSOR_FORWARD_CONST_METHOD(linear_cend)
  470. XTENSOR_FORWARD_METHOD(linear_rbegin)
  471. XTENSOR_FORWARD_METHOD(linear_rend)
  472. XTENSOR_FORWARD_CONST_METHOD(linear_rbegin)
  473. XTENSOR_FORWARD_CONST_METHOD(linear_rend)
  474. XTENSOR_FORWARD_CONST_METHOD(linear_crbegin)
  475. XTENSOR_FORWARD_CONST_METHOD(linear_crend)
  476. template <class T = E>
  477. std::enable_if_t<has_strides<T>::value, const inner_strides_type&> strides() const
  478. {
  479. return m_ptr->strides();
  480. }
  481. template <class T = E>
  482. std::enable_if_t<has_strides<T>::value, const inner_strides_type&> backstrides() const
  483. {
  484. return m_ptr->backstrides();
  485. }
  486. template <class T = E>
  487. std::enable_if_t<has_data_interface<T>::value, pointer> data() noexcept
  488. {
  489. return m_ptr->data();
  490. }
  491. template <class T = E>
  492. std::enable_if_t<has_data_interface<T>::value, pointer> data() const noexcept
  493. {
  494. return m_ptr->data();
  495. }
  496. template <class T = E>
  497. std::enable_if_t<has_data_interface<T>::value, size_type> data_offset() const noexcept
  498. {
  499. return m_ptr->data_offset();
  500. }
  501. template <class T = E>
  502. std::enable_if_t<has_data_interface<T>::value, typename T::storage_type&> storage() noexcept
  503. {
  504. return m_ptr->storage();
  505. }
  506. template <class T = E>
  507. std::enable_if_t<has_data_interface<T>::value, const typename T::storage_type&> storage() const noexcept
  508. {
  509. return m_ptr->storage();
  510. }
  511. template <class It>
  512. reference element(It first, It last)
  513. {
  514. return m_ptr->element(first, last);
  515. }
  516. template <class It>
  517. const_reference element(It first, It last) const
  518. {
  519. return m_ptr->element(first, last);
  520. }
  521. template <class S>
  522. bool broadcast_shape(S& shape, bool reuse_cache = false) const
  523. {
  524. return m_ptr->broadcast_shape(shape, reuse_cache);
  525. }
  526. template <class S>
  527. bool has_linear_assign(const S& strides) const noexcept
  528. {
  529. return m_ptr->has_linear_assign(strides);
  530. }
  531. template <class S>
  532. auto stepper_begin(const S& shape) noexcept -> decltype(std::declval<E>().stepper_begin(shape))
  533. {
  534. return m_ptr->stepper_begin(shape);
  535. }
  536. template <class S>
  537. auto stepper_end(const S& shape, layout_type l) noexcept
  538. -> decltype(std::declval<E>().stepper_end(shape, l))
  539. {
  540. return m_ptr->stepper_end(shape, l);
  541. }
  542. template <class S>
  543. auto stepper_begin(const S& shape) const noexcept
  544. -> decltype(std::declval<const E>().stepper_begin(shape))
  545. {
  546. return static_cast<const E*>(m_ptr.get())->stepper_begin(shape);
  547. }
  548. template <class S>
  549. auto stepper_end(const S& shape, layout_type l) const noexcept
  550. -> decltype(std::declval<const E>().stepper_end(shape, l))
  551. {
  552. return static_cast<const E*>(m_ptr.get())->stepper_end(shape, l);
  553. }
  554. private:
  555. std::shared_ptr<E> m_ptr;
  556. };
  557. /**
  558. * Constructor for xshared expression (note: usually the free function
  559. * `make_xshared` is recommended).
  560. *
  561. * @param ptr shared ptr that contains the expression
  562. * @sa make_xshared
  563. */
  564. template <class E>
  565. inline xshared_expression<E>::xshared_expression(const std::shared_ptr<E>& ptr)
  566. : m_ptr(ptr)
  567. {
  568. }
  569. /**
  570. * Return the number of times this expression is referenced.
  571. * Internally calls the use_count() function of the std::shared_ptr.
  572. */
  573. template <class E>
  574. inline long xshared_expression<E>::use_count() const noexcept
  575. {
  576. return m_ptr.use_count();
  577. }
  578. namespace detail
  579. {
  580. template <class E>
  581. inline xshared_expression<E> make_xshared_impl(xsharable_expression<E>&& expr)
  582. {
  583. if (expr.p_shared == nullptr)
  584. {
  585. expr.p_shared = std::make_shared<E>(std::move(expr).derived_cast());
  586. }
  587. return xshared_expression<E>(expr.p_shared);
  588. }
  589. }
  590. /**
  591. * Helper function to create shared expression from any xexpression
  592. *
  593. * @param expr rvalue expression that will be shared
  594. * @return xshared expression
  595. */
  596. template <class E>
  597. inline xshared_expression<E> make_xshared(xexpression<E>&& expr)
  598. {
  599. static_assert(
  600. is_xsharable_expression<E>::value,
  601. "make_shared requires E to inherit from xsharable_expression"
  602. );
  603. return detail::make_xshared_impl(std::move(expr.derived_cast()));
  604. }
  605. /**
  606. * Helper function to create shared expression from any xexpression
  607. *
  608. * @param expr rvalue expression that will be shared
  609. * @return xshared expression
  610. * @sa make_xshared
  611. */
  612. template <class E>
  613. inline auto share(xexpression<E>& expr)
  614. {
  615. return make_xshared(std::move(expr));
  616. }
  617. /**
  618. * Helper function to create shared expression from any xexpression
  619. *
  620. * @param expr rvalue expression that will be shared
  621. * @return xshared expression
  622. * @sa make_xshared
  623. */
  624. template <class E>
  625. inline auto share(xexpression<E>&& expr)
  626. {
  627. return make_xshared(std::move(expr));
  628. }
  629. #undef XTENSOR_FORWARD_METHOD
  630. }
  631. #endif