refcnt.hh revision 8221
12SN/A/* 21762SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan 32SN/A * All rights reserved. 42SN/A * 52SN/A * Redistribution and use in source and binary forms, with or without 62SN/A * modification, are permitted provided that the following conditions are 72SN/A * met: redistributions of source code must retain the above copyright 82SN/A * notice, this list of conditions and the following disclaimer; 92SN/A * redistributions in binary form must reproduce the above copyright 102SN/A * notice, this list of conditions and the following disclaimer in the 112SN/A * documentation and/or other materials provided with the distribution; 122SN/A * neither the name of the copyright holders nor the names of its 132SN/A * contributors may be used to endorse or promote products derived from 142SN/A * this software without specific prior written permission. 152SN/A * 162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu * 282665Ssaidi@eecs.umich.edu * Authors: Nathan Binkert 292SN/A */ 302SN/A 313877Sbinkertn@umich.edu#ifndef __BASE_REFCNT_HH__ 323877Sbinkertn@umich.edu#define __BASE_REFCNT_HH__ 332147SN/A 348221Snate@binkert.org/** 358221Snate@binkert.org * @file base/refcnt.hh 368221Snate@binkert.org * 378221Snate@binkert.org * Classes for managing reference counted objects. 388221Snate@binkert.org */ 398221Snate@binkert.org 408221Snate@binkert.org/** 418221Snate@binkert.org * Derive from RefCounted if you want to enable reference counting of 428221Snate@binkert.org * this class. If you want to use automatic reference counting, you 438221Snate@binkert.org * should use RefCountingPtr<T> instead of regular pointers. 448221Snate@binkert.org */ 452SN/Aclass RefCounted 462SN/A{ 472SN/A private: 488221Snate@binkert.org // The reference count is mutable because one may want to 498221Snate@binkert.org // reference count a const pointer. This really is OK because 508221Snate@binkert.org // const is about logical constness of the object not really about 518221Snate@binkert.org // strictly disallowing an object to change. 527866Snate@binkert.org mutable int count; 532SN/A 542SN/A private: 557057Snate@binkert.org // Don't allow a default copy constructor or copy operator on 567057Snate@binkert.org // these objects because the default operation will copy the 577057Snate@binkert.org // reference count as well and we certainly don't want that. 582SN/A RefCounted(const RefCounted &); 597057Snate@binkert.org RefCounted &operator=(const RefCounted &); 602SN/A 612SN/A public: 628221Snate@binkert.org /** 638221Snate@binkert.org * We initialize the reference count to zero and the first object 648221Snate@binkert.org * to take ownership of it must increment it to one. 658221Snate@binkert.org * 668221Snate@binkert.org * @attention A memory leak will occur if you never assign a newly 678221Snate@binkert.org * constructed object to a reference counting pointer. 688221Snate@binkert.org */ 692SN/A RefCounted() : count(0) {} 708221Snate@binkert.org 718221Snate@binkert.org /** 728221Snate@binkert.org * We make the destructor virtual because we're likely to have 738221Snate@binkert.org * virtual functions on reference counted objects. 748221Snate@binkert.org * 758221Snate@binkert.org * @todo Even if this were true, does it matter? Shouldn't the 768221Snate@binkert.org * derived class indicate this? This only matters if we would 778221Snate@binkert.org * ever choose to delete a "RefCounted *" which I doubt we'd ever 788221Snate@binkert.org * do. We don't ever delete a "void *". 798221Snate@binkert.org */ 802SN/A virtual ~RefCounted() {} 812SN/A 828221Snate@binkert.org /// Increment the reference count 832SN/A void incref() { ++count; } 848221Snate@binkert.org 858221Snate@binkert.org /// Decrement the reference count and destroy the object if all 868221Snate@binkert.org /// references are gone. 872SN/A void decref() { if (--count <= 0) delete this; } 882SN/A}; 892SN/A 908221Snate@binkert.org/** 918221Snate@binkert.org * If you want a reference counting pointer to a mutable object, 928221Snate@binkert.org * create it like this: 938221Snate@binkert.org * @code 948221Snate@binkert.org * typedef RefCountingPtr<Foo> FooPtr; 958221Snate@binkert.org * @endcode 968221Snate@binkert.org * 978221Snate@binkert.org * @attention Do not use "const FooPtr" 988221Snate@binkert.org * To create a reference counting pointer to a const object, use this: 998221Snate@binkert.org * @code 1008221Snate@binkert.org * typedef RefCountingPtr<const Foo> ConstFooPtr; 1018221Snate@binkert.org * @endcode 1028221Snate@binkert.org * 1038221Snate@binkert.org * These two usages are analogous to iterator and const_iterator in the stl. 1048221Snate@binkert.org */ 1052SN/Atemplate <class T> 1062SN/Aclass RefCountingPtr 1072SN/A{ 1081078SN/A protected: 1098221Snate@binkert.org /// The stored pointer. 1108221Snate@binkert.org /// Arguably this should be private. 1112SN/A T *data; 1122SN/A 1138221Snate@binkert.org /** 1148221Snate@binkert.org * Copy a new pointer value and increment the reference count if 1158221Snate@binkert.org * it is a valid pointer. Note, this does not delete the 1168221Snate@binkert.org * reference any existing object. 1178221Snate@binkert.org * @param d Pointer to store. 1188221Snate@binkert.org */ 1198221Snate@binkert.org void 1208221Snate@binkert.org copy(T *d) 1211114SN/A { 1222SN/A data = d; 1232SN/A if (data) 1242SN/A data->incref(); 1252SN/A } 1268221Snate@binkert.org 1278221Snate@binkert.org /** 1288221Snate@binkert.org * Delete the reference to any existing object if it is non NULL. 1298221Snate@binkert.org * @attention this doesn't clear the pointer value, so a double 1308221Snate@binkert.org * decref could happen if not careful. 1318221Snate@binkert.org */ 1328221Snate@binkert.org void 1338221Snate@binkert.org del() 1341114SN/A { 1352SN/A if (data) 1362SN/A data->decref(); 1372SN/A } 1388221Snate@binkert.org 1398221Snate@binkert.org /** 1408221Snate@binkert.org * Drop the old reference and change it to something new. 1418221Snate@binkert.org */ 1428221Snate@binkert.org void 1438221Snate@binkert.org set(T *d) 1441114SN/A { 1458221Snate@binkert.org // Need to check if we're actually changing because otherwise 1468221Snate@binkert.org // we could delete the last reference before adding the new 1478221Snate@binkert.org // reference. 1488221Snate@binkert.org if (data != d) { 1498221Snate@binkert.org del(); 1508221Snate@binkert.org copy(d); 1518221Snate@binkert.org } 1521114SN/A } 1531114SN/A 1548221Snate@binkert.org public: 1558221Snate@binkert.org /// Create an empty reference counting pointer. 1568221Snate@binkert.org RefCountingPtr() : data(0) {} 1572SN/A 1588221Snate@binkert.org /// Create a new reference counting pointer to some object 1598221Snate@binkert.org /// (probably something newly created). Adds a reference. 1602SN/A RefCountingPtr(T *data) { copy(data); } 1618221Snate@binkert.org 1628221Snate@binkert.org /// Create a new reference counting pointer by copying another 1638221Snate@binkert.org /// one. Adds a reference. 164502SN/A RefCountingPtr(const RefCountingPtr &r) { copy(r.data); } 1658221Snate@binkert.org 1668221Snate@binkert.org /// Destroy the pointer and any reference it may hold. 1672SN/A ~RefCountingPtr() { del(); } 1682SN/A 1698221Snate@binkert.org // The following pointer access functions are const because they 1708221Snate@binkert.org // don't actually change the pointer, though the user could change 1718221Snate@binkert.org // what is pointed to. This is analagous to a "Foo * const". 1728221Snate@binkert.org 1738221Snate@binkert.org /// Access a member variable. 1747866Snate@binkert.org T *operator->() const { return data; } 1758221Snate@binkert.org 1768221Snate@binkert.org /// Dereference the pointer. 1777866Snate@binkert.org T &operator*() const { return *data; } 1788221Snate@binkert.org 1798221Snate@binkert.org /// Directly access the pointer itself without taking a reference. 1807866Snate@binkert.org T *get() const { return data; } 1812SN/A 1828221Snate@binkert.org /// Assign a new value to the pointer 1833877Sbinkertn@umich.edu const RefCountingPtr &operator=(T *p) { set(p); return *this; } 1848221Snate@binkert.org 1858221Snate@binkert.org /// Copy the pointer from another RefCountingPtr 1863877Sbinkertn@umich.edu const RefCountingPtr &operator=(const RefCountingPtr &r) 1871114SN/A { return operator=(r.data); } 1882SN/A 1898221Snate@binkert.org /// Check if the pointer is empty 1902SN/A bool operator!() const { return data == 0; } 1918221Snate@binkert.org 1928221Snate@binkert.org /// Check if the pointer is non-empty 1932SN/A operator bool() const { return data != 0; } 1942SN/A}; 1952SN/A 1968221Snate@binkert.org/// Check for equality of two reference counting pointers. 1972SN/Atemplate<class T> 1988220Snate@binkert.orginline bool operator==(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r) 1992SN/A{ return l.get() == r.get(); } 2002SN/A 2018221Snate@binkert.org/// Check for equality of of a reference counting pointers and a 2028221Snate@binkert.org/// regular pointer 2032SN/Atemplate<class T> 2048220Snate@binkert.orginline bool operator==(const RefCountingPtr<T> &l, const T *r) 2052SN/A{ return l.get() == r; } 2062SN/A 2078221Snate@binkert.org/// Check for equality of of a reference counting pointers and a 2088221Snate@binkert.org/// regular pointer 2092SN/Atemplate<class T> 2108220Snate@binkert.orginline bool operator==(const T *l, const RefCountingPtr<T> &r) 2112SN/A{ return l == r.get(); } 2122SN/A 2138221Snate@binkert.org/// Check for inequality of two reference counting pointers. 2142SN/Atemplate<class T> 2158220Snate@binkert.orginline bool operator!=(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r) 2162SN/A{ return l.get() != r.get(); } 2172SN/A 2188221Snate@binkert.org/// Check for inequality of of a reference counting pointers and a 2198221Snate@binkert.org/// regular pointer 2202SN/Atemplate<class T> 2218220Snate@binkert.orginline bool operator!=(const RefCountingPtr<T> &l, const T *r) 2222SN/A{ return l.get() != r; } 2232SN/A 2248221Snate@binkert.org/// Check for inequality of of a reference counting pointers and a 2258221Snate@binkert.org/// regular pointer 2262SN/Atemplate<class T> 2278220Snate@binkert.orginline bool operator!=(const T *l, const RefCountingPtr<T> &r) 2282SN/A{ return l != r.get(); } 2292SN/A 2303877Sbinkertn@umich.edu#endif // __BASE_REFCNT_HH__ 231