Main Page | Class Hierarchy | Class List | File List | Class 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 #ifndef REF_ALWAYS_USE_LOCKS
00133 #  define REF_ALWAYS_USE_LOCKS 1
00134 #endif
00135 
00136 #if REF_CHECK_STACK
00137 #include <unistd.h>
00138 #ifndef HAVE_SBRK_DEC
00139 extern "C" void * sbrk(ssize_t);
00140 #endif
00141 #define DO_REF_CHECK_STACK(p) (((void*) (p) > sbrk(0)) && (p)->managed())
00142 #else // REF_CHECK_STACK
00143 #define DO_REF_CHECK_STACK(p) (0)
00144 #endif // REF_CHECK_STACK
00145 
00146 #if REF_MANAGE
00147 #define DO_REF_UNMANAGE(p) ((p)->unmanage())
00148 #else // REF_MANAGE
00149 #define DO_REF_UNMANAGE(p)
00150 #endif // REF_MANAGE
00151 
00152 #if REF_USE_LOCKS
00153 #define __REF_LOCK__(p) p->lock_ptr()
00154 #define __REF_UNLOCK__(p) p->unlock_ptr()
00155 #if REF_ALWAYS_USE_LOCKS
00156 #define __REF_INITLOCK__() use_locks(true)
00157 #else
00158 #define __REF_INITLOCK__() ref_lock_ = 0xff
00159 #endif
00160 #else
00161 #define __REF_LOCK__(p)
00162 #define __REF_UNLOCK__(p)
00163 #define __REF_INITLOCK__()
00164 #endif
00165 
00166 namespace sc {
00167 
00168 typedef unsigned long refcount_t;
00169 
00194 class RefCount: public Identity {
00195   private:
00196 #if REF_MANAGE
00197 #  define REF_MAX_NREF (UINT_MAX - 1)
00198 #  define REF_MANAGED_CODE UINT_MAX
00199 #else
00200 #  define REF_MAX_NREF UINT_MAX
00201 #endif
00202     unsigned int _reference_count_;
00203 #if REF_USE_LOCKS
00204     unsigned char ref_lock_;
00205 #endif
00206 
00207     void error(const char*) const;
00208     void too_many_refs() const;
00209     void not_enough_refs() const;
00210   protected:
00211     RefCount(): _reference_count_(0) {
00212         __REF_INITLOCK__();
00213         //std::cout << "ref_lock_ = " << (int) ref_lock_ << std::endl;
00214       }
00215     RefCount(const RefCount&): _reference_count_(0) {
00216         __REF_INITLOCK__();
00217         //std::cout << "ref_lock_ = " << (int) ref_lock_ << std::endl;
00218       }
00219 
00220     // Assigment should not overwrite the reference count.
00221     RefCount& operator=(const RefCount&) { return *this; }
00222   public:
00223     virtual ~RefCount();
00224 
00226     int lock_ptr() const;
00228     int unlock_ptr() const;
00229 
00231     void use_locks(bool inVal);
00232 
00234     refcount_t nreference() const {
00235 #       if REF_MANAGE
00236         if (!managed()) return 1;
00237 #       endif
00238         return _reference_count_;
00239       }
00240 
00242     refcount_t reference() {
00243 #       if REF_MANAGE
00244         if (!managed()) return 1;
00245 #       endif
00246         __REF_LOCK__(this);
00247 #       if REF_CHECK_MAX_NREF
00248         if (_reference_count_ >= REF_MAX_NREF) too_many_refs();
00249 #       endif
00250         _reference_count_++;
00251         refcount_t r = _reference_count_;
00252         __REF_UNLOCK__(this);
00253         return r;
00254       }
00255 
00257     refcount_t dereference() {
00258 #       if REF_MANAGE
00259         if (!managed()) return 1;
00260 #       endif
00261         __REF_LOCK__(this);
00262 #       if REF_CHECK_MIN_NREF
00263         if (_reference_count_ == 0) not_enough_refs();
00264 #       endif
00265         _reference_count_--;
00266         refcount_t r = _reference_count_;
00267         __REF_UNLOCK__(this);
00268         return r;
00269       }
00270 
00271 #if REF_MANAGE
00272     int managed() const {
00273         return _reference_count_ != REF_MANAGED_CODE;
00274       }
00280     void unmanage() {
00281         _reference_count_ = REF_MANAGED_CODE;
00282       }
00283 #else // REF_MANAGE
00284 
00285     int managed() const { return 1; }
00286 #endif // REF_MANAGE
00287 };
00288 
00292 class RefBase {
00293   protected:
00295     void warn ( const char * msg) const;
00297     void warn_ref_to_stack() const;
00299     void warn_skip_stack_delete() const;
00301     void warn_bad_ref_count() const;
00303     void ref_info(RefCount*p,std::ostream& os) const;
00304     void ref_info(std::ostream& os) const;
00305     void check_pointer() const;
00306     void reference(RefCount *);
00307     int dereference(RefCount *);
00308   public:
00309     virtual ~RefBase();
00311     virtual RefCount* parentpointer() const = 0;
00314     void require_nonnull() const;
00315 };
00316 
00330 template <class T>
00331 class  Ref  : public RefBase {
00332   private:
00333     T* p;
00334   public:
00336     Ref(): p(0) {}
00338     Ref(T*a) : p(0)
00339     {
00340       if (a) {
00341           p = a;
00342           reference(p);
00343         }
00344     }
00346     Ref(const Ref<T> &a) : p(0)
00347     {
00348       if (a.pointer()) {
00349           p = a.pointer();
00350           reference(p);
00351         }
00352     }
00354     template <class A> Ref(const Ref<A> &a): p(0)
00355     {
00356       if (a.pointer()) {
00357           p = a.pointer();
00358           reference(p);
00359         }
00360     }
00361 //      /** Create a reference to the object a.  Do a
00362 //          dynamic_cast to convert a to the appropiate type. */
00363 //      Ref(const RefBase&a) {
00364 //          p = dynamic_cast<T*>(a.parentpointer());
00365 //          reference(p);
00366 //        }
00367 //      /** Create a reference to the object a.  Do a
00368 //          dynamic_cast to convert a to the appropiate type. */
00369 //      Ref(RefCount*a): p(0) {
00370 //        operator<<(a);
00371 //        }
00374     ~Ref()
00375     {
00376       clear();
00377     }
00380     T* operator->() const { return p; }
00382     T* pointer() const { return p; }
00384     RefCount *parentpointer() const { return p; }
00385 
00386     operator T*() const { return p; }
00389     T& operator *() const { return *p; };
00392     int null() const { return p == 0; }
00394     int nonnull() const { return p != 0; }
00397     template <class A> int operator==(const Ref<A>&a) const
00398         { return eq(p,a.pointer()); }
00399     template <class A> int operator>=(const Ref<A>&a) const
00400         { return ge(p,a.pointer()); }
00401     template <class A> int operator<=(const Ref<A>&a) const
00402         { return le(p,a.pointer()); }
00403     template <class A> int operator>(const Ref<A>&a) const
00404         { return gt(p,a.pointer()); }
00405     template <class A> int operator<(const Ref<A>&a) const
00406         { return lt(p,a.pointer()); }
00407     template <class A> int operator!=(const Ref<A>&a) const
00408         { return ne(p,a.pointer()); }
00411     int compare(const Ref<T> &a) const {
00412       return eq(p,a.p)?0:((lt(p,a.p)?-1:1));
00413     }
00415     void clear()
00416     {
00417       if (p) {
00418           int ref = dereference(p);
00419           if (ref == 0)
00420               delete p;
00421           p = 0;
00422         }
00423     }
00425     Ref<T>& operator=(const Ref<T> & c)
00426     {
00427       T *cp = c.pointer();
00428       if (cp) {
00429           cp->reference();
00430           clear();
00431           p=cp;
00432         }
00433       else {
00434           clear();
00435         }
00436       return *this;
00437     }
00439     template <class A> Ref<T>& operator=(const Ref<A> & c)
00440     {
00441       A *cp = c.pointer();
00442       if (cp) {
00443           cp->reference();
00444           clear();
00445           p=cp;
00446         }
00447       else {
00448           clear();
00449         }
00450       return *this;
00451     }
00453     Ref<T>& operator<<(const RefBase&a) {
00454         T* cr = dynamic_cast<T*>(a.parentpointer());
00455         if (cr) {
00456             reference(cr);
00457             clear();
00458           }
00459         p = cr;
00460         return *this;
00461       }
00465     Ref<T>& operator<<(RefCount *a) {
00466         T* cr = dynamic_cast<T*>(a);
00467         if (cr) assign_pointer(cr);
00468         else if (a && a->nreference() <= 0) delete a;
00469         return *this;
00470       }
00472     Ref<T>& operator=(T* cr)
00473     {
00474       assign_pointer(cr);
00475       return *this;
00476     }
00478     void assign_pointer(T* cr)
00479     {
00480       if (cr) {
00481           if (DO_REF_CHECK_STACK(cr)) {
00482               DO_REF_UNMANAGE(cr);
00483               warn_ref_to_stack();
00484             }
00485           cr->reference();
00486         }
00487       clear();
00488       p = cr;
00489     }
00491     void check_pointer() const
00492     {
00493       if (p && p->nreference() <= 0) {
00494           warn_bad_ref_count();
00495         }
00496     }
00498     void ref_info(std::ostream& os) const
00499     {
00500       RefBase::ref_info(p,os);
00501     }
00503     void warn(const char*s) const { RefBase::warn(s); }
00504 };
00505 
00506 }
00507 
00508 #endif
00509 
00510 // ///////////////////////////////////////////////////////////////////////////
00511 
00512 // Local Variables:
00513 // mode: c++
00514 // c-file-style: "CLJ"
00515 // End:

Generated at Fri Nov 26 23:50:58 2004 for MPQC 2.2.2 using the documentation package Doxygen 1.3.9.1.