From 652d6ef2a312eba17adfa25790c23425c96c6af3 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Fri, 1 Mar 2024 20:18:09 -0500 Subject: [PATCH] Add enable_shared_from_sibling. --- .../network/async/enable_shared_from_base.hpp | 61 ++++++++++++++++++- .../impl/async/enable_shared_from_base.ipp | 44 ++++++++++++- 2 files changed, 101 insertions(+), 4 deletions(-) diff --git a/include/bitcoin/network/async/enable_shared_from_base.hpp b/include/bitcoin/network/async/enable_shared_from_base.hpp index 53b6ec120..d091a03d0 100644 --- a/include/bitcoin/network/async/enable_shared_from_base.hpp +++ b/include/bitcoin/network/async/enable_shared_from_base.hpp @@ -25,8 +25,18 @@ namespace libbitcoin { namespace network { -/// Thread safe, base class. -/// Empty base optimization using CRTP. +// "The constructors of std::shared_ptr detect the presence of an unambiguous +// and accessible (i.e. public inheritance is mandatory) +// enable_shared_from_this base and assign the newly created std::shared_ptr +// to weak-this if not already owned by a live std::shared_ptr. +// Constructing a std::shared_ptr for an object that is already managed by +// another std::shared_ptr will not consult weak-this and is undefined behavior. +// It is permitted to call shared_from_this only on a previously shared object, +// i.e. on an object managed by std::shared_ptr. Otherwise, +// std::bad_weak_ptr is thrown(by the shared_ptr constructor).." +// en.cppreference.com/w/cpp/memory/enable_shared_from_this + +/// Base instance must be downcastable to Derived. /// Because enable_shared_from_this does not support inheritance. template class enable_shared_from_base @@ -42,6 +52,53 @@ class enable_shared_from_base std::shared_ptr shared_from_base() NOEXCEPT; }; +/// Sibling instance must be castable to Derived:Base. +/// Because enable_shared_from_this/base do not support multiple inheritance. +/// Avoids diamond inheritance ambiguity by requiring a primary inheritance +/// linear path (sibling) from which classes in an independent path (Base) +/// may obtain a shared pointer within their own path (Derived). +template +class enable_shared_from_sibling +{ +public: + DELETE_COPY_MOVE(enable_shared_from_sibling); + + enable_shared_from_sibling() NOEXCEPT; + + /// Must be a polymorphic type (to use dynamic_cast). + virtual ~enable_shared_from_sibling() NOEXCEPT; + + /// Simplifies capture of the shared pointer for a nop handler. + void nop() volatile NOEXCEPT; + +protected: + /// Sibling (not Derived:Base) implements enable_shared_from... + /// Use in Derived to create shared instance of Derived from its Sibling. + /// Undefined behavior if cast from Sibling* to Derived* not well formed. + template = true> + std::shared_ptr shared_from_sibling() NOEXCEPT; +}; + +// class foo__ : enabled_shared_from_base +// class foo_ : foo__ +// class foo: foo_ +// auto fooptr = foo.shared_from_this() +// auto foo_ptr = foo.shared_from_base() +// auto foo__ptr = foo.shared_from_base() +// +// class bar__ : enabled_shared_from_sibling +// class bar_ : bar__ +// class bar : bar_ +// bar__/bar_/bar must be joined with foo. +// +// class foobar : public foo, public bar +// auto barptr = foobar.shared_from_sibling() +// auto bar_ptr = foobar.shared_from_sibling() +// auto bar__ptr = foobar.shared_from_sibling() +// auto fooptr = foobar.shared_from_base() +// auto foo_ptr = foobar.shared_from_base() +// auto foo__ptr = foobar.shared_from_base() + } // namespace network } // namespace libbitcoin diff --git a/include/bitcoin/network/impl/async/enable_shared_from_base.ipp b/include/bitcoin/network/impl/async/enable_shared_from_base.ipp index 8ab481136..cae5dfc17 100644 --- a/include/bitcoin/network/impl/async/enable_shared_from_base.ipp +++ b/include/bitcoin/network/impl/async/enable_shared_from_base.ipp @@ -24,9 +24,13 @@ namespace libbitcoin { namespace network { + +// enable_shared_from_base : enable_shared_from_this +// ---------------------------------------------------------------------------- template -void enable_shared_from_base::nop() volatile NOEXCEPT +void enable_shared_from_base:: +nop() volatile NOEXCEPT { } @@ -35,8 +39,44 @@ template > std::shared_ptr enable_shared_from_base:: shared_from_base() NOEXCEPT { - // Instance must be downcastable to Derived. + BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) return std::static_pointer_cast(this->shared_from_this()); + BC_POP_WARNING() +} + +// enable_shared_from_sibling +// ---------------------------------------------------------------------------- + +template +enable_shared_from_sibling:: +enable_shared_from_sibling() NOEXCEPT +{ +} + +template +enable_shared_from_sibling:: +~enable_shared_from_sibling() NOEXCEPT +{ +} + +template +void enable_shared_from_sibling:: +nop() volatile NOEXCEPT +{ +} + +template +template > +std::shared_ptr enable_shared_from_sibling:: +shared_from_sibling() NOEXCEPT +{ + BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) + // Obtain shared pointer to object from Sibling class inheritance path. + const auto sibling = dynamic_cast(this)->shared_from_this(); + BC_POP_WARNING() + + // Cast pointer back to Derived (from Base) class it was created from. + return std::dynamic_pointer_cast(sibling); } } // namespace network