1 /*
2  *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #ifndef WEBRTC_BASE_REFERENCECOUNTEDSINGLETONFACTORY_H_
12 #define WEBRTC_BASE_REFERENCECOUNTEDSINGLETONFACTORY_H_
13 
14 #include "webrtc/base/common.h"
15 #include "webrtc/base/criticalsection.h"
16 #include "webrtc/base/logging.h"
17 #include "webrtc/base/scoped_ptr.h"
18 
19 namespace rtc {
20 
21 template <typename Interface> class rcsf_ptr;
22 
23 // A ReferenceCountedSingletonFactory is an object which owns another object,
24 // and doles out the owned object to consumers in a reference-counted manner.
25 // Thus, the factory owns at most one object of the desired kind, and
26 // hands consumers a special pointer to it, through which they can access it.
27 // When the consumers delete the pointer, the reference count goes down,
28 // and if the reference count hits zero, the factory can throw the object
29 // away.  If a consumer requests the pointer and the factory has none,
30 // it can create one on the fly and pass it back.
31 template <typename Interface>
32 class ReferenceCountedSingletonFactory {
33   friend class rcsf_ptr<Interface>;
34  public:
ReferenceCountedSingletonFactory()35   ReferenceCountedSingletonFactory() : ref_count_(0) {}
36 
~ReferenceCountedSingletonFactory()37   virtual ~ReferenceCountedSingletonFactory() {
38     ASSERT(ref_count_ == 0);
39   }
40 
41  protected:
42   // Must be implemented in a sub-class. The sub-class may choose whether or not
43   // to cache the instance across lifetimes by either reset()'ing or not
44   // reset()'ing the scoped_ptr in CleanupInstance().
45   virtual bool SetupInstance() = 0;
46   virtual void CleanupInstance() = 0;
47 
48   scoped_ptr<Interface> instance_;
49 
50  private:
GetInstance()51   Interface* GetInstance() {
52     rtc::CritScope cs(&crit_);
53     if (ref_count_ == 0) {
54       if (!SetupInstance()) {
55         LOG(LS_VERBOSE) << "Failed to setup instance";
56         return NULL;
57       }
58       ASSERT(instance_.get() != NULL);
59     }
60     ++ref_count_;
61 
62     LOG(LS_VERBOSE) << "Number of references: " << ref_count_;
63     return instance_.get();
64   }
65 
ReleaseInstance()66   void ReleaseInstance() {
67     rtc::CritScope cs(&crit_);
68     ASSERT(ref_count_ > 0);
69     ASSERT(instance_.get() != NULL);
70     --ref_count_;
71     LOG(LS_VERBOSE) << "Number of references: " << ref_count_;
72     if (ref_count_ == 0) {
73       CleanupInstance();
74     }
75   }
76 
77   CriticalSection crit_;
78   int ref_count_;
79 
80   RTC_DISALLOW_COPY_AND_ASSIGN(ReferenceCountedSingletonFactory);
81 };
82 
83 template <typename Interface>
84 class rcsf_ptr {
85  public:
86   // Create a pointer that uses the factory to get the instance.
87   // This is lazy - it won't generate the instance until it is requested.
rcsf_ptr(ReferenceCountedSingletonFactory<Interface> * factory)88   explicit rcsf_ptr(ReferenceCountedSingletonFactory<Interface>* factory)
89       : instance_(NULL),
90         factory_(factory) {
91   }
92 
~rcsf_ptr()93   ~rcsf_ptr() {
94     release();
95   }
96 
97   Interface& operator*() {
98     EnsureAcquired();
99     return *instance_;
100   }
101 
102   Interface* operator->() {
103     EnsureAcquired();
104     return instance_;
105   }
106 
107   // Gets the pointer, creating the singleton if necessary. May return NULL if
108   // creation failed.
get()109   Interface* get() {
110     Acquire();
111     return instance_;
112   }
113 
114   // Set instance to NULL and tell the factory we aren't using the instance
115   // anymore.
release()116   void release() {
117     if (instance_) {
118       instance_ = NULL;
119       factory_->ReleaseInstance();
120     }
121   }
122 
123   // Lets us know whether instance is valid or not right now.
124   // Even though attempts to use the instance will automatically create it, it
125   // is advisable to check this because creation can fail.
valid()126   bool valid() const {
127     return instance_ != NULL;
128   }
129 
130   // Returns the factory that this pointer is using.
factory()131   ReferenceCountedSingletonFactory<Interface>* factory() const {
132     return factory_;
133   }
134 
135  private:
EnsureAcquired()136   void EnsureAcquired() {
137     Acquire();
138     ASSERT(instance_ != NULL);
139   }
140 
Acquire()141   void Acquire() {
142     // Since we're getting a singleton back, acquire is a noop if instance is
143     // already populated.
144     if (!instance_) {
145       instance_ = factory_->GetInstance();
146     }
147   }
148 
149   Interface* instance_;
150   ReferenceCountedSingletonFactory<Interface>* factory_;
151 
152   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(rcsf_ptr);
153 };
154 
155 };  // namespace rtc
156 
157 #endif  // WEBRTC_BASE_REFERENCECOUNTEDSINGLETONFACTORY_H_
158