2
* Copyright 2010 Google Inc.
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
17
// Author: jmarantz@google.com (Joshua Marantz)
19
// Implements a generic ref-counted class, with full sharing. This
20
// class does *not* implement copy-on-write semantics, but it provides
21
// 'unique()', which helps implement COW at a higher level.
23
// There are two pointer templates here:
24
// - RefCountedPtr<T> --- requires T to inherit off RefCounted<T>,
25
// stores it by pointer to supports full polymorphism.
26
// - RefCountedObj<T> --- no requirements on T besides default and copy
27
// construction, but stores T by value so it must always store exactly T.
29
// TODO(jmaessen): explore adding C++x0 shared_ptr support
31
#ifndef PAGESPEED_KERNEL_UTIL_REF_COUNTED_PTR_H_
32
#define PAGESPEED_KERNEL_UTIL_REF_COUNTED_PTR_H_
34
#include "base/logging.h"
35
#include "pagespeed/kernel/base/atomic_int32.h"
36
#include "pagespeed/kernel/base/basictypes.h"
38
namespace net_instaweb {
43
RefCounted() : ref_count_(0) {}
44
~RefCounted() { DCHECK_EQ(0, ref_count_.value()); }
47
if (ref_count_.BarrierIncrement(-1) == 0) {
48
delete static_cast<T*>(this);
53
ref_count_.NoBarrierIncrement(1);
57
return (ref_count_.value() == 1);
61
AtomicInt32 ref_count_;
62
DISALLOW_COPY_AND_ASSIGN(RefCounted<T>);
65
// Template class to help make reference-counted pointers. You can use
66
// a typedef or subclass RefCountedPtr<YourClass>. YourClass has to inherit
71
RefCountedPtr() : ptr_(NULL) {}
72
explicit RefCountedPtr(T* t) : ptr_(t) {
78
RefCountedPtr(const RefCountedPtr<T>& src)
86
explicit RefCountedPtr(const RefCountedPtr<U>& src)
87
: ptr_(static_cast<T*>(src.ptr_)) {
99
RefCountedPtr<T>& operator=(const RefCountedPtr<T>& other) {
100
// ref before deref to deal with self-assignment.
101
if (other.ptr_ != NULL) {
102
other.ptr_->AddRef();
112
RefCountedPtr<T>& operator=(const RefCountedPtr<U>& other) {
113
if (other.ptr_ != NULL) {
114
other.ptr_->AddRef();
119
ptr_ = static_cast<T*>(other.ptr_);
123
T* operator->() const { return ptr_; }
124
T* get() const { return ptr_; }
126
// Determines whether any other RefCountedPtr objects share the same
127
// storage. This can be used to create copy-on-write semantics if
129
bool unique() const { return !this->ptr_ || this->ptr_->HasOneRef(); }
132
RefCountedPtr<U> StaticCast() const {
133
return RefCountedPtr<U>(static_cast<U*>(this->get()));
137
*this = RefCountedPtr();
140
*this = RefCountedPtr(ptr);
142
void reset(const RefCountedPtr& src) {
147
template <class U> friend class RefCountedPtr;
148
operator void*() const; // don't compare directly to NULL; use get()
149
operator T*() const; // don't assign directly to pointer; use get()
151
// Note that copy and assign of RefCountedPtr is allowed -- that
152
// is how the reference counts are updated.
156
// If you can't inherit off RefCounted due to using a pre-existing
157
// class, you can use RefCountedObj instead. This however is limited to
158
// having a single type (so no polymorphism). It also has slightly
159
// different semantics in that it initializes to a default-constructed object
162
class RefCountedObj {
164
RefCountedObj() : data_ptr_(new Data()) {}
165
explicit RefCountedObj(const T& val) : data_ptr_(new Data(val)) {}
167
// Determines whether any other RefCountedObj objects share the same
168
// storage. This can be used to create copy-on-write semantics if
170
bool unique() const { return data_ptr_.unique(); }
172
T* get() { return &data_ptr_->value; }
173
const T* get() const { return &data_ptr_->value; }
174
T* operator->() { return &data_ptr_->value; }
175
const T* operator->() const { return &data_ptr_->value; }
176
T& operator*() { return data_ptr_->value; }
177
const T& operator*() const { return data_ptr_->value; }
179
// Sets the object to contain a new value, detaching it
180
// from any other RefCountedObj instances that were previously
182
void reset(const T& val) { data_ptr_.reset(new Data(val)); }
185
struct Data : public RefCounted<Data> {
187
explicit Data(const T& val) : value(val) {}
191
RefCountedPtr<Data> data_ptr_;
194
operator void*() const; // don't compare directly to NULL; use get()
195
operator T*() const; // don't assign directly to pointer; use get()
197
// Copying, etc., are OK thanks to data_ptr_.
200
// Macro for users implementing C++ ref-counted classes to prevent
201
// explicit destruction. Once a class is reference counted, it
202
// should never be stack-allocated or explicitly deleted. It should
203
// only be deleted by the reference count object. Put this declaration
204
// in the 'protected:' or 'private:' section, and group it with
205
// a destructor declaration.
207
// This is only required for RefCountedPtr<T>, not RefCountedObj<T>.
209
#define REFCOUNT_FRIEND_DECLARATION(class_name) \
210
friend class net_instaweb::RefCounted<class_name>
212
} // namespace net_instaweb
214
#endif // PAGESPEED_KERNEL_UTIL_REF_COUNTED_PTR_H_