// file : cult/mm/bits/evptr.hxx // author : Boris Kolpackov // copyright : Copyright (c) 2005-2010 Boris Kolpackov // license : GNU GPL v2 + exceptions; see accompanying LICENSE file #ifndef CULT_MM_BITS_EVPTR_HXX #define CULT_MM_BITS_EVPTR_HXX #include #include #include #include #include // assert namespace Cult { namespace MM { //@@ Should be in mm/evptr.hxx // struct Clone: virtual Exception {}; template class Evptr; namespace Bits { template (x::*f) () const = &x::clone> struct Helper; //@@ Should be generalized and moved to Cult::meta // template struct has_clone { template static Meta::Yes test (Helper*); template static Meta::No test (...); static Boolean const r = sizeof (test (0)) == sizeof (Meta::Yes); }; //@@ Need to incorporate tests for polymorpism and NonCopyable. // template ::r> struct Cloner; template struct Cloner { static X* clone (X const* cp) { return cp->clone ().release (); } }; template struct Cloner { static X* clone (X const*) { throw MM::Clone (); } }; } namespace Bits { template class Transfer; } namespace Bits { template class EvptrBase { protected: ~EvptrBase () { free (p_ ? p_ : cp_, c_); } EvptrBase (X* p, X const* cp, Counter* c, Boolean inc = true) : p_ (p), cp_ (cp), c_ (c) { assert (!(p_ != 0 && cp_ != 0)); if (cp_ != 0 && c_ && inc) c_->inc_ref (); } public: X* get () const { return get_ (); } X* release () { X* p (get_ ()); c_ = 0; p_ = 0; cp_ = 0; return p; } Size count () const { if (c_ == 0) throw NullPointer (); return c_->count (); } public: // Conversion to Boolean. // typedef X* (EvptrBase::*BooleanConvertible)() const; operator BooleanConvertible () const { return c_ ? &EvptrBase::get : 0; } protected: Void assign (X const* cp, Counter* c) { if (c_ && c_ == c) throw SelfAssignment (); free (p_ ? p_ : cp_, c_); if (c) c->inc_ref (); c_ = c; p_ = 0; cp_ = cp; } Void transfer (X* p, X const* cp, Counter* c) { free (p_ ? p_ : cp_, c_); c_ = c; p_ = p; cp_ = cp; } protected: X* get_ () const { if (c_ == 0) return 0; assert (p_ != 0 || cp_ != 0); if (p_ != 0) { if (c_->count () == 1) return p_; else { // Convert to shared case. // cp_ = p_; p_ = 0; } } // Shared case with cloning. // // Check if we are the sole owner. // if (c_->count () == 1) { // Convert to exclusive case. // p_ = const_cast (cp_); cp_ = 0; } else { assert (cp_ != 0); //p_ = cp_->clone ().release (); p_ = Cloner::clone (cp_); free (cp_, c_); cp_ = 0; c_ = locate (p_, *counted); } return p_; } static Void free (X const* p, Counter* c) { if (c && c->dec_ref ()) { assert (p != 0); delete p; } } private: template friend class Evptr; template friend class Transfer; mutable X* p_; mutable X const* cp_; mutable Counter* c_; }; template class EvptrBase { protected: ~EvptrBase () { free (p_ ? p_ : cp_, c_); } EvptrBase (X const* p, X const* cp, Counter* c, Boolean inc = true) : p_ (p), cp_ (cp), c_ (c) { assert (!(p_ != 0 && cp_ != 0)); if (cp_ != 0 && c_ && inc) c_->inc_ref (); } public: X const* get () { return get_ (); } //@@ Should clone if shared? // X const* release () { X const* p (get_ ()); c_ = 0; p_ = 0; cp_ = 0; return p; } Size count () const { if (c_ == 0) throw NullPointer (); return c_->count (); } public: // Conversion to Boolean. // typedef X const* (EvptrBase::*BooleanConvertible)() const; operator BooleanConvertible () const { return c_ ? &EvptrBase::get : 0; } protected: Void assign (X const* cp, Counter* c) { if (c_ && c_ == c) throw SelfAssignment (); free (p_ ? p_ : cp_, c_); if (c) c->inc_ref (); c_ = c; p_ = 0; cp_ = cp; } Void transfer (X const* p, X const* cp, Counter* c) { free (p_ ? p_ : cp_, c_); c_ = c; p_ = p; cp_ = cp; } protected: X const* get_ () const { return p_ ? p_ : cp_; } static Void free (X const* p, Counter* c) { if (c && c->dec_ref ()) { assert (p != 0); delete p; } } private: template friend class Evptr; template friend class Transfer; mutable X const* p_; mutable X const* cp_; mutable Counter* c_; }; } namespace Bits { template class Transfer : protected EvptrBase { public: Transfer (Transfer const& ct) : EvptrBase (ct.p_, ct.cp_, ct.c_, false) { Transfer& t (const_cast&> (ct)); t.c_ = 0; t.p_ = 0; t.cp_ = 0; } private: Transfer (X* p, X const* cp, Counter* c) : EvptrBase (p, cp, c, false) { } template friend class Evptr; private: Transfer& operator= (Transfer const&); }; } } } #endif // CULT_MM_BITS_EVPTR_HXX