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