Main Page   Class Hierarchy   Compound List   File List   Compound Members   Related Pages  

ref.h

00001 //
00002 // ref.h --- definitions of the reference counting classes
00003 //
00004 // Copyright (C) 1996 Limit Point Systems, Inc.
00005 //
00006 // Author: Curtis Janssen <cljanss@limitpt.com>
00007 // Maintainer: LPS
00008 //
00009 // This file is part of the SC Toolkit.
00010 //
00011 // The SC Toolkit is free software; you can redistribute it and/or modify
00012 // it under the terms of the GNU Library General Public License as published by
00013 // the Free Software Foundation; either version 2, or (at your option)
00014 // any later version.
00015 //
00016 // The SC Toolkit is distributed in the hope that it will be useful,
00017 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 // GNU Library General Public License for more details.
00020 //
00021 // You should have received a copy of the GNU Library General Public License
00022 // along with the SC Toolkit; see the file COPYING.LIB.  If not, write to
00023 // the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
00024 //
00025 // The U.S. Government is granted a limited license as per AL 91-7.
00026 //
00027 
00028 //   This is the main include file for the reference counting classes.
00029 // This includes two other files: reftmpl.h and refmacr.h.  The
00030 // former is a template declaration for the reference counted classes
00031 // and the latter is generated from the former by a perl script and
00032 // provides CPP macros that declare reference counting classes.
00033 //
00034 //   The behaviour of the package can be modified with the following five
00035 // macros, each of which should be undefined, 0, or 1:
00036 //
00037 // REF_CHECK_STACK:  If this is 1 referenced objects are checked to see if they
00038 // reside on the stack, in which case storage for the object is not managed,
00039 // if management is enabled.  This feature can be confused by multiple threads
00040 // and memory checking libraries.
00041 //
00042 // REF_MANAGE:  If this is 1 the manage and unmanage members are enabled.
00043 //
00044 // REF_CHECK_MAX_NREF:  If this is 1 the reference count is checked before
00045 // it is incremented to make sure it isn't too big.
00046 //
00047 // REF_CHECK_MIN_NREF:  If this is 1 the reference count is checked before
00048 // it is decremented to make sure it isn't already zero.
00049 //
00050 // REF_USE_LOCKS:  If this is 1 then critical regions are locked before they
00051 // are entered.  This prevents erroneous behavior when multiple threads
00052 // share reference counted objects.  This will slow down certain operations,
00053 // so it should be set to 0 if your application does not need to be thread
00054 // safe.
00055 //
00056 // If a macro is undefined, then the behaviour is architecture
00057 // dependent--usually, the macro will be set to 1 in this case.
00058 // For maximum efficiency and for normal operation after the program is
00059 // debugged, compile with all of the above macros defined to zero.
00060 // This can also be done with -DREF_OPTIMIZE.
00061 //
00062 //   An include file can be used to set these options as well.  This has
00063 // the advantage that dependency checking will force an automatic
00064 // recompile of all affected files if the options change.  The file
00065 // <scconfig.h> will be include if -DHAVE_CONFIG_H is specified.
00066 //
00067 //   Note that all source code that uses references must be compiled with
00068 // the same value REF_MANAGE.  Changing this can change the storage layout
00069 // and the interpretation of the reference count data.
00070 
00071 
00072 #ifdef __GNUC__
00073 #pragma interface
00074 #endif
00075 
00076 #ifndef _util_ref_ref_h
00077 #define _util_ref_ref_h
00078 
00079 #include <iostream>
00080 #include <stdlib.h>
00081 #include <limits.h>
00082 
00083 #include <util/ref/identity.h>
00084 
00085 #ifdef HAVE_CONFIG_H
00086 #include <scconfig.h>
00087 #endif
00088 
00089 #ifdef REF_OPTIMIZE
00090 #ifndef REF_CHECK_STACK
00091 # define REF_CHECK_STACK   0
00092 #endif
00093 #ifndef REF_MANAGE
00094 # define REF_MANAGE        0
00095 #endif
00096 #ifndef REF_CHECK_MAX_NREF
00097 # define REF_CHECK_MAX_NREF 0
00098 #endif
00099 #ifndef REF_CHECK_MIN_NREF
00100 # define REF_CHECK_MIN_NREF 0
00101 #endif
00102 #endif
00103 
00104 #ifdef SUNMOS
00105 #ifndef REF_CHECK_STACK
00106 #define REF_CHECK_STACK 0
00107 #endif
00108 #else
00109 #ifndef REF_CHECK_STACK
00110 #define REF_CHECK_STACK 0
00111 #endif
00112 #endif
00113 
00114 #ifndef REF_MANAGE
00115 #define REF_MANAGE 1
00116 #endif
00117 
00118 #ifndef REF_CHECK_MAX_NREF
00119 #define REF_CHECK_MAX_NREF 1
00120 #endif
00121 
00122 #ifndef REF_CHECK_MIN_NREF
00123 #define REF_CHECK_MIN_NREF 1
00124 #endif
00125 
00126 #ifndef REF_USE_LOCKS
00127 #  if HAVE_STHREAD || HAVE_CREATETHREAD || HAVE_PTHREAD
00128 #    define REF_USE_LOCKS 1
00129 #  endif
00130 #endif
00131 
00132 #if REF_CHECK_STACK
00133 #include <unistd.h>
00134 #ifndef HAVE_SBRK_DEC
00135 extern "C" void * sbrk(ssize_t);
00136 #endif
00137 #define DO_REF_CHECK_STACK(p) (((void*) (p) > sbrk(0)) && (p)->managed())
00138 #else // REF_CHECK_STACK
00139 #define DO_REF_CHECK_STACK(p) (0)
00140 #endif // REF_CHECK_STACK
00141 
00142 #if REF_MANAGE
00143 #define DO_REF_UNMANAGE(p) ((p)->unmanage())
00144 #else // REF_MANAGE
00145 #define DO_REF_UNMANAGE(p)
00146 #endif // REF_MANAGE
00147 
00148 #if REF_USE_LOCKS
00149 #define __REF_LOCK__(p) p->lock_ptr()
00150 #define __REF_UNLOCK__(p) p->unlock_ptr()
00151 #define __REF_INITLOCK__() ref_lock_ = 0xff
00152 #else
00153 #define __REF_LOCK__(p)
00154 #define __REF_UNLOCK__(p)
00155 #define __REF_INITLOCK__()
00156 #endif
00157 
00158 typedef unsigned long refcount_t;
00159 
00184 class RefCount: public Identity {
00185   private:
00186 #if REF_MANAGE
00187 #  define REF_MAX_NREF (UINT_MAX - 1)
00188 #  define REF_MANAGED_CODE UINT_MAX
00189 #else
00190 #  define REF_MAX_NREF UINT_MAX
00191 #endif
00192     unsigned int _reference_count_;
00193 #if REF_USE_LOCKS
00194     unsigned char ref_lock_;
00195 #endif
00196 
00197     void error(const char*) const;
00198     void too_many_refs() const;
00199     void not_enough_refs() const;
00200   protected:
00201     RefCount(): _reference_count_(0) {
00202         __REF_INITLOCK__();
00203         //std::cout << "ref_lock_ = " << (int) ref_lock_ << std::endl;
00204       }
00205     RefCount(const RefCount&): _reference_count_(0) {
00206         __REF_INITLOCK__();
00207         //std::cout << "ref_lock_ = " << (int) ref_lock_ << std::endl;
00208       }
00209 
00210     // Assigment should not overwrite the reference count.
00211     RefCount& operator=(const RefCount&) { return *this; }
00212   public:
00213     virtual ~RefCount();
00214 
00216     int lock_ptr() const;
00218     int unlock_ptr() const;
00219 
00221     void use_locks(bool inVal);
00222 
00224     refcount_t nreference() const {
00225 #       if REF_MANAGE
00226         if (!managed()) return 1;
00227 #       endif
00228         return _reference_count_;
00229       }
00230 
00232     refcount_t reference() {
00233 #       if REF_MANAGE
00234         if (!managed()) return 1;
00235 #       endif
00236         __REF_LOCK__(this);
00237 #       if REF_CHECK_MAX_NREF
00238         if (_reference_count_ >= REF_MAX_NREF) too_many_refs();
00239 #       endif
00240         _reference_count_++;
00241         refcount_t r = _reference_count_;
00242         __REF_UNLOCK__(this);
00243         return r;
00244       }
00245 
00247     refcount_t dereference() {
00248 #       if REF_MANAGE
00249         if (!managed()) return 1;
00250 #       endif
00251         __REF_LOCK__(this);
00252 #       if REF_CHECK_MIN_NREF
00253         if (_reference_count_ == 0) not_enough_refs();
00254 #       endif
00255         _reference_count_--;
00256         refcount_t r = _reference_count_;
00257         __REF_UNLOCK__(this);
00258         return r;
00259       }
00260 
00261 #if REF_MANAGE
00262     int managed() const {
00263         return _reference_count_ != REF_MANAGED_CODE;
00264       }
00270     void unmanage() {
00271         _reference_count_ = REF_MANAGED_CODE;
00272       }
00273 #else // REF_MANAGE
00274 
00275     int managed() const { return 1; }
00276 #endif // REF_MANAGE
00277 };
00278 
00282 class RefBase {
00283   protected:
00285     void warn ( const char * msg) const;
00287     void warn_ref_to_stack() const;
00289     void warn_skip_stack_delete() const;
00291     void warn_bad_ref_count() const;
00293     void ref_info(RefCount*p,std::ostream& os) const;
00294     void ref_info(std::ostream& os) const;
00295     void check_pointer() const;
00296     void reference(RefCount *);
00297     int dereference(RefCount *);
00298   public:
00299     virtual ~RefBase();
00301     virtual RefCount* parentpointer() const = 0;
00304     void require_nonnull() const;
00305 };
00306 
00320 template <class T>
00321 class  Ref  : public RefBase {
00322   private:
00323     T* p;
00324   public:
00326     Ref(): p(0) {}
00328     Ref(T*a) : p(0)
00329     {
00330       if (a) {
00331           p = a;
00332           reference(p);
00333         }
00334     }
00336     Ref(const Ref<T> &a) : p(0)
00337     {
00338       if (a.pointer()) {
00339           p = a.pointer();
00340           reference(p);
00341         }
00342     }
00344     template <class A> Ref(const Ref<A> &a): p(0)
00345     {
00346       if (a.pointer()) {
00347           p = a.pointer();
00348           reference(p);
00349         }
00350     }
00351 //      /** Create a reference to the object a.  Do a
00352 //          dynamic_cast to convert a to the appropiate type. */
00353 //      Ref(const RefBase&a) {
00354 //          p = dynamic_cast<T*>(a.parentpointer());
00355 //          reference(p);
00356 //        }
00357 //      /** Create a reference to the object a.  Do a
00358 //          dynamic_cast to convert a to the appropiate type. */
00359 //      Ref(RefCount*a): p(0) {
00360 //        operator<<(a);
00361 //        }
00364     ~Ref()
00365     {
00366       clear();
00367     }
00370     T* operator->() const { return p; }
00372     T* pointer() const { return p; }
00374     RefCount *parentpointer() const { return p; }
00375 
00376     operator T*() const { return p; }
00379     T& operator *() const { return *p; };
00382     int null() const { return p == 0; }
00384     int nonnull() const { return p != 0; }
00387     template <class A> int operator==(const Ref<A>&a) const
00388         { return eq(p,a.pointer()); }
00389     template <class A> int operator>=(const Ref<A>&a) const
00390         { return ge(p,a.pointer()); }
00391     template <class A> int operator<=(const Ref<A>&a) const
00392         { return le(p,a.pointer()); }
00393     template <class A> int operator>(const Ref<A>&a) const
00394         { return gt(p,a.pointer()); }
00395     template <class A> int operator<(const Ref<A>&a) const
00396         { return lt(p,a.pointer()); }
00397     template <class A> int operator!=(const Ref<A>&a) const
00398         { return ne(p,a.pointer()); }
00401     int compare(const Ref<T> &a) const {
00402       return eq(p,a.p)?0:((lt(p,a.p)?-1:1));
00403     }
00405     void clear()
00406     {
00407       if (p) {
00408           int ref = dereference(p);
00409           if (ref == 0)
00410               delete p;
00411           p = 0;
00412         }
00413     }
00415     Ref<T>& operator=(const Ref<T> & c)
00416     {
00417       T *cp = c.pointer();
00418       if (cp) {
00419           cp->reference();
00420           clear();
00421           p=cp;
00422         }
00423       else {
00424           clear();
00425         }
00426       return *this;
00427     }
00429     template <class A> Ref<T>& operator=(const Ref<A> & c)
00430     {
00431       A *cp = c.pointer();
00432       if (cp) {
00433           cp->reference();
00434           clear();
00435           p=cp;
00436         }
00437       else {
00438           clear();
00439         }
00440       return *this;
00441     }
00443     Ref<T>& operator<<(const RefBase&a) {
00444         T* cr = dynamic_cast<T*>(a.parentpointer());
00445         if (cr) {
00446             reference(cr);
00447             clear();
00448           }
00449         p = cr;
00450         return *this;
00451       }
00455     Ref<T>& operator<<(RefCount *a) {
00456         T* cr = dynamic_cast<T*>(a);
00457         if (cr) assign_pointer(cr);
00458         else if (a && a->nreference() <= 0) delete a;
00459         return *this;
00460       }
00462     Ref<T>& operator=(T* cr)
00463     {
00464       assign_pointer(cr);
00465       return *this;
00466     }
00468     void assign_pointer(T* cr)
00469     {
00470       if (cr) {
00471           if (DO_REF_CHECK_STACK(cr)) {
00472               DO_REF_UNMANAGE(cr);
00473               warn_ref_to_stack();
00474             }
00475           cr->reference();
00476         }
00477       clear();
00478       p = cr;
00479     }
00481     void check_pointer() const
00482     {
00483       if (p && p->nreference() <= 0) {
00484           warn_bad_ref_count();
00485         }
00486     }
00488     void ref_info(std::ostream& os) const
00489     {
00490       RefBase::ref_info(p,os);
00491     }
00493     void warn(const char*s) const { RefBase::warn(s); }
00494 };
00495 
00496 #endif
00497 
00498 // ///////////////////////////////////////////////////////////////////////////
00499 
00500 // Local Variables:
00501 // mode: c++
00502 // c-file-style: "CLJ"
00503 // End:

Generated at Thu Oct 4 18:08:47 2001 for MPQC 2.0.0 using the documentation package Doxygen 1.2.5.