summaryrefslogtreecommitdiff
path: root/libcult/cult/mm
diff options
context:
space:
mode:
authorJörg Frings-Fürst <jff@merkur>2014-05-18 16:08:14 +0200
committerJörg Frings-Fürst <jff@merkur>2014-05-18 16:08:14 +0200
commita15cf65c44d5c224169c32ef5495b68c758134b7 (patch)
tree3419f58fc8e1b315ba8171910ee044c5d467c162 /libcult/cult/mm
Imported Upstream version 3.3.0.2upstream/3.3.0.2
Diffstat (limited to 'libcult/cult/mm')
-rw-r--r--libcult/cult/mm/arch/generic/counter.hxx45
-rw-r--r--libcult/cult/mm/arch/generic/counter.ixx47
-rw-r--r--libcult/cult/mm/arch/i386/counter.hxx43
-rw-r--r--libcult/cult/mm/arch/i386/counter.ixx46
-rw-r--r--libcult/cult/mm/arch/i386/i486/i586/i686/x86_64/counter.hxx43
-rw-r--r--libcult/cult/mm/arch/i386/i486/i586/i686/x86_64/counter.ixx46
-rw-r--r--libcult/cult/mm/bits/evptr.hxx379
-rw-r--r--libcult/cult/mm/bits/shptr.hxx85
-rw-r--r--libcult/cult/mm/buffer.cxx140
-rw-r--r--libcult/cult/mm/buffer.hxx80
-rw-r--r--libcult/cult/mm/counter.cxx14
-rw-r--r--libcult/cult/mm/counter.hxx79
-rw-r--r--libcult/cult/mm/counter.ixx38
-rw-r--r--libcult/cult/mm/evptr.hxx221
-rw-r--r--libcult/cult/mm/exception.hxx31
-rw-r--r--libcult/cult/mm/new.cxx192
-rw-r--r--libcult/cult/mm/new.hxx297
-rw-r--r--libcult/cult/mm/new.ixx36
-rw-r--r--libcult/cult/mm/shptr.hxx139
-rw-r--r--libcult/cult/mm/static-ptr.hxx75
20 files changed, 2076 insertions, 0 deletions
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 <boris@kolpackov.net>
+// 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 <cult/types/fundamental.hxx>
+#include <cult/sched/spin.hxx>
+
+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 <cult/mm/arch/generic/counter.ixx>
+
+#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 <boris@kolpackov.net>
+// copyright : Copyright (c) 2005-2010 Boris Kolpackov
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+#include <cult/sched/lock.hxx>
+
+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 <boris@kolpackov.net>
+// 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 <cult/types/fundamental.hxx>
+
+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 <cult/mm/arch/i386/counter.ixx>
+
+#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 <boris@kolpackov.net>
+// 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 <boris@kolpackov.net>
+// 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 <cult/types/fundamental.hxx>
+
+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 <cult/mm/arch/i386/i486/i586/i686/x86_64/counter.ixx>
+
+#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 <boris@kolpackov.net>
+// 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 <boris@kolpackov.net>
+// 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 <cult/types/fundamental.hxx>
+
+#include <cult/meta/answer.hxx>
+
+#include <cult/mm/counter.hxx>
+#include <cult/mm/exception.hxx>
+
+#include <cassert> // assert
+
+namespace Cult
+{
+ namespace MM
+ {
+
+ //@@ Should be in mm/evptr.hxx
+ //
+ struct Clone: virtual Exception {};
+
+ template <typename X>
+ class Evptr;
+
+ namespace Bits
+ {
+ template <typename x, Evptr<x> (x::*f) () const = &x::clone>
+ struct Helper;
+
+ //@@ Should be generalized and moved to Cult::meta
+ //
+ template <typename X>
+ struct has_clone
+ {
+ template <typename y>
+ static Meta::Yes
+ test (Helper<y>*);
+
+ template <typename>
+ static Meta::No
+ test (...);
+
+ static Boolean const r = sizeof (test<X> (0)) == sizeof (Meta::Yes);
+ };
+
+ //@@ Need to incorporate tests for polymorpism and NonCopyable.
+ //
+
+ template <typename X, Boolean = has_clone<X>::r>
+ struct Cloner;
+
+ template <typename X>
+ struct Cloner<X, true>
+ {
+ static X*
+ clone (X const* cp)
+ {
+ return cp->clone ().release ();
+ }
+ };
+
+ template <typename X>
+ struct Cloner<X, false>
+ {
+ static X*
+ clone (X const*)
+ {
+ throw MM::Clone ();
+ }
+ };
+ }
+
+ namespace Bits
+ {
+ template <typename X>
+ class Transfer;
+ }
+
+ namespace Bits
+ {
+ template <typename X>
+ 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<X*> (cp_);
+ cp_ = 0;
+ }
+ else
+ {
+ assert (cp_ != 0);
+
+ //p_ = cp_->clone ().release ();
+
+ p_ = Cloner<X>::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 <typename>
+ friend class Evptr;
+
+ template <typename>
+ friend class Transfer;
+
+ mutable X* p_;
+ mutable X const* cp_;
+ mutable Counter* c_;
+ };
+
+
+ template <typename X>
+ class EvptrBase<X const>
+ {
+ 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 <typename>
+ friend class Evptr;
+
+ template <typename>
+ friend class Transfer;
+
+ mutable X const* p_;
+ mutable X const* cp_;
+ mutable Counter* c_;
+ };
+ }
+
+ namespace Bits
+ {
+ template <typename X>
+ class Transfer : protected EvptrBase<X>
+ {
+ public:
+ Transfer (Transfer<X> const& ct)
+ : EvptrBase<X> (ct.p_, ct.cp_, ct.c_, false)
+ {
+ Transfer<X>& t (const_cast<Transfer<X>&> (ct));
+
+ t.c_ = 0;
+ t.p_ = 0;
+ t.cp_ = 0;
+ }
+
+ private:
+ Transfer (X* p, X const* cp, Counter* c)
+ : EvptrBase<X> (p, cp, c, false)
+ {
+ }
+
+ template <typename>
+ friend class Evptr;
+
+ private:
+ Transfer<X>&
+ operator= (Transfer<X> 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 <boris@kolpackov.net>
+// 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 <cult/types/fundamental.hxx>
+
+#include <cult/mm/counter.hxx>
+#include <cult/mm/exception.hxx>
+
+namespace Cult
+{
+ namespace MM
+ {
+ namespace Bits
+ {
+ template <typename X>
+ 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<typename y>
+ Void
+ assign (Shptr<y> 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 <typename>
+ 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 <boris@kolpackov.net>
+// copyright : Copyright (c) 2005-2010 Boris Kolpackov
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+#include <cult/mm/buffer.hxx>
+
+#include <cstdlib> // malloc, realloc, free
+#include <cstring> // 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<Char const*> (b_);
+ }
+
+ Char* Buffer::
+ data ()
+ {
+ return reinterpret_cast<Char*> (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 <boris@kolpackov.net>
+// 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 <cult/types/fundamental.hxx>
+
+#include <cult/mm/exception.hxx>
+
+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 <boris@kolpackov.net>
+// copyright : Copyright (c) 2005-2010 Boris Kolpackov
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+#include <cult/mm/counter.hxx>
+
+namespace Cult
+{
+ namespace MM
+ {
+ StaticPtr<Key<Counter> > 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 <boris@kolpackov.net>
+// 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 <cult/mm/arch/counter.hxx>
+
+#else
+
+// Single-threaded version.
+//
+
+#include <cult/types/fundamental.hxx>
+
+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 <cult/mm/counter.ixx>
+
+#endif // CULT_THREADS
+
+
+#include <cult/mm/new.hxx>
+#include <cult/mm/static-ptr.hxx>
+
+namespace Cult
+{
+ namespace MM
+ {
+ extern StaticPtr<Key<Counter> > counted;
+
+
+ // Non-member inc_ref. Especially useful for messing with `this'.
+ //
+ template <typename X>
+ 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 <boris@kolpackov.net>
+// 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 <boris@kolpackov.net>
+// 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 <cult/types/fundamental.hxx>
+
+#include <cult/mm/exception.hxx>
+#include <cult/mm/bits/evptr.hxx>
+
+#include <typeinfo> //@@ tmp
+
+namespace Cult
+{
+ namespace MM
+ {
+ // Leaks resource should dec_ref fail.
+ //
+ template <typename X>
+ class Evptr: public Bits::EvptrBase<X>
+ {
+ typedef Bits::EvptrBase<X> 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 <typename Y>
+ Evptr (Bits::Transfer<Y> const& ct)
+ : Base (ct.p_, ct.cp_, ct.c_, false)
+ {
+ Bits::Transfer<Y>& t (const_cast<Bits::Transfer<Y>&> (ct));
+
+ t.c_ = 0;
+ t.p_ = 0;
+ t.cp_ = 0;
+ }
+
+ template <typename Y>
+ Evptr (Evptr<Y> 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 <typename Y>
+ Evptr (Evptr<Y const> 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 <typename Y>
+ Evptr&
+ operator= (Evptr<Y> const& ep)
+ {
+ this->assign (ep.cp_ ? ep.cp_ : ep.p_, ep.c_);
+
+ return *this;
+ }
+
+ template <typename Y>
+ Evptr&
+ operator= (Bits::Transfer<Y> const& ct)
+ {
+ Bits::Transfer<Y>& t (const_cast<Bits::Transfer<Y>&> (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<X>
+ operator~ ()
+ {
+ Counter* c (c_);
+ X* p (p_);
+ X const* cp (cp_);
+
+ c_ = 0;
+ p_ = 0;
+ cp_ = 0;
+
+ return Bits::Transfer<X> (p, cp, c);
+ }
+
+ public:
+ using Base::p_;
+ using Base::cp_;
+ using Base::c_;
+
+ // Object pointed to by this becomes null.
+ //
+ template<typename Y>
+ Evptr<Y>
+ s_cast ()
+ {
+ if (p_)
+ {
+ Counter* c (c_);
+ Y* p (static_cast<Y*> (p_));
+
+
+ c_ = 0;
+ p_ = 0;
+ cp_ = 0;
+
+ return Evptr<Y> (p, 0, c);
+ }
+ else
+ {
+ Counter* c (c_);
+ Y const* cp (static_cast<Y const*> (cp_));
+
+ c_ = 0;
+ p_ = 0;
+ cp_ = 0;
+
+ return Evptr<Y> (0, cp, c);
+ }
+ }
+
+ // Object pointed to by this becomes null if dynamic_cast succeeds.
+ //
+ template<typename Y>
+ Evptr<Y>
+ d_cast ()
+ {
+ if (p_)
+ {
+ if (Y* p = dynamic_cast<Y*> (p_))
+ {
+ Counter* c (c_);
+
+ c_ = 0;
+ p_ = 0;
+ cp_ = 0;
+
+ return Evptr<Y> (p, 0, c);
+ }
+ }
+ else if (Y const* cp = dynamic_cast<Y const*> (cp_))
+ {
+ Counter* c (c_);
+
+ c_ = 0;
+ p_ = 0;
+ cp_ = 0;
+
+ return Evptr<Y> (0, cp, c);
+ }
+
+ return Evptr<Y> (0);
+ }
+
+
+ private:
+ Evptr (X* p, X const* cp, Counter* c) // for *_cast
+ : Base (p, cp, c, false)
+ {
+ }
+
+ private:
+ template <typename>
+ 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 <boris@kolpackov.net>
+// 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 <cult/eh/exception.hxx>
+
+#include <new> // 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 <boris@kolpackov.net>
+// copyright : Copyright (c) 2005-2010 Boris Kolpackov
+// license : GNU GPL v2 + exceptions; see accompanying LICENSE file
+
+#include <cult/mm/new.hxx>
+#include <cult/mm/counter.hxx>
+
+#include <cstdlib> // std::malloc, std::free
+
+#include <cult/trace/stream.hxx>
+
+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<Char*> (
+ std::malloc (size + zone_size + map_size)));
+
+ Char* base (block + zone_size + map_size);
+
+ Offset* map (reinterpret_cast<Offset*> (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<Char*> (p));
+
+ Offset* map (reinterpret_cast<Offset*> (base) - 1); // Map bottom.
+
+ Char* block (reinterpret_cast<Char*> (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<MM::Bits::Block&> (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<MM::Bits::Block&> (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 <boris@kolpackov.net>
+// 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 <cult/config.hxx>
+
+#include <cult/types/fundamental.hxx>
+
+#include <cult/mm/exception.hxx>
+
+#include <cult/meta/polymorphic-p.hxx>
+
+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 <typename X>
+ 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<X*> (p)->~X ();
+ }
+ };
+
+
+ struct Absent : virtual Exception {};
+
+
+ namespace Bits
+ {
+ Void*
+ locate (Void const* p, KeyBase const& k) throw (Absent);
+
+ template <typename X, Boolean poly = Meta::polymorphic_p<X>::r>
+ struct Locator;
+
+ template <typename X>
+ struct Locator<X, false>
+ {
+ static Void*
+ locate (X* p, KeyBase const& k) throw (Absent)
+ {
+ return Bits::locate (p, k);
+ }
+ };
+
+ template <typename X>
+ struct Locator<X, true>
+ {
+ static Void*
+ locate (X* p, KeyBase const& k) throw (Absent)
+ {
+ return Bits::locate (dynamic_cast<Void const*> (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 <typename X, typename Y>
+ inline
+ Y*
+ locate (X* p, Key<Y> const& k) throw (Absent)
+ {
+ return p ? reinterpret_cast<Y*> (Bits::Locator<X>::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<Char*> (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 <cult/mm/new.ixx>
+
+#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 <boris@kolpackov.net>
+// 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<Char*> (const_cast<Void*> (p)));
+
+ Offset* map (reinterpret_cast<Offset*> (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 <boris@kolpackov.net>
+// 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 <cult/types/fundamental.hxx>
+
+#include <cult/mm/exception.hxx>
+#include <cult/mm/bits/shptr.hxx>
+
+namespace Cult
+{
+ namespace MM
+ {
+ // Leaks resource should dec_ref fail.
+ //
+ template <typename X>
+ class Shptr : public Bits::Shptr<X>
+ {
+ typedef Bits::Shptr<X> Base;
+
+ public:
+ Shptr (X* p = 0)
+ : Base (p, locate (p, *counted), false)
+ {
+ }
+
+ Shptr (Shptr const& ap)
+ : Base (ap.p_, ap.c_)
+ {
+ }
+
+ template <typename Y>
+ Shptr (Shptr<Y> 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 <typename Y>
+ Shptr&
+ operator= (Shptr<Y> 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<X>::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<typename Y>
+ Shptr<Y>
+ d_cast () const
+ {
+ Y* p (dynamic_cast<Y*> (p_));
+ return Shptr<Y> (p, p ? c_ : 0);
+ }
+
+ private:
+ Shptr (X* p, Counter* c)
+ : Base (p, c)
+ {
+ }
+
+ template <typename>
+ 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 <boris@kolpackov.net>
+// 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 <cult/types/fundamental.hxx>
+
+#include <cult/mm/new.hxx> // operator new
+
+namespace Cult
+{
+ namespace MM
+ {
+ namespace Bits
+ {
+ struct Default {};
+ }
+
+ template <typename X, typename Id = Bits::Default>
+ 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 <typename X, typename Id>
+ X* StaticPtr<X, Id>::i_ = 0;
+ }
+}
+
+#endif // CULT_MM_STATIC_PTR_HXX