Panda3D
updateSeq.I
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file updateSeq.I
10  * @author drose
11  * @date 1999-09-30
12  */
13 
14 /**
15  * Creates an UpdateSeq in the given state.
16  */
17 constexpr UpdateSeq::
18 UpdateSeq(unsigned int seq) : _seq(seq) {
19 }
20 
21 /**
22  * Creates an UpdateSeq in the 'initial' state.
23  */
24 constexpr UpdateSeq::
25 UpdateSeq() : _seq((unsigned int)SC_initial) {
26 }
27 
28 /**
29  *
30  */
31 INLINE UpdateSeq::
32 UpdateSeq(const UpdateSeq &copy) : _seq(AtomicAdjust::get(copy._seq)) {
33 }
34 
35 /**
36  *
37  */
38 constexpr UpdateSeq::
39 UpdateSeq(const UpdateSeq &&from) noexcept : _seq(from._seq) {
40 }
41 
42 /**
43  *
44  */
45 INLINE UpdateSeq &UpdateSeq::
46 operator = (const UpdateSeq &copy) {
47  AtomicAdjust::set(_seq, AtomicAdjust::get(copy._seq));
48  return *this;
49 }
50 
51 /**
52  * Resets the UpdateSeq to the 'initial' state.
53  */
54 INLINE void UpdateSeq::
55 clear() {
56  AtomicAdjust::set(_seq, (AtomicAdjust::Integer)SC_initial);
57 }
58 
59 /**
60  * Returns true if the UpdateSeq is in the 'initial' state.
61  */
62 INLINE bool UpdateSeq::
63 is_initial() const {
64  return AtomicAdjust::get(_seq) == (AtomicAdjust::Integer)SC_initial;
65 }
66 
67 /**
68  * Returns true if the UpdateSeq is in the 'old' state.
69  */
70 INLINE bool UpdateSeq::
71 is_old() const {
72  return AtomicAdjust::get(_seq) == (AtomicAdjust::Integer)SC_old;
73 }
74 
75 /**
76  * Returns true if the UpdateSeq is in the 'fresh' state.
77  */
78 INLINE bool UpdateSeq::
79 is_fresh() const {
80  return AtomicAdjust::get(_seq) == (AtomicAdjust::Integer)SC_fresh;
81 }
82 
83 /**
84  * Returns true if the UpdateSeq is in any special states, i.e. 'initial',
85  * 'old', or 'fresh'.
86  */
87 INLINE bool UpdateSeq::
88 is_special() const {
89  // This relies on the assumption that (~0 + 1) == 0.
90  return (((unsigned int)AtomicAdjust::get(_seq) + 1u) <= 2u);
91 }
92 
93 /**
94  *
95  */
96 INLINE bool UpdateSeq::
97 operator == (const UpdateSeq &other) const {
98  return AtomicAdjust::get(_seq) == AtomicAdjust::get(other._seq);
99 }
100 
101 /**
102  *
103  */
104 INLINE bool UpdateSeq::
105 operator != (const UpdateSeq &other) const {
106  return AtomicAdjust::get(_seq) != AtomicAdjust::get(other._seq);
107 }
108 
109 /**
110  *
111  */
112 INLINE bool UpdateSeq::
113 operator < (const UpdateSeq &other) const {
114  return priv_lt(AtomicAdjust::get(_seq), AtomicAdjust::get(other._seq));
115 }
116 
117 /**
118  *
119  */
120 INLINE bool UpdateSeq::
121 operator <= (const UpdateSeq &other) const {
122  return priv_le(AtomicAdjust::get(_seq), AtomicAdjust::get(other._seq));
123 }
124 
125 /**
126  *
127  */
128 INLINE bool UpdateSeq::
129 operator > (const UpdateSeq &other) const {
130  return (other < (*this));
131 }
132 
133 /**
134  *
135  */
136 INLINE bool UpdateSeq::
137 operator >= (const UpdateSeq &other) const {
138  return (other <= (*this));
139 }
140 
141 /**
142  *
143  */
144 INLINE UpdateSeq UpdateSeq::
145 operator ++ () {
146  AtomicAdjust::Integer old_seq = AtomicAdjust::get(_seq);
147  AtomicAdjust::Integer new_seq = old_seq + 1;
148  if (priv_is_special(new_seq)) {
149  // Oops, wraparound. We don't want to confuse the new value with our
150  // special cases.
151  new_seq = (AtomicAdjust::Integer)SC_old + 1;
152  }
153 
154 #ifdef HAVE_THREADS
155  AtomicAdjust::Integer result = AtomicAdjust::compare_and_exchange(_seq, old_seq, new_seq);
156  while (result != old_seq) {
157  // Some other thread beat us to it; try again.
158  old_seq = AtomicAdjust::get(_seq);
159  new_seq = old_seq + 1;
160  if (priv_is_special(new_seq)) {
161  // Oops, wraparound. We don't want to confuse the new value with our
162  // special cases.
163  new_seq = (AtomicAdjust::Integer)SC_old + 1;
164  }
165  result = AtomicAdjust::compare_and_exchange(_seq, old_seq, new_seq);
166  }
167 #else
168  _seq = new_seq;
169 #endif // HAVE_THREADS
170 
171  return *this;
172 }
173 
174 /**
175  *
176  */
177 INLINE UpdateSeq UpdateSeq::
178 operator ++ (int) {
179  AtomicAdjust::Integer old_seq = AtomicAdjust::get(_seq);
180  AtomicAdjust::Integer new_seq = old_seq + 1;
181  if (priv_is_special(new_seq)) {
182  // Oops, wraparound. We don't want to confuse the new value with our
183  // special cases.
184  new_seq = (AtomicAdjust::Integer)SC_old + 1;
185  }
186 
187 #ifdef HAVE_THREADS
188  AtomicAdjust::Integer result = AtomicAdjust::compare_and_exchange(_seq, old_seq, new_seq);
189  while (result != old_seq) {
190  // Some other thread beat us to it; try again.
191  old_seq = AtomicAdjust::get(_seq);
192  new_seq = old_seq + 1;
193  if (priv_is_special(new_seq)) {
194  // Oops, wraparound. We don't want to confuse the new value with our
195  // special cases.
196  new_seq = (AtomicAdjust::Integer)SC_old + 1;
197  }
198  result = AtomicAdjust::compare_and_exchange(_seq, old_seq, new_seq);
199  }
200 #else
201  _seq = new_seq;
202 #endif // HAVE_THREADS
203 
204  UpdateSeq temp;
205  temp._seq = old_seq;
206  return temp;
207 }
208 
209 /**
210  * Returns the internal integer value associated with the UpdateSeq. Useful
211  * for debugging only.
212  */
213 INLINE AtomicAdjust::Integer UpdateSeq::
214 get_seq() const {
215  return _seq;
216 }
217 
218 /**
219  *
220  */
221 INLINE void UpdateSeq::
222 output(std::ostream &out) const {
223  AtomicAdjust::Integer seq = AtomicAdjust::get(_seq);
224  switch (seq) {
225  case (AtomicAdjust::Integer)SC_initial:
226  out << "initial";
227  break;
228 
229  case (AtomicAdjust::Integer)SC_old:
230  out << "old";
231  break;
232 
233  case (AtomicAdjust::Integer)SC_fresh:
234  out << "fresh";
235  break;
236 
237  default:
238  out << (int)seq;
239  }
240 }
241 
242 /**
243  * The private implementation of is_special().
244  */
245 INLINE bool UpdateSeq::
246 priv_is_special(AtomicAdjust::Integer seq) {
247  // This relies on the assumption that (~0 + 1) == 0.
248  return (((unsigned int)seq + 1) <= 2);
249 }
250 
251 /**
252  * The private implementation of operator < ().
253  */
254 INLINE bool UpdateSeq::
255 priv_lt(AtomicAdjust::Integer a, AtomicAdjust::Integer b) {
256  // The special cases of SC_initial or SC_old are less than all other non-
257  // special numbers, and SC_initial is less than SC_old. The special case of
258  // SC_fresh is greater than all other non-special numbers. For all other
259  // cases, we use a circular comparision such that n < m iff (signed)(n - m)
260  // < 0.
261  return
262  (priv_is_special(a) || priv_is_special(b)) ? ((unsigned int)a < (unsigned int)b) :
263  ((signed int)(a - b) < 0);
264 }
265 
266 /**
267  * The private implementation of operator <= ().
268  */
269 INLINE bool UpdateSeq::
270 priv_le(AtomicAdjust::Integer a, AtomicAdjust::Integer b) {
271  return (a == b) || priv_lt(a, b);
272 }
273 
274 INLINE std::ostream &operator << (std::ostream &out, const UpdateSeq &value) {
275  value.output(out);
276  return out;
277 }
void clear()
Resets the UpdateSeq to the 'initial' state.
Definition: updateSeq.I:55
bool is_special() const
Returns true if the UpdateSeq is in any special states, i.e.
Definition: updateSeq.I:88
bool is_initial() const
Returns true if the UpdateSeq is in the 'initial' state.
Definition: updateSeq.I:63
A trivial implementation for atomic adjustments for systems that don't require multiprogramming,...
constexpr UpdateSeq()
Creates an UpdateSeq in the 'initial' state.
Definition: updateSeq.I:25
static Integer get(const Integer &var)
Atomically retrieves the snapshot value of the indicated variable.
bool is_fresh() const
Returns true if the UpdateSeq is in the 'fresh' state.
Definition: updateSeq.I:79
static Integer set(Integer &var, Integer new_value)
Atomically changes the indicated variable and returns the original value.
bool is_old() const
Returns true if the UpdateSeq is in the 'old' state.
Definition: updateSeq.I:71
This is a sequence number that increments monotonically.
Definition: updateSeq.h:37
static Integer compare_and_exchange(Integer &mem, Integer old_value, Integer new_value)
Atomic compare and exchange.