X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fbase%2Frefcnt.hh;h=baf08c62e3461977d994f82aed9cc8d341cb467d;hb=b312a41f21b6f76607fe7480a915a4c5093386a3;hp=6672d4a5f58de6a4d171fb16f636f6e47af3e9ff;hpb=3c95f5958fd1a90cf83d85e1b24fb700c07bae91;p=gem5.git diff --git a/src/base/refcnt.hh b/src/base/refcnt.hh index 6672d4a5f..baf08c62e 100644 --- a/src/base/refcnt.hh +++ b/src/base/refcnt.hh @@ -28,98 +28,203 @@ * Authors: Nathan Binkert */ -#ifndef __REFCNT_HH__ -#define __REFCNT_HH__ +#ifndef __BASE_REFCNT_HH__ +#define __BASE_REFCNT_HH__ -#include //For the NULL macro definition +/** + * @file base/refcnt.hh + * + * Classes for managing reference counted objects. + */ +/** + * Derive from RefCounted if you want to enable reference counting of + * this class. If you want to use automatic reference counting, you + * should use RefCountingPtr instead of regular pointers. + */ class RefCounted { private: - int count; + // The reference count is mutable because one may want to + // reference count a const pointer. This really is OK because + // const is about logical constness of the object not really about + // strictly disallowing an object to change. + mutable int count; private: + // Don't allow a default copy constructor or copy operator on + // these objects because the default operation will copy the + // reference count as well and we certainly don't want that. RefCounted(const RefCounted &); + RefCounted &operator=(const RefCounted &); public: + /** + * We initialize the reference count to zero and the first object + * to take ownership of it must increment it to one. + * + * @attention A memory leak will occur if you never assign a newly + * constructed object to a reference counting pointer. + */ RefCounted() : count(0) {} + + /** + * We make the destructor virtual because we're likely to have + * virtual functions on reference counted objects. + * + * @todo Even if this were true, does it matter? Shouldn't the + * derived class indicate this? This only matters if we would + * ever choose to delete a "RefCounted *" which I doubt we'd ever + * do. We don't ever delete a "void *". + */ virtual ~RefCounted() {} + /// Increment the reference count void incref() { ++count; } + + /// Decrement the reference count and destroy the object if all + /// references are gone. void decref() { if (--count <= 0) delete this; } }; +/** + * If you want a reference counting pointer to a mutable object, + * create it like this: + * @code + * typedef RefCountingPtr FooPtr; + * @endcode + * + * @attention Do not use "const FooPtr" + * To create a reference counting pointer to a const object, use this: + * @code + * typedef RefCountingPtr ConstFooPtr; + * @endcode + * + * These two usages are analogous to iterator and const_iterator in the stl. + */ template class RefCountingPtr { protected: + /// The stored pointer. + /// Arguably this should be private. T *data; - void copy(T *d) + /** + * Copy a new pointer value and increment the reference count if + * it is a valid pointer. Note, this does not delete the + * reference any existing object. + * @param d Pointer to store. + */ + void + copy(T *d) { data = d; if (data) data->incref(); } - void del() + + /** + * Delete the reference to any existing object if it is non NULL. + * @attention this doesn't clear the pointer value, so a double + * decref could happen if not careful. + */ + void + del() { if (data) data->decref(); } - void set(T *d) - { - if (data == d) - return; - del(); - copy(d); + /** + * Drop the old reference and change it to something new. + */ + void + set(T *d) + { + // Need to check if we're actually changing because otherwise + // we could delete the last reference before adding the new + // reference. + if (data != d) { + del(); + copy(d); + } } - public: - RefCountingPtr() : data(NULL) {} + /// Create an empty reference counting pointer. + RefCountingPtr() : data(0) {} + + /// Create a new reference counting pointer to some object + /// (probably something newly created). Adds a reference. RefCountingPtr(T *data) { copy(data); } + + /// Create a new reference counting pointer by copying another + /// one. Adds a reference. RefCountingPtr(const RefCountingPtr &r) { copy(r.data); } + + /// Destroy the pointer and any reference it may hold. ~RefCountingPtr() { del(); } - T *operator->() { return data; } - T &operator*() { return *data; } - T *get() { return data; } + // The following pointer access functions are const because they + // don't actually change the pointer, though the user could change + // what is pointed to. This is analagous to a "Foo * const". - const T *operator->() const { return data; } - const T &operator*() const { return *data; } - const T *get() const { return data; } + /// Access a member variable. + T *operator->() const { return data; } - RefCountingPtr &operator=(T *p) { set(p); return *this; } - RefCountingPtr &operator=(const RefCountingPtr &r) + /// Dereference the pointer. + T &operator*() const { return *data; } + + /// Directly access the pointer itself without taking a reference. + T *get() const { return data; } + + /// Assign a new value to the pointer + const RefCountingPtr &operator=(T *p) { set(p); return *this; } + + /// Copy the pointer from another RefCountingPtr + const RefCountingPtr &operator=(const RefCountingPtr &r) { return operator=(r.data); } + /// Check if the pointer is empty bool operator!() const { return data == 0; } + + /// Check if the pointer is non-empty operator bool() const { return data != 0; } }; +/// Check for equality of two reference counting pointers. template -bool operator==(const RefCountingPtr &l, const RefCountingPtr &r) +inline bool operator==(const RefCountingPtr &l, const RefCountingPtr &r) { return l.get() == r.get(); } +/// Check for equality of of a reference counting pointers and a +/// regular pointer template -bool operator==(const RefCountingPtr &l, const T *r) +inline bool operator==(const RefCountingPtr &l, const T *r) { return l.get() == r; } +/// Check for equality of of a reference counting pointers and a +/// regular pointer template -bool operator==(const T &l, const RefCountingPtr &r) +inline bool operator==(const T *l, const RefCountingPtr &r) { return l == r.get(); } +/// Check for inequality of two reference counting pointers. template -bool operator!=(const RefCountingPtr &l, const RefCountingPtr &r) +inline bool operator!=(const RefCountingPtr &l, const RefCountingPtr &r) { return l.get() != r.get(); } +/// Check for inequality of of a reference counting pointers and a +/// regular pointer template -bool operator!=(const RefCountingPtr &l, const T *r) +inline bool operator!=(const RefCountingPtr &l, const T *r) { return l.get() != r; } +/// Check for inequality of of a reference counting pointers and a +/// regular pointer template -bool operator!=(const T &l, const RefCountingPtr &r) +inline bool operator!=(const T *l, const RefCountingPtr &r) { return l != r.get(); } -#endif // __REFCNT_HH__ +#endif // __BASE_REFCNT_HH__