ClassRef.h

00001 /*  _________________________________________________________________________
00002  *
00003  *  UTILIB: A utility library for developing portable C++ codes.
00004  *  Copyright (c) 2001, Sandia National Laboratories.
00005  *  This software is distributed under the GNU Lesser General Public License.
00006  *  For more information, see the README file in the top UTILIB directory.
00007  *  _________________________________________________________________________
00008  */
00009 
00010 //
00011 // ClassRef.h
00012 //
00036 #ifndef __ClassRef_h
00037 #define __ClassRef_h
00038 
00039 #define __math_h_NO_ARRAYS
00040 #include "_math.h"
00041 #undef __math_h_NO_ARRAYS
00042 #include "errmsg.h"
00043 
00044 typedef size_t size_type;
00045 
00046 
00047 template <class V> 
00048 class ClassRef {
00049  
00050 public:
00051 
00053   static int num_refs_limit;
00054 
00056   ClassRef() {own=DataNotOwned; ref=0; ref_ptrs=0; ptrlen=0; const_ref=FALSE;}
00058   virtual ~ClassRef() {if (ref_ptrs) delete [] ref_ptrs;}
00059 
00061   void update_refs()
00062         {
00063         if (const_ref == TRUE)
00064            ErrAbort("Setting data for an ClassRef object with constant data references.");
00065         for (int i=0; i<ref; i++)
00066           copy_data(ref_ptrs[i]);
00067         }
00069   void acquire(V* array);
00071   bool release(V* array);
00073   void resize_ref_ptrs(const int);
00075   virtual void copy_data(V* array) = 0;
00077   virtual void reset_data(V* array) = 0;
00079   virtual void delete_data() = 0;
00080 
00082   EnumDataOwned own;
00084   int ref;
00085 
00087   void freeze()
00088         { const_ref=TRUE; }
00090   int const_ref;
00091 
00092 protected:
00093 
00095   int ptrlen;
00097   V** ref_ptrs;
00098 };
00099 
00100 
00101 template <class V>
00102 int ClassRef<V>::num_refs_limit=32;
00103 
00104 
00105 
00106 template <class V>
00107 void ClassRef<V>::acquire(V* array)
00108 {
00109 if (const_ref == FALSE) {
00110    //
00111    // Ignore num_refs_limit if this is a constant reference
00112    //
00113    if (ref == num_refs_limit)
00114       ErrAbort(errmsg("Exceeded maximum number of reference counts allowed in ClassRef<V>::num_refs_limit = %d",num_refs_limit));
00115 
00116    if (ref == ptrlen)
00117       resize_ref_ptrs(ptrlen*2+2);
00118    ref_ptrs[ref++] = array;
00119    }
00120 copy_data(array);
00121 }
00122 
00123 
00124 
00125 template <class V>
00126 bool ClassRef<V>::release(V* array)
00127 {
00128 if (const_ref == FALSE) {
00129    V** tmp = ref_ptrs;
00130    int i=0;
00131    for (i=0; i<(ref-1); i++, tmp++)
00132      if (*tmp == array)  break;
00133    if (i < (ref-1))
00134       ref_ptrs[i] = ref_ptrs[--ref];
00135    else
00136       ref--;
00137    if ((ptrlen > 2) && (ref < ptrlen/2))
00138       resize_ref_ptrs(ref);
00139    }
00140 else
00141    ref--;
00142 
00143 if (ref == 0) {
00144    delete_data();
00145    own = DataNotOwned;
00146    const_ref=FALSE;
00147    delete [] ref_ptrs;
00148    ref_ptrs = 0;
00149    }
00150 
00151 reset_data(array);
00152 return (ref == 0);
00153 }
00154 
00155 
00156 
00157 template <class V>
00158 void ClassRef<V>::resize_ref_ptrs(const int newlen)
00159 {
00160 V** tmp = new V* [newlen];
00161 if (ref) {
00162    for (int i=0; i<min(ref,newlen); i++)
00163      tmp[i] = ref_ptrs[i];
00164    delete [] ref_ptrs;
00165    }
00166 ptrlen = newlen;
00167 ref_ptrs=tmp;
00168 }
00169 
00170 
00171 
00172 template <class T, class V> 
00173 class ArrayRef : public ClassRef<V> {
00174  
00175 public:
00176 
00178   ArrayRef() {Len=0; Data=0;}
00180   virtual ~ArrayRef() {if (own) delete [] Data;}
00181 
00183   void copy_data(V* array);
00185   void reset_data(V* array);
00187   void delete_data()
00188         { if (own) delete [] Data; Data=0; }
00189 
00191   void set_data(T* Data_, size_type Len_, EnumDataOwned own_);
00192 
00194   T* Data;
00196   size_type Len;
00197 
00198 };
00199 
00200 
00201 template <class T, class V>
00202 void ArrayRef<T,V>::copy_data(V* array)
00203 {
00204 array->Data = Data;
00205 array->Len  = Len;
00206 }
00207 
00208 
00209 template <class T, class V>
00210 void ArrayRef<T,V>::reset_data(V* array)
00211 {
00212 array->Data = 0;
00213 array->Len  = 0;
00214 }
00215 
00216 
00217 template <class T, class V>
00218 void ArrayRef<T,V>::set_data(T* Data_, size_type Len_, EnumDataOwned own_)
00219 {
00220 if (const_ref == TRUE)
00221    ErrAbort("Setting data for an ArrayRef object with constant data references.");
00222 
00223 if (Data && own && (Len > 0))
00224    delete [] Data;
00225 if (Len_ > 0) {
00226    Data = Data_;
00227    own = own_;
00228    Len = Len_;
00229    }
00230 else {
00231    Data=0;
00232    Len=0;
00233    own=DataNotOwned;
00234    }
00235 update_refs();
00236 }
00237 
00238 #endif