Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-17 08:52:03

0001 // Copyright (c) 2018-2025 Jean-Louis Leroy
0002 // Distributed under the Boost Software License, Version 1.0.
0003 // See accompanying file LICENSE_1_0.txt
0004 // or copy at http://www.boost.org/LICENSE_1_0.txt)
0005 
0006 #ifndef BOOST_OPENMETHOD_INTEROP_SHARED_PTR_HPP
0007 #define BOOST_OPENMETHOD_INTEROP_SHARED_PTR_HPP
0008 
0009 #include <boost/openmethod/core.hpp>
0010 #include <memory>
0011 
0012 namespace boost::openmethod {
0013 namespace detail {
0014 
0015 template<class T>
0016 struct shared_ptr_cast_traits {
0017     static_assert(false_t<T>, "cast only allowed to a shared_ptr");
0018 };
0019 
0020 template<class T>
0021 struct shared_ptr_cast_traits<std::shared_ptr<T>> {
0022     using virtual_type = T;
0023 };
0024 
0025 template<class T>
0026 struct shared_ptr_cast_traits<const std::shared_ptr<T>&> {
0027     using virtual_type = T;
0028 };
0029 
0030 template<class T>
0031 struct shared_ptr_cast_traits<std::shared_ptr<T>&&> {
0032     using virtual_type = T;
0033 };
0034 
0035 template<typename T, class Registry>
0036 struct validate_method_parameter<std::shared_ptr<T>&, Registry, void>
0037     : std::false_type {
0038     static_assert(
0039         false_t<T>,
0040         "std::shared_ptr cannot be passed by non-const lvalue reference");
0041 };
0042 
0043 template<typename T, class Registry>
0044 struct validate_method_parameter<
0045     virtual_ptr<std::shared_ptr<T>, Registry>&, Registry, void>
0046     : std::false_type {
0047     static_assert(
0048         false_t<T>,
0049         "std::shared_ptr cannot be passed by non-const lvalue reference");
0050 };
0051 
0052 } // namespace detail
0053 
0054 //! Specialize virtual_traits for std::shared_ptr by value.
0055 //!
0056 //! @tparam Class A class type, possibly cv-qualified.
0057 //! @tparam Registry A @ref registry.
0058 template<typename Class, class Registry>
0059 struct virtual_traits<std::shared_ptr<Class>, Registry> {
0060     //! Rebind to a different element type.
0061     //!
0062     //! @tparam Other The new element type.
0063     template<class Other>
0064     using rebind = std::shared_ptr<Other>;
0065 
0066     //! `Class`, stripped from cv-qualifiers.
0067     using virtual_type = std::remove_cv_t<Class>;
0068 
0069     //! Return a reference to a non-modifiable `Class` object.
0070     //! @param arg A reference to a `std::shared_ptr<Class>`.
0071     //! @return A reference to the object pointed to.
0072     static auto peek(const std::shared_ptr<Class>& arg) -> const Class& {
0073         return *arg;
0074     }
0075 
0076     //! Cast to another type.
0077     //!
0078     //! Cast to a `std::shared_ptr` to another type. If possible, use
0079     //! `std::static_pointer_cast`. Otherwise, use `std::dynamic_pointer_cast`.
0080     //!
0081     //! @tparam Derived A lvalue reference type to a `std::shared_ptr`.
0082     //! @param obj A reference to a `const shared_ptr<Class>`.
0083     //! @return A `std::shared_ptr` to the same object, cast to
0084     //! `Derived::element_type`.
0085     template<class Derived>
0086     static auto cast(const std::shared_ptr<Class>& obj) -> decltype(auto) {
0087         using namespace boost::openmethod::detail;
0088 
0089         if constexpr (requires_dynamic_cast<
0090                           Class*, typename Derived::element_type*>) {
0091             return std::dynamic_pointer_cast<
0092                 typename shared_ptr_cast_traits<Derived>::virtual_type>(obj);
0093         } else {
0094             return std::static_pointer_cast<
0095                 typename shared_ptr_cast_traits<Derived>::virtual_type>(obj);
0096         }
0097     }
0098 
0099 #if __cplusplus >= 202002L
0100     //! Move-cast to another type (since c++20)
0101     //!
0102     //! Cast to a `std::shared_ptr` xvalue reference to another type. If
0103     //! possible, use `std::static_pointer_cast`. Otherwise, use
0104     //! `std::dynamic_pointer_cast`.
0105     //!
0106     //! @note This overload is only available for C++20 and above, because
0107     //! rvalue references overloads of `std::static_pointer_cast` and
0108     //! `std::dynamic_pointer_cast` were not available before.
0109     //!
0110     //! @tparam Derived A xvalue reference to a `std::shared_ptr`.
0111     //! @param obj A xvalue reference to a `shared_ptr<Class>`.
0112     //! @return A `std::shared_ptr&&` to the same object, cast to
0113     //! `Derived::element_type`.
0114     template<class Derived>
0115     static auto cast(std::shared_ptr<Class>&& obj) -> decltype(auto) {
0116         using namespace boost::openmethod::detail;
0117 
0118         if constexpr (requires_dynamic_cast<
0119                           Class*, decltype(std::declval<Derived>().get())>) {
0120             return std::dynamic_pointer_cast<
0121                 typename shared_ptr_cast_traits<Derived>::virtual_type>(
0122                 std::move(obj));
0123         } else {
0124             return std::static_pointer_cast<
0125                 typename shared_ptr_cast_traits<Derived>::virtual_type>(
0126                 std::move(obj));
0127         }
0128     }
0129 #endif
0130 };
0131 
0132 //! Specialize virtual_traits for std::shared_ptr by reference.
0133 //!
0134 //! @note Passing a `std::shared_ptr` in a method call by const reference
0135 //! creates a temporary `std::shared_ptr` and passes it by const reference to
0136 //! the overrider. This is necessary because virtual arguments need to be cast
0137 //! to the type expected by the overrider.
0138 //!
0139 //! @tparam Class A class type, possibly cv-qualified.
0140 //! @tparam Registry A @ref registry.
0141 template<class Class, class Registry>
0142 struct virtual_traits<const std::shared_ptr<Class>&, Registry> {
0143   public:
0144     //! Rebind to a different element type.
0145     //!
0146     //! @tparam Other The new element type.
0147     template<class Other>
0148     using rebind = std::shared_ptr<Other>;
0149 
0150     //! `Class`, stripped from cv-qualifiers.
0151     using virtual_type = std::remove_cv_t<Class>;
0152 
0153     //! Return a reference to a non-modifiable `Class` object.
0154     //! @param arg A reference to a `std::shared_ptr<Class>`.
0155     //! @return A reference to the object pointed to.
0156     static auto peek(const std::shared_ptr<Class>& arg) -> const Class& {
0157         return *arg;
0158     }
0159 
0160     //! Cast to another type.
0161     //!
0162     //! Cast to a `std::shared_ptr` to another type. If possible, use
0163     //! `std::static_pointer_cast`. Otherwise, use `std::dynamic_pointer_cast`.
0164     //!
0165     //! @tparam Derived A lvalue reference type to a `std::shared_ptr`.
0166     //! @param obj A reference to a `const shared_ptr<Class>`.
0167     //! @return A `std::shared_ptr` to the same object, cast to
0168     //! `Derived::element_type`.
0169     template<class Other>
0170     static auto cast(const std::shared_ptr<Class>& obj) {
0171         using namespace boost::openmethod::detail;
0172 
0173         if constexpr (requires_dynamic_cast<Class*, Other>) {
0174             return std::dynamic_pointer_cast<
0175                 typename shared_ptr_cast_traits<Other>::virtual_type>(obj);
0176         } else {
0177             return std::static_pointer_cast<
0178                 typename shared_ptr_cast_traits<Other>::virtual_type>(obj);
0179         }
0180     }
0181 };
0182 
0183 //! Alias for a `virtual_ptr<std::shared_ptr<T>>`.
0184 template<class Class, class Registry = BOOST_OPENMETHOD_DEFAULT_REGISTRY>
0185 using shared_virtual_ptr = virtual_ptr<std::shared_ptr<Class>, Registry>;
0186 
0187 //! Create a new object and return a `shared_virtual_ptr` to it.
0188 //!
0189 //! Create an object using `std::make_shared`, and return a @ref
0190 //! shared_virtual_ptr pointing to it. Since the exact class of the object is
0191 //! known, the `virtual_ptr` is created using @ref final_virtual_ptr.
0192 //!
0193 //! `Class` is _not_ required to be a polymorphic class.
0194 //!
0195 //! @tparam Class The class of the object to create.
0196 //! @tparam Registry A @ref registry.
0197 //! @tparam T Types of the arguments to pass to the constructor of `Class`.
0198 //! @param args Arguments to pass to the constructor of `Class`.
0199 //! @return A `shared_virtual_ptr<Class, Registry>` pointing to a newly
0200 //! created object of type `Class`.
0201 template<
0202     class Class, class Registry = BOOST_OPENMETHOD_DEFAULT_REGISTRY,
0203     typename... T>
0204 inline auto make_shared_virtual(T&&... args) {
0205     return final_virtual_ptr<Registry>(
0206         std::make_shared<Class>(std::forward<T>(args)...));
0207 }
0208 
0209 namespace aliases {
0210 using boost::openmethod::make_shared_virtual;
0211 using boost::openmethod::shared_virtual_ptr;
0212 } // namespace aliases
0213 
0214 } // namespace boost::openmethod
0215 
0216 #endif