xclosure.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. /***************************************************************************
  2. * Copyright (c) Sylvain Corlay and Johan Mabille 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 XTL_CLOSURE_HPP
  10. #define XTL_CLOSURE_HPP
  11. #include <memory>
  12. #include <type_traits>
  13. #include <utility>
  14. #include "xtl_config.hpp"
  15. namespace xtl
  16. {
  17. #ifdef __cpp_lib_as_const
  18. using std::as_const;
  19. #else
  20. template <class T>
  21. constexpr std::add_const_t<T>& as_const(T& t) noexcept
  22. {
  23. return t;
  24. }
  25. template <class T>
  26. constexpr std::add_const_t<T&&>& as_const(T&& t) noexcept = delete;
  27. #endif
  28. /****************
  29. * closure_type *
  30. ****************/
  31. template <class S>
  32. struct closure_type
  33. {
  34. using underlying_type = std::conditional_t<std::is_const<std::remove_reference_t<S>>::value,
  35. const std::decay_t<S>,
  36. std::decay_t<S>>;
  37. using type = typename std::conditional<std::is_lvalue_reference<S>::value,
  38. underlying_type&,
  39. underlying_type>::type;
  40. };
  41. template <class S>
  42. using closure_type_t = typename closure_type<S>::type;
  43. template <class S>
  44. struct const_closure_type
  45. {
  46. using underlying_type = std::decay_t<S>;
  47. using type = typename std::conditional<std::is_lvalue_reference<S>::value,
  48. std::add_const_t<underlying_type>&,
  49. underlying_type>::type;
  50. };
  51. template <class S>
  52. using const_closure_type_t = typename const_closure_type<S>::type;
  53. /********************
  54. * ptr_closure_type *
  55. ********************/
  56. template <class S>
  57. struct ptr_closure_type
  58. {
  59. using underlying_type = std::conditional_t<std::is_const<std::remove_reference_t<S>>::value,
  60. const std::decay_t<S>,
  61. std::decay_t<S>>;
  62. using type = std::conditional_t<std::is_lvalue_reference<S>::value,
  63. underlying_type*,
  64. underlying_type>;
  65. };
  66. template <class S>
  67. using ptr_closure_type_t = typename ptr_closure_type<S>::type;
  68. template <class S>
  69. struct const_ptr_closure_type
  70. {
  71. using underlying_type = const std::decay_t<S>;
  72. using type = std::conditional_t<std::is_lvalue_reference<S>::value,
  73. underlying_type*,
  74. underlying_type>;
  75. };
  76. template <class S>
  77. using const_ptr_closure_type_t = typename const_ptr_closure_type<S>::type;
  78. /********************
  79. * xclosure_wrapper *
  80. ********************/
  81. template <class CT>
  82. class xclosure_wrapper
  83. {
  84. public:
  85. using self_type = xclosure_wrapper<CT>;
  86. using closure_type = CT;
  87. using const_closure_type = std::add_const_t<CT>;
  88. using value_type = std::decay_t<CT>;
  89. using reference = std::conditional_t<
  90. std::is_const<std::remove_reference_t<CT>>::value,
  91. const value_type&, value_type&
  92. >;
  93. using pointer = std::conditional_t<
  94. std::is_const<std::remove_reference_t<CT>>::value,
  95. const value_type*, value_type*
  96. >;
  97. xclosure_wrapper(value_type&& e);
  98. xclosure_wrapper(reference e);
  99. xclosure_wrapper(const self_type& rhs) = default;
  100. xclosure_wrapper(self_type&& rhs) = default;
  101. self_type& operator=(const self_type& rhs);
  102. self_type& operator=(self_type&& rhs);
  103. template <class T>
  104. self_type& operator=(T&&);
  105. operator closure_type() noexcept;
  106. operator const_closure_type() const noexcept;
  107. std::add_lvalue_reference_t<closure_type> get() & noexcept;
  108. std::add_lvalue_reference_t<std::add_const_t<closure_type>> get() const & noexcept;
  109. closure_type get() && noexcept;
  110. pointer operator&() noexcept;
  111. bool equal(const self_type& rhs) const;
  112. void swap(self_type& rhs);
  113. private:
  114. using storing_type = ptr_closure_type_t<CT>;
  115. storing_type m_wrappee;
  116. template <class T>
  117. std::enable_if_t<std::is_lvalue_reference<CT>::value, std::add_lvalue_reference_t<std::remove_pointer_t<T>>>
  118. deref(T val) const;
  119. template <class T>
  120. std::enable_if_t<!std::is_lvalue_reference<CT>::value, std::add_lvalue_reference_t<T>>
  121. deref(T& val) const;
  122. template <class T>
  123. std::enable_if_t<std::is_lvalue_reference<CT>::value, T>
  124. get_pointer(T val) const;
  125. template <class T>
  126. std::enable_if_t<!std::is_lvalue_reference<CT>::value, std::add_pointer_t<T>>
  127. get_pointer(T& val) const;
  128. template <class T, class CTA>
  129. std::enable_if_t<std::is_lvalue_reference<CT>::value, T>
  130. get_storage_init(CTA&& e) const;
  131. template <class T, class CTA>
  132. std::enable_if_t<!std::is_lvalue_reference<CT>::value, T>
  133. get_storage_init(CTA&& e) const;
  134. };
  135. // TODO: remove this (backward compatibility)
  136. template <class CT>
  137. using closure_wrapper = xclosure_wrapper<CT>;
  138. /********************
  139. * xclosure_pointer *
  140. ********************/
  141. template <class CT>
  142. class xclosure_pointer
  143. {
  144. public:
  145. using self_type = xclosure_pointer<CT>;
  146. using closure_type = CT;
  147. using value_type = std::decay_t<CT>;
  148. using reference = std::conditional_t<
  149. std::is_const<std::remove_reference_t<CT>>::value,
  150. const value_type&, value_type&
  151. >;
  152. using const_reference = const value_type&;
  153. using pointer = std::conditional_t<
  154. std::is_const<std::remove_reference_t<CT>>::value,
  155. const value_type*, value_type*
  156. >;
  157. xclosure_pointer(value_type&& e);
  158. xclosure_pointer(reference e);
  159. reference operator*() noexcept;
  160. const_reference operator*() const noexcept;
  161. pointer operator->() const noexcept;
  162. private:
  163. using storing_type = closure_type_t<CT>;
  164. storing_type m_wrappee;
  165. };
  166. /***********************************
  167. * xclosure_wrapper implementation *
  168. ***********************************/
  169. template <class CT>
  170. inline xclosure_wrapper<CT>::xclosure_wrapper(value_type&& e)
  171. : m_wrappee(get_storage_init<storing_type>(std::move(e)))
  172. {
  173. }
  174. template <class CT>
  175. inline xclosure_wrapper<CT>::xclosure_wrapper(reference e)
  176. : m_wrappee(get_storage_init<storing_type>(e))
  177. {
  178. }
  179. template <class CT>
  180. inline auto xclosure_wrapper<CT>::operator=(const self_type& rhs) -> self_type&
  181. {
  182. deref(m_wrappee) = deref(rhs.m_wrappee);
  183. return *this;
  184. }
  185. template <class CT>
  186. inline auto xclosure_wrapper<CT>::operator=(self_type&& rhs) -> self_type&
  187. {
  188. swap(rhs);
  189. return *this;
  190. }
  191. template <class CT>
  192. template <class T>
  193. inline auto xclosure_wrapper<CT>::operator=(T&& t) -> self_type&
  194. {
  195. deref(m_wrappee) = std::forward<T>(t);
  196. return *this;
  197. }
  198. template <class CT>
  199. inline xclosure_wrapper<CT>::operator typename xclosure_wrapper<CT>::closure_type() noexcept
  200. {
  201. return deref(m_wrappee);
  202. }
  203. template <class CT>
  204. inline xclosure_wrapper<CT>::operator typename xclosure_wrapper<CT>::const_closure_type() const noexcept
  205. {
  206. return deref(m_wrappee);
  207. }
  208. template <class CT>
  209. inline auto xclosure_wrapper<CT>::get() & noexcept -> std::add_lvalue_reference_t<closure_type>
  210. {
  211. return deref(m_wrappee);
  212. }
  213. template <class CT>
  214. inline auto xclosure_wrapper<CT>::get() const & noexcept -> std::add_lvalue_reference_t<std::add_const_t<closure_type>>
  215. {
  216. return deref(m_wrappee);
  217. }
  218. template <class CT>
  219. inline auto xclosure_wrapper<CT>::get() && noexcept -> closure_type
  220. {
  221. return deref(m_wrappee);
  222. }
  223. template <class CT>
  224. inline auto xclosure_wrapper<CT>::operator&() noexcept -> pointer
  225. {
  226. return get_pointer(m_wrappee);
  227. }
  228. template <class CT>
  229. template <class T>
  230. inline std::enable_if_t<std::is_lvalue_reference<CT>::value, std::add_lvalue_reference_t<std::remove_pointer_t<T>>>
  231. xclosure_wrapper<CT>::deref(T val) const
  232. {
  233. return *val;
  234. }
  235. template <class CT>
  236. template <class T>
  237. inline std::enable_if_t<!std::is_lvalue_reference<CT>::value, std::add_lvalue_reference_t<T>>
  238. xclosure_wrapper<CT>::deref(T& val) const
  239. {
  240. return val;
  241. }
  242. template <class CT>
  243. template <class T>
  244. inline std::enable_if_t<std::is_lvalue_reference<CT>::value, T>
  245. xclosure_wrapper<CT>::get_pointer(T val) const
  246. {
  247. return val;
  248. }
  249. template <class CT>
  250. template <class T>
  251. inline std::enable_if_t<!std::is_lvalue_reference<CT>::value, std::add_pointer_t<T>>
  252. xclosure_wrapper<CT>::get_pointer(T& val) const
  253. {
  254. return &val;
  255. }
  256. template <class CT>
  257. template <class T, class CTA>
  258. inline std::enable_if_t<std::is_lvalue_reference<CT>::value, T>
  259. xclosure_wrapper<CT>::get_storage_init(CTA&& e) const
  260. {
  261. return &e;
  262. }
  263. template <class CT>
  264. template <class T, class CTA>
  265. inline std::enable_if_t<!std::is_lvalue_reference<CT>::value, T>
  266. xclosure_wrapper<CT>::get_storage_init(CTA&& e) const
  267. {
  268. return e;
  269. }
  270. template <class CT>
  271. inline bool xclosure_wrapper<CT>::equal(const self_type& rhs) const
  272. {
  273. return deref(m_wrappee) == rhs.deref(rhs.m_wrappee);
  274. }
  275. template <class CT>
  276. inline void xclosure_wrapper<CT>::swap(self_type& rhs)
  277. {
  278. using std::swap;
  279. swap(deref(m_wrappee), deref(rhs.m_wrappee));
  280. }
  281. template <class CT>
  282. inline bool operator==(const xclosure_wrapper<CT>& lhs, const xclosure_wrapper<CT>& rhs)
  283. {
  284. return lhs.equal(rhs);
  285. }
  286. template <class CT>
  287. inline bool operator!=(const xclosure_wrapper<CT>& lhs, const xclosure_wrapper<CT>& rhs)
  288. {
  289. return !(lhs == rhs);
  290. }
  291. template <class CT>
  292. inline void swap(xclosure_wrapper<CT>& lhs, xclosure_wrapper<CT>& rhs)
  293. {
  294. lhs.swap(rhs);
  295. }
  296. /***********************************
  297. * xclosure_pointer implementation *
  298. ***********************************/
  299. template <class CT>
  300. inline xclosure_pointer<CT>::xclosure_pointer(value_type&& e)
  301. : m_wrappee(std::move(e))
  302. {
  303. }
  304. template <class CT>
  305. inline xclosure_pointer<CT>::xclosure_pointer(reference e)
  306. : m_wrappee(e)
  307. {
  308. }
  309. template <class CT>
  310. inline auto xclosure_pointer<CT>::operator*() noexcept -> reference
  311. {
  312. return m_wrappee;
  313. }
  314. template <class CT>
  315. inline auto xclosure_pointer<CT>::operator*() const noexcept -> const_reference
  316. {
  317. return m_wrappee;
  318. }
  319. template <class CT>
  320. inline auto xclosure_pointer<CT>::operator->() const noexcept -> pointer
  321. {
  322. return const_cast<pointer>(std::addressof(m_wrappee));
  323. }
  324. /*****************************
  325. * closure and const_closure *
  326. *****************************/
  327. template <class T>
  328. inline decltype(auto) closure(T&& t)
  329. {
  330. return xclosure_wrapper<closure_type_t<T>>(std::forward<T>(t));
  331. }
  332. template <class T>
  333. inline decltype(auto) const_closure(T&& t)
  334. {
  335. return xclosure_wrapper<const_closure_type_t<T>>(std::forward<T>(t));
  336. }
  337. /*********************************************
  338. * closure_pointer and const_closure_pointer *
  339. *********************************************/
  340. template <class T>
  341. inline auto closure_pointer(T&& t)
  342. {
  343. return xclosure_pointer<closure_type_t<T>>(std::forward<T>(t));
  344. }
  345. template <class T>
  346. inline auto const_closure_pointer(T&& t)
  347. {
  348. return xclosure_pointer<const_closure_type_t<T>>(std::forward<T>(t));
  349. }
  350. }
  351. #endif