113481Sgiacomo.travaglini@arm.com// Copyright 2003 Google Inc. 213481Sgiacomo.travaglini@arm.com// All rights reserved. 313481Sgiacomo.travaglini@arm.com// 413481Sgiacomo.travaglini@arm.com// Redistribution and use in source and binary forms, with or without 513481Sgiacomo.travaglini@arm.com// modification, are permitted provided that the following conditions are 613481Sgiacomo.travaglini@arm.com// met: 713481Sgiacomo.travaglini@arm.com// 813481Sgiacomo.travaglini@arm.com// * Redistributions of source code must retain the above copyright 913481Sgiacomo.travaglini@arm.com// notice, this list of conditions and the following disclaimer. 1013481Sgiacomo.travaglini@arm.com// * Redistributions in binary form must reproduce the above 1113481Sgiacomo.travaglini@arm.com// copyright notice, this list of conditions and the following disclaimer 1213481Sgiacomo.travaglini@arm.com// in the documentation and/or other materials provided with the 1313481Sgiacomo.travaglini@arm.com// distribution. 1413481Sgiacomo.travaglini@arm.com// * Neither the name of Google Inc. nor the names of its 1513481Sgiacomo.travaglini@arm.com// contributors may be used to endorse or promote products derived from 1613481Sgiacomo.travaglini@arm.com// this software without specific prior written permission. 1713481Sgiacomo.travaglini@arm.com// 1813481Sgiacomo.travaglini@arm.com// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1913481Sgiacomo.travaglini@arm.com// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2013481Sgiacomo.travaglini@arm.com// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2113481Sgiacomo.travaglini@arm.com// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2213481Sgiacomo.travaglini@arm.com// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2313481Sgiacomo.travaglini@arm.com// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2413481Sgiacomo.travaglini@arm.com// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2513481Sgiacomo.travaglini@arm.com// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2613481Sgiacomo.travaglini@arm.com// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2713481Sgiacomo.travaglini@arm.com// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2813481Sgiacomo.travaglini@arm.com// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2913481Sgiacomo.travaglini@arm.com// 3013481Sgiacomo.travaglini@arm.com// Authors: Dan Egnor (egnor@google.com) 3113481Sgiacomo.travaglini@arm.com// 3213481Sgiacomo.travaglini@arm.com// A "smart" pointer type with reference tracking. Every pointer to a 3313481Sgiacomo.travaglini@arm.com// particular object is kept on a circular linked list. When the last pointer 3413481Sgiacomo.travaglini@arm.com// to an object is destroyed or reassigned, the object is deleted. 3513481Sgiacomo.travaglini@arm.com// 3613481Sgiacomo.travaglini@arm.com// Used properly, this deletes the object when the last reference goes away. 3713481Sgiacomo.travaglini@arm.com// There are several caveats: 3813481Sgiacomo.travaglini@arm.com// - Like all reference counting schemes, cycles lead to leaks. 3913481Sgiacomo.travaglini@arm.com// - Each smart pointer is actually two pointers (8 bytes instead of 4). 4013481Sgiacomo.travaglini@arm.com// - Every time a pointer is assigned, the entire list of pointers to that 4113481Sgiacomo.travaglini@arm.com// object is traversed. This class is therefore NOT SUITABLE when there 4213481Sgiacomo.travaglini@arm.com// will often be more than two or three pointers to a particular object. 4313481Sgiacomo.travaglini@arm.com// - References are only tracked as long as linked_ptr<> objects are copied. 4413481Sgiacomo.travaglini@arm.com// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS 4513481Sgiacomo.travaglini@arm.com// will happen (double deletion). 4613481Sgiacomo.travaglini@arm.com// 4713481Sgiacomo.travaglini@arm.com// A good use of this class is storing object references in STL containers. 4813481Sgiacomo.travaglini@arm.com// You can safely put linked_ptr<> in a vector<>. 4913481Sgiacomo.travaglini@arm.com// Other uses may not be as good. 5013481Sgiacomo.travaglini@arm.com// 5113481Sgiacomo.travaglini@arm.com// Note: If you use an incomplete type with linked_ptr<>, the class 5213481Sgiacomo.travaglini@arm.com// *containing* linked_ptr<> must have a constructor and destructor (even 5313481Sgiacomo.travaglini@arm.com// if they do nothing!). 5413481Sgiacomo.travaglini@arm.com// 5513481Sgiacomo.travaglini@arm.com// Bill Gibbons suggested we use something like this. 5613481Sgiacomo.travaglini@arm.com// 5713481Sgiacomo.travaglini@arm.com// Thread Safety: 5813481Sgiacomo.travaglini@arm.com// Unlike other linked_ptr implementations, in this implementation 5913481Sgiacomo.travaglini@arm.com// a linked_ptr object is thread-safe in the sense that: 6013481Sgiacomo.travaglini@arm.com// - it's safe to copy linked_ptr objects concurrently, 6113481Sgiacomo.travaglini@arm.com// - it's safe to copy *from* a linked_ptr and read its underlying 6213481Sgiacomo.travaglini@arm.com// raw pointer (e.g. via get()) concurrently, and 6313481Sgiacomo.travaglini@arm.com// - it's safe to write to two linked_ptrs that point to the same 6413481Sgiacomo.travaglini@arm.com// shared object concurrently. 6513481Sgiacomo.travaglini@arm.com// TODO(wan@google.com): rename this to safe_linked_ptr to avoid 6613481Sgiacomo.travaglini@arm.com// confusion with normal linked_ptr. 6713481Sgiacomo.travaglini@arm.com 6813481Sgiacomo.travaglini@arm.com#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ 6913481Sgiacomo.travaglini@arm.com#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ 7013481Sgiacomo.travaglini@arm.com 7113481Sgiacomo.travaglini@arm.com#include <stdlib.h> 7213481Sgiacomo.travaglini@arm.com#include <assert.h> 7313481Sgiacomo.travaglini@arm.com 7413481Sgiacomo.travaglini@arm.com#include "gtest/internal/gtest-port.h" 7513481Sgiacomo.travaglini@arm.com 7613481Sgiacomo.travaglini@arm.comnamespace testing { 7713481Sgiacomo.travaglini@arm.comnamespace internal { 7813481Sgiacomo.travaglini@arm.com 7913481Sgiacomo.travaglini@arm.com// Protects copying of all linked_ptr objects. 8013481Sgiacomo.travaglini@arm.comGTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex); 8113481Sgiacomo.travaglini@arm.com 8213481Sgiacomo.travaglini@arm.com// This is used internally by all instances of linked_ptr<>. It needs to be 8313481Sgiacomo.travaglini@arm.com// a non-template class because different types of linked_ptr<> can refer to 8413481Sgiacomo.travaglini@arm.com// the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)). 8513481Sgiacomo.travaglini@arm.com// So, it needs to be possible for different types of linked_ptr to participate 8613481Sgiacomo.travaglini@arm.com// in the same circular linked list, so we need a single class type here. 8713481Sgiacomo.travaglini@arm.com// 8813481Sgiacomo.travaglini@arm.com// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr<T>. 8913481Sgiacomo.travaglini@arm.comclass linked_ptr_internal { 9013481Sgiacomo.travaglini@arm.com public: 9113481Sgiacomo.travaglini@arm.com // Create a new circle that includes only this instance. 9213481Sgiacomo.travaglini@arm.com void join_new() { 9313481Sgiacomo.travaglini@arm.com next_ = this; 9413481Sgiacomo.travaglini@arm.com } 9513481Sgiacomo.travaglini@arm.com 9613481Sgiacomo.travaglini@arm.com // Many linked_ptr operations may change p.link_ for some linked_ptr 9713481Sgiacomo.travaglini@arm.com // variable p in the same circle as this object. Therefore we need 9813481Sgiacomo.travaglini@arm.com // to prevent two such operations from occurring concurrently. 9913481Sgiacomo.travaglini@arm.com // 10013481Sgiacomo.travaglini@arm.com // Note that different types of linked_ptr objects can coexist in a 10113481Sgiacomo.travaglini@arm.com // circle (e.g. linked_ptr<Base>, linked_ptr<Derived1>, and 10213481Sgiacomo.travaglini@arm.com // linked_ptr<Derived2>). Therefore we must use a single mutex to 10313481Sgiacomo.travaglini@arm.com // protect all linked_ptr objects. This can create serious 10413481Sgiacomo.travaglini@arm.com // contention in production code, but is acceptable in a testing 10513481Sgiacomo.travaglini@arm.com // framework. 10613481Sgiacomo.travaglini@arm.com 10713481Sgiacomo.travaglini@arm.com // Join an existing circle. 10813481Sgiacomo.travaglini@arm.com void join(linked_ptr_internal const* ptr) 10913481Sgiacomo.travaglini@arm.com GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) { 11013481Sgiacomo.travaglini@arm.com MutexLock lock(&g_linked_ptr_mutex); 11113481Sgiacomo.travaglini@arm.com 11213481Sgiacomo.travaglini@arm.com linked_ptr_internal const* p = ptr; 11313481Sgiacomo.travaglini@arm.com while (p->next_ != ptr) { 11413481Sgiacomo.travaglini@arm.com assert(p->next_ != this && 11513481Sgiacomo.travaglini@arm.com "Trying to join() a linked ring we are already in. " 11613481Sgiacomo.travaglini@arm.com "Is GMock thread safety enabled?"); 11713481Sgiacomo.travaglini@arm.com p = p->next_; 11813481Sgiacomo.travaglini@arm.com } 11913481Sgiacomo.travaglini@arm.com p->next_ = this; 12013481Sgiacomo.travaglini@arm.com next_ = ptr; 12113481Sgiacomo.travaglini@arm.com } 12213481Sgiacomo.travaglini@arm.com 12313481Sgiacomo.travaglini@arm.com // Leave whatever circle we're part of. Returns true if we were the 12413481Sgiacomo.travaglini@arm.com // last member of the circle. Once this is done, you can join() another. 12513481Sgiacomo.travaglini@arm.com bool depart() 12613481Sgiacomo.travaglini@arm.com GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) { 12713481Sgiacomo.travaglini@arm.com MutexLock lock(&g_linked_ptr_mutex); 12813481Sgiacomo.travaglini@arm.com 12913481Sgiacomo.travaglini@arm.com if (next_ == this) return true; 13013481Sgiacomo.travaglini@arm.com linked_ptr_internal const* p = next_; 13113481Sgiacomo.travaglini@arm.com while (p->next_ != this) { 13213481Sgiacomo.travaglini@arm.com assert(p->next_ != next_ && 13313481Sgiacomo.travaglini@arm.com "Trying to depart() a linked ring we are not in. " 13413481Sgiacomo.travaglini@arm.com "Is GMock thread safety enabled?"); 13513481Sgiacomo.travaglini@arm.com p = p->next_; 13613481Sgiacomo.travaglini@arm.com } 13713481Sgiacomo.travaglini@arm.com p->next_ = next_; 13813481Sgiacomo.travaglini@arm.com return false; 13913481Sgiacomo.travaglini@arm.com } 14013481Sgiacomo.travaglini@arm.com 14113481Sgiacomo.travaglini@arm.com private: 14213481Sgiacomo.travaglini@arm.com mutable linked_ptr_internal const* next_; 14313481Sgiacomo.travaglini@arm.com}; 14413481Sgiacomo.travaglini@arm.com 14513481Sgiacomo.travaglini@arm.comtemplate <typename T> 14613481Sgiacomo.travaglini@arm.comclass linked_ptr { 14713481Sgiacomo.travaglini@arm.com public: 14813481Sgiacomo.travaglini@arm.com typedef T element_type; 14913481Sgiacomo.travaglini@arm.com 15013481Sgiacomo.travaglini@arm.com // Take over ownership of a raw pointer. This should happen as soon as 15113481Sgiacomo.travaglini@arm.com // possible after the object is created. 15213481Sgiacomo.travaglini@arm.com explicit linked_ptr(T* ptr = NULL) { capture(ptr); } 15313481Sgiacomo.travaglini@arm.com ~linked_ptr() { depart(); } 15413481Sgiacomo.travaglini@arm.com 15513481Sgiacomo.travaglini@arm.com // Copy an existing linked_ptr<>, adding ourselves to the list of references. 15613481Sgiacomo.travaglini@arm.com template <typename U> linked_ptr(linked_ptr<U> const& ptr) { copy(&ptr); } 15713481Sgiacomo.travaglini@arm.com linked_ptr(linked_ptr const& ptr) { // NOLINT 15813481Sgiacomo.travaglini@arm.com assert(&ptr != this); 15913481Sgiacomo.travaglini@arm.com copy(&ptr); 16013481Sgiacomo.travaglini@arm.com } 16113481Sgiacomo.travaglini@arm.com 16213481Sgiacomo.travaglini@arm.com // Assignment releases the old value and acquires the new. 16313481Sgiacomo.travaglini@arm.com template <typename U> linked_ptr& operator=(linked_ptr<U> const& ptr) { 16413481Sgiacomo.travaglini@arm.com depart(); 16513481Sgiacomo.travaglini@arm.com copy(&ptr); 16613481Sgiacomo.travaglini@arm.com return *this; 16713481Sgiacomo.travaglini@arm.com } 16813481Sgiacomo.travaglini@arm.com 16913481Sgiacomo.travaglini@arm.com linked_ptr& operator=(linked_ptr const& ptr) { 17013481Sgiacomo.travaglini@arm.com if (&ptr != this) { 17113481Sgiacomo.travaglini@arm.com depart(); 17213481Sgiacomo.travaglini@arm.com copy(&ptr); 17313481Sgiacomo.travaglini@arm.com } 17413481Sgiacomo.travaglini@arm.com return *this; 17513481Sgiacomo.travaglini@arm.com } 17613481Sgiacomo.travaglini@arm.com 17713481Sgiacomo.travaglini@arm.com // Smart pointer members. 17813481Sgiacomo.travaglini@arm.com void reset(T* ptr = NULL) { 17913481Sgiacomo.travaglini@arm.com depart(); 18013481Sgiacomo.travaglini@arm.com capture(ptr); 18113481Sgiacomo.travaglini@arm.com } 18213481Sgiacomo.travaglini@arm.com T* get() const { return value_; } 18313481Sgiacomo.travaglini@arm.com T* operator->() const { return value_; } 18413481Sgiacomo.travaglini@arm.com T& operator*() const { return *value_; } 18513481Sgiacomo.travaglini@arm.com 18613481Sgiacomo.travaglini@arm.com bool operator==(T* p) const { return value_ == p; } 18713481Sgiacomo.travaglini@arm.com bool operator!=(T* p) const { return value_ != p; } 18813481Sgiacomo.travaglini@arm.com template <typename U> 18913481Sgiacomo.travaglini@arm.com bool operator==(linked_ptr<U> const& ptr) const { 19013481Sgiacomo.travaglini@arm.com return value_ == ptr.get(); 19113481Sgiacomo.travaglini@arm.com } 19213481Sgiacomo.travaglini@arm.com template <typename U> 19313481Sgiacomo.travaglini@arm.com bool operator!=(linked_ptr<U> const& ptr) const { 19413481Sgiacomo.travaglini@arm.com return value_ != ptr.get(); 19513481Sgiacomo.travaglini@arm.com } 19613481Sgiacomo.travaglini@arm.com 19713481Sgiacomo.travaglini@arm.com private: 19813481Sgiacomo.travaglini@arm.com template <typename U> 19913481Sgiacomo.travaglini@arm.com friend class linked_ptr; 20013481Sgiacomo.travaglini@arm.com 20113481Sgiacomo.travaglini@arm.com T* value_; 20213481Sgiacomo.travaglini@arm.com linked_ptr_internal link_; 20313481Sgiacomo.travaglini@arm.com 20413481Sgiacomo.travaglini@arm.com void depart() { 20513481Sgiacomo.travaglini@arm.com if (link_.depart()) delete value_; 20613481Sgiacomo.travaglini@arm.com } 20713481Sgiacomo.travaglini@arm.com 20813481Sgiacomo.travaglini@arm.com void capture(T* ptr) { 20913481Sgiacomo.travaglini@arm.com value_ = ptr; 21013481Sgiacomo.travaglini@arm.com link_.join_new(); 21113481Sgiacomo.travaglini@arm.com } 21213481Sgiacomo.travaglini@arm.com 21313481Sgiacomo.travaglini@arm.com template <typename U> void copy(linked_ptr<U> const* ptr) { 21413481Sgiacomo.travaglini@arm.com value_ = ptr->get(); 21513481Sgiacomo.travaglini@arm.com if (value_) 21613481Sgiacomo.travaglini@arm.com link_.join(&ptr->link_); 21713481Sgiacomo.travaglini@arm.com else 21813481Sgiacomo.travaglini@arm.com link_.join_new(); 21913481Sgiacomo.travaglini@arm.com } 22013481Sgiacomo.travaglini@arm.com}; 22113481Sgiacomo.travaglini@arm.com 22213481Sgiacomo.travaglini@arm.comtemplate<typename T> inline 22313481Sgiacomo.travaglini@arm.combool operator==(T* ptr, const linked_ptr<T>& x) { 22413481Sgiacomo.travaglini@arm.com return ptr == x.get(); 22513481Sgiacomo.travaglini@arm.com} 22613481Sgiacomo.travaglini@arm.com 22713481Sgiacomo.travaglini@arm.comtemplate<typename T> inline 22813481Sgiacomo.travaglini@arm.combool operator!=(T* ptr, const linked_ptr<T>& x) { 22913481Sgiacomo.travaglini@arm.com return ptr != x.get(); 23013481Sgiacomo.travaglini@arm.com} 23113481Sgiacomo.travaglini@arm.com 23213481Sgiacomo.travaglini@arm.com// A function to convert T* into linked_ptr<T> 23313481Sgiacomo.travaglini@arm.com// Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation 23413481Sgiacomo.travaglini@arm.com// for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg)) 23513481Sgiacomo.travaglini@arm.comtemplate <typename T> 23613481Sgiacomo.travaglini@arm.comlinked_ptr<T> make_linked_ptr(T* ptr) { 23713481Sgiacomo.travaglini@arm.com return linked_ptr<T>(ptr); 23813481Sgiacomo.travaglini@arm.com} 23913481Sgiacomo.travaglini@arm.com 24013481Sgiacomo.travaglini@arm.com} // namespace internal 24113481Sgiacomo.travaglini@arm.com} // namespace testing 24213481Sgiacomo.travaglini@arm.com 24313481Sgiacomo.travaglini@arm.com#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ 244