blob: 500150f6fd558394f1cf3b5c8d3eb69777beb0a0 [file] [log] [blame]
henrike@webrtc.orgf0488722014-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
jbauch555604a2016-04-26 03:13:22 -070014#include <memory>
15
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000016#include "webrtc/base/common.h"
kwiberg4485ffb2016-04-26 08:14:39 -070017#include "webrtc/base/constructormagic.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000018#include "webrtc/base/criticalsection.h"
19#include "webrtc/base/logging.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000020
21namespace rtc {
22
23template <typename Interface> class rcsf_ptr;
24
25// A ReferenceCountedSingletonFactory is an object which owns another object,
26// and doles out the owned object to consumers in a reference-counted manner.
27// Thus, the factory owns at most one object of the desired kind, and
28// hands consumers a special pointer to it, through which they can access it.
29// When the consumers delete the pointer, the reference count goes down,
30// and if the reference count hits zero, the factory can throw the object
31// away. If a consumer requests the pointer and the factory has none,
32// it can create one on the fly and pass it back.
33template <typename Interface>
34class ReferenceCountedSingletonFactory {
35 friend class rcsf_ptr<Interface>;
36 public:
37 ReferenceCountedSingletonFactory() : ref_count_(0) {}
38
39 virtual ~ReferenceCountedSingletonFactory() {
40 ASSERT(ref_count_ == 0);
41 }
42
43 protected:
44 // Must be implemented in a sub-class. The sub-class may choose whether or not
45 // to cache the instance across lifetimes by either reset()'ing or not
jbauch555604a2016-04-26 03:13:22 -070046 // reset()'ing the unique_ptr in CleanupInstance().
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000047 virtual bool SetupInstance() = 0;
48 virtual void CleanupInstance() = 0;
49
jbauch555604a2016-04-26 03:13:22 -070050 std::unique_ptr<Interface> instance_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000051
52 private:
53 Interface* GetInstance() {
54 rtc::CritScope cs(&crit_);
55 if (ref_count_ == 0) {
56 if (!SetupInstance()) {
57 LOG(LS_VERBOSE) << "Failed to setup instance";
58 return NULL;
59 }
60 ASSERT(instance_.get() != NULL);
61 }
62 ++ref_count_;
63
64 LOG(LS_VERBOSE) << "Number of references: " << ref_count_;
65 return instance_.get();
66 }
67
68 void ReleaseInstance() {
69 rtc::CritScope cs(&crit_);
70 ASSERT(ref_count_ > 0);
71 ASSERT(instance_.get() != NULL);
72 --ref_count_;
73 LOG(LS_VERBOSE) << "Number of references: " << ref_count_;
74 if (ref_count_ == 0) {
75 CleanupInstance();
76 }
77 }
78
79 CriticalSection crit_;
80 int ref_count_;
81
henrikg3c089d72015-09-16 05:37:44 -070082 RTC_DISALLOW_COPY_AND_ASSIGN(ReferenceCountedSingletonFactory);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000083};
84
85template <typename Interface>
86class rcsf_ptr {
87 public:
88 // Create a pointer that uses the factory to get the instance.
89 // This is lazy - it won't generate the instance until it is requested.
90 explicit rcsf_ptr(ReferenceCountedSingletonFactory<Interface>* factory)
91 : instance_(NULL),
92 factory_(factory) {
93 }
94
95 ~rcsf_ptr() {
96 release();
97 }
98
99 Interface& operator*() {
100 EnsureAcquired();
101 return *instance_;
102 }
103
104 Interface* operator->() {
105 EnsureAcquired();
106 return instance_;
107 }
108
109 // Gets the pointer, creating the singleton if necessary. May return NULL if
110 // creation failed.
111 Interface* get() {
112 Acquire();
113 return instance_;
114 }
115
116 // Set instance to NULL and tell the factory we aren't using the instance
117 // anymore.
118 void release() {
119 if (instance_) {
120 instance_ = NULL;
121 factory_->ReleaseInstance();
122 }
123 }
124
125 // Lets us know whether instance is valid or not right now.
126 // Even though attempts to use the instance will automatically create it, it
127 // is advisable to check this because creation can fail.
128 bool valid() const {
129 return instance_ != NULL;
130 }
131
132 // Returns the factory that this pointer is using.
133 ReferenceCountedSingletonFactory<Interface>* factory() const {
134 return factory_;
135 }
136
137 private:
138 void EnsureAcquired() {
139 Acquire();
140 ASSERT(instance_ != NULL);
141 }
142
143 void Acquire() {
144 // Since we're getting a singleton back, acquire is a noop if instance is
145 // already populated.
146 if (!instance_) {
147 instance_ = factory_->GetInstance();
148 }
149 }
150
151 Interface* instance_;
152 ReferenceCountedSingletonFactory<Interface>* factory_;
153
henrikg3c089d72015-09-16 05:37:44 -0700154 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(rcsf_ptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000155};
156
157}; // namespace rtc
158
159#endif // WEBRTC_BASE_REFERENCECOUNTEDSINGLETONFACTORY_H_