blob: 7138c8c5e15774650356ce26818d4343e72c8f95 [file] [log] [blame]
henrike@webrtc.orgf7795df2014-05-13 18:00:26 +00001/*
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
19namespace rtc {
20
21template <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.
31template <typename Interface>
32class ReferenceCountedSingletonFactory {
33 friend class rcsf_ptr<Interface>;
34 public:
35 ReferenceCountedSingletonFactory() : ref_count_(0) {}
36
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:
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
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 DISALLOW_COPY_AND_ASSIGN(ReferenceCountedSingletonFactory);
81};
82
83template <typename Interface>
84class 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.
88 explicit rcsf_ptr(ReferenceCountedSingletonFactory<Interface>* factory)
89 : instance_(NULL),
90 factory_(factory) {
91 }
92
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.
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.
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.
126 bool valid() const {
127 return instance_ != NULL;
128 }
129
130 // Returns the factory that this pointer is using.
131 ReferenceCountedSingletonFactory<Interface>* factory() const {
132 return factory_;
133 }
134
135 private:
136 void EnsureAcquired() {
137 Acquire();
138 ASSERT(instance_ != NULL);
139 }
140
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 DISALLOW_IMPLICIT_CONSTRUCTORS(rcsf_ptr);
153};
154
155}; // namespace rtc
156
157#endif // WEBRTC_BASE_REFERENCECOUNTEDSINGLETONFACTORY_H_