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