/* * Copyright 2004 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef WEBRTC_BASE_REFERENCECOUNTEDSINGLETONFACTORY_H_ #define WEBRTC_BASE_REFERENCECOUNTEDSINGLETONFACTORY_H_ #include "webrtc/base/common.h" #include "webrtc/base/criticalsection.h" #include "webrtc/base/logging.h" #include "webrtc/base/scoped_ptr.h" namespace rtc { template class rcsf_ptr; // A ReferenceCountedSingletonFactory is an object which owns another object, // and doles out the owned object to consumers in a reference-counted manner. // Thus, the factory owns at most one object of the desired kind, and // hands consumers a special pointer to it, through which they can access it. // When the consumers delete the pointer, the reference count goes down, // and if the reference count hits zero, the factory can throw the object // away. If a consumer requests the pointer and the factory has none, // it can create one on the fly and pass it back. template class ReferenceCountedSingletonFactory { friend class rcsf_ptr; public: ReferenceCountedSingletonFactory() : ref_count_(0) {} virtual ~ReferenceCountedSingletonFactory() { ASSERT(ref_count_ == 0); } protected: // Must be implemented in a sub-class. The sub-class may choose whether or not // to cache the instance across lifetimes by either reset()'ing or not // reset()'ing the scoped_ptr in CleanupInstance(). virtual bool SetupInstance() = 0; virtual void CleanupInstance() = 0; scoped_ptr instance_; private: Interface* GetInstance() { rtc::CritScope cs(&crit_); if (ref_count_ == 0) { if (!SetupInstance()) { LOG(LS_VERBOSE) << "Failed to setup instance"; return NULL; } ASSERT(instance_.get() != NULL); } ++ref_count_; LOG(LS_VERBOSE) << "Number of references: " << ref_count_; return instance_.get(); } void ReleaseInstance() { rtc::CritScope cs(&crit_); ASSERT(ref_count_ > 0); ASSERT(instance_.get() != NULL); --ref_count_; LOG(LS_VERBOSE) << "Number of references: " << ref_count_; if (ref_count_ == 0) { CleanupInstance(); } } CriticalSection crit_; int ref_count_; DISALLOW_COPY_AND_ASSIGN(ReferenceCountedSingletonFactory); }; template class rcsf_ptr { public: // Create a pointer that uses the factory to get the instance. // This is lazy - it won't generate the instance until it is requested. explicit rcsf_ptr(ReferenceCountedSingletonFactory* factory) : instance_(NULL), factory_(factory) { } ~rcsf_ptr() { release(); } Interface& operator*() { EnsureAcquired(); return *instance_; } Interface* operator->() { EnsureAcquired(); return instance_; } // Gets the pointer, creating the singleton if necessary. May return NULL if // creation failed. Interface* get() { Acquire(); return instance_; } // Set instance to NULL and tell the factory we aren't using the instance // anymore. void release() { if (instance_) { instance_ = NULL; factory_->ReleaseInstance(); } } // Lets us know whether instance is valid or not right now. // Even though attempts to use the instance will automatically create it, it // is advisable to check this because creation can fail. bool valid() const { return instance_ != NULL; } // Returns the factory that this pointer is using. ReferenceCountedSingletonFactory* factory() const { return factory_; } private: void EnsureAcquired() { Acquire(); ASSERT(instance_ != NULL); } void Acquire() { // Since we're getting a singleton back, acquire is a noop if instance is // already populated. if (!instance_) { instance_ = factory_->GetInstance(); } } Interface* instance_; ReferenceCountedSingletonFactory* factory_; DISALLOW_IMPLICIT_CONSTRUCTORS(rcsf_ptr); }; }; // namespace rtc #endif // WEBRTC_BASE_REFERENCECOUNTEDSINGLETONFACTORY_H_