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
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     RefBase() {};
00310     virtual ~RefBase();
00312     virtual RefCount* parentpointer() const = 0;
00315     void require_nonnull() const;
00316 };
00317 
00331 template <class T>
00332 class  Ref  : public RefBase {
00333   private:
00334     T* p;
00335   public:
00337     Ref(): p(0) {}
00339     Ref(T*a) : p(0)
00340     {
00341       if (a) {
00342           p = a;
00343           reference(p);
00344         }
00345     }
00347     Ref(const Ref<T> &a) : p(0)
00348     {
00349       if (a.pointer()) {
00350           p = a.pointer();
00351           reference(p);
00352         }
00353     }
00355     template <class A> Ref(const Ref<A> &a): p(0)
00356     {
00357       if (a.pointer()) {
00358           p = a.pointer();
00359           reference(p);
00360         }
00361     }
00362 //      /** Create a reference to the object a.  Do a
00363 //          dynamic_cast to convert a to the appropiate type. */
00364 //      Ref(const RefBase&a) {
00365 //          p = dynamic_cast<T*>(a.parentpointer());
00366 //          reference(p);
00367 //        }
00368 //      /** Create a reference to the object a.  Do a
00369 //          dynamic_cast to convert a to the appropiate type. */
00370 //      Ref(RefCount*a): p(0) {
00371 //        operator<<(a);
00372 //        }
00375     ~Ref()
00376     {
00377       clear();
00378     }
00381     T* operator->() const { return p; }
00383     T* pointer() const { return p; }
00385     RefCount *parentpointer() const { return p; }
00386 
00387     operator T*() const { return p; }
00390     T& operator *() const { return *p; };
00393     int null() const { return p == 0; }
00395     int nonnull() const { return p != 0; }
00398     template <class A> int operator==(const Ref<A>&a) const
00399         { return eq(p,a.pointer()); }
00400     template <class A> int operator>=(const Ref<A>&a) const
00401         { return ge(p,a.pointer()); }
00402     template <class A> int operator<=(const Ref<A>&a) const
00403         { return le(p,a.pointer()); }
00404     template <class A> int operator>(const Ref<A>&a) const
00405         { return gt(p,a.pointer()); }
00406     template <class A> int operator<(const Ref<A>&a) const
00407         { return lt(p,a.pointer()); }
00408     template <class A> int operator!=(const Ref<A>&a) const
00409         { return ne(p,a.pointer()); }
00412     int compare(const Ref<T> &a) const {
00413       return eq(p,a.p)?0:((lt(p,a.p)?-1:1));
00414     }
00416     void clear()
00417     {
00418       if (p) {
00419           int ref = dereference(p);
00420           if (ref == 0)
00421               delete p;
00422           p = 0;
00423         }
00424     }
00426     Ref<T>& operator=(const Ref<T> & c)
00427     {
00428       T *cp = c.pointer();
00429       if (cp) {
00430           cp->reference();
00431           clear();
00432           p=cp;
00433         }
00434       else {
00435           clear();
00436         }
00437       return *this;
00438     }
00440     template <class A> Ref<T>& operator=(const Ref<A> & c)
00441     {
00442       A *cp = c.pointer();
00443       if (cp) {
00444           cp->reference();
00445           clear();
00446           p=cp;
00447         }
00448       else {
00449           clear();
00450         }
00451       return *this;
00452     }
00454     Ref<T>& operator<<(const RefBase&a) {
00455         T* cr = dynamic_cast<T*>(a.parentpointer());
00456         if (cr) {
00457             reference(cr);
00458             clear();
00459           }
00460         p = cr;
00461         return *this;
00462       }
00466     Ref<T>& operator<<(RefCount *a) {
00467         T* cr = dynamic_cast<T*>(a);
00468         if (cr) assign_pointer(cr);
00469         else if (a && a->nreference() <= 0) delete a;
00470         return *this;
00471       }
00473     Ref<T>& operator=(T* cr)
00474     {
00475       assign_pointer(cr);
00476       return *this;
00477     }
00479     void assign_pointer(T* cr)
00480     {
00481       if (cr) {
00482           if (DO_REF_CHECK_STACK(cr)) {
00483               DO_REF_UNMANAGE(cr);
00484               warn_ref_to_stack();
00485             }
00486           cr->reference();
00487         }
00488       clear();
00489       p = cr;
00490     }
00492     void check_pointer() const
00493     {
00494       if (p && p->nreference() <= 0) {
00495           warn_bad_ref_count();
00496         }
00497     }
00499     void ref_info(std::ostream& os) const
00500     {
00501       RefBase::ref_info(p,os);
00502     }
00504     void warn(const char*s) const { RefBase::warn(s); }
00505 };
00506 
00507 }
00508 
00509 #endif
00510 
00511 // ///////////////////////////////////////////////////////////////////////////
00512 
00513 // Local Variables:
00514 // mode: c++
00515 // c-file-style: "CLJ"
00516 // End:

Generated at Mon Dec 3 23:23:40 2007 for MPQC 2.3.1 using the documentation package Doxygen 1.5.2.