/* P.hpp - customised shared_ptr with ordering and type relationships Copyright (C) Lumiera.org 2008, Hermann Vosseler This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /** @file p.hpp ** Customised refcounting smart pointer. ** Template derived from std::shared_ptr adding total ordering and ** type relationships implemented by forwarding to the pointees. In all other ** respects, it should behave exactly as shared_ptr and is able to cooperate ** and share ownership with other shared_ptr instantiations. ** ** By default different instantiations of shared_ptr are completely unrelated types, ** even if using inheritance related type parameters for instantiation: a shared_ptr ** isn't some kind-of shared_ptr -- we need to do an explicit static_ptr_cast. Another ** common problem is the definition of equality and ordering relations for shared_ptr: ** equality is based on the equality of the managed pointers, while ordering is built upon ** the ref count. While generally this may be a good compromise, in our case it hinders treating ** the smart ptrs within the application almost as if they were the objects themselves and proved ** an obstacle for writing generic helper functions. ** ** the P template resolves these problems by implementing the ordering operators in terms of ** the corresponding operators on the pointee and by allowing to specify a base class smart-ptr ** as template parameter. ** ** @see asset.hpp ** @see custom-shared-ptr-test.cpp ** @see orderingofassetstest.cpp */ #ifndef LIB_P_H #define LIB_P_H #include "lib/error.hpp" #include "lib/meta/util.hpp" #include namespace lib { using std::shared_ptr; using std::weak_ptr; /** * Customised refcounting smart pointer template, built upon * std::shared_ptr, but forwarding type relationships and * ordering operators to the pointee objects. * @param TAR the visible pointee type * @param BASE the shared-ptr type used as implementation * @note if the BASE smart-ptr type used as implementation * implies another pointer type than the one used on * the interface (=type TAR), then every access to the * pointee causes an dynamic cast. Thus the pointee types * need to support RTTI. */ template > class P : public BASE { public: P ( ) : BASE() {} template explicit P (Y* p) : BASE(p) {} template P (Y* p, D d) : BASE(p,d){} P (P const& r) : BASE(r) {} P (P const&& rr) : BASE(rr) {} template P (shared_ptr const& r) : BASE(r) {} template explicit P (weak_ptr const& wr) : BASE(wr) {} template explicit P (std::auto_ptr && ar) : BASE(std::move(ar)) {} P& operator= (P const& r) { BASE::operator= (r); return *this; } P& operator= (P const&& rr) { BASE::operator= (rr); return *this; } template P& operator=(shared_ptr const& sr) { BASE::operator= (sr); return *this; } template P& operator=(std::auto_ptr && ar) { BASE::operator= (std::move(ar)); return *this; } TAR* get() const { return dynamic_cast (BASE::get()); } TAR& operator*() const { return *get(); } TAR* operator->() const { return get(); } void swap(P& b) { BASE::swap (b);} operator std::string() const noexcept; private: /* === friend operators injected into enclosing namespace for ADL === */ //////////////////TICKET #932 Clang is unable to fill in the default template argument. Resolved in newer versions of Clang. Temporary workaround: add second parameter B template friend inline bool operator== (P const& p, P<_O_, B> const& q) { return (p && q)? (*p == *q) : (!p && !q); } template friend inline bool operator!= (P const& p, P<_O_, B> const& q) { return (p && q)? (*p != *q) : !(!p && !q); } template friend inline bool operator< (P const& p, P<_O_, B> const& q) { REQUIRE (p && q); return *p < *q; } ///< @note deliberately not allowing comparison on NIL ////TICKET #307 : problem with equality test in associative containers, where equal(a,b) := !(a < b) && !(b < a) template friend inline bool operator> (P const& p, P<_O_, B> const& q) { REQUIRE (p && q); return *q < *p; } template friend inline bool operator<= (P const& p, P<_O_, B> const& q) { REQUIRE (p && q); return *p <= *q;} template friend inline bool operator>= (P const& p, P<_O_, B> const& q) { REQUIRE (p && q); return *p >= *q;} }; /** Helper to create and manage by lib::P * @tparam X the type of the new object to create on the heap * @param ctorArgs arbitrary arguments to pass to ctor of `X` * @return managing smart-ptr of type P, holding onto the * object just created on the heap. */ template inline P newP (ARGS&&... ctorArgs) { return P{new X {std::forward(ctorArgs)...}}; } /** * use custom string conversion on pointee, if applicable, * otherwise fall back to a human readable type string.S */ template inline P::operator std::string() const noexcept try { if (BASE::get()) return util::StringConv::invoke (this->operator*()); else return "⟂ P<"+meta::typeStr()+">"; } catch(...) { return meta::FAILURE_INDICATOR; } } // namespace lib #endif