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/arch/generic/counter.hxx | 45 +++ libcult/cult/mm/arch/generic/counter.ixx | 47 +++ libcult/cult/mm/arch/i386/counter.hxx | 43 +++ libcult/cult/mm/arch/i386/counter.ixx | 46 +++ .../mm/arch/i386/i486/i586/i686/x86_64/counter.hxx | 43 +++ .../mm/arch/i386/i486/i586/i686/x86_64/counter.ixx | 46 +++ libcult/cult/mm/bits/evptr.hxx | 379 +++++++++++++++++++++ libcult/cult/mm/bits/shptr.hxx | 85 +++++ libcult/cult/mm/buffer.cxx | 140 ++++++++ libcult/cult/mm/buffer.hxx | 80 +++++ libcult/cult/mm/counter.cxx | 14 + libcult/cult/mm/counter.hxx | 79 +++++ libcult/cult/mm/counter.ixx | 38 +++ libcult/cult/mm/evptr.hxx | 221 ++++++++++++ libcult/cult/mm/exception.hxx | 31 ++ libcult/cult/mm/new.cxx | 192 +++++++++++ libcult/cult/mm/new.hxx | 297 ++++++++++++++++ libcult/cult/mm/new.ixx | 36 ++ libcult/cult/mm/shptr.hxx | 139 ++++++++ libcult/cult/mm/static-ptr.hxx | 75 ++++ 20 files changed, 2076 insertions(+) create mode 100644 libcult/cult/mm/arch/generic/counter.hxx create mode 100644 libcult/cult/mm/arch/generic/counter.ixx create mode 100644 libcult/cult/mm/arch/i386/counter.hxx create mode 100644 libcult/cult/mm/arch/i386/counter.ixx create mode 100644 libcult/cult/mm/arch/i386/i486/i586/i686/x86_64/counter.hxx create mode 100644 libcult/cult/mm/arch/i386/i486/i586/i686/x86_64/counter.ixx create mode 100644 libcult/cult/mm/bits/evptr.hxx create mode 100644 libcult/cult/mm/bits/shptr.hxx create mode 100644 libcult/cult/mm/buffer.cxx create mode 100644 libcult/cult/mm/buffer.hxx create mode 100644 libcult/cult/mm/counter.cxx create mode 100644 libcult/cult/mm/counter.hxx create mode 100644 libcult/cult/mm/counter.ixx create mode 100644 libcult/cult/mm/evptr.hxx create mode 100644 libcult/cult/mm/exception.hxx create mode 100644 libcult/cult/mm/new.cxx create mode 100644 libcult/cult/mm/new.hxx create mode 100644 libcult/cult/mm/new.ixx create mode 100644 libcult/cult/mm/shptr.hxx create mode 100644 libcult/cult/mm/static-ptr.hxx (limited to 'libcult/cult/mm') diff --git a/libcult/cult/mm/arch/generic/counter.hxx b/libcult/cult/mm/arch/generic/counter.hxx new file mode 100644 index 0000000..6a26759 --- /dev/null +++ b/libcult/cult/mm/arch/generic/counter.hxx @@ -0,0 +1,45 @@ +// file : cult/mm/arch/generic/counter.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Boris Kolpackov +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CULT_MM_ARCH_GENERIC_COUNTER_HXX +#define CULT_MM_ARCH_GENERIC_COUNTER_HXX + +#include +#include + +namespace Cult +{ + namespace MM + { + class Counter: public NonCopyable + { + public: + Counter (); + + // After failure assume the counter has its old value. + // + Void + inc_ref (); + + + // After failure assume the counter has its new value. + // + Boolean + dec_ref (); + + + Size + count () const; + + private: + Size value_; + mutable Sched::Spin spin_; + }; + } +} + +#include + +#endif // CULT_MM_ARCH_GENERIC_COUNTER_HXX diff --git a/libcult/cult/mm/arch/generic/counter.ixx b/libcult/cult/mm/arch/generic/counter.ixx new file mode 100644 index 0000000..648d28a --- /dev/null +++ b/libcult/cult/mm/arch/generic/counter.ixx @@ -0,0 +1,47 @@ +// file : cult/mm/arch/generic/counter.ixx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Boris Kolpackov +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +namespace Cult +{ + namespace MM + { + inline + Counter:: + Counter () + : value_ (1) + { + } + + inline + Void Counter:: + inc_ref () + { + Sched::Lock l (spin_); + + ++value_; + } + + inline + Boolean Counter:: + dec_ref () + { + Sched::Lock l (spin_); + + return --value_ == 0; + + } + + inline + Size Counter:: + count () const + { + Sched::Lock l (spin_); + + return value_; + } + } +} diff --git a/libcult/cult/mm/arch/i386/counter.hxx b/libcult/cult/mm/arch/i386/counter.hxx new file mode 100644 index 0000000..21f5f63 --- /dev/null +++ b/libcult/cult/mm/arch/i386/counter.hxx @@ -0,0 +1,43 @@ +// file : cult/mm/arch/i386/counter.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Boris Kolpackov +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CULT_MM_ARCH_I386_COUNTER_HXX +#define CULT_MM_ARCH_I386_COUNTER_HXX + +#include + +namespace Cult +{ + namespace MM + { + class Counter: public NonCopyable + { + public: + Counter (); + + // After failure assume the counter has its old value. + // + Void + inc_ref (); + + + // After failure assume the counter has its new value. + // + Boolean + dec_ref (); + + + Size + count () const; + + private: + Size value_; + }; + } +} + +#include + +#endif // CULT_MM_ARCH_I386_COUNTER_HXX diff --git a/libcult/cult/mm/arch/i386/counter.ixx b/libcult/cult/mm/arch/i386/counter.ixx new file mode 100644 index 0000000..8279394 --- /dev/null +++ b/libcult/cult/mm/arch/i386/counter.ixx @@ -0,0 +1,46 @@ +// file : cult/mm/arch/i386/counter.ixx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Boris Kolpackov +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +namespace Cult +{ + namespace MM + { + inline + Counter:: + Counter () + : value_ (1) + { + } + + inline + Void Counter:: + inc_ref () + { + asm volatile ("lock; incl %0" + :"=m" (value_) + :"m" (value_)); + } + + inline + Boolean Counter:: + dec_ref () + { + register unsigned char r; + + asm volatile("lock; decl %0; setz %1" + :"=m" (value_), "=rm" (r) + :"m" (value_)); + + return r != 0; + } + + inline + Size Counter:: + count () const + { + return value_; + } + } +} diff --git a/libcult/cult/mm/arch/i386/i486/i586/i686/x86_64/counter.hxx b/libcult/cult/mm/arch/i386/i486/i586/i686/x86_64/counter.hxx new file mode 100644 index 0000000..5869b09 --- /dev/null +++ b/libcult/cult/mm/arch/i386/i486/i586/i686/x86_64/counter.hxx @@ -0,0 +1,43 @@ +// file : cult/mm/arch/i386/i486/i586/i686/x86_64/counter.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Boris Kolpackov +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CULT_MM_ARCH_I386_I486_I586_I686_X86_64_COUNTER_HXX +#define CULT_MM_ARCH_I386_I486_I586_I686_X86_64_COUNTER_HXX + +#include + +namespace Cult +{ + namespace MM + { + class Counter: public NonCopyable + { + public: + Counter (); + + // After failure assume the counter has its old value. + // + Void + inc_ref (); + + + // After failure assume the counter has its new value. + // + Boolean + dec_ref (); + + + Size + count () const; + + private: + Size value_; + }; + } +} + +#include + +#endif // CULT_MM_ARCH_I386_I486_I586_I686_X86_64_COUNTER_HXX diff --git a/libcult/cult/mm/arch/i386/i486/i586/i686/x86_64/counter.ixx b/libcult/cult/mm/arch/i386/i486/i586/i686/x86_64/counter.ixx new file mode 100644 index 0000000..9e9e7f4 --- /dev/null +++ b/libcult/cult/mm/arch/i386/i486/i586/i686/x86_64/counter.ixx @@ -0,0 +1,46 @@ +// file : cult/mm/arch/i386/i486/i586/i686/x86_64/counter.ixx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Boris Kolpackov +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +namespace Cult +{ + namespace MM + { + inline + Counter:: + Counter () + : value_ (1) + { + } + + inline + Void Counter:: + inc_ref () + { + asm volatile ("lock; incq %0" + :"=m" (value_) + :"m" (value_)); + } + + inline + Boolean Counter:: + dec_ref () + { + register unsigned char r; + + asm volatile("lock; decq %0; setz %1" + :"=m" (value_), "=rm" (r) + :"m" (value_)); + + return r != 0; + } + + inline + Size Counter:: + count () const + { + return value_; + } + } +} 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 diff --git a/libcult/cult/mm/bits/shptr.hxx b/libcult/cult/mm/bits/shptr.hxx new file mode 100644 index 0000000..7089c53 --- /dev/null +++ b/libcult/cult/mm/bits/shptr.hxx @@ -0,0 +1,85 @@ +// file : cult/mm/bits/shptr.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Boris Kolpackov +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CULT_MM_BITS_SHPTR_HXX +#define CULT_MM_BITS_SHPTR_HXX + +#include + +#include +#include + +namespace Cult +{ + namespace MM + { + namespace Bits + { + template + class Shptr + { + protected: + ~Shptr () + { + if (c_ && c_->dec_ref ()) delete p_; + } + + Shptr (X* p, Counter* c, Boolean inc = true) + : p_ (p), c_ (c) + { + if (c_ && inc) c_->inc_ref (); + } + + protected: + X* + release_ () throw () + { + X* tmp (p_); + + c_ = 0; + p_ = 0; + + return tmp; + } + + protected: + template + Void + assign (Shptr const& bp, Boolean inc = true) + { + assign (bp.p_, bp.c_, inc); + } + + Void + assign (X* p, Counter* c, Boolean inc) + { + if (c_ && c_ == c) throw SelfAssignment (); + + if (c_) + { + Counter* t (c_); + c_ = 0; + p_ = 0; + t->dec_ref (); + } + + if (c && inc) c->inc_ref (); + + p_ = p; + c_ = c; + } + + protected: + template + friend class Shptr; + + X* p_; + Counter* c_; + }; + } + } +} + +#endif // CULT_MM_BITS_SHPTR_HXX diff --git a/libcult/cult/mm/buffer.cxx b/libcult/cult/mm/buffer.cxx new file mode 100644 index 0000000..c3a28ff --- /dev/null +++ b/libcult/cult/mm/buffer.cxx @@ -0,0 +1,140 @@ +// file : cult/mm/buffer.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Boris Kolpackov +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +#include // malloc, realloc, free +#include // memcpy + +namespace Cult +{ + namespace MM + { + Buffer:: + ~Buffer () + { + std::free (b_); + } + + Buffer:: + Buffer (Size capacity, Size size) throw (ZeroCapacity, Bounds, BadAlloc) + : c_ (capacity), s_ (size), p_ (0) + { + if (c_ == 0) throw ZeroCapacity (); + if (s_ > c_) throw Bounds (); + + b_ = std::malloc (c_); + + if (b_ == 0) throw BadAlloc (); + } + + Buffer:: + Buffer (void const* p, size_t s) + : c_ (s), s_ (s), p_ (0) + { + if (c_ == 0) throw ZeroCapacity (); + + b_ = std::malloc (c_); + + if (b_ == 0) throw BadAlloc (); + + std::memcpy (b_, p, s); + } + + + Buffer:: + Buffer (Buffer const& b) + : c_ (b.c_), s_ (b.s_), p_ (b.p_) + { + b_ = std::malloc (c_); + + if (b_ == 0) throw BadAlloc (); + + std::memcpy (b_, b.b_, s_); + } +/* + Buffer& + operator= (Buffer const&) + { + return *this; + } +*/ + + // capacity + // + + Size Buffer:: + capacity () const throw () + { + return c_; + } + + Boolean Buffer:: + capacity (Size c) throw (ZeroCapacity, Bounds, BadAlloc) + { + if (c == 0) throw ZeroCapacity (); + if (s_ > c) throw Bounds (); + + Void* b (std::realloc (b_, c)); + + if (b == 0) throw BadAlloc (); + + c_ = c; + + if (b == b_) return false; + + b_ = b; + + return true; + } + + // size + // + + Size Buffer:: + size () const throw () + { + return s_; + } + + void Buffer:: + size (Size s) throw (Bounds) + { + if (s > c_ || p_ > s) throw Bounds (); + + s_ = s; + } + + // position + // + + Index Buffer:: + position () const throw () + { + return p_; + } + + Void Buffer:: + position (Index p) throw (Bounds) + { + if (p > s_) throw Bounds (); + + p_ = p; + } + + + Char const* Buffer:: + data () const + { + return reinterpret_cast (b_); + } + + Char* Buffer:: + data () + { + return reinterpret_cast (b_); + } + } +} diff --git a/libcult/cult/mm/buffer.hxx b/libcult/cult/mm/buffer.hxx new file mode 100644 index 0000000..d50c824 --- /dev/null +++ b/libcult/cult/mm/buffer.hxx @@ -0,0 +1,80 @@ +// file : cult/mm/buffer.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Boris Kolpackov +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CULT_MM_BUFFER_HXX +#define CULT_MM_BUFFER_HXX + +#include + +#include + +namespace Cult +{ + namespace MM + { + //@@ why can't capacity be zero? + // + + class Buffer + { + public: + struct Bounds: virtual Exception {}; + struct ZeroCapacity: virtual Exception {}; + + public: + virtual + ~Buffer (); + + Buffer (Size capacity, Size size = 0) + throw (ZeroCapacity, Bounds, BadAlloc); + + Buffer (Void const*, Size size); + + Buffer (Buffer const& other); + + private: + Buffer& + operator= (Buffer const&); + + public: + Size + capacity () const throw (); + + // Returns true if the underlying buffer has been moved. + // + Boolean + capacity (Size capacity) throw (ZeroCapacity, Bounds, BadAlloc); + + public: + Size + size () const throw (); + + Void + size (Size size) throw (Bounds); + + public: + Index + position () const throw (); + + Void + position (Index) throw (Bounds); + + public: + Char const* + data () const; + + Char* + data (); + + private: + Void* b_; + Size c_, s_, p_; + }; + } + + using MM::Buffer; +} + +#endif // CULT_MM_BUFFER_HXX diff --git a/libcult/cult/mm/counter.cxx b/libcult/cult/mm/counter.cxx new file mode 100644 index 0000000..7d43e3c --- /dev/null +++ b/libcult/cult/mm/counter.cxx @@ -0,0 +1,14 @@ +// file : cult/mm/counter.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Boris Kolpackov +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include + +namespace Cult +{ + namespace MM + { + StaticPtr > counted; + } +} diff --git a/libcult/cult/mm/counter.hxx b/libcult/cult/mm/counter.hxx new file mode 100644 index 0000000..12e1e70 --- /dev/null +++ b/libcult/cult/mm/counter.hxx @@ -0,0 +1,79 @@ +// file : cult/mm/counter.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Boris Kolpackov +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CULT_MM_COUNTER_HXX +#define CULT_MM_COUNTER_HXX + +#ifdef CULT_THREADS + +// Multi-threaded version is architecture-specific. +// +#include + +#else + +// Single-threaded version. +// + +#include + +namespace Cult +{ + namespace MM + { + class Counter: public NonCopyable + { + public: + Counter (); + + // After failure assume the counter has its old value. + // + Void + inc_ref (); + + + // After failure assume the counter has its new value. + // + Boolean + dec_ref (); + + + Size + count () const; + + private: + Size value_; + }; + } +} + +#include + +#endif // CULT_THREADS + + +#include +#include + +namespace Cult +{ + namespace MM + { + extern StaticPtr > counted; + + + // Non-member inc_ref. Especially useful for messing with `this'. + // + template + X* + inc_ref (X* p) + { + locate (p, *counted)->inc_ref (); + return p; + } + } +} + +#endif // CULT_MM_COUNTER_HXX diff --git a/libcult/cult/mm/counter.ixx b/libcult/cult/mm/counter.ixx new file mode 100644 index 0000000..f807552 --- /dev/null +++ b/libcult/cult/mm/counter.ixx @@ -0,0 +1,38 @@ +// file : cult/mm/counter.ixx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Boris Kolpackov +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +namespace Cult +{ + namespace MM + { + inline + Counter:: + Counter () + : value_ (1) + { + } + + inline + Void Counter:: + inc_ref () + { + ++value_; + } + + inline + Boolean Counter:: + dec_ref () + { + return --value_ == 0; + } + + inline + Size Counter:: + count () const + { + return value_; + } + } +} diff --git a/libcult/cult/mm/evptr.hxx b/libcult/cult/mm/evptr.hxx new file mode 100644 index 0000000..ed0bd93 --- /dev/null +++ b/libcult/cult/mm/evptr.hxx @@ -0,0 +1,221 @@ +// file : cult/mm/evptr.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Boris Kolpackov +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CULT_MM_EVPTR_HXX +#define CULT_MM_EVPTR_HXX + +#include + +#include +#include + +#include //@@ tmp + +namespace Cult +{ + namespace MM + { + // Leaks resource should dec_ref fail. + // + template + class Evptr: public Bits::EvptrBase + { + typedef Bits::EvptrBase Base; + + public: + Evptr (X* p = 0) + : Base (p, 0, locate (p, *counted)) + { + } + + Evptr (Evptr const& ep) + : Base (0, ep.cp_ ? ep.cp_ : ep.p_, ep.c_) + { + } + + template + Evptr (Bits::Transfer const& ct) + : Base (ct.p_, ct.cp_, ct.c_, false) + { + Bits::Transfer& t (const_cast&> (ct)); + + t.c_ = 0; + t.p_ = 0; + t.cp_ = 0; + } + + template + Evptr (Evptr const& ep) + : Base (0, ep.cp_ ? ep.cp_ : ep.p_, ep.c_) + { + //@@ + //printf ("X : %s\n", typeid (X).name ()); + //printf ("Y : %s\n", typeid (Y).name ()); + } + + template + Evptr (Evptr const& ep) + : Base (0, ep.cp_ ? ep.cp_ : ep.p_, ep.c_) + { + //@@ + //printf ("X : %s\n", typeid (X).name ()); + //printf ("Y : %s const\n", typeid (Y).name ()); + } + + public: + // After failure leaves object in destructable state. + // + Evptr& + operator= (Evptr const& ep) + { + this->assign (ep.cp_ ? ep.cp_ : ep.p_, ep.c_); + + return *this; + } + + template + Evptr& + operator= (Evptr const& ep) + { + this->assign (ep.cp_ ? ep.cp_ : ep.p_, ep.c_); + + return *this; + } + + template + Evptr& + operator= (Bits::Transfer const& ct) + { + Bits::Transfer& t (const_cast&> (ct)); + + transfer (t.p_, t.cp_, t.c_); + + t.c_ = 0; + t.p_ = 0; + t.cp_ = 0; + + return *this; + } + + protected: + using Base::get_; + + public: + X* + operator-> () const + { + if (X* p = get_ ()) return p; + + throw NullPointer (); + } + + X& + operator* () const + { + if (X* p = get_ ()) return *p; + + throw NullPointer (); + } + + Bits::Transfer + operator~ () + { + Counter* c (c_); + X* p (p_); + X const* cp (cp_); + + c_ = 0; + p_ = 0; + cp_ = 0; + + return Bits::Transfer (p, cp, c); + } + + public: + using Base::p_; + using Base::cp_; + using Base::c_; + + // Object pointed to by this becomes null. + // + template + Evptr + s_cast () + { + if (p_) + { + Counter* c (c_); + Y* p (static_cast (p_)); + + + c_ = 0; + p_ = 0; + cp_ = 0; + + return Evptr (p, 0, c); + } + else + { + Counter* c (c_); + Y const* cp (static_cast (cp_)); + + c_ = 0; + p_ = 0; + cp_ = 0; + + return Evptr (0, cp, c); + } + } + + // Object pointed to by this becomes null if dynamic_cast succeeds. + // + template + Evptr + d_cast () + { + if (p_) + { + if (Y* p = dynamic_cast (p_)) + { + Counter* c (c_); + + c_ = 0; + p_ = 0; + cp_ = 0; + + return Evptr (p, 0, c); + } + } + else if (Y const* cp = dynamic_cast (cp_)) + { + Counter* c (c_); + + c_ = 0; + p_ = 0; + cp_ = 0; + + return Evptr (0, cp, c); + } + + return Evptr (0); + } + + + private: + Evptr (X* p, X const* cp, Counter* c) // for *_cast + : Base (p, cp, c, false) + { + } + + private: + template + friend class Evptr; + }; + } + + using MM::Evptr; +} + +#endif // CULT_MM_EVPTR_HXX diff --git a/libcult/cult/mm/exception.hxx b/libcult/cult/mm/exception.hxx new file mode 100644 index 0000000..38b3412 --- /dev/null +++ b/libcult/cult/mm/exception.hxx @@ -0,0 +1,31 @@ +// file : cult/mm/exceptions.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Boris Kolpackov +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CULT_MM_EXCEPTIONS_HXX +#define CULT_MM_EXCEPTIONS_HXX + +#include + +#include // std::bad_alloc + +namespace Cult +{ + namespace MM + { + typedef std::bad_alloc StdBadAlloc; + + struct Exception: virtual EH::Exception {}; + + struct BadAlloc: virtual Exception, StdBadAlloc {}; + + //@@ who uses this? + // + struct SelfAssignment: virtual Exception {}; + + struct NullPointer : virtual Exception {}; + } +} + +#endif // CULT_MM_EXCEPTIONS_HXX diff --git a/libcult/cult/mm/new.cxx b/libcult/cult/mm/new.cxx new file mode 100644 index 0000000..2443f1f --- /dev/null +++ b/libcult/cult/mm/new.cxx @@ -0,0 +1,192 @@ +// file : cult/mm/new.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Boris Kolpackov +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include +#include + +#include // std::malloc, std::free + +#include + +namespace +{ + Cult::Trace::Stream& + tout () + { + static Cult::Trace::Stream o ("Cult::MM", 7); + return o; + } +} + +namespace Cult +{ + namespace MM + { + using Bits::Offset; + + + namespace + { + Void* + allocate (Size size, KeyList const& l) throw (StdBadAlloc) + { + Size zone_size (0); + + for (KeyList::Iterator i (l.begin ()); i != l.end (); ++i) + { + zone_size += (*i)->size (); + } + + Size map_size ((l.size () + 1) * sizeof (Offset)); + + //tout () << "allocate: size: " << size + // << " map size: " << map_size + // << " zone size: " << zone_size; + + Char* block (reinterpret_cast ( + std::malloc (size + zone_size + map_size))); + + Char* base (block + zone_size + map_size); + + Offset* map (reinterpret_cast (base) - 1); // map bottom + Char* zone (block + zone_size); // zone bottom + + //tout () << 9 << "allocate:" << '\n' + // << " block : " << (Void*) block << '\n' + // << " base : " << (Void*) base << '\n' + // << " map : " << (Void*) zone << '\n' + // << " zone : " << (Void*) block; + + + // Initialize zone map and construct services. + // + for (KeyList::Iterator i (l.begin ()); i != l.end (); ++i) + { + KeyBase const& k (**i); + + zone -= k.size (); // now at the beginning of the block + + try + { + k.construct (zone); + } + catch (...) + { + std::free (block); + throw StdBadAlloc (); + } + + map->key = &k; + map->offset = base - zone; + + --map; + } + + // Last element. + // + map->key = 0; + map->offset = 0; + + return base; + } + + Void + free (Void* p) throw () + { + Char* base (reinterpret_cast (p)); + + Offset* map (reinterpret_cast (base) - 1); // Map bottom. + + Char* block (reinterpret_cast (map)); + + while (map->key != 0) + { + Char* zone (base - map->offset); + + block = zone; // Last zone is the begining of the block. + + map->key->destroy (zone); + + --map; + } + + //tout () << 9 << "free:" << '\n' + // << " block : " << (Void*) block; + + std::free (block); + } + } + } +} + +namespace Cult +{ + namespace MM + { + namespace Bits + { +#ifdef CULT_THREADS + __thread + Block* first_ __attribute__ ((tls_model ("initial-exec"))) = 0; +#else + Block* first_ = 0; +#endif + } + } +} + +using namespace Cult; + +Void* +operator new (Size s) throw (MM::StdBadAlloc) +{ + return MM::allocate (s, *MM::counted); +} + +Void* +operator new (Size size, MM::KeyList const& list, MM::Bits::Block const& b) + throw (MM::StdBadAlloc) +{ + Void* p (MM::allocate (size, list)); + + const_cast (b).set (p, size); + + return p; +} + +Void +operator delete (Void* p) throw () +{ + if (p) MM::free (p); +} + +Void +operator delete (Void* p, Size) throw () +{ + if (p) MM::free (p); +} + +namespace Cult +{ + namespace MM + { + + Void* ServiceAwareObject:: + operator new (Size size, Bits::Block const& block) + { + Void* p (allocate (size, *MM::counted)); + + const_cast (block).set (p, size); + + return p; + } + + Void ServiceAwareObject:: + operator delete (Void* p, Size) + { + if (p) MM::free (p); + } + } +} diff --git a/libcult/cult/mm/new.hxx b/libcult/cult/mm/new.hxx new file mode 100644 index 0000000..2b815b4 --- /dev/null +++ b/libcult/cult/mm/new.hxx @@ -0,0 +1,297 @@ +// file : cult/mm/new.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Boris Kolpackov +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CULT_MM_NEW_HXX +#define CULT_MM_NEW_HXX + +#include + +#include + +#include + +#include + +namespace Cult +{ + namespace MM + { + class KeyBase + { + public: + // Returned size should be a multiple of a "perfect" size, + // sizeof (size_t) * 2. + // + virtual Size + size () const = 0; + + virtual Void + construct (Void* p) const = 0; + + virtual Void + destroy (Void* p) const = 0; + + virtual + ~KeyBase () + { + } + }; + + + template + class Key: public KeyBase, public NonCopyable + { + public: + Key () + { + } + + virtual Size + size () const + { + //@@ I can do this transparently in allocate(). + // + Size align (sizeof (Size) * 2); + Size size (sizeof (X)); + + return align * (size / align + ((size % align) ? 1 : 0)); + } + + virtual Void + construct (Void* p) const + { + new (p) X; + } + + virtual Void + destroy (Void* p) const + { + reinterpret_cast (p)->~X (); + } + }; + + + struct Absent : virtual Exception {}; + + + namespace Bits + { + Void* + locate (Void const* p, KeyBase const& k) throw (Absent); + + template ::r> + struct Locator; + + template + struct Locator + { + static Void* + locate (X* p, KeyBase const& k) throw (Absent) + { + return Bits::locate (p, k); + } + }; + + template + struct Locator + { + static Void* + locate (X* p, KeyBase const& k) throw (Absent) + { + return Bits::locate (dynamic_cast (p), k); + } + }; + + // Note that this structure has a "perfect" size: sizeof (size_t) * 2. + // If its size is added to the properly-aligned pointer the result will + // still be a properly-aligned pointer. + // + struct Offset //@@ better name would be OffsetMap + { + KeyBase const* key; + Size offset; + }; + } + + + template + inline + Y* + locate (X* p, Key const& k) throw (Absent) + { + return p ? reinterpret_cast (Bits::Locator::locate (p, k)) : 0; + } + + class KeyList + { + public: + KeyList () + : size_ (0) + { + } + + KeyList (KeyBase const& k) + : size_ (1) + { + keys_[0] = &k; + } + + friend KeyList + operator| (KeyList const& list, KeyBase const& key); + + public: + typedef KeyBase const* const* Iterator; + + Iterator + begin () const + { + return keys_; + } + + Iterator + end () const + { + return &(keys_[size_]); + } + + Size + size () const + { + return size_; + } + + private: + KeyBase const* keys_[8]; + Size size_; + }; + + inline KeyList + operator| (KeyList const& list, KeyBase const& key) + { + //@@ Need to throw on overflow. + // + KeyList r (list); + r.keys_[r.size_++] = &key; + return r; + } + + inline KeyList + operator| (KeyBase const& a, KeyBase const& b) + { + return KeyList (a) | b; + } + } +} + +namespace Cult +{ + namespace MM + { + namespace Bits + { + class Block; + +#ifdef CULT_THREADS + extern __thread + Block* first_ __attribute__ ((tls_model ("initial-exec"))); +#else + extern + Block* first_; +#endif + + class Block + { + public: + Block () + { + } + + ~Block () + { + //@@ assert (first_ == this); + first_ = next_; + } + + Void + set (Void* p, Size size) + { + p_ = reinterpret_cast (p); + size_ = size; + + next_ = first_; + first_ = this; + } + + public: + static Void* + locate (Void const* p) + { + return locate (p, first_); + } + + private: + static Void* + locate (Void const* p, Block* b) + { + if (b) + { + if (p >= b->p_ && p < b->p_ + b->size_) return b->p_; + else return locate (p, b->next_); + } + + return 0; + } + + private: + Char* p_; + Size size_; + + Block* next_; + }; + } + } +} + +Cult::Void* +operator new (Cult::Size) throw (Cult::MM::StdBadAlloc); + +Cult::Void* +operator new (Cult::Size, + Cult::MM::KeyList const&, + Cult::MM::Bits::Block const& = Cult::MM::Bits::Block ()) + throw (Cult::MM::StdBadAlloc); + +//@@ Need a special operator new that just allocates memory (to use in +// static_ptr for instance). +// + +Cult::Void +operator delete (Cult::Void*) throw (); + +Cult::Void +operator delete (Cult::Void*, Cult::Size) throw (); + + +namespace Cult +{ + namespace MM + { + // Inherit from this class if you plan to access service objects + // from a ctor. + // + struct ServiceAwareObject + { + static Void* + operator new (Size s, Bits::Block const& b = Bits::Block ()); + + static Void + operator delete (Void* p, Size s); + }; + } +} + +#include + +#endif // CULT_MM_NEW_HXX diff --git a/libcult/cult/mm/new.ixx b/libcult/cult/mm/new.ixx new file mode 100644 index 0000000..c3287fb --- /dev/null +++ b/libcult/cult/mm/new.ixx @@ -0,0 +1,36 @@ +// file : cult/mm/new.ixx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Boris Kolpackov +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +namespace Cult +{ + namespace MM + { + namespace Bits + { + inline + Void* + locate (Void const* p, KeyBase const& k) throw (Absent) + { + if (Void* bp = Block::locate (p)) p = bp; + + Char* base (reinterpret_cast (const_cast (p))); + + Offset* map (reinterpret_cast (base) - 1); // Map bottom. + + while (map->key != 0) + { + if (map->key == &k) + { + return base - map->offset; + } + + --map; + } + + throw Absent (); + } + } + } +} diff --git a/libcult/cult/mm/shptr.hxx b/libcult/cult/mm/shptr.hxx new file mode 100644 index 0000000..6630b1c --- /dev/null +++ b/libcult/cult/mm/shptr.hxx @@ -0,0 +1,139 @@ +// file : cult/mm/Shptr.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Boris Kolpackov +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CULT_MM_SHPTR_HXX +#define CULT_MM_SHPTR_HXX + +#include + +#include +#include + +namespace Cult +{ + namespace MM + { + // Leaks resource should dec_ref fail. + // + template + class Shptr : public Bits::Shptr + { + typedef Bits::Shptr Base; + + public: + Shptr (X* p = 0) + : Base (p, locate (p, *counted), false) + { + } + + Shptr (Shptr const& ap) + : Base (ap.p_, ap.c_) + { + } + + template + Shptr (Shptr const& ap) + : Base (ap.p_, ap.c_) + { + } + + public: + // After failure leaves object in destructable state. + // + Shptr& + operator= (Shptr const& ap) + { + this->assign (ap); + return *this; + } + + template + Shptr& + operator= (Shptr const& ap) + { + this->assign (ap); + return *this; + } + + public: + X* + operator-> () const + { + if (p_ == 0) + throw NullPointer (); + + return p_; + } + + X& + operator* () const + { + if (p_ == 0) + throw NullPointer (); + + return *p_; + } + + // conversion to bool + // + typedef X* (Shptr::*BooleanConvertible)() const; + + operator BooleanConvertible () const throw () + { + return p_ ? &Shptr::operator-> : 0; + } + + public: + X* + get () const throw () + { + return p_; + } + + X* + release () throw () + { + return release_ (); + } + + Size + count () const + { + if (p_ == 0) + throw NullPointer (); + + return c_->count (); + } + + public: + template + Shptr + d_cast () const + { + Y* p (dynamic_cast (p_)); + return Shptr (p, p ? c_ : 0); + } + + private: + Shptr (X* p, Counter* c) + : Base (p, c) + { + } + + template + friend class Shptr; + + protected: + using Base::release_; + + using Base::p_; + using Base::c_; + }; + } + + using MM::Shptr; +} + +#endif // CULT_MM_SHPTR_HXX diff --git a/libcult/cult/mm/static-ptr.hxx b/libcult/cult/mm/static-ptr.hxx new file mode 100644 index 0000000..d3dffbd --- /dev/null +++ b/libcult/cult/mm/static-ptr.hxx @@ -0,0 +1,75 @@ +// file : cult/mm/static-ptr.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Boris Kolpackov +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef CULT_MM_STATIC_PTR_HXX +#define CULT_MM_STATIC_PTR_HXX + +#include + +#include // operator new + +namespace Cult +{ + namespace MM + { + namespace Bits + { + struct Default {}; + } + + template + class StaticPtr: public NonCopyable + { + public: + X& + operator* () const + { + return instance (); + } + + X* + operator-> () const + { + return &instance (); + } + + public: + StaticPtr () + { + if (i_ == 0) i_ = instance_ (); + } + + ~StaticPtr () + { + // Note that we don't delete the object in order to avoid + // destruction order problem. + // + } + + private: + static X& + instance () + { + if (i_ == 0) i_ = instance_ (); + + return *i_; + } + + static X* + instance_ () + { + static X* i = new (KeyList ()) X; + return i; + } + + static X* i_; + }; + + template + X* StaticPtr::i_ = 0; + } +} + +#endif // CULT_MM_STATIC_PTR_HXX -- cgit v1.2.3