1 // Copyright (C) 2000 Sean Cavanaugh
2 // This file is licensed under the terms of the Lesser GNU Public License
3 // (see LPGL.txt, or http://www.gnu.org/copyleft/lesser.txt)
4
5 #ifndef ReferenceCounter_H__
6 #define ReferenceCounter_H__
7
8 #if _MSC_VER > 1000
9 #pragma once
10 #endif // _MSC_VER > 1000
11
12 #ifdef _WIN32
13 #define WIN32_LEAN_AND_MEAN
14 #include <windows.h>
15 #endif
16
17 #ifdef HAVE_SYS_ATOMIC_H
18 #include <sys/atomic.h>
19 #endif
20
21 #ifdef HAVE_ASM_ATOMIC_H
22 #include <asm/atomic.h>
23 #endif
24
25 /*!
26 \author Sean Cavanaugh
27 \email sean@dimensionalrift.com
28 \cvsauthor $Author: sean $
29 \date $Date: 2000/09/11 20:28:24 $
30 \version $Revision: 1.1 $
31 \brief ReferenceCounter abstracts a reference counted integer with proper thread safe access
32 The interface is not platform specific in any way, except the protected data
33 is platform specific, as well as the implementation details
34 */
35
36 class ReferenceCounter
37 {
38 // Construction
39 public:
40 ReferenceCounter();
41 ReferenceCounter(int InitialValue);
~ReferenceCounter()42 virtual ~ReferenceCounter() {} // Should optimize to nothing except in the derived-class case
ReferenceCounter(const ReferenceCounter & other)43 ReferenceCounter(const ReferenceCounter& other) {copy(other);}
44 ReferenceCounter& operator=(const ReferenceCounter& other) {copy(other); return *this;}
45
46 public:
47 // User functions
48 inline int add(int amt);// increment the value by amt, returns the ORIGINAL value
49 inline int sub(int amt);// increment the value by amt, returns the ORIGINAL value
50 inline int inc();// increment the value, returns the NEW value
51 inline int dec();// decrement the value, returns the NEW value
52 inline int read() const;// read the current value
53 inline void write(int newvalue);// change the counter to a new value blindly
54 inline int swap(int newvalue);// change the counter to a new value, and return the ORIGINAL value
55
56 // Convenient Operators
57 int operator++() {return inc();}
58 int operator--() {return dec();}
59 int operator++(int) {return inc() - 1;}
60 int operator--(int) {return dec() + 1;}
61 int operator+=(int amt) {return add(amt) + amt;}
62 int operator-=(int amt) {return sub(amt) - amt;}
63 int operator=(int value) {write(value); return value;}
64 operator int() const {return read();}
65
66 // Internal Methods
67 protected:
68 inline void copy(const ReferenceCounter& other);
69
70 // Data
71 protected:
72 #ifdef SINGLE_THREADED
73 int m_atom;
74 #else //SINGLE_THREADED
75
76 #ifdef _WIN32
77 long m_atom;
78 #endif
79 #ifdef HAVE_ATOMIC
80 atomic_t m_atom;
81 #endif
82
83 #endif//SINGLE_THREADED
84 };
85
86
87 #ifdef SINGLE_THREADED
ReferenceCounter()88 inline ReferenceCounter::ReferenceCounter()
89 {
90 m_atom = 0;
91 }
ReferenceCounter(int InitialValue)92 inline ReferenceCounter::ReferenceCounter(int InitialValue)
93 {
94 m_atom = InitialValue;
95 }
add(int amt)96 inline int ReferenceCounter::add(int amt)
97 {
98 m_atom += amt;
99 return m_atom;
100 }
sub(int amt)101 inline int ReferenceCounter::sub(int amt)
102 {
103 m_atom -= amt;
104 return m_atom;
105 }
inc()106 inline int ReferenceCounter::inc()
107 {
108 m_atom++;
109 return m_atom;
110 }
dec()111 inline int ReferenceCounter::dec()
112 {
113 m_atom--;
114 return m_atom;
115 }
swap(int newvalue)116 inline int ReferenceCounter::swap(int newvalue)
117 {
118 int rval = m_atom;
119 m_atom = newvalue;
120 return rval;
121 }
write(int newvalue)122 inline void ReferenceCounter::write(int newvalue)
123 {
124 m_atom = newvalue;
125 }
read()126 inline int ReferenceCounter::read() const
127 {
128 return m_atom;
129 }
copy(const ReferenceCounter & other)130 inline void ReferenceCounter::copy(const ReferenceCounter& other)
131 {
132 m_atom = other.m_atom;
133 }
134 #else // SINGLE_THREADED
135
136 #ifdef _WIN32
ReferenceCounter()137 inline ReferenceCounter::ReferenceCounter()
138 {
139 m_atom = 0;
140 }
ReferenceCounter(int InitialValue)141 inline ReferenceCounter::ReferenceCounter(int InitialValue)
142 {
143 m_atom = InitialValue;
144 }
add(int amt)145 inline int ReferenceCounter::add(int amt)
146 {
147 return InterlockedExchangeAdd(&m_atom, amt);
148 }
sub(int amt)149 inline int ReferenceCounter::sub(int amt)
150 {
151 return InterlockedExchangeAdd(&m_atom, -amt);
152 }
inc()153 inline int ReferenceCounter::inc()
154 {
155 return InterlockedIncrement(&m_atom);
156 }
dec()157 inline int ReferenceCounter::dec()
158 {
159 return InterlockedDecrement(&m_atom);
160 }
swap(int newvalue)161 inline int ReferenceCounter::swap(int newvalue)
162 {
163 return InterlockedExchange(&m_atom, newvalue);
164 }
write(int newvalue)165 inline void ReferenceCounter::write(int newvalue)
166 {
167 InterlockedExchange(&m_atom, newvalue);
168 }
read()169 inline int ReferenceCounter::read() const
170 {
171 return m_atom;
172 }
copy(const ReferenceCounter & other)173 inline void ReferenceCounter::copy(const ReferenceCounter& other)
174 {
175 m_atom = other.m_atom;
176 }
177 #endif//_WIN32
178
179 #ifdef HAVE_ATOMIC
ReferenceCounter()180 inline ReferenceCounter::ReferenceCounter()
181 {
182 m_atom.counter = 0;
183 }
ReferenceCounter(int InitialValue)184 inline ReferenceCounter::ReferenceCounter(int InitialValue)
185 {
186 m_atom.counter = InitialValue;
187 }
add(int amt)188 inline int ReferenceCounter::add(int amt)
189 {
190 int rval = atomic_read(&m_atom);
191 atomic_add(amt, &m_atom);
192 return rval;
193 }
sub(int amt)194 inline int ReferenceCounter::sub(int amt)
195 {
196 int rval = atomic_read(&m_atom);
197 atomic_sub(amt, &m_atom);
198 return rval;
199 }
inc()200 inline int ReferenceCounter::inc()
201 {
202 int rval = atomic_read(&m_atom);
203 atomic_inc(&m_atom);
204 return rval + 1;
205 }
dec()206 inline int ReferenceCounter::dec()
207 {
208 int rval = atomic_read(&m_atom);
209 atomic_dec(&m_atom);
210 return rval - 1;
211 }
swap(int newvalue)212 inline int ReferenceCounter::swap(int newvalue)
213 {
214 int rval = atomic_read(&m_atom);
215 atomic_set(&m_atom, newvalue);
216 return rval;
217 }
write(int newvalue)218 inline void ReferenceCounter::write(int newvalue)
219 {
220 atomic_set(&m_atom, newvalue);
221 }
read()222 inline int ReferenceCounter::read() const
223 {
224 return atomic_read(&m_atom);
225 }
copy(const ReferenceCounter & other)226 inline void ReferenceCounter::copy(const ReferenceCounter& other)
227 {
228 m_atom.counter = other.read();
229 }
230 #endif//HAVE_ATOMIC
231 #endif//SINGLE_THREADED
232
233 #endif//ReferenceCounter_H__
234