-
Notifications
You must be signed in to change notification settings - Fork 0
/
ref_counted.h
130 lines (108 loc) · 3.88 KB
/
ref_counted.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/* THOR - THOR Template Library
* Joshua M. Kriegshauser
*
* ref_counted.h
*
* This file defines a base class that can be used for reference counted classes
*/
#ifndef THOR_REF_COUNTED_H
#define THOR_REF_COUNTED_H
#pragma once
#ifndef THOR_BASETYPES_H
#include "basetypes.h"
#endif
#ifndef THOR_POLICY_H
#include "policy.h"
#endif
namespace thor
{
///////////////////////////////////////////////////////////////////////////////
// ref_counted
// A base class for reference counted types.
///////////////////////////////////////////////////////////////////////////////
template <typename T_REFCOUNT_POLICY = policy::thread_safe_ref_count,
typename T_DELETE_POLICY = policy::delete_this_on_zero_refcount,
size_type initial_refcount = 0>
class ref_counted : private T_REFCOUNT_POLICY, protected T_DELETE_POLICY
{
typedef T_REFCOUNT_POLICY refcount_policy;
typedef T_DELETE_POLICY delete_policy;
static const thor_size_type not_referenced = thor_size_type(-1);
THOR_DECLARE_NOCOPY(ref_counted);
public:
typedef size_type thor_size_type;
ref_counted() : refcount_policy(initial_refcount) {}
virtual ~ref_counted()
{
THOR_DEBUG_ASSERT(refcount_ == 0 || refcount_ == not_referenced); // Should have a zero refcount when destroyed
}
void add_ref()
{
THOR_DEBUG_ASSERT(refcount_ != not_referenced);
++refcount_;
}
void release()
{
THOR_DEBUG_ASSERT(refcount_ != not_referenced && refcount_ > 0);
if (--refcount_ == 0)
{
on_zero_refcount(); // Could potentially delete this
}
}
size_type get_ref_count() const
{
return refcount_;
}
void make_not_referenced()
{
THOR_DEBUG_ASSERT(refcount_ == initial_refcount);
refcount_ = not_referenced;
}
};
///////////////////////////////////////////////////////////////////////////////
// ref_pointer
// a smart pointer type to automatically handle reference counts
///////////////////////////////////////////////////////////////////////////////
template <class T> class ref_pointer
{
public:
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
explicit ref_pointer() : value_(0) {}
ref_pointer(pointer value, bool addref = true) : value_(value) { if (value_ && addref) value_->add_ref(); }
ref_pointer(const ref_pointer& rhs) : value_(rhs.value_) { if (value_) value_->add_ref(); }
template <class U> ref_pointer(const ref_pointer<U>& rhs) : value_(rhs.value_) { if (value_) value_->add_ref(); }
~ref_pointer() { if (value_) value_->release(); value_ = 0; }
ref_pointer& operator = (reference value) { return assign(&value, false); }
ref_pointer& operator = (pointer value) { return assign(value); }
ref_pointer& operator = (const ref_pointer& rhs) { return assign(rhs.value_); }
template <class U> ref_pointer& operator = (const ref_pointer<U>& rhs) { return assign(rhs.value_); }
const_pointer operator -> () const { THOR_DEBUG_ASSERT(value_); return value_; }
pointer operator -> () { THOR_DEBUG_ASSERT(value_); return value_; }
const_reference operator * () const { THOR_DEBUG_ASSERT(value_); return *value_; }
reference operator * () { THOR_DEBUG_ASSERT(value_); return *value_; }
operator pointer () { return value_; }
operator const_pointer () const { return value_; }
ref_pointer& assign(pointer value, bool addref = true)
{
if (value && addref)
{
value->add_ref();
}
if (value_)
{
value_->release();
}
value_ = value;
return *this;
}
pointer get() { return value_; }
const_pointer get() const { return value_; }
private:
pointer value_;
};
}
#endif