- Main Page
- Related Pages
- Classes
- Files

# 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: