/*************************************************************************** * Copyright (c) Sylvain Corlay and Johan Mabille 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 XTL_CLOSURE_HPP #define XTL_CLOSURE_HPP #include #include #include #include "xtl_config.hpp" namespace xtl { #ifdef __cpp_lib_as_const using std::as_const; #else template constexpr std::add_const_t& as_const(T& t) noexcept { return t; } template constexpr std::add_const_t& as_const(T&& t) noexcept = delete; #endif /**************** * closure_type * ****************/ template struct closure_type { using underlying_type = std::conditional_t>::value, const std::decay_t, std::decay_t>; using type = typename std::conditional::value, underlying_type&, underlying_type>::type; }; template using closure_type_t = typename closure_type::type; template struct const_closure_type { using underlying_type = std::decay_t; using type = typename std::conditional::value, std::add_const_t&, underlying_type>::type; }; template using const_closure_type_t = typename const_closure_type::type; /******************** * ptr_closure_type * ********************/ template struct ptr_closure_type { using underlying_type = std::conditional_t>::value, const std::decay_t, std::decay_t>; using type = std::conditional_t::value, underlying_type*, underlying_type>; }; template using ptr_closure_type_t = typename ptr_closure_type::type; template struct const_ptr_closure_type { using underlying_type = const std::decay_t; using type = std::conditional_t::value, underlying_type*, underlying_type>; }; template using const_ptr_closure_type_t = typename const_ptr_closure_type::type; /******************** * xclosure_wrapper * ********************/ template class xclosure_wrapper { public: using self_type = xclosure_wrapper; using closure_type = CT; using const_closure_type = std::add_const_t; using value_type = std::decay_t; using reference = std::conditional_t< std::is_const>::value, const value_type&, value_type& >; using pointer = std::conditional_t< std::is_const>::value, const value_type*, value_type* >; xclosure_wrapper(value_type&& e); xclosure_wrapper(reference e); xclosure_wrapper(const self_type& rhs) = default; xclosure_wrapper(self_type&& rhs) = default; self_type& operator=(const self_type& rhs); self_type& operator=(self_type&& rhs); template self_type& operator=(T&&); operator closure_type() noexcept; operator const_closure_type() const noexcept; std::add_lvalue_reference_t get() & noexcept; std::add_lvalue_reference_t> get() const & noexcept; closure_type get() && noexcept; pointer operator&() noexcept; bool equal(const self_type& rhs) const; void swap(self_type& rhs); private: using storing_type = ptr_closure_type_t; storing_type m_wrappee; template std::enable_if_t::value, std::add_lvalue_reference_t>> deref(T val) const; template std::enable_if_t::value, std::add_lvalue_reference_t> deref(T& val) const; template std::enable_if_t::value, T> get_pointer(T val) const; template std::enable_if_t::value, std::add_pointer_t> get_pointer(T& val) const; template std::enable_if_t::value, T> get_storage_init(CTA&& e) const; template std::enable_if_t::value, T> get_storage_init(CTA&& e) const; }; // TODO: remove this (backward compatibility) template using closure_wrapper = xclosure_wrapper; /******************** * xclosure_pointer * ********************/ template class xclosure_pointer { public: using self_type = xclosure_pointer; using closure_type = CT; using value_type = std::decay_t; using reference = std::conditional_t< std::is_const>::value, const value_type&, value_type& >; using const_reference = const value_type&; using pointer = std::conditional_t< std::is_const>::value, const value_type*, value_type* >; xclosure_pointer(value_type&& e); xclosure_pointer(reference e); reference operator*() noexcept; const_reference operator*() const noexcept; pointer operator->() const noexcept; private: using storing_type = closure_type_t; storing_type m_wrappee; }; /*********************************** * xclosure_wrapper implementation * ***********************************/ template inline xclosure_wrapper::xclosure_wrapper(value_type&& e) : m_wrappee(get_storage_init(std::move(e))) { } template inline xclosure_wrapper::xclosure_wrapper(reference e) : m_wrappee(get_storage_init(e)) { } template inline auto xclosure_wrapper::operator=(const self_type& rhs) -> self_type& { deref(m_wrappee) = deref(rhs.m_wrappee); return *this; } template inline auto xclosure_wrapper::operator=(self_type&& rhs) -> self_type& { swap(rhs); return *this; } template template inline auto xclosure_wrapper::operator=(T&& t) -> self_type& { deref(m_wrappee) = std::forward(t); return *this; } template inline xclosure_wrapper::operator typename xclosure_wrapper::closure_type() noexcept { return deref(m_wrappee); } template inline xclosure_wrapper::operator typename xclosure_wrapper::const_closure_type() const noexcept { return deref(m_wrappee); } template inline auto xclosure_wrapper::get() & noexcept -> std::add_lvalue_reference_t { return deref(m_wrappee); } template inline auto xclosure_wrapper::get() const & noexcept -> std::add_lvalue_reference_t> { return deref(m_wrappee); } template inline auto xclosure_wrapper::get() && noexcept -> closure_type { return deref(m_wrappee); } template inline auto xclosure_wrapper::operator&() noexcept -> pointer { return get_pointer(m_wrappee); } template template inline std::enable_if_t::value, std::add_lvalue_reference_t>> xclosure_wrapper::deref(T val) const { return *val; } template template inline std::enable_if_t::value, std::add_lvalue_reference_t> xclosure_wrapper::deref(T& val) const { return val; } template template inline std::enable_if_t::value, T> xclosure_wrapper::get_pointer(T val) const { return val; } template template inline std::enable_if_t::value, std::add_pointer_t> xclosure_wrapper::get_pointer(T& val) const { return &val; } template template inline std::enable_if_t::value, T> xclosure_wrapper::get_storage_init(CTA&& e) const { return &e; } template template inline std::enable_if_t::value, T> xclosure_wrapper::get_storage_init(CTA&& e) const { return e; } template inline bool xclosure_wrapper::equal(const self_type& rhs) const { return deref(m_wrappee) == rhs.deref(rhs.m_wrappee); } template inline void xclosure_wrapper::swap(self_type& rhs) { using std::swap; swap(deref(m_wrappee), deref(rhs.m_wrappee)); } template inline bool operator==(const xclosure_wrapper& lhs, const xclosure_wrapper& rhs) { return lhs.equal(rhs); } template inline bool operator!=(const xclosure_wrapper& lhs, const xclosure_wrapper& rhs) { return !(lhs == rhs); } template inline void swap(xclosure_wrapper& lhs, xclosure_wrapper& rhs) { lhs.swap(rhs); } /*********************************** * xclosure_pointer implementation * ***********************************/ template inline xclosure_pointer::xclosure_pointer(value_type&& e) : m_wrappee(std::move(e)) { } template inline xclosure_pointer::xclosure_pointer(reference e) : m_wrappee(e) { } template inline auto xclosure_pointer::operator*() noexcept -> reference { return m_wrappee; } template inline auto xclosure_pointer::operator*() const noexcept -> const_reference { return m_wrappee; } template inline auto xclosure_pointer::operator->() const noexcept -> pointer { return const_cast(std::addressof(m_wrappee)); } /***************************** * closure and const_closure * *****************************/ template inline decltype(auto) closure(T&& t) { return xclosure_wrapper>(std::forward(t)); } template inline decltype(auto) const_closure(T&& t) { return xclosure_wrapper>(std::forward(t)); } /********************************************* * closure_pointer and const_closure_pointer * *********************************************/ template inline auto closure_pointer(T&& t) { return xclosure_pointer>(std::forward(t)); } template inline auto const_closure_pointer(T&& t) { return xclosure_pointer>(std::forward(t)); } } #endif