| /* |
| * Copyright (c) 2017-2018 ARM Limited |
| * All rights reserved. |
| * |
| * The license below extends only to copyright in the software and shall |
| * not be construed as granting a license to any other intellectual |
| * property including but not limited to intellectual property relating |
| * to a hardware implementation of the functionality of the software |
| * licensed hereunder. You may use the software subject to the license |
| * terms below provided that you ensure that this notice is replicated |
| * unmodified and in its entirety in all distributions of the software, |
| * modified or unmodified, in source code or in binary form. |
| * |
| * 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__ |
| |
| #include <type_traits> |
| |
| /** |
| * @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() const { ++count; } |
| |
| /// Decrement the reference count and destroy the object if all |
| /// references are gone. |
| void decref() const { 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 |
| { |
| public: |
| using PtrType = T*; |
| |
| protected: |
| /** Convenience aliases for const/non-const versions of T w/ friendship. */ |
| /** @{ */ |
| static constexpr auto TisConst = std::is_const<T>::value; |
| using ConstT = typename std::conditional<TisConst, |
| RefCountingPtr<T>, |
| RefCountingPtr<typename std::add_const<T>::type>>::type; |
| friend ConstT; |
| using NonConstT = typename std::conditional<TisConst, |
| RefCountingPtr<typename std::remove_const<T>::type>, |
| RefCountingPtr<T>>::type; |
| friend NonConstT; |
| /** @} */ |
| /// 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); } |
| |
| /** Move-constructor. |
| * Does not add a reference. |
| */ |
| RefCountingPtr(RefCountingPtr&& r) |
| { |
| data = r.data; |
| r.data = nullptr; |
| } |
| |
| template <bool B = TisConst> |
| RefCountingPtr(const NonConstT &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; } |
| |
| template <bool B = TisConst> |
| operator RefCountingPtr<typename std::enable_if<!B, ConstT>::type>() |
| { |
| return RefCountingPtr<const T>(*this); |
| } |
| |
| /// 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); } |
| |
| /// Move-assign the pointer from another RefCountingPtr |
| const RefCountingPtr &operator=(RefCountingPtr&& r) |
| { |
| /* This happens regardless of whether the pointer is the same or not, |
| * because of the move semantics, the rvalue needs to be 'destroyed'. |
| */ |
| del(); |
| data = r.data; |
| r.data = nullptr; |
| return *this; |
| } |
| |
| /// 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__ |