summaryrefslogtreecommitdiff
path: root/libodb/odb/details/shared-ptr
diff options
context:
space:
mode:
Diffstat (limited to 'libodb/odb/details/shared-ptr')
-rw-r--r--libodb/odb/details/shared-ptr/base.cxx83
-rw-r--r--libodb/odb/details/shared-ptr/base.hxx131
-rw-r--r--libodb/odb/details/shared-ptr/base.ixx119
-rw-r--r--libodb/odb/details/shared-ptr/base.txx198
-rw-r--r--libodb/odb/details/shared-ptr/counter-type.hxx23
-rw-r--r--libodb/odb/details/shared-ptr/exception.hxx31
6 files changed, 585 insertions, 0 deletions
diff --git a/libodb/odb/details/shared-ptr/base.cxx b/libodb/odb/details/shared-ptr/base.cxx
new file mode 100644
index 0000000..d937400
--- /dev/null
+++ b/libodb/odb/details/shared-ptr/base.cxx
@@ -0,0 +1,83 @@
+// file : odb/details/shared-ptr/base.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/shared-ptr/base.hxx>
+#include <odb/details/shared-ptr/exception.hxx>
+
+using std::size_t;
+
+namespace odb
+{
+ namespace details
+ {
+ share shared = share (1);
+ share exclusive = share (2);
+
+ const char* not_shared::
+ what () const ODB_NOTHROW_NOEXCEPT
+ {
+ return "object is not shared";
+ }
+
+ not_shared* not_shared::
+ clone () const
+ {
+ return new not_shared (*this);
+ }
+
+ namespace bits
+ {
+ size_t* locator_common::
+ counter (void* x)
+ {
+ size_t* p (static_cast<size_t*> (x));
+
+ if (*(--p) != 0xDEADBEEF)
+ throw not_shared ();
+
+ return --p;
+ }
+ }
+ }
+}
+
+void*
+#ifdef ODB_CXX11
+operator new (size_t n, odb::details::share s)
+#else
+operator new (size_t n, odb::details::share s) throw (std::bad_alloc)
+#endif
+{
+ if (s == odb::details::shared)
+ {
+ // Here we need to make sure we don't break the alignment of the
+ // returned block. For that we need to know the maximum alignment
+ // of this platform. Twice the pointer size is a good guess for
+ // most platforms.
+ //
+ size_t* p = static_cast<size_t*> (operator new (n + 2 * sizeof (size_t)));
+ *p++ = 1; // Initial count.
+ *p++ = 0xDEADBEEF; // Signature.
+ return p;
+ }
+ else
+ return operator new (n);
+
+}
+
+void
+operator delete (void* p, odb::details::share s) ODB_NOTHROW_NOEXCEPT
+{
+ // This version of operator delete is only called when the c-tor
+ // fails. In this case there is no object and we can just free the
+ // memory.
+ //
+ if (s == odb::details::shared)
+ {
+ size_t* sp = static_cast<size_t*> (p);
+ sp -= 2;
+ operator delete (sp);
+ }
+ else
+ operator delete (p);
+}
diff --git a/libodb/odb/details/shared-ptr/base.hxx b/libodb/odb/details/shared-ptr/base.hxx
new file mode 100644
index 0000000..8cd4c86
--- /dev/null
+++ b/libodb/odb/details/shared-ptr/base.hxx
@@ -0,0 +1,131 @@
+// file : odb/details/shared-ptr/base.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_SHARED_PTR_BASE_HXX
+#define ODB_DETAILS_SHARED_PTR_BASE_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/config.hxx> // ODB_CXX11, ODB_NOTHROW_NOEXCEPT
+
+#include <new>
+#include <cstddef> // std::size_t
+
+#ifdef ODB_CXX11
+#include <atomic>
+#endif
+
+#include <odb/details/export.hxx>
+#include <odb/details/shared-ptr/counter-type.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ struct share
+ {
+ explicit
+ share (char id);
+
+ bool
+ operator== (share) const;
+
+ private:
+ char id_;
+ };
+
+ extern LIBODB_EXPORT share shared;
+ extern LIBODB_EXPORT share exclusive;
+ }
+}
+
+#ifdef ODB_CXX11
+LIBODB_EXPORT void*
+operator new (std::size_t, odb::details::share);
+#else
+LIBODB_EXPORT void*
+operator new (std::size_t, odb::details::share) throw (std::bad_alloc);
+#endif
+
+LIBODB_EXPORT void
+operator delete (void*, odb::details::share) ODB_NOTHROW_NOEXCEPT;
+
+namespace odb
+{
+ namespace details
+ {
+ class LIBODB_EXPORT shared_base
+ {
+ public:
+ shared_base ();
+ shared_base (const shared_base&);
+ shared_base&
+ operator= (const shared_base&);
+
+ void
+ _inc_ref ();
+
+ bool
+ _dec_ref ();
+
+ std::size_t
+ _ref_count () const;
+
+#ifdef ODB_CXX11
+ void*
+ operator new (std::size_t);
+
+ void*
+ operator new (std::size_t, share);
+#else
+ void*
+ operator new (std::size_t) throw (std::bad_alloc);
+
+ void*
+ operator new (std::size_t, share) throw (std::bad_alloc);
+#endif
+
+ void
+ operator delete (void*, share) ODB_NOTHROW_NOEXCEPT;
+
+ void
+ operator delete (void*) ODB_NOTHROW_NOEXCEPT;
+
+ struct refcount_callback
+ {
+ void* arg;
+
+ // Return true if the object should be deleted, false otherwise.
+ //
+ bool (*zero_counter) (void*);
+ };
+
+ protected:
+#ifdef ODB_CXX11
+ std::atomic<std::size_t> counter_;
+#else
+ std::size_t counter_;
+#endif
+ refcount_callback* callback_;
+ };
+
+ template <typename X>
+ inline X*
+ inc_ref (X*);
+
+ template <typename X>
+ inline void
+ dec_ref (X*);
+
+ template <typename X>
+ inline std::size_t
+ ref_count (const X*);
+ }
+}
+
+#include <odb/details/shared-ptr/base.ixx>
+#include <odb/details/shared-ptr/base.txx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_SHARED_PTR_BASE_HXX
diff --git a/libodb/odb/details/shared-ptr/base.ixx b/libodb/odb/details/shared-ptr/base.ixx
new file mode 100644
index 0000000..1e2fd4b
--- /dev/null
+++ b/libodb/odb/details/shared-ptr/base.ixx
@@ -0,0 +1,119 @@
+// file : odb/details/shared-ptr/base.ixx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+namespace odb
+{
+ namespace details
+ {
+ // share
+ //
+
+ inline share::
+ share (char id)
+ : id_ (id)
+ {
+ }
+
+ inline bool share::
+ operator== (share x) const
+ {
+ return id_ == x.id_;
+ }
+
+ // shared_base
+ //
+
+ inline shared_base::
+ shared_base ()
+ : counter_ (1), callback_ (0)
+ {
+ }
+
+ inline shared_base::
+ shared_base (const shared_base&)
+ : counter_ (1), callback_ (0)
+ {
+ }
+
+ inline shared_base& shared_base::
+ operator= (const shared_base&)
+ {
+ return *this;
+ }
+
+ inline void shared_base::
+ _inc_ref ()
+ {
+#ifdef ODB_CXX11
+ counter_.fetch_add (1, std::memory_order_relaxed);
+#else
+ ++counter_;
+#endif
+ }
+
+ inline bool shared_base::
+ _dec_ref ()
+ {
+ // While there are ways to avoid acquire (which is unnecessary except
+ // when the counter drops to zero), for our use-cases we'd rather keep
+ // it simple.
+ //
+ return
+#ifdef ODB_CXX11
+ counter_.fetch_sub (1, std::memory_order_acq_rel) == 1
+#else
+ --counter_ == 0
+#endif
+ ? callback_ == 0 || callback_->zero_counter (callback_->arg)
+ : false;
+ }
+
+ inline std::size_t shared_base::
+ _ref_count () const
+ {
+#ifdef ODB_CXX11
+ return counter_.load (std::memory_order_relaxed);
+#else
+ return counter_;
+#endif
+ }
+
+#ifdef ODB_CXX11
+ inline void* shared_base::
+ operator new (std::size_t n)
+ {
+ return ::operator new (n);
+ }
+
+ inline void* shared_base::
+ operator new (std::size_t n, share)
+ {
+ return ::operator new (n);
+ }
+#else
+ inline void* shared_base::
+ operator new (std::size_t n) throw (std::bad_alloc)
+ {
+ return ::operator new (n);
+ }
+
+ inline void* shared_base::
+ operator new (std::size_t n, share) throw (std::bad_alloc)
+ {
+ return ::operator new (n);
+ }
+#endif
+
+ inline void shared_base::
+ operator delete (void* p, share) ODB_NOTHROW_NOEXCEPT
+ {
+ ::operator delete (p);
+ }
+
+ inline void shared_base::
+ operator delete (void* p) ODB_NOTHROW_NOEXCEPT
+ {
+ ::operator delete (p);
+ }
+ }
+}
diff --git a/libodb/odb/details/shared-ptr/base.txx b/libodb/odb/details/shared-ptr/base.txx
new file mode 100644
index 0000000..77a957d
--- /dev/null
+++ b/libodb/odb/details/shared-ptr/base.txx
@@ -0,0 +1,198 @@
+// file : odb/details/shared-ptr/base.txx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/meta/answer.hxx>
+#include <odb/details/meta/polymorphic-p.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ namespace bits
+ {
+ // Support for locating the counter in the memory block.
+ //
+ struct LIBODB_EXPORT locator_common
+ {
+ static std::size_t*
+ counter (void*);
+ };
+
+ template <typename X, bool poly = meta::polymorphic_p<X>::result>
+ struct locator;
+
+ template <typename X>
+ struct locator<X, false>: locator_common
+ {
+ static std::size_t*
+ counter (X* x)
+ {
+ return locator_common::counter (x);
+ }
+ };
+
+ template <typename X>
+ struct locator<X, true>: locator_common
+ {
+ static std::size_t*
+ counter (X* x)
+ {
+ return locator_common::counter (dynamic_cast<void*> (x));
+ }
+ };
+
+ template <typename X>
+ std::size_t*
+ counter (const X* p)
+ {
+ return bits::locator<X>::counter (const_cast<X*> (p));
+ }
+
+ // Counter type and operations.
+ //
+ meta::no test (...);
+ meta::yes test (shared_base*);
+
+ template <typename X,
+ std::size_t A = sizeof (bits::test (reinterpret_cast<X*> (0)))>
+ struct counter_type;
+
+ template <typename X>
+ struct counter_type<X, sizeof (meta::no)>
+ {
+ typedef typename details::counter_type<X>::counter r;
+ };
+
+ template <typename X>
+ struct counter_type<X, sizeof (meta::yes)>
+ {
+ typedef shared_base r;
+ };
+
+ template <typename X, typename Y>
+ struct counter_ops;
+
+ template <typename X>
+ struct counter_ops<X, X>
+ {
+ counter_ops (const X* p) : counter_ (p ? bits::counter (p) : 0) {}
+ counter_ops (const counter_ops& x) : counter_ (x.counter_) {}
+
+ template <typename Z>
+ counter_ops (const counter_ops<Z, Z>& x) : counter_ (x.counter_) {}
+
+ counter_ops&
+ operator= (const counter_ops& x)
+ {
+ counter_ = x.counter_;
+ return *this;
+ }
+
+ template <typename Z>
+ counter_ops&
+ operator= (const counter_ops<Z, Z>& x)
+ {
+ counter_ = x.counter_;
+ return *this;
+ }
+
+ void
+ reset (const X* p)
+ {
+ counter_ = p ? bits::counter (p) : 0;
+ }
+
+ void
+ inc (X*)
+ {
+ (*counter_)++;
+ }
+
+ void
+ dec (X* p)
+ {
+ if (--(*counter_) == 0)
+ {
+ p->~X ();
+
+ // Counter is the top of the memory block.
+ //
+ operator delete (counter_);
+ }
+ }
+
+ std::size_t
+ count (const X*) const
+ {
+ return *counter_;
+ }
+
+ std::size_t* counter_;
+ };
+
+ template <typename Y>
+ struct counter_ops<shared_base, Y>
+ {
+ counter_ops (const Y*) {}
+ counter_ops (const counter_ops&) {}
+
+ template <typename Z>
+ counter_ops (const counter_ops<shared_base, Z>&) {}
+
+ counter_ops&
+ operator= (const counter_ops&)
+ {
+ return *this;
+ }
+
+ template <typename Z>
+ counter_ops&
+ operator= (const counter_ops<shared_base, Z>&)
+ {
+ return *this;
+ }
+
+ void
+ reset (const Y*) {}
+
+ void
+ inc (shared_base* p) {p->_inc_ref ();}
+
+ void
+ dec (Y* p)
+ {
+ if (static_cast<shared_base*> (p)->_dec_ref ())
+ delete p;
+ }
+
+ std::size_t
+ count (const shared_base* p) const {return p->_ref_count ();}
+ };
+ }
+
+ template <typename X>
+ inline X*
+ inc_ref (X* p)
+ {
+ bits::counter_ops<typename bits::counter_type<X>::r, X> c (p);
+ c.inc (p);
+ return p;
+ }
+
+ template <typename X>
+ inline void
+ dec_ref (X* p)
+ {
+ bits::counter_ops<typename bits::counter_type<X>::r, X> c (p);
+ c.dec (p);
+ }
+
+ template <typename X>
+ inline std::size_t
+ ref_count (const X* p)
+ {
+ bits::counter_ops<typename bits::counter_type<X>::r, X> c (p);
+ return c.count (p);
+ }
+ }
+}
diff --git a/libodb/odb/details/shared-ptr/counter-type.hxx b/libodb/odb/details/shared-ptr/counter-type.hxx
new file mode 100644
index 0000000..2b6caad
--- /dev/null
+++ b/libodb/odb/details/shared-ptr/counter-type.hxx
@@ -0,0 +1,23 @@
+// file : odb/details/shared-ptr/counter-type.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_SHARED_PTR_COUNTER_TYPE_HXX
+#define ODB_DETAILS_SHARED_PTR_COUNTER_TYPE_HXX
+
+#include <odb/pre.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ template <typename X>
+ struct counter_type
+ {
+ typedef X counter;
+ };
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_SHARED_PTR_COUNTER_TYPE_HXX
diff --git a/libodb/odb/details/shared-ptr/exception.hxx b/libodb/odb/details/shared-ptr/exception.hxx
new file mode 100644
index 0000000..0ed50be
--- /dev/null
+++ b/libodb/odb/details/shared-ptr/exception.hxx
@@ -0,0 +1,31 @@
+// file : odb/details/shared-ptr/exception.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_SHARED_PTR_EXCEPTION_HXX
+#define ODB_DETAILS_SHARED_PTR_EXCEPTION_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/exception.hxx>
+
+#include <odb/details/config.hxx> // ODB_NOTHROW_NOEXCEPT
+#include <odb/details/export.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ struct LIBODB_EXPORT not_shared: exception
+ {
+ virtual const char*
+ what () const ODB_NOTHROW_NOEXCEPT;
+
+ virtual not_shared*
+ clone () const;
+ };
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_SHARED_PTR_EXCEPTION_HXX