CppAD: A C++ Algorithmic Differentiation Package 20110419
track_new_del.hpp
Go to the documentation of this file.
00001 /* $Id$ */
00002 # ifndef CPPAD_TRACK_NEW_DEL_INCLUDED
00003 # define CPPAD_TRACK_NEW_DEL_INCLUDED
00004 
00005 /* --------------------------------------------------------------------------
00006 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-08 Bradley M. Bell
00007 
00008 CppAD is distributed under multiple licenses. This distribution is under
00009 the terms of the 
00010                     Common Public License Version 1.0.
00011 
00012 A copy of this license is included in the COPYING file of this distribution.
00013 Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
00014 -------------------------------------------------------------------------- */
00015 /*
00016 $begin TrackNewDel$$
00017 $spell
00018         cppad.hpp
00019         Cpp
00020         newptr
00021         Vec
00022         oldptr
00023         newlen
00024         ncopy
00025         const
00026 $$
00027 
00028 $section Routines That Track Use of New and Delete$$
00029 $index new, track$$
00030 $index delete, track$$
00031 $index track, new and delete$$
00032 $index memory, track$$
00033 
00034 $head Syntax$$
00035 $syntax%# include <cppad/track_new_del.hpp>
00036 %$$
00037 $syntax%%newptr% = TrackNewVec(%file%, %line%, %newlen%, %oldptr%)
00038 %$$
00039 $syntax%TrackDelVec(%file%, %line%, %oldptr%)
00040 %$$
00041 $syntax%%newptr% = TrackExtend(%file%, %line%, %newlen%, %ncopy%, %oldptr%)
00042 %$$
00043 $syntax%%count% = TrackCount(%file%, %line%)%$$
00044 
00045 
00046 $head Purpose$$
00047 These routines 
00048 aid in the use of $code new[]$$ and  $code delete[]$$
00049 during the execution of a C++ program.
00050 
00051 $head Include$$
00052 The file $code cppad/track_new_del.hpp$$ is included by 
00053 $code cppad/cppad.hpp$$
00054 but it can also be included separately with out the rest of the 
00055 CppAD include files.
00056 
00057 
00058 $head file$$
00059 The argument $italic file$$ has prototype
00060 $syntax%
00061         const char *%file%
00062 %$$
00063 It should be the source code file name 
00064 where the call to $code TrackNew$$ is located.
00065 The best way to accomplish this is the use the preprocessor symbol
00066 $code __FILE__$$ for this argument.
00067 
00068 $head line$$
00069 The argument $italic line$$ has prototype
00070 $syntax%
00071         int %line%
00072 %$$
00073 It should be the source code file line number 
00074 where the call to $code TrackNew$$ is located.
00075 The best way to accomplish this is the use the preprocessor symbol
00076 $code __LINE__$$ for this argument.
00077 
00078 $head oldptr$$
00079 The argument $italic oldptr$$ has prototype
00080 $syntax%
00081         %Type% *%oldptr%
00082 %$$
00083 This argument is used to identify the type $italic Type$$.
00084 
00085 $subhead OpenMP$$
00086 $index OpenMP, TrackNewDel$$
00087 $index TrackNewDel, OpenMP$$ 
00088 In the case of multi-threading with OpenMP,
00089 calls with the argument $italic oldptr$$ must be made with the
00090 same thread as when $italic oldptr$$ was created
00091 (except for $code TrackNewVec$$ where the value of $italic oldptr$$
00092 does not matter).
00093 
00094 
00095 $head newlen$$
00096 The argument $italic newlen$$ has prototype
00097 $syntax%
00098         size_t %newlen%
00099 %$$
00100 
00101 $head head newptr$$
00102 The return value $italic newptr$$ has prototype
00103 $syntax%
00104         %Type% *%newptr%
00105 %$$
00106 It points to the newly allocated vector of objects
00107 that were allocated using
00108 $syntax%
00109         new Type[%newlen%]
00110 %$$
00111 
00112 $head ncopy$$
00113 The argument $italic ncopy$$ has prototype
00114 $syntax%
00115         size_t %ncopy%
00116 %$$
00117 This specifies the number of elements that are copied from
00118 the old array to the new array.
00119 The value of $italic ncopy$$ 
00120 must be less than or equal $italic newlen$$.
00121 
00122 $head TrackNewVec$$
00123 $index TrackNewVec$$
00124 $index NDEBUG$$
00125 If $code NDEBUG$$ is defined, this routine only sets
00126 $syntax%
00127         %newptr% = %Type% new[%newlen%]
00128 %$$
00129 The value of $italic oldptr$$ does not matter 
00130 (except that it is used to identify $italic Type$$).
00131 If $code NDEBUG$$ is not defined, $code TrackNewVec$$ also
00132 tracks the this memory allocation.
00133 In this case, if memory cannot be allocated
00134 $xref/ErrorHandler/$$ is used to generate a message
00135 stating that there was not sufficient memory.
00136 
00137 $subhead Macro$$
00138 $index CPPAD_TRACK_NEW_VEC$$
00139 The preprocessor macro call
00140 $syntax%
00141         CPPAD_TRACK_NEW_VEC(%newlen%, %oldptr%)
00142 %$$
00143 expands to
00144 $syntax%
00145         CppAD::TrackNewVec(__FILE__, __LINE__, %newlen%, %oldptr%)
00146 %$$
00147 
00148 $subhead Deprecated$$
00149 $index  CppADTrackNewVec$$
00150 The preprocessor macro $code CppADTrackNewVec$$ is the
00151 same as $code CPPAD_TRACK_NEW_VEC$$.
00152 It has been deprecated; i.e.,
00153 it is still defined in the CppAD distribution, but it should
00154 not be used.
00155 
00156 $head TrackDelVec$$
00157 $index TrackDelVec$$
00158 This routine is used to a vector of objects 
00159 that have been allocated using $code TrackNew$$ or $code TrackExtend$$.
00160 If $code NDEBUG$$ is defined, this routine only frees memory with
00161 $syntax%
00162         delete [] %oldptr%
00163 %$$
00164 If $code NDEBUG$$ is not defined, $code TrackDelete$$ also checks that
00165 $italic oldptr$$ was allocated by $code TrackNew$$ or $code TrackExtend$$
00166 and has not yet been freed.
00167 If this is not the case,
00168 $xref/ErrorHandler/$$ is used to generate an error message.
00169 
00170 $subhead Macro$$
00171 $index CPPAD_TRACK_DEL_VEC$$
00172 The preprocessor macro call
00173 $syntax%
00174         CPPAD_TRACK_DEL_VEC(%oldptr%)
00175 %$$
00176 expands to
00177 $syntax%
00178         CppAD::TrackDelVec(__FILE__, __LINE__, %oldptr%)
00179 %$$
00180 
00181 $subhead Deprecated$$
00182 $index  CppADTrackDelVec$$
00183 The preprocessor macro $code CppADTrackDelVec$$ is the
00184 same as $code CPPAD_TRACK_DEL_VEC$$.
00185 It has been deprecated; i.e.,
00186 it is still defined in the CppAD distribution, but it should
00187 not be used.
00188 
00189 $head TrackExtend$$
00190 $index TrackExtend$$
00191 This routine is used to 
00192 allocate a new vector (using $code TrackNewVec$$),
00193 copy $italic ncopy$$ elements from the old vector to the new vector.
00194 If $italic ncopy$$ is greater than zero, $italic oldptr$$ 
00195 must have been allocated using $code TrackNewVec$$ or $code TrackExtend$$.
00196 In this case, the vector pointed to by $italic oldptr$$ 
00197 must be have at least $italic ncopy$$ elements
00198 and it will be deleted (using $code TrackDelVec$$).
00199 Note that the dependence of $code TrackExtend$$ on $code NDEBUG$$
00200 is indirectly through the routines $code TrackNewVec$$ and 
00201 $code TrackDelVec$$.
00202 
00203 $subhead Macro$$
00204 $index CPPAD_TRACK_EXTEND$$
00205 The preprocessor macro call
00206 $syntax%
00207         CPPAD_TRACK_EXTEND(%newlen%, %ncopy%, %oldptr%)
00208 %$$
00209 expands to
00210 $syntax%
00211         CppAD::TrackExtend(__FILE__, __LINE__, %newlen%, %ncopy%, %oldptr%)
00212 %$$
00213 
00214 $subhead Deprecated$$
00215 $index  CppADTrackExtend$$
00216 The preprocessor macro $code CppADTrackExtend$$ is the
00217 same as $code CPPAD_TRACK_EXTEND$$.
00218 It has been deprecated; i.e.,
00219 it is still defined in the CppAD distribution, but it should
00220 not be used.
00221 
00222 $head TrackCount$$
00223 $index TrackCount$$
00224 The return value $italic count$$ has prototype
00225 $syntax%
00226         size_t %count%
00227 %$$
00228 If $code NDEBUG$$ is defined, $italic count$$ will be zero.
00229 Otherwise, it will be
00230 the number of vectors that 
00231 have been allocated
00232 (by $code TrackNewVec$$ or $code TrackExtend$$)
00233 and not yet freed
00234 (by $code TrackDelete$$).
00235 
00236 $subhead Macro$$
00237 $index CPPAD_TRACK_COUNT$$
00238 The preprocessor macro call
00239 $syntax%
00240         CPPAD_TRACK_COUNT()
00241 %$$
00242 expands to
00243 $syntax%
00244         CppAD::TrackCount(__FILE__, __LINE__)
00245 %$$
00246 
00247 $subhead Deprecated$$
00248 $index  CppADTrackNewVec$$
00249 The preprocessor macro $code CppADTrackCount$$ is the
00250 same as $code CPPAD_TRACK_COUNT$$.
00251 It has been deprecated; i.e.,
00252 it is still defined in the CppAD distribution, but it should
00253 not be used.
00254 
00255 $subhead OpenMP$$
00256 $index OpenMP, TrackCount$$
00257 $index TrackCount, OpenMP$$
00258 In the case of multi-threading with OpenMP,
00259 the information for all of the threads is checked 
00260 so only one thread can be running
00261 when this routine is called.
00262 
00263 $head Example$$
00264 $children%
00265         example/track_new_del.cpp
00266 %$$
00267 The file $xref/TrackNewDel.cpp/$$
00268 contains an example and test of these functions.
00269 It returns true, if it succeeds, and false otherwise.
00270 
00271 $end
00272 ------------------------------------------------------------------------------
00273 */
00274 # include <cppad/local/cppad_assert.hpp>
00275 # include <sstream>
00276 # include <string>
00277 
00278 # ifdef _OPENMP
00279 # include <omp.h>
00280 # endif
00281 
00282 
00283 # ifndef CPPAD_NULL
00284 # define CPPAD_NULL     0
00285 # endif
00286 
00287 # ifndef CPPAD_MAX_NUM_THREADS
00288 # ifdef _OPENMP
00289 # define CPPAD_MAX_NUM_THREADS 32
00290 # else
00291 # define CPPAD_MAX_NUM_THREADS 1
00292 # endif
00293 # endif
00294 
00295 # define CPPAD_TRACK_DEBUG 0
00296 
00297 // -------------------------------------------------------------------------
00298 # define CPPAD_TRACK_NEW_VEC(newlen, oldptr) \
00299         CppAD::TrackNewVec(__FILE__, __LINE__, newlen, oldptr)
00300 
00301 # define CPPAD_TRACK_DEL_VEC(oldptr) \
00302         CppAD::TrackDelVec(__FILE__, __LINE__, oldptr)
00303 
00304 # define CPPAD_TRACK_EXTEND(newlen, ncopy, oldptr) \
00305         CppAD::TrackExtend(__FILE__, __LINE__, newlen, ncopy, oldptr)
00306 
00307 # define CPPAD_TRACK_COUNT() \
00308         CppAD::TrackCount(__FILE__, __LINE__)
00309 // -------------------------------------------------------------------------
00310 # define CppADTrackNewVec CPPAD_TRACK_NEW_VEC
00311 # define CppADTrackDelVec CPPAD_TRACK_DEL_VEC
00312 # define CppADTrackExtend CPPAD_TRACK_EXTEND
00313 # define CppADTrackCount  CPPAD_TRACK_COUNT
00314 // -------------------------------------------------------------------------
00315 namespace CppAD { // Begin CppAD namespace
00316 
00317 // TrackElement ------------------------------------------------------------
00318 class TrackElement {
00319         
00320 public:
00321         std::string   file;   // corresponding file name
00322         int           line;   // corresponding line number
00323         void          *ptr;   // value returned by TrackNew
00324         TrackElement *next;   // next element in linked list
00325 
00326         // default contructor (used to initialize root)
00327         TrackElement(void)
00328         : file(""), line(0), ptr(CPPAD_NULL), next(CPPAD_NULL)
00329         { }
00330         
00331         TrackElement(const char *f, int l, void *p)
00332         : file(f), line(l), ptr(p), next(CPPAD_NULL)
00333         {       CPPAD_ASSERT_UNKNOWN( p != CPPAD_NULL);
00334         }
00335 
00336         // There is only one tracking list and it starts it here
00337         static TrackElement *root_for(size_t thread)
00338         {       static TrackElement root[CPPAD_MAX_NUM_THREADS];
00339                 CPPAD_ASSERT_UNKNOWN( thread < CPPAD_MAX_NUM_THREADS );
00340                 return root + thread;
00341         }
00342 
00343         // There is only one tracking list and it starts it here
00344         static TrackElement *Root(void)
00345         {
00346 # ifdef _OPENMP
00347                 size_t thread = static_cast<size_t> ( omp_get_thread_num() );
00348 # else
00349                 size_t thread = 0;
00350 # endif
00351                 CPPAD_ASSERT_KNOWN(
00352                         thread < CPPAD_MAX_NUM_THREADS,
00353                         "TrackNewDel: too many OpenMP threads are active."
00354                 );
00355                 return root_for(thread); 
00356         }
00357 
00358         // Print the linked list
00359         static void Print(size_t thread)
00360         {       using std::cout;
00361                 using std::endl;
00362                 TrackElement *E = Root();
00363                 // convert int(size_t) to avoid warning on _MSC_VER systems
00364                 cout << "Begin Track List for thread " << int(thread) << endl;
00365                 while( E->next != CPPAD_NULL )
00366                 {       E = E->next;
00367                         cout << "next = " << E->next;
00368                         cout << ", ptr  = " << E->ptr;
00369                         cout << ", line = " << E->line;
00370                         cout << ", file = " << E->file;
00371                         cout << endl;
00372                 }
00373                 cout << "End Track List for thread " << int(thread) << endl;
00374                 cout << endl;
00375         }
00376 }; 
00377 
00378 
00379 // TrackError ----------------------------------------------------------------
00380 inline void TrackError(
00381         const char *routine,
00382         const char *file,
00383         int         line,
00384         const char *msg )
00385 {
00386         std::ostringstream buf;
00387         buf << routine
00388             << ": at line "
00389             << line
00390             << " in file "
00391             << file
00392             << std::endl
00393             << msg; 
00394         std::string str = buf.str();
00395         size_t      n   = str.size();
00396         size_t i;
00397         char *message = new char[n + 1];
00398         for(i = 0; i < n; i++)
00399                 message[i] = str[i];
00400         message[n] = '\0';
00401         CPPAD_ASSERT_KNOWN( false , message);
00402 }
00403 
00404 // TrackNewVec ---------------------------------------------------------------
00405 # ifdef NDEBUG
00406 template <class Type>
00407 inline Type *TrackNewVec(
00408         const char *file, int line, size_t len, Type * /* oldptr */ )
00409 {       return (new Type[len]); 
00410 }
00411 
00412 # else
00413 
00414 template <class Type>
00415 Type *TrackNewVec(
00416         const char *file          , 
00417         int         line          , 
00418         size_t      len           ,
00419         Type       * /* oldptr */ )
00420 {
00421         // try to allocate the new memrory
00422         Type *newptr = CPPAD_NULL;
00423         try
00424         {       newptr = new Type[len];
00425         }
00426         catch(...)
00427         {       TrackError("TrackNewVec", file, line, 
00428                         "Cannot allocate sufficient memory"
00429                 );
00430         }
00431         // create tracking element
00432         void *vptr = static_cast<void *>(newptr);
00433         TrackElement *E = new TrackElement(file, line, vptr);
00434 
00435         // get the root
00436         TrackElement *root = TrackElement::Root();
00437 
00438         // put this elemenent at the front of linked list
00439         E->next    = root->next;  
00440         root->next = E;
00441 
00442         return newptr;
00443 }
00444 
00445 # endif
00446 
00447 // TrackDelVec --------------------------------------------------------------
00448 # ifdef NDEBUG
00449 template <class Type>
00450 inline void TrackDelVec(const char *file, int line, Type *oldptr)
00451 {        delete [] oldptr; 
00452 }
00453 
00454 # else
00455 
00456 template <class Type>
00457 void TrackDelVec(
00458         const char *file    ,
00459         int         line    ,
00460         Type       *oldptr  )
00461 {
00462         TrackElement        *P;
00463         TrackElement        *E;
00464 
00465         // search list for pointer
00466         P          = TrackElement::Root();
00467         E          = P->next;
00468         void *vptr = static_cast<void *>(oldptr);
00469         while(E != CPPAD_NULL && E->ptr != vptr)
00470         {       P = E;
00471                 E = E->next;
00472         }
00473 
00474         // check if pointer was not in list
00475         if( E == CPPAD_NULL || E->ptr != vptr ) TrackError(
00476                 "TrackDelVec", file, line, 
00477                 "Invalid value for the argument oldptr.\n"
00478                 "Possible linking of debug and NDEBUG compliations of CppAD."
00479         ); 
00480 
00481         // remove tracking element from list
00482         P->next = E->next;
00483 
00484         // delete allocated pointer
00485         delete [] oldptr;
00486 
00487         // delete tracking element
00488         delete E;
00489 
00490         return;
00491 }
00492 
00493 # endif
00494 
00495 // TrackExtend --------------------------------------------------------------
00496 template <class Type>
00497 Type *TrackExtend(
00498         const char *file    , 
00499         int         line    , 
00500         size_t      newlen  , 
00501         size_t      ncopy   ,
00502         Type       *oldptr  ) 
00503 {       // check size of ncopy
00504         CPPAD_ASSERT_KNOWN( 
00505                 ncopy <= newlen,
00506                 "TrackExtend: ncopy is greater than newlen."
00507         );
00508 
00509         // allocate the new memrory
00510         Type *newptr = TrackNewVec(file, line, newlen, oldptr);
00511 
00512         // copy the data
00513         size_t i = ncopy;
00514         while(i)
00515         {       --i;
00516                 newptr[i] = oldptr[i];
00517         }
00518 
00519         // delete the old vector 
00520         if( ncopy > 0 )
00521                 TrackDelVec(file, line, oldptr);
00522 
00523         return newptr;
00524 }
00525 
00526 // TrackCount --------------------------------------------------------------
00527 inline size_t TrackCount(const char *file, int line)
00528 {
00529         size_t count = 0;
00530         size_t thread;
00531         for(thread = 0; thread < CPPAD_MAX_NUM_THREADS; thread++)
00532         {
00533                 TrackElement *E = TrackElement::root_for(thread);
00534 # if CPPAD_TRACK_DEBUG
00535                 if( E->next != CPPAD_NULL )
00536                         TrackElement::Print(thread);
00537 # endif
00538 
00539                 while( E->next != CPPAD_NULL ) 
00540                 {       ++count;
00541                         E = E->next;
00542                 }
00543         }
00544         return count;
00545 }
00546 // ---------------------------------------------------------------------------
00547 
00548 } // End CppAD namespace
00549 
00550 # undef CppADDebugTrack
00551 
00552 # endif