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