/* * libjingle * Copyright 2004--2010, Google Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. 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. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. */ #ifndef TALK_BASE_REFERENCECOUNTEDSINGLETONFACTORY_H_ #define TALK_BASE_REFERENCECOUNTEDSINGLETONFACTORY_H_ #include "talk/base/common.h" #include "talk/base/criticalsection.h" #include "talk/base/logging.h" #include "talk/base/scoped_ptr.h" namespace talk_base { 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() { talk_base::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() { talk_base::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 talk_base #endif // TALK_BASE_REFERENCECOUNTEDSINGLETONFACTORY_H_