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
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_
158