| /* | |
| * Copyright (c) 2002-2005 The Regents of The University of Michigan | |
| * All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions are | |
| * met: redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer; | |
| * redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution; | |
| * neither the name of the copyright holders nor the names of its | |
| * contributors may be used to endorse or promote products derived from | |
| * this software without specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| * | |
| * Authors: Nathan Binkert | |
| */ | |
| #ifndef __BASE_REFCNT_HH__ | |
| #define __BASE_REFCNT_HH__ | |
| /** | |
| * @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<T> instead of regular pointers. | |
| */ | |
| class RefCounted | |
| { | |
| private: | |
| // 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<Foo> FooPtr; | |
| * @endcode | |
| * | |
| * @attention Do not use "const FooPtr" | |
| * To create a reference counting pointer to a const object, use this: | |
| * @code | |
| * typedef RefCountingPtr<const Foo> ConstFooPtr; | |
| * @endcode | |
| * | |
| * These two usages are analogous to iterator and const_iterator in the stl. | |
| */ | |
| template <class T> | |
| class RefCountingPtr | |
| { | |
| protected: | |
| /// The stored pointer. | |
| /// Arguably this should be private. | |
| T *data; | |
| /** | |
| * 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(); | |
| } | |
| /** | |
| * 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(); | |
| } | |
| /** | |
| * 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: | |
| /// 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(); } | |
| // 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". | |
| /// Access a member variable. | |
| T *operator->() const { return data; } | |
| /// 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<class T> | |
| inline bool operator==(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r) | |
| { return l.get() == r.get(); } | |
| /// Check for equality of of a reference counting pointers and a | |
| /// regular pointer | |
| template<class T> | |
| inline bool operator==(const RefCountingPtr<T> &l, const T *r) | |
| { return l.get() == r; } | |
| /// Check for equality of of a reference counting pointers and a | |
| /// regular pointer | |
| template<class T> | |
| inline bool operator==(const T *l, const RefCountingPtr<T> &r) | |
| { return l == r.get(); } | |
| /// Check for inequality of two reference counting pointers. | |
| template<class T> | |
| inline bool operator!=(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r) | |
| { return l.get() != r.get(); } | |
| /// Check for inequality of of a reference counting pointers and a | |
| /// regular pointer | |
| template<class T> | |
| inline bool operator!=(const RefCountingPtr<T> &l, const T *r) | |
| { return l.get() != r; } | |
| /// Check for inequality of of a reference counting pointers and a | |
| /// regular pointer | |
| template<class T> | |
| inline bool operator!=(const T *l, const RefCountingPtr<T> &r) | |
| { return l != r.get(); } | |
| #endif // __BASE_REFCNT_HH__ |