MPQC  3.0.0-alpha
ref.h
1 //
2 // ref.h --- definitions of the reference counting classes
3 //
4 // Copyright (C) 1996 Limit Point Systems, Inc.
5 //
6 // Author: Curtis Janssen <cljanss@limitpt.com>
7 // Maintainer: LPS
8 //
9 // This file is part of the SC Toolkit.
10 //
11 // The SC Toolkit is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU Library General Public License as published by
13 // the Free Software Foundation; either version 2, or (at your option)
14 // any later version.
15 //
16 // The SC Toolkit is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU Library General Public License for more details.
20 //
21 // You should have received a copy of the GNU Library General Public License
22 // along with the SC Toolkit; see the file COPYING.LIB. If not, write to
23 // the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24 //
25 // The U.S. Government is granted a limited license as per AL 91-7.
26 //
27 
28 // This is the main include file for the reference counting classes.
29 // This includes two other files: reftmpl.h and refmacr.h. The
30 // former is a template declaration for the reference counted classes
31 // and the latter is generated from the former by a perl script and
32 // provides CPP macros that declare reference counting classes.
33 //
34 // The behaviour of the package can be modified with the following five
35 // macros, each of which should be undefined, 0, or 1:
36 //
37 // REF_CHECK_STACK: If this is 1 referenced objects are checked to see if they
38 // reside on the stack, in which case storage for the object is not managed,
39 // if management is enabled. This feature can be confused by multiple threads
40 // and memory checking libraries.
41 //
42 // REF_MANAGE: If this is 1 the manage and unmanage members are enabled.
43 //
44 // REF_CHECK_MAX_NREF: If this is 1 the reference count is checked before
45 // it is incremented to make sure it isn't too big.
46 //
47 // REF_CHECK_MIN_NREF: If this is 1 the reference count is checked before
48 // it is decremented to make sure it isn't already zero.
49 //
50 // REF_USE_LOCKS: If this is 1 then critical regions are locked before they
51 // are entered. This prevents erroneous behavior when multiple threads
52 // share reference counted objects. This will slow down certain operations,
53 // so it should be set to 0 if your application does not need to be thread
54 // safe.
55 //
56 // If a macro is undefined, then the behaviour is architecture
57 // dependent--usually, the macro will be set to 1 in this case.
58 // For maximum efficiency and for normal operation after the program is
59 // debugged, compile with all of the above macros defined to zero.
60 // This can also be done with -DREF_OPTIMIZE.
61 //
62 // An include file can be used to set these options as well. This has
63 // the advantage that dependency checking will force an automatic
64 // recompile of all affected files if the options change. The file
65 // <mpqc_config.h> will be include if -DHAVE_CONFIG_H is specified.
66 //
67 // Note that all source code that uses references must be compiled with
68 // the same value REF_MANAGE. Changing this can change the storage layout
69 // and the interpretation of the reference count data.
70 
71 
72 #ifndef _util_ref_ref_h
73 #define _util_ref_ref_h
74 
75 #include <iostream>
76 #include <stdlib.h>
77 #include <limits.h>
78 #include <cassert>
79 #include <util/misc/assert.h>
80 
81 #ifdef HAVE_CONFIG_H
82 #include <mpqc_config.h>
83 #endif
84 
85 #ifdef REF_OPTIMIZE
86 #ifndef REF_CHECK_STACK
87 # define REF_CHECK_STACK 0
88 #endif
89 #ifndef REF_MANAGE
90 # define REF_MANAGE 0
91 #endif
92 #ifndef REF_CHECK_MAX_NREF
93 # define REF_CHECK_MAX_NREF 0
94 #endif
95 #ifndef REF_CHECK_MIN_NREF
96 # define REF_CHECK_MIN_NREF 0
97 #endif
98 #endif
99 
100 #ifdef SUNMOS
101 #ifndef REF_CHECK_STACK
102 #define REF_CHECK_STACK 0
103 #endif
104 #else
105 #ifndef REF_CHECK_STACK
106 #define REF_CHECK_STACK 0
107 #endif
108 #endif
109 
110 #ifndef REF_MANAGE
111 #define REF_MANAGE 1
112 #endif
113 
114 #ifndef REF_CHECK_MAX_NREF
115 #define REF_CHECK_MAX_NREF 1
116 #endif
117 
118 #ifndef REF_CHECK_MIN_NREF
119 #define REF_CHECK_MIN_NREF 1
120 #endif
121 
122 #ifndef REF_USE_LOCKS
123 #if HAVE_STHREAD || HAVE_CREATETHREAD || HAVE_PTHREAD
124 #define REF_USE_LOCKS 1
125 #endif
126 #else // REF_USE_LOCKS
127 #warning "REF_USE_LOCKS not defined"
128 #endif
129 
130 #ifndef REF_ALWAYS_USE_LOCKS
131 #define REF_ALWAYS_USE_LOCKS 1
132 #endif
133 
134 #if REF_CHECK_STACK
135 #include <unistd.h>
136 #ifndef HAVE_SBRK_DEC
137 extern "C" void * sbrk(ssize_t);
138 #endif
139 #define DO_REF_CHECK_STACK(p) (((void*) (p) > sbrk(0)) && (p)->managed())
140 #else // REF_CHECK_STACK
141 #define DO_REF_CHECK_STACK(p) (0)
142 #endif // REF_CHECK_STACK
143 
144 #if REF_MANAGE
145 #define DO_REF_UNMANAGE(p) ((p)->unmanage())
146 #else // REF_MANAGE
147 #define DO_REF_UNMANAGE(p)
148 #endif // REF_MANAGE
149 
150 #if REF_USE_LOCKS
151 #define __REF_LOCK__(p) p->lock_ptr()
152 #define __REF_UNLOCK__(p) p->unlock_ptr()
153 #if REF_ALWAYS_USE_LOCKS
154 #define __REF_INITLOCK__() use_locks(true)
155 #else
156 #define __REF_INITLOCK__() ref_lock_ = 0xff
157 #endif
158 #else
159 #define __REF_LOCK__(p)
160 #define __REF_UNLOCK__(p)
161 #define __REF_INITLOCK__()
162 #endif
163 
164 namespace sc {
165 
166 typedef unsigned long refcount_t;
167 
192 class RefCount {
193  private:
194 #if REF_MANAGE
195 # define REF_MAX_NREF (UINT_MAX - 1)
196 # define REF_MANAGED_CODE UINT_MAX
197 #else
198 # define REF_MAX_NREF UINT_MAX
199 #endif
200  unsigned int _reference_count_;
201 #if REF_USE_LOCKS
202  unsigned char ref_lock_;
203 #endif
204 
205  void error(const char*) const;
206  void too_many_refs() const;
207  void not_enough_refs() const;
208  protected:
209  RefCount(): _reference_count_(0) {
210  __REF_INITLOCK__();
211  //std::cout << "ref_lock_ = " << (int) ref_lock_ << std::endl;
212  }
213  RefCount(const RefCount&): _reference_count_(0) {
214  __REF_INITLOCK__();
215  //std::cout << "ref_lock_ = " << (int) ref_lock_ << std::endl;
216  }
217 
218  // Assigment should not overwrite the reference count.
219  RefCount& operator=(const RefCount&) { return *this; }
220  public:
221  virtual ~RefCount();
222 
252  size_t identifier() const { return reinterpret_cast<const size_t>(this); }
253 
255  int lock_ptr() const;
257  int unlock_ptr() const;
258 
260  void use_locks(bool inVal);
261 
263  refcount_t nreference() const {
264 # if REF_MANAGE
265  if (!managed()) return 1;
266 # endif
267  return _reference_count_;
268  }
269 
271  refcount_t reference() {
272 # if REF_MANAGE
273  if (!managed()) return 1;
274 # endif
275  __REF_LOCK__(this);
276 # if REF_CHECK_MAX_NREF
277  if (_reference_count_ >= REF_MAX_NREF) too_many_refs();
278 # endif
279  _reference_count_++;
280  refcount_t r = _reference_count_;
281  __REF_UNLOCK__(this);
282  return r;
283  }
284 
286  refcount_t dereference() {
287 # if REF_MANAGE
288  if (!managed()) return 1;
289 # endif
290  __REF_LOCK__(this);
291 # if REF_CHECK_MIN_NREF
292  if (_reference_count_ == 0) not_enough_refs();
293 # endif
294  _reference_count_--;
295  refcount_t r = _reference_count_;
296  __REF_UNLOCK__(this);
297  return r;
298  }
299 
300 #if REF_MANAGE
301  int managed() const {
302  return _reference_count_ != REF_MANAGED_CODE;
303  }
309  void unmanage() {
310  _reference_count_ = REF_MANAGED_CODE;
311  }
312 #else // REF_MANAGE
313  int managed() const { return 1; }
315 #endif // REF_MANAGE
316 };
317 
321 class RefBase {
322  protected:
324  void warn ( const char * msg) const;
326  void warn_ref_to_stack() const;
328  void warn_skip_stack_delete() const;
330  void warn_bad_ref_count() const;
332  void ref_info(RefCount*p,std::ostream& os) const;
333  void ref_info(std::ostream& os) const;
334  void check_pointer() const;
335  void reference(RefCount *);
336  int dereference(RefCount *);
337  public:
338  RefBase() {};
339  virtual ~RefBase();
341  virtual RefCount* parentpointer() const = 0;
344  void require_nonnull() const;
345 };
346 
360 template <class T>
361 class Ref : public RefBase {
362  public:
363  typedef T element_type;
364  private:
365  T* p;
366  public:
368  Ref(): p(0) {}
370  Ref(T*a) : p(0)
371  {
372  if (a) {
373  p = a;
374  reference(p);
375  }
376  }
378  Ref(const Ref<T> &a) : p(0)
379  {
380  if (a.pointer()) {
381  p = a.pointer();
382  reference(p);
383  }
384  }
386  template <class A> Ref(const Ref<A> &a): p(0)
387  {
388  if (a.pointer()) {
389  p = a.pointer();
390  reference(p);
391  }
392  }
393 // /** Create a reference to the object a. Do a
394 // dynamic_cast to convert a to the appropiate type. */
395 // Ref(const RefBase&a) {
396 // p = dynamic_cast<T*>(a.parentpointer());
397 // reference(p);
398 // }
399 // /** Create a reference to the object a. Do a
400 // dynamic_cast to convert a to the appropiate type. */
401 // Ref(RefCount*a): p(0) {
402 // operator<<(a);
403 // }
407  {
408  clear();
409  }
411  T* operator->() const { MPQC_ASSERT(p!=0); return p; }
413  T* pointer() const { return p; }
415  RefCount *parentpointer() const { return p; }
416 
417  operator T*() const { return p; }
420  T& operator *() const { MPQC_ASSERT(p!=0); return *p; };
423  bool null() const { return p == 0; }
424  bool operator!() const {
425  return null();
426  }
427 
428 
433  template <class A> int operator==(const Ref<A>&a) const
434  {
435  // If both pointers are 0 then they are equal
436  if(p == 0 && a.pointer() == 0){
437  return 1;
438  }
439  // If one pointer is 0 and the other is not then they are different
440  else if((p != 0 && a.pointer() == 0) || (p == 0 && a.pointer() != 0)){
441  return 0;
442  }
443  // If both pointers are not 0 then we need to check the identifiers.
444  else{
445  return p->identifier() == a->identifier();
446  }
447  }
448 
449  template <class A> int operator>=(const Ref<A>&a) const
450  {
451  // If both pointers are 0 then they are equal
452  if(p == 0 && a.pointer() == 0){
453  return 1;
454  }
455  // If p != 0 and a.p == 0 then the one that exists (p) is greater
456  else if((p != 0 && a.pointer() == 0)){
457  return 1;
458  }
459  // If p == 0 and a.p != 0 then the one that exists (a.p) is greater
460  else if((p == 0 && a.pointer() != 0)){
461  return 0;
462  }
463  // If both pointers are not 0 then we need to check the identifiers.
464  else{
465  return p->identifier() >= a->identifier();
466  }
467  }
468 
469  template <class A> int operator<=(const Ref<A>&a) const
470  {
471  // If both pointers are 0 then they are equal
472  if(p == 0 && a.pointer() == 0){
473  return 1;
474  }
475  // If p != 0 and a.p == 0 then the one that exists (p) is greater
476  else if((p != 0 && a.pointer() == 0)){
477  return 0;
478  }
479  // If p == 0 and a.p != 0 then the one that exists (a.p) is greater
480  else if((p == 0 && a.pointer() != 0)){
481  return 1;
482  }
483  // If both pointers are not 0 then we need to check the identifiers.
484  else{
485  return p->identifier() <= a->identifier();
486  }
487  }
488 
489  template <class A> int operator>(const Ref<A>&a) const
490  {
491  // If both pointers are 0 then they are equal
492  if(p == 0 && a.pointer() == 0){
493  return 0;
494  }
495  // If p != 0 and a.p == 0 then the one that exists (p) is greater
496  else if((p != 0 && a.pointer() == 0)){
497  return 1;
498  }
499  // If p == 0 and a.p != 0 then the one that exists (a.p) is greater
500  else if((p == 0 && a.pointer() != 0)){
501  return 0;
502  }
503  // If both pointers are not 0 then we need to check the identifiers.
504  else{
505  return p->identifier() > a->identifier();
506  }
507  }
508 
509  template <class A> int operator<(const Ref<A>&a) const
510  {
511  // If both pointers are 0 then they are equal
512  if(p == 0 && a.pointer() == 0){
513  return 0;
514  }
515  // If p != 0 and a.p == 0 then the one that exists (p) is greater
516  else if((p != 0 && a.pointer() == 0)){
517  return 0;
518  }
519  // If p == 0 and a.p != 0 then the one that exists (a.p) is greater
520  else if((p == 0 && a.pointer() != 0)){
521  return 1;
522  }
523  // If both pointers are not 0 then we need to check the identifiers.
524  else{
525  return p->identifier() < a->identifier();
526  }
527  }
528 
529  template <class A> int operator!=(const Ref<A>&a) const
530  {
531  // If both pointers are 0 then equal
532  if(p == 0 && a.pointer() == 0){
533  return 0;
534  }
535  // If one pointer is 0 and one is not then they are not equal
536  else if((p != 0 && a.pointer() == 0) || (p == 0 && a.pointer() != 0)){
537  return 1;
538  }
539  // If both pointers are not 0 then check id.
540  else{
541  return p->identifier() != a->identifier();
542  }
543  }
546  int compare(const Ref<T> &a) const {
547  return (p->identifier() == a->identifier())?0:(((p->identifier() < a->identifier())?-1:1));
548  }
550  void clear()
551  {
552  if (p) {
553  int ref = dereference(p);
554  if (ref == 0)
555  delete p;
556  p = 0;
557  }
558  }
560  Ref<T>& operator=(const Ref<T> & c)
561  {
562  T *cp = c.pointer();
563  if (cp) {
564  cp->reference();
565  clear();
566  p=cp;
567  }
568  else {
569  clear();
570  }
571  return *this;
572  }
574  template <class A> Ref<T>& operator=(const Ref<A> & c)
575  {
576  A *cp = c.pointer();
577  if (cp) {
578  cp->reference();
579  clear();
580  p=cp;
581  }
582  else {
583  clear();
584  }
585  return *this;
586  }
589  T* cr = dynamic_cast<T*>(a.parentpointer());
590  if (cr) {
591  reference(cr);
592  clear();
593  }
594  p = cr;
595  return *this;
596  }
601  T* cr = dynamic_cast<T*>(a);
602  if (cr) assign_pointer(cr);
603  else if (a && a->nreference() <= 0) delete a;
604  return *this;
605  }
608  {
609  assign_pointer(cr);
610  return *this;
611  }
613  void assign_pointer(T* cr)
614  {
615  if (cr) {
616  if (DO_REF_CHECK_STACK(cr)) {
617  DO_REF_UNMANAGE(cr);
619  }
620  cr->reference();
621  }
622  clear();
623  p = cr;
624  }
626  void check_pointer() const
627  {
628  if (p && p->nreference() <= 0) {
630  }
631  }
633  void ref_info(std::ostream& os) const
634  {
635  RefBase::ref_info(p,os);
636  }
638  void warn(const char*s) const { RefBase::warn(s); }
639 
641  bool nonnull() const { return !null(); }
642 
643  protected:
644 };
645 
646 template <class T>
647 std::ostream&
648 operator<<(std::ostream& os, const Ref<T>& r) {
649  r.ref_info(os);
650  return os;
651 }
652 
658 template <typename T, typename EqualTo = std::equal_to<T> >
660  bool operator()(const Ref<T>& obj1, const Ref<T>& obj2) {
661  EqualTo equal_functor;
662  return equal_functor(*obj1,*obj2);
663  }
664 };
665 
666 }
667 
668 #endif
669 
670 // ///////////////////////////////////////////////////////////////////////////
671 
672 // Local Variables:
673 // mode: c++
674 // c-file-style: "CLJ"
675 // End:
sc::RefBase::warn_bad_ref_count
void warn_bad_ref_count() const
Called when the reference count is corrupted.
sc::Ref::operator==
int operator==(const Ref< A > &a) const
Ordering and equivalence operators are determined by the identifier if both pointers are not null.
Definition: ref.h:433
sc::RefBase::warn_ref_to_stack
void warn_ref_to_stack() const
Called when stack data is referenced.
sc::Ref::compare
int compare(const Ref< T > &a) const
Compare two objects returning -1, 0, or 1.
Definition: ref.h:546
sc::Ref::nonnull
bool nonnull() const
Return !null().
Definition: ref.h:641
sc::RefBase::warn_skip_stack_delete
void warn_skip_stack_delete() const
Called when the deletion of stack data is skipped.
sc::Ref
A template class that maintains references counts.
Definition: ref.h:361
sc::Ref::Ref
Ref(const Ref< T > &a)
Create a reference to the object referred to by a.
Definition: ref.h:378
sc::Ref::Ref
Ref(const Ref< A > &a)
Create a reference to the object referred to by a.
Definition: ref.h:386
sc::Ref::operator<<
Ref< T > & operator<<(const RefBase &a)
Assignment to the object that a references using dynamic_cast.
Definition: ref.h:588
sc::Ref::operator=
Ref< T > & operator=(T *cr)
Assignment to cr.
Definition: ref.h:607
sc::Ref::pointer
T * pointer() const
Returns a pointer the reference counted object.
Definition: ref.h:413
sc::Ref::operator->
T * operator->() const
Returns the reference counted object.
Definition: ref.h:411
sc::Ref::operator*
T & operator*() const
Returns a C++ reference to the reference counted object.
Definition: ref.h:420
sc::Ref::clear
void clear()
Refer to the null object.
Definition: ref.h:550
sc::RefBase
Provides a few utility routines common to all Ref template instantiations.
Definition: ref.h:321
sc::RefCount::unlock_ptr
int unlock_ptr() const
Unlock this object.
sc::RefBase::ref_info
void ref_info(RefCount *p, std::ostream &os) const
Print information about the reference.
sc::RefCount::nreference
refcount_t nreference() const
Return the reference count.
Definition: ref.h:263
sc::Ref::Ref
Ref(T *a)
Create a reference to the object a.
Definition: ref.h:370
sc::RefCount::lock_ptr
int lock_ptr() const
Lock this object.
sc::operator<<
std::vector< unsigned int > operator<<(const GaussianBasisSet &B, const GaussianBasisSet &A)
computes a map from basis functions in A to the equivalent basis functions in B.
sc::Ref::assign_pointer
void assign_pointer(T *cr)
Assignment to cr.
Definition: ref.h:613
sc::RefCount::unmanage
void unmanage()
Turn off the reference counting mechanism for this object.
Definition: ref.h:309
sc::RefBase::parentpointer
virtual RefCount * parentpointer() const =0
Returns the DescribedClass pointer for the contained object.
sc::RefCount::dereference
refcount_t dereference()
Decrement the reference count and return the new count.
Definition: ref.h:286
sc::RefBase::require_nonnull
void require_nonnull() const
Requires that a nonnull reference is held.
sc::RefCount::use_locks
void use_locks(bool inVal)
start and stop using locks on this object
sc::Ref::Ref
Ref()
Create a reference to a null object.
Definition: ref.h:368
sc::Ref::~Ref
~Ref()
Create a reference to the object a.
Definition: ref.h:406
sc::Ref::ref_info
void ref_info(std::ostream &os) const
Print information about the reference to os.
Definition: ref.h:633
sc::RefCount::identifier
size_t identifier() const
Return the unique identifier for this object that can be compared for different objects of different ...
Definition: ref.h:252
sc::Ref::operator=
Ref< T > & operator=(const Ref< A > &c)
Assignment to c.
Definition: ref.h:574
sc::Ref::warn
void warn(const char *s) const
Print a warning concerning the reference.
Definition: ref.h:638
sc::RefCount
The base class for all reference counted objects.
Definition: ref.h:192
sc::Ref::check_pointer
void check_pointer() const
Check the validity of the pointer.
Definition: ref.h:626
sc::Ref::operator=
Ref< T > & operator=(const Ref< T > &c)
Assignment to c.
Definition: ref.h:560
sc
Contains all MPQC code up to version 3.
Definition: mpqcin.h:14
sc::RefBase::warn
void warn(const char *msg) const
Print a warning message.
sc::RefObjectEqual
this functor can be used as a binary predicate for standard algorithms.
Definition: ref.h:659
sc::Ref::parentpointer
RefCount * parentpointer() const
Implements the parentpointer pure virtual in the base class.
Definition: ref.h:415
sc::RefCount::reference
refcount_t reference()
Increment the reference count and return the new count.
Definition: ref.h:271

Generated at Sun Jan 26 2020 23:23:59 for MPQC 3.0.0-alpha using the documentation package Doxygen 1.8.16.