From a15cf65c44d5c224169c32ef5495b68c758134b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Sun, 18 May 2014 16:08:14 +0200 Subject: Imported Upstream version 3.3.0.2 --- libcult/cult/mm/bits/evptr.hxx | 379 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 379 insertions(+) create mode 100644 libcult/cult/mm/bits/evptr.hxx (limited to 'libcult/cult/mm/bits/evptr.hxx') diff --git a/libcult/cult/mm/bits/evptr.hxx b/libcult/cult/mm/bits/evptr.hxx new file mode 100644 index 0000000..02f0b48 --- /dev/null +++ b/libcult/cult/mm/bits/evptr.hxx @@ -0,0 +1,379 @@ +// 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 -- cgit v1.2.3