|
Boost : |
From: Greg Colvin (gcolvin_at_[hidden])
Date: 2000-01-30 15:03:00
> > Greg,
> >
> > I really think it's time to trot out your new implementation which uses
> > deque so we can test against that (I'm thinking the allocation cost will be
> > much lower since the deque works like a pool allocator). If you need help
> > finishing it, please call on me.
> >
> > -Dave
>
> I've appended cyclic_ptr.hpp and cyclic_ptr.cpp, which compile with EDG's latest,
> and are not conditionalized for anything else. Define NDEBUG for performance
> tests, but note that I haven't yet tuned the allocation.
In reading my post I saw some mistakes the compiler and my test program missed,
one of which (a missing inline declaration) might slow down assignment.
////////////////////////////////////////////////////////////////////////////////
// cyclic_ptr.hpp
namespace boost {
template<typename> struct weak_ptr;
/////////////////////////////////////////////////////////////////////////////
// Each handle refers to a deleter_base object, and cyclic_ptr constructor
// takes an optional deleter argument. Derive from deleter to customize
// destroy function, but don't mess with recycle.
struct deleter_base {
virtual void destroy(void*)=0;
virtual void recycle(void*)=0;
};
template<typename T> struct deleter : deleter_base {
void destroy(void* p) { delete(reinterpret_cast<T*>(p)); }
void recycle(void* p) { if (T* q = reinterpret_cast<T*>(p)) *q = *q; }
};
/////////////////////////////////////////////////////////////////////////////
// Recycler handle class for cyclic_ptr and weak_ptr.
// Collect cycles of cyclic_ptr by calling recycler::recycle().
struct recycler {
static void recycle() throw();
private:
template<typename> friend struct recyclable_base;
template<typename> friend struct cyclic_ptr;
template<typename> friend struct weak_ptr;
recycler() : p(0),n(0),n_weak(0),action(0) {}
void* p;
long n, n_weak;
deleter_base* action;
void do_it();
void decrement();
void decrement_weak();
static recycler* alloc(void*,deleter_base*);
static void free(recycler*);
};
/////////////////////////////////////////////////////////////////////////////
// Base class for cyclic_ptr and weak_ptr.
// Initializes handle with appropriate deleter.
template<typename T> class recyclable_base {
template<typename> friend struct cyclic_ptr;
template<typename> friend struct weak_ptr;
recycler* ph;
T* p;
recycler* new_handle(T* q,deleter_base* d) { return recycler::alloc(q,d);}
static deleter<T>& default_deleter() { static deleter<T> r; return r; }
};
/////////////////////////////////////////////////////////////////////////////
// The object pointed to is deleted when the last cyclic_ptr pointing to it
// is destroyed, or when a recycler::recycle() call finds no cyclic_ptr to
// the object outside a cycle.
template<typename T> struct cyclic_ptr : recyclable_base<T> {
typedef T element_type;
long use_count() const throw() { return ph->n; }
bool unique() const throw() { return use_count() == 1; }
explicit
cyclic_ptr(T* q=0,deleter<T>& r=default_deleter()) {
p = q, ph = new_handle(q,&r), ph->n = 1;
}
cyclic_ptr(const cyclic_ptr& r) throw() {
p = r.p, ph = r.ph, ++ph->n;
}
~cyclic_ptr() { ph->decrement(); }
cyclic_ptr& operator=(const cyclic_ptr& r) throw() {
copy(r);
return *this;
}
template<typename U> cyclic_ptr(const cyclic_ptr<U>& r) throw() {
p = r.p, ph = r.ph, ++ph->n;
}
template<typename U> cyclic_ptr& operator=(const cyclic_ptr<U>& r) throw() {
copy(r);
return *this;
}
template<typename U> cyclic_ptr(std::auto_ptr<U>& r) {
p = r.release(), ph = new_handle(p,&default_deleter()), ph->n = 1;
}
template<typename U> cyclic_ptr& operator=(std::auto_ptr<U>& r) {
p = r.release(), ph = new_handle(p,&default_deleter()), ph->n = 1;
return *this;
}
template<typename U> cyclic_ptr(const weak_ptr<U>&) throw();
template<typename U> cyclic_ptr& operator=(const weak_ptr<U>&) throw();
void reset(T* p=0,deleter<T>& r=default_deleter()) {
if (--ph->n == 0)
free(ph);
ph = new_handle(p,&r), ph->n = 1;
}
T* get() const throw() { return p; }
T& operator*() const throw() { return *get(); }
T* operator->() const throw() { return get(); }
operator T*() const throw() { return get(); }
private:
template<typename U> void copy(const recyclable_base<U>&);
};
/////////////////////////////////////////////////////////////////////////////
// A weak_ptr does not prevent a shared object from being destroyed, but
// when it is destroyed weak_ptr::get() returns 0.
template<typename T> struct weak_ptr : recyclable_base<T> {
typedef T element_type;
weak_ptr() { p = 0, ph = new_handle(0,0), ph->n_weak = 1; }
weak_ptr(const weak_ptr& r) throw() { p = r.p, ph = r.ph, ++ph->n_weak; }
~weak_ptr() { if (ph) ph->decrement_weak(); }
weak_ptr& operator=(const weak_ptr& r) throw() {
copy(r);
return *this;
}
template<typename U> weak_ptr(const weak_ptr<U>& r) throw() {
p = r.p, ph = r.ph, ++ph->n_weak;
}
template<typename U> weak_ptr& operator=(const weak_ptr<U>& r) throw() {
copy(r);
return *this;
}
template<typename U> weak_ptr(const cyclic_ptr<U>& r) throw() {
p = r.p, ph = r.ph, ++ph->n_weak;
}
template<typename U> weak_ptr& operator=(const cyclic_ptr<U>& r) throw() {
copy(r);
return *this;
}
T* get() const throw() {
return ph->n ? p : 0; }
T& operator*() const throw() { return *get(); }
T* operator->() const throw() { return get(); }
operator T*() const throw() { return get(); }
private:
template<typename U> void copy(const recyclable_base<U>&);
};
template<typename T> template<typename U>
inline cyclic_ptr<T>::cyclic_ptr(const weak_ptr<U>& r) throw() {
p = r.p, ph = r.ph, ++ph->n;
}
template<typename T> template<typename U>
inline cyclic_ptr<T>& cyclic_ptr<T>::operator=(const weak_ptr<U>& r) throw() {
copy(r);
return *this;
}
}
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk