OpendTect  6.6
refcount.h
Go to the documentation of this file.
1 #pragma once
2 
3 /*+
4 ________________________________________________________________________
5 
6  (C) dGB Beheer B.V.; (LICENSE) http://opendtect.org/OpendTect_license.txt
7  Author: K. Tingdahl
8  Date: 13-11-2003
9  Contents: Basic functionality for reference counting
10  RCS: $Id$
11 ________________________________________________________________________
12 
13 -*/
14 
15 #include "atomic.h"
16 #include "objectset.h"
17 #include "thread.h"
18 
19 template <class T> class WeakPtr;
20 template <class T> class RefMan;
21 template <class T> class ConstRefMan;
22 
23 
24 #define mInvalidRefCount (-1)
25 
109 namespace RefCount
111 {
112 class WeakPtrBase;
113 
117 mExpClass(Basic) Counter
118 {
119 public:
120 
121  void ref();
122  bool tryRef();
126  bool unRef();
130  void unRefDontInvalidate();
132 
133  od_int32 count() const { return count_.load(); }
134  bool refIfReffed();
136 
137  void clearAllObservers();
138  void addObserver(WeakPtrBase* obj);
139  void removeObserver(WeakPtrBase* obj);
140 
141  Counter();
142  Counter(const Counter& a);
143 
144  static od_int32 cInvalidRefCount();
145  static od_int32 cStartRefCount();
146 
147 private:
148 
149  ObjectSet<WeakPtrBase> observers_;
150  Threads::SpinLock observerslock_;
151 
153 };
154 
159 mExpClass(Basic) Referenced
160 {
161 public:
162 
163  void ref() const;
164  void unRef() const;
165  void unRefNoDelete() const;
166 
167 protected:
168 
169  Referenced() {}
170  Referenced(const Referenced&);
171  Referenced& operator =(const Referenced&);
172  virtual ~Referenced();
173 
174 private:
175 
176  friend class WeakPtrBase;
177  virtual void refNotify() const {}
178  virtual void unRefNotify() const {}
179  virtual void unRefNoDeleteNotify() const {}
180  virtual void prepareForDelete() {}
181 
182  mutable Counter refcount_;
183 
184 public:
185 
186  int nrRefs() const;
188  bool refIfReffed() const;
190  bool tryRef() const;
192 
193  void addObserver(WeakPtrBase* obs);
195  void removeObserver(WeakPtrBase* obs);
197  static bool isSane(const Referenced*);
198  /*Returns true if this really is a referenced
199  (i.e. has magicnumber set ) */
200 
201 private:
202 
203  const od_uint64 magicnumber_ = 0x123456789abcdef;
204 
205 };
206 
207 
208 template <class T>
209 inline void refIfObjIsReffed( const T* obj )
210 {
211  if ( obj )
212  {
213  mDynamicCastGet( const RefCount::Referenced*, reffed, obj );
214  if ( reffed )
215  reffed->ref();
216  }
217 }
218 
219 template <class T>
220 inline void unRefIfObjIsReffed( const T* obj )
221 {
222  if ( obj )
223  {
224  mDynamicCastGet( const RefCount::Referenced*, reffed, obj );
225  if ( reffed )
226  reffed->unRef();
227  }
228 }
229 
230 template <class T> inline void refIfObjIsReffed( const T& obj )
231 { refIfObjIsReffed( &obj ); }
232 template <class T> inline void unRefIfObjIsReffed( const T& obj )
233 { unRefIfObjIsReffed( &obj ); }
234 
235 
236 
237 mExpClass(Basic) WeakPtrBase
238 {
239 public:
240 
241  typedef Threads::SpinLock LockType;
242 
243  operator bool() const;
244  bool operator!() const;
245  bool operator==( const WeakPtrBase& r ) const
246  { return ptr_==r.ptr_; }
247 
248 protected:
249 
250  WeakPtrBase();
251  void set(Referenced*);
252 
253  friend class Counter;
254 
255  void clearPtr();
256  mutable LockType lock_;
257  Referenced* ptr_;
258 
259 };
260 
261 
262 mExpClass(Basic) WeakPtrSetBase
263 {
264 public:
265 
266  mExpClass(Basic) CleanupBlocker
267  {
268  public:
269  CleanupBlocker( WeakPtrSetBase& base )
270  : base_( base ) { base_.blockCleanup(); }
271 
272  ~CleanupBlocker() { base_.unblockCleanup(); }
273  private:
274 
275  WeakPtrSetBase& base_;
276 
277  };
278 
279 protected:
280 
281  Threads::Atomic<int> blockcleanup_ = 0;
282 
283 private:
284 
285  friend class CleanupBlocker;
286  void blockCleanup();
287  void unblockCleanup();
288 
289 };
290 
291 
292 }; //RefCount namespace end
293 
294 
298 template <class T>
299 mClass(Basic) WeakPtr : public RefCount::WeakPtrBase
300 {
301 public:
302 
303  WeakPtr(RefCount::Referenced* p = 0) { set(p); }
304  WeakPtr(const WeakPtr<T>& p) : WeakPtr<T>( p.ptr_ ) {}
305  WeakPtr(RefMan<T>& p) : WeakPtr<T>(p.ptr()) {}
306  ~WeakPtr() { set( 0 ); }
307 
308  inline WeakPtr<T>& operator=(const WeakPtr<T>& p);
309  RefMan<T>& operator=(RefMan<T>& p)
310  { set(p.ptr()); return p; }
311  T* operator=(T* p)
312  { set(p); return p; }
313 
314  RefMan<T> get() const;
315 
316 };
317 
318 
319 //A collection of weak pointers
320 
321 template <class T>
322 mClass(Basic) WeakPtrSet : public RefCount::WeakPtrSetBase
323 {
324 public:
325 
326  typedef Threads::SpinLock LockType;
327  typedef TypeSet<WeakPtr<T> > SetType;
328  typedef int idx_type;
329  typedef int size_type;
330 
331  bool operator+=(const WeakPtr<T>&);
332  //Returns if added (i.e. not duplicate)
333  bool operator+=(RefMan<T>&);
334  //Returns if added (i.e. not duplicate)
335  size_type size() const;
336  RefMan<T> operator[](idx_type);
337  ConstRefMan<T> operator[](idx_type) const;
338 
339  idx_type indexOf(T*) const;
340 
341 
342 private:
343 
344  mutable LockType lock_;
345  SetType ptrs_;
346 
347 };
348 
349 
350 
351 #define mRefCountImplWithDestructor(ClassName, DestructorImpl, delfunc ) \
352 public: \
353  void ref() const \
354  { \
355  refcount_.ref(); \
356  refNotify(); \
357  } \
358  bool refIfReffed() const \
359  { \
360  if ( !refcount_.refIfReffed() ) \
361  return false; \
362  \
363  refNotify(); \
364  return true; \
365  } \
366  void unRef() const \
367  { \
368  unRefNotify(); \
369  if ( refcount_.unRef() ) \
370  delfunc; \
371  return; \
372  } \
373  \
374  void unRefNoDelete() const \
375  { \
376  unRefNoDeleteNotify(); \
377  refcount_.unRefDontInvalidate(); \
378  } \
379  int nrRefs() const { return refcount_.count(); } \
380 private: \
381  virtual void refNotify() const {} \
382  virtual void unRefNotify() const {} \
383  virtual void unRefNoDeleteNotify() const {} \
384  mutable ReferenceCounter refcount_; \
385 protected: \
386  DestructorImpl; \
387 private:
388 
389 
391 #define mRefCountImpl(ClassName) \
392 mRefCountImplWithDestructor(ClassName, virtual ~ClassName(), delete this; )
393 
395 #define mRefCountImplNoDestructor(ClassName) \
396 mRefCountImplWithDestructor(ClassName, virtual ~ClassName() {}, delete this; )
397 
398 
400 inline void refPtr( const RefCount::Referenced* ptr )
401 {
402  if ( ptr )
403  ptr->ref();
404 }
405 
407 inline void unRefPtr( const RefCount::Referenced* ptr )
408 {
409  if ( ptr )
410  ptr->unRef();
411 }
412 
414 inline void unRefNoDeletePtr( const RefCount::Referenced* ptr )
415 {
416  if ( ptr )
417  ptr->unRefNoDelete();
418 }
419 
421 template <class T> inline
422 void unRefAndZeroPtr( T*& ptr )
423 {
424  mDynamicCastGet(RefCount::Referenced*,refptr,ptr)
425  if ( refptr )
426  unRefPtr( refptr );
427  else if ( !ptr )
428  return;
429  else
430  ptr->unRef();
431  ptr = 0;
432 }
433 
434 template <class T> inline
435 void unRefAndZeroPtr( const T*& ptr )
436 {
437  mDynamicCastGet(const RefCount::Referenced*,refptr,ptr)
438  if ( refptr )
439  unRefPtr( refptr );
440  else if ( !ptr )
441  return;
442  else
443  ptr->unRef();
444  ptr = 0;
445 }
446 
447 
449 template <class T> inline
450 void unRefPtr( const T* ptr )
451 {
452  if ( !ptr ) return;
453  ptr->unRef();
454 }
455 
456 
458 template <class T> inline
459 void unRefNoDeletePtr( const T* ptr )
460 {
461  if ( !ptr ) return;
462  ptr->unRefNoDelete();
463 }
464 
465 
467 template <class T> inline
468 void refPtr( const T* ptr )
469 {
470  if ( !ptr ) return;
471  ptr->ref();
472 }
473 
474 mObjectSetApplyToAllFunc( deepUnRef, unRefPtr( os[idx] ), os.plainErase() )
475 mObjectSetApplyToAllFunc( deepUnRefNoDelete, unRefNoDeletePtr( os[idx] ),
476  os.plainErase() )
477 mObjectSetApplyToAllFunc( deepRef, refPtr( os[idx] ), )
478 
479 
483 mClass(Basic) ReferenceCounter
484 {
485 public:
486  inline void ref();
487  inline bool unRef();
491  inline void unRefDontInvalidate();
493 
494  od_int32 count() const { return count_.load(); }
495  inline bool refIfReffed();
497 
498 private:
499 
501 };
502 
503 
504 #ifdef __win__
505 # define mDeclareCounters od_int32 oldcount = count_.load(), newcount = 0
506 #else
507 # define mDeclareCounters od_int32 oldcount = count_.load(), newcount;
508 #endif
509 
510 inline void ReferenceCounter::ref()
511 {
512  mDeclareCounters;
513 
514  do
515  {
516  if ( oldcount==mInvalidRefCount )
517  {
518  pErrMsg("Invalid ref");
519 #ifdef __debug__
520  DBG::forceCrash(false);
521  newcount = 0; //To fool unitialized code warning
522 #else
523  newcount = 1; //Hoping for the best
524 #endif
525  }
526  else
527  {
528  newcount = oldcount+1;
529  }
530 
531  } while ( !count_.setIfValueIs( oldcount, newcount, &oldcount ) );
532 }
533 
534 
535 inline bool ReferenceCounter::unRef()
536 {
537  mDeclareCounters;
538 
539  do
540  {
541  if ( oldcount==mInvalidRefCount )
542  {
543  pErrMsg("Invalid reference.");
544 #ifdef __debug__
545  DBG::forceCrash(false);
546  newcount = 0; //To fool unitialized code warning
547 #else
548  return false;
549 #endif
550  }
551  else if ( oldcount==1 )
552  newcount = mInvalidRefCount;
553  else
554  newcount = oldcount-1;
555 
556  } while ( !count_.setIfValueIs(oldcount,newcount, &oldcount ) );
557 
558  return newcount==mInvalidRefCount;
559 }
560 
561 
562 inline bool ReferenceCounter::refIfReffed()
563 {
564  mDeclareCounters;
565 
566  do
567  {
568  if ( oldcount==mInvalidRefCount )
569  {
570  pErrMsg("Invalid ref");
571 #ifdef __debug__
572  DBG::forceCrash(false);
573 #else
574  return false; //Hoping for the best
575 #endif
576  }
577  else if ( !oldcount )
578  return false;
579 
580  newcount = oldcount+1;
581 
582  } while ( !count_.setIfValueIs( oldcount, newcount, &oldcount ) );
583 
584  return true;
585 }
586 
587 
588 inline void ReferenceCounter::unRefDontInvalidate()
589 {
590  mDeclareCounters;
591 
592  do
593  {
594  if ( oldcount==mInvalidRefCount )
595  {
596  pErrMsg("Invalid reference.");
597 #ifdef __debug__
598  DBG::forceCrash(false);
599  newcount = 0; //Fool the unitialized warning
600 #else
601  newcount = 0; //Hope for the best
602 #endif
603  }
604  else
605  newcount = oldcount-1;
606 
607  } while ( !count_.setIfValueIs( oldcount, newcount, &oldcount ) );
608 }
609 
610 #undef mDeclareCounters
611 
612 
613 //Implementations and legacy stuff below
614 
615 template <class T>
617 {
618  RefMan<T> ptr = wp.get();
619  ptr.setNoDelete( true );
620  set( ptr.ptr() );
621  return *this;
622 }
623 
624 
625 template <class T>
627 {
628  RefMan<T> res = 0;
629  if ( ptr_ && ptr_->tryRef() )
630  {
631  //reffed once through tryRef
632  res = (T*)ptr_;
633 
634  //unref the ref from tryRef
635  ptr_->unRef();
636  }
637 
638  return res;
639 }
640 
641 
642 template <class T> inline
643 bool WeakPtrSet<T>::operator+=( RefMan<T>& toadd )
644 {
645  T* ptr = toadd.ptr();
646  return WeakPtrSet<T>::operator+=( WeakPtr<T>(ptr) );
647 }
648 
649 template <class T> inline
650 bool WeakPtrSet<T>::operator+=( const WeakPtr<T>& toadd )
651 {
652  lock_.lock();
653 
654  const bool docleanup = blockcleanup_.setIfValueIs( 0, -1, nullptr );
655  for ( int idx=ptrs_.size()-1; idx>=0; idx-- )
656  {
657  if ( docleanup && !ptrs_[idx] )
658  { ptrs_.removeSingle( idx ); continue; }
659 
660  if ( ptrs_[idx]==toadd )
661  {
662  if ( docleanup )
663  blockcleanup_ = 0;
664  lock_.unLock();
665  return false;
666  }
667  }
668 
669  if ( docleanup )
670  blockcleanup_ = 0;
671 
672  ptrs_ += toadd;
673  lock_.unLock();
674 
675  return true;
676 }
677 
678 
679 template <class T> inline
680 int WeakPtrSet<T>::size() const
681 {
682  lock_.lock();
683  const int res = ptrs_.size();
684  lock_.unLock();
685  return res;
686 }
687 
688 
689 template <class T> inline
690 RefMan<T> WeakPtrSet<T>::operator[]( int idx )
691 {
692  lock_.lock();
693  RefMan<T> res = ptrs_.validIdx(idx) ? ptrs_[idx].get() : RefMan<T>( 0 );
694  lock_.unLock();
695  return res;
696 }
697 
698 
699 
700 template <class T> inline
701 ConstRefMan<T> WeakPtrSet<T>::operator[]( int idx ) const
702 {
703  lock_.lock();
704  ConstRefMan<T> res = ptrs_.validIdx(idx) ? ptrs_[idx].get() :
705  ConstRefMan<T>( 0 );
706  lock_.unLock();
707  return res;
708 }
ConstRefMan
Definition: ptrman.h:233
od_uint64
#define od_uint64
Definition: plftypes.h:36
ObjectSet
Set of pointers to objects.
Definition: commontypes.h:31
mExpClass
#define mExpClass(module)
Definition: commondefs.h:177
mDynamicCastGet
#define mDynamicCastGet(typ, out, in)
Definition: commondefs.h:148
operator==
bool operator==(const ArrayNDInfo &a1, const ArrayNDInfo &a2)
Definition: arrayndinfo.h:81
RefMan::setNoDelete
void setNoDelete(bool yn)
Definition: ptrman.h:494
RefMan::unRef
static void unRef(T *p)
Definition: ptrman.h:512
mObjectSetApplyToAllFunc
#define mObjectSetApplyToAllFunc(fn, op, extra)
Definition: objectset.h:144
Threads::SpinLock
Is an alternative to Mutex. It is a lock which causes a thread trying to acquire it to simply wait in...
Definition: atomic.h:108
indexOf
BufferStringSet::idx_type indexOf(const BufferStringSet &, const char *)
mClass
#define mClass(module)
Definition: commondefs.h:181
NonConstPtrManBase::ptr
const T * ptr() const
Definition: ptrman.h:100
pErrMsg
#define pErrMsg(msg)
Usual access point for programmer error messages.
Definition: errmsg.h:37
Conv::set
void set(T &_to, const F &fr)
template based type conversion
Definition: convert.h:27
WeakPtr
Definition: ptrman.h:22
od_int32
#define od_int32
Definition: plftypes.h:30
mInvalidRefCount
#define mInvalidRefCount
Definition: refcount.h:24
atomic.h
DBG::forceCrash
void forceCrash(bool withdump)
thread.h
objectset.h
Threads::Atomic
Definition: atomic.h:27
TypeSet
Sets of (small) copyable elements.
Definition: commontypes.h:29
RefMan
Definition: ptrman.h:206

Generated at for the OpendTect seismic interpretation project. Copyright (C): dGB Beheer B.V. 1995-2021