00001 /* 00002 * This file is part of the "Archon" framework. 00003 * (http://files3d.sourceforge.net) 00004 * 00005 * Copyright © 2002 by Kristian Spangsege and Brian Kristiansen. 00006 * 00007 * Permission to use, copy, modify, and distribute this software and 00008 * its documentation under the terms of the GNU General Public License is 00009 * hereby granted. No representations are made about the suitability of 00010 * this software for any purpose. It is provided "as is" without express 00011 * or implied warranty. See the GNU General Public License 00012 * (http://www.gnu.org/copyleft/gpl.html) for more details. 00013 * 00014 * The characters in this file are ISO8859-1 encoded. 00015 * 00016 * The documentation in this file is in "Doxygen" style 00017 * (http://www.doxygen.org). 00018 */ 00019 00020 #ifndef ARCHON_UTILITIES_MUTA_REF_H 00021 #define ARCHON_UTILITIES_MUTA_REF_H 00022 00023 #include <archon/util/exception.H> 00024 #include <archon/util/atomic.H> 00025 00026 namespace Archon 00027 { 00028 namespace Utilities 00029 { 00030 using namespace std; 00031 00075 template<typename T> 00076 struct MutaRef 00077 { 00078 typedef T ObjectType; 00079 00111 void reset(T *q = 0) 00112 { 00113 _reset(q); 00114 } 00115 00147 void mutate() 00148 { 00149 if(!p) return; 00150 00151 /* 00152 * Since this MutaRef variable exists, the reference count of 00153 * the referenced object cannot be zero. It cannot _become_ 00154 * zero since concurrent access to a MutaRef variable is 00155 * forbidden. 00156 * 00157 * If we find the object to be in the leaked state we know 00158 * it will remain in the leaked state (zero was not an 00159 * option.) If we find that the object has a reference count 00160 * of 1 we known that this MutaRef variable is the only 00161 * counted reference to the object, thus no new counted 00162 * references can be made to the object during the execution 00163 * of this function. Neither can the object enter the leaked 00164 * state. 00165 * 00166 * In summary, both -1 and 1 are stable states individually. 00167 * 00168 * Please note that the inverse of the test is not stable 00169 * (state 1 may be entered after the test but before the clone 00170 * operation), thus, the cloning may be carried out in vain. 00171 */ 00172 if(p->refCount == -1 || p->refCount == 1) return; 00173 00174 _clone(); 00175 } 00176 00202 void leak() 00203 { 00204 if(!p) return; 00205 00206 /* 00207 * Since this MutaRef variable exists, the reference count of 00208 * the referenced object cannot be zero. It cannot become zero 00209 * since concurrent access to a MutaRef variable is forbidden. 00210 * 00211 * If we find that the object is in the leaked state we know 00212 * that it will remain in the leaked state (zero was not an 00213 * option.) So, in this case we are done. 00214 */ 00215 if(p->refCount == -1) return; 00216 00217 /* 00218 * At this point we know that the reference count is at least 00219 * 1. If we find it to be 1 we know that it will remain on 00220 * 1. Thus, failure of the following test is enough to 00221 * guarantee that the referenced object is unshared. 00222 * 00223 * We also have a guarantee that the referenced object is 00224 * unshared after calling clone(). 00225 */ 00226 if(p->refCount != 1) _clone(); 00227 00228 /* 00229 * At this point we know for sure that the reference count is 00230 * equal to 1 and will remain equal to 1 untill the assignment 00231 * below modifies it. 00232 */ 00233 p->refCount = -1; 00234 } 00235 00239 MutaRef(): p(0) {} 00240 00244 MutaRef(const MutaRef &r): p(_copy(r.p)) {} 00245 00246 ~MutaRef() 00247 { 00248 _break(); 00249 } 00250 00254 MutaRef &operator=(const MutaRef &r) 00255 { 00256 _reset(r.p); 00257 return *this; 00258 } 00259 00260 T *operator->() const 00261 { 00262 if(p) return p; 00263 ARCHON_THROW1(StateException, "Dereferencing null"); 00264 } 00265 00266 operator bool() const { return p; } 00267 00268 private: 00269 T *p; 00270 00271 void _clone() 00272 { 00273 _break(dynamic_cast<T *>(p->refClone())); 00274 ++p->refCount; 00275 } 00276 00292 static T *_copy(T *q) 00293 { 00294 if(!q) return 0; 00295 00296 if(q->refCount == -1) q = dynamic_cast<T *>(q->refClone()); 00297 00298 /* 00299 * It is important that the incrementation below never happens 00300 * on an object in the leaked state. 00301 * 00302 * A transition to the leaked state can only occur from a 00303 * state where the reference count is 1. Thus to become -1 it 00304 * must fist become 1. 00305 * 00306 * When the reference count reaches 1 there must be 00307 * exactly 1 other MutaRef variables pointing to the same 00308 * object as this MutaRef variable (this MutaRef varibale 00309 * does not yet count.) 00310 * 00311 * This rules out the cases where the reference count is zero 00312 * at entry and the those where we did a clone operation, 00313 * since in those cases no other MutaRef variable could exist 00314 * (we are busy creating the first one.) 00315 * 00316 * Consequently this case must be one where we are 00317 * constructing this MutaRef variable as a copy of another. 00318 * 00319 * Since the construction of this MutaRef variable is not yet 00320 * complete, a transition to the leaked state must be 00321 * performed by calling leak() on some other MutaRef variable. 00322 * 00323 * Since there was only 1 other MutaRef variable, the one on 00324 * which leak() is called must be the same one that we are 00325 * copying. 00326 * 00327 * Now, such concurrent access is illegal and thus impossible. 00328 * 00329 * In other words, we know that the reference count cannot be 00330 * -1 when the following incrementation occurs. 00331 */ 00332 ++q->refCount; 00333 00334 return q; 00335 } 00336 00349 void _break(T *q = 0) 00350 { 00351 /* 00352 * If we find the object to be in the leaked state, there is 00353 * only one reference to the object which must be the 00354 * reference we are about to destroy. Since this reference is 00355 * protected against access from other threads, the reference 00356 * count will remain on -1 untill the object is destoyed 00357 * below. 00358 * 00359 * On the other hand, if we find the object not to be in the 00360 * leaked state, we know that the reference count will be at 00361 * least 1 and that it will continue to be at least 1 until 00362 * modified by this thread below. We know this because the 00363 * refernce count was not 0 at entry and cannot become 0 prior 00364 * to the modification below since this variable represented 00365 * one reference at entry and access from other threads is 00366 * forbidden. Further more, a transition to the leaked state 00367 * can only be initiated when the reference count is equal to 00368 * 1. If the reference count is 1 or does become 1 the object 00369 * can no longer be accessed by other threads and thus, a 00370 * transition to the leaked state is impossible. 00371 */ 00372 if(p && (p->refCount == -1 || p->refCount.decAndZeroTest())) 00373 p->refDelete(); 00374 00375 p = q; 00376 } 00377 00378 void _reset(T *q) 00379 { 00380 if(p == q) return; 00381 _break(_copy(q)); 00382 } 00383 }; 00384 00385 struct MutaRefObjectBase 00386 { 00387 protected: 00393 virtual MutaRefObjectBase *refClone() const = 0; 00394 00400 virtual void refDelete() throw() 00401 { 00402 delete this; 00403 } 00404 00405 MutaRefObjectBase(): refCount(0) {} 00406 00410 virtual ~MutaRefObjectBase() {} 00411 00412 private: 00413 template<typename T> friend struct MutaRef; 00414 00415 /* 00416 * <pre> 00417 * 00418 * -1 Leaked object 00419 * 0 Fresh unreferenced object (or abandoned object) 00420 * >0 Referenced object 00421 * 00422 * Fresh Referenced Leaked Abandoned 00423 * 00424 * ,--> (-1) 00425 * (0) ---> (>0) --< 00426 * `------------> (0) 00427 * 00428 * </pre> 00429 * 00430 * The abandoned state will only exist shortly since it triggers 00431 * the deletion of the object. 00432 */ 00433 mutable Atomic refCount; 00434 }; 00435 00444 template<typename T> 00445 struct MutaRefObject: MutaRefObjectBase 00446 { 00447 MutaRefObject(T v): value(v) {} 00448 00449 MutaRefObject *refClone() const { return new MutaRefObject(value); } 00450 00451 T value; 00452 }; 00453 } 00454 } 00455 00456 #endif // ARCHON_UTILITIES_MUTA_REF_H