CppAD: A C++ Algorithmic Differentiation Package  20171217
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
track_new_del.hpp
Go to the documentation of this file.
1 # ifndef CPPAD_UTILITY_TRACK_NEW_DEL_HPP
2 # define CPPAD_UTILITY_TRACK_NEW_DEL_HPP
3 
4 /* --------------------------------------------------------------------------
5 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
6 
7 CppAD is distributed under multiple licenses. This distribution is under
8 the terms of the
9  Eclipse Public License Version 1.0.
10 
11 A copy of this license is included in the COPYING file of this distribution.
12 Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
13 -------------------------------------------------------------------------- */
14 /*
15 $begin TrackNewDel$$
16 $spell
17  cppad.hpp
18  Cpp
19  newptr
20  Vec
21  oldptr
22  newlen
23  ncopy
24  const
25 $$
26 
27 $section Routines That Track Use of New and Delete$$
28 $mindex memory NDEBUG CPPAD_TRACK_NEW_VEC CppADTrackNewVec CPPAD_TRACK_DEL_VEC CppADTrackDelVec CPPAD_TRACK_EXTEND CppADTrackExtend CPPAD_TRACK_COUNT thread multi$$
29 
30 $head Deprecated 2007-07-23$$
31 All these routines have been deprecated.
32 You should use the $cref thread_alloc$$ memory allocator instead
33 (which works better in both a single thread and
34 properly in multi-threading environment).
35 
36 $head Syntax$$
37 $codei%# include <cppad/utility/track_new_del.hpp>
38 %$$
39 $icode%newptr% = TrackNewVec(%file%, %line%, %newlen%, %oldptr%)
40 %$$
41 $codei%TrackDelVec(%file%, %line%, %oldptr%)
42 %$$
43 $icode%newptr% = TrackExtend(%file%, %line%, %newlen%, %ncopy%, %oldptr%)
44 %$$
45 $icode%count% = TrackCount(%file%, %line%)%$$
46 
47 
48 $head Purpose$$
49 These routines
50 aid in the use of $code new[]$$ and $code delete[]$$
51 during the execution of a C++ program.
52 
53 $head Include$$
54 The file $code cppad/track_new_del.hpp$$ is included by
55 $code cppad/cppad.hpp$$
56 but it can also be included separately with out the rest of the
57 CppAD include files.
58 
59 
60 $head file$$
61 The argument $icode file$$ has prototype
62 $codei%
63  const char *%file%
64 %$$
65 It should be the source code file name
66 where the call to $code TrackNew$$ is located.
67 The best way to accomplish this is the use the preprocessor symbol
68 $code __FILE__$$ for this argument.
69 
70 $head line$$
71 The argument $icode line$$ has prototype
72 $codei%
73  int %line%
74 %$$
75 It should be the source code file line number
76 where the call to $code TrackNew$$ is located.
77 The best way to accomplish this is the use the preprocessor symbol
78 $code __LINE__$$ for this argument.
79 
80 $head oldptr$$
81 The argument $icode oldptr$$ has prototype
82 $codei%
83  %Type% *%oldptr%
84 %$$
85 This argument is used to identify the type $icode Type$$.
86 
87 $head newlen$$
88 The argument $icode newlen$$ has prototype
89 $codei%
90  size_t %newlen%
91 %$$
92 
93 $head head newptr$$
94 The return value $icode newptr$$ has prototype
95 $codei%
96  %Type% *%newptr%
97 %$$
98 It points to the newly allocated vector of objects
99 that were allocated using
100 $codei%
101  new Type[%newlen%]
102 %$$
103 
104 $head ncopy$$
105 The argument $icode ncopy$$ has prototype
106 $codei%
107  size_t %ncopy%
108 %$$
109 This specifies the number of elements that are copied from
110 the old array to the new array.
111 The value of $icode ncopy$$
112 must be less than or equal $icode newlen$$.
113 
114 $head TrackNewVec$$
115 If $code NDEBUG$$ is defined, this routine only sets
116 $codei%
117  %newptr% = %Type% new[%newlen%]
118 %$$
119 The value of $icode oldptr$$ does not matter
120 (except that it is used to identify $icode Type$$).
121 If $code NDEBUG$$ is not defined, $code TrackNewVec$$ also
122 tracks the this memory allocation.
123 In this case, if memory cannot be allocated
124 $cref ErrorHandler$$ is used to generate a message
125 stating that there was not sufficient memory.
126 
127 $subhead Macro$$
128 The preprocessor macro call
129 $codei%
130  CPPAD_TRACK_NEW_VEC(%newlen%, %oldptr%)
131 %$$
132 expands to
133 $codei%
134  CppAD::TrackNewVec(__FILE__, __LINE__, %newlen%, %oldptr%)
135 %$$
136 
137 $subhead Previously Deprecated$$
138 The preprocessor macro $code CppADTrackNewVec$$ is the
139 same as $code CPPAD_TRACK_NEW_VEC$$ and was previously deprecated.
140 
141 $head TrackDelVec$$
142 This routine is used to a vector of objects
143 that have been allocated using $code TrackNew$$ or $code TrackExtend$$.
144 If $code NDEBUG$$ is defined, this routine only frees memory with
145 $codei%
146  delete [] %oldptr%
147 %$$
148 If $code NDEBUG$$ is not defined, $code TrackDelete$$ also checks that
149 $icode oldptr$$ was allocated by $code TrackNew$$ or $code TrackExtend$$
150 and has not yet been freed.
151 If this is not the case,
152 $cref ErrorHandler$$ is used to generate an error message.
153 
154 $subhead Macro$$
155 The preprocessor macro call
156 $codei%
157  CPPAD_TRACK_DEL_VEC(%oldptr%)
158 %$$
159 expands to
160 $codei%
161  CppAD::TrackDelVec(__FILE__, __LINE__, %oldptr%)
162 %$$
163 
164 $subhead Previously Deprecated$$
165 The preprocessor macro $code CppADTrackDelVec$$ is the
166 same as $code CPPAD_TRACK_DEL_VEC$$ was previously deprecated.
167 
168 $head TrackExtend$$
169 This routine is used to
170 allocate a new vector (using $code TrackNewVec$$),
171 copy $icode ncopy$$ elements from the old vector to the new vector.
172 If $icode ncopy$$ is greater than zero, $icode oldptr$$
173 must have been allocated using $code TrackNewVec$$ or $code TrackExtend$$.
174 In this case, the vector pointed to by $icode oldptr$$
175 must be have at least $icode ncopy$$ elements
176 and it will be deleted (using $code TrackDelVec$$).
177 Note that the dependence of $code TrackExtend$$ on $code NDEBUG$$
178 is indirectly through the routines $code TrackNewVec$$ and
179 $code TrackDelVec$$.
180 
181 $subhead Macro$$
182 The preprocessor macro call
183 $codei%
184  CPPAD_TRACK_EXTEND(%newlen%, %ncopy%, %oldptr%)
185 %$$
186 expands to
187 $codei%
188  CppAD::TrackExtend(__FILE__, __LINE__, %newlen%, %ncopy%, %oldptr%)
189 %$$
190 
191 $subhead Previously Deprecated$$
192 The preprocessor macro $code CppADTrackExtend$$ is the
193 same as $code CPPAD_TRACK_EXTEND$$ and was previously deprecated.
194 
195 $head TrackCount$$
196 The return value $icode count$$ has prototype
197 $codei%
198  size_t %count%
199 %$$
200 If $code NDEBUG$$ is defined, $icode count$$ will be zero.
201 Otherwise, it will be
202 the number of vectors that
203 have been allocated
204 (by $code TrackNewVec$$ or $code TrackExtend$$)
205 and not yet freed
206 (by $code TrackDelete$$).
207 
208 $subhead Macro$$
209 The preprocessor macro call
210 $codei%
211  CPPAD_TRACK_COUNT()
212 %$$
213 expands to
214 $codei%
215  CppAD::TrackCount(__FILE__, __LINE__)
216 %$$
217 
218 $subhead Previously Deprecated$$
219 The preprocessor macro $code CppADTrackCount$$ is the
220 same as $code CPPAD_TRACK_COUNT$$ and was previously deprecated.
221 
222 $head Multi-Threading$$
223 These routines cannot be used $cref/in_parallel/ta_in_parallel/$$
224 execution mode.
225 Use the $cref thread_alloc$$ routines instead.
226 
227 $head Example$$
228 $children%
229  example/deprecated/track_new_del.cpp
230 %$$
231 The file $cref TrackNewDel.cpp$$
232 contains an example and test of these functions.
233 It returns true, if it succeeds, and false otherwise.
234 
235 $end
236 ------------------------------------------------------------------------------
237 */
238 # include <cppad/core/define.hpp>
239 # include <cppad/core/cppad_assert.hpp>
241 # include <sstream>
242 # include <string>
243 
244 # ifndef CPPAD_TRACK_DEBUG
245 # define CPPAD_TRACK_DEBUG 0
246 # endif
247 
248 // -------------------------------------------------------------------------
249 # define CPPAD_TRACK_NEW_VEC(newlen, oldptr) \
250  CppAD::TrackNewVec(__FILE__, __LINE__, newlen, oldptr)
251 
252 # define CPPAD_TRACK_DEL_VEC(oldptr) \
253  CppAD::TrackDelVec(__FILE__, __LINE__, oldptr)
254 
255 # define CPPAD_TRACK_EXTEND(newlen, ncopy, oldptr) \
256  CppAD::TrackExtend(__FILE__, __LINE__, newlen, ncopy, oldptr)
257 
258 # define CPPAD_TRACK_COUNT() \
259  CppAD::TrackCount(__FILE__, __LINE__)
260 // -------------------------------------------------------------------------
261 # define CppADTrackNewVec CPPAD_TRACK_NEW_VEC
262 # define CppADTrackDelVec CPPAD_TRACK_DEL_VEC
263 # define CppADTrackExtend CPPAD_TRACK_EXTEND
264 # define CppADTrackCount CPPAD_TRACK_COUNT
265 // -------------------------------------------------------------------------
266 namespace CppAD { // Begin CppAD namespace
267 
268 // TrackElement ------------------------------------------------------------
270 
271 public:
272  std::string file; // corresponding file name
273  int line; // corresponding line number
274  void *ptr; // value returned by TrackNew
275  TrackElement *next; // next element in linked list
276 
277  // default contructor (used to initialize root)
279  : file(""), line(0), ptr(CPPAD_NULL), next(CPPAD_NULL)
280  { }
281 
282  TrackElement(const char *f, int l, void *p)
283  : file(f), line(l), ptr(p), next(CPPAD_NULL)
284  { CPPAD_ASSERT_UNKNOWN( p != CPPAD_NULL);
285  }
286 
287  // There is only one tracking list and it starts it here
288  static TrackElement *Root(void)
290  static TrackElement root;
291  return &root;
292  }
293 
294  // Print one tracking element
295  static void Print(TrackElement* E)
296  {
298  using std::cout;
299  cout << "E = " << E;
300  cout << ", E->next = " << E->next;
301  cout << ", E->ptr = " << E->ptr;
302  cout << ", E->line = " << E->line;
303  cout << ", E->file = " << E->file;
304  cout << std::endl;
305  }
306 
307  // Print the linked list for a thread
308  static void Print(void)
309  {
311  using std::cout;
312  using std::endl;
313  TrackElement *E = Root();
314  // convert int(size_t) to avoid warning on _MSC_VER systems
315  cout << "Begin Track List" << endl;
316  while( E->next != CPPAD_NULL )
317  { E = E->next;
318  Print(E);
319  }
320  cout << "End Track List:" << endl;
321  cout << endl;
322  }
323 };
324 
325 
326 // TrackError ----------------------------------------------------------------
327 inline void TrackError(
328  const char *routine,
329  const char *file,
330  int line,
331  const char *msg )
332 {
334  std::ostringstream buf;
335  buf << routine
336  << ": at line "
337  << line
338  << " in file "
339  << file
340  << std::endl
341  << msg;
342  std::string str = buf.str();
343  size_t n = str.size();
344  size_t i;
345  char *message = new char[n + 1];
346  for(i = 0; i < n; i++)
347  message[i] = str[i];
348  message[n] = '\0';
349  CPPAD_ASSERT_KNOWN( false , message);
350 }
351 
352 // TrackNewVec ---------------------------------------------------------------
353 # ifdef NDEBUG
354 template <class Type>
355 inline Type *TrackNewVec(
356  const char *file, int line, size_t len, Type * /* oldptr */ )
357 {
358 # if CPPAD_TRACK_DEBUG
359  static bool first = true;
360  if( first )
361  { std::cout << "NDEBUG is defined for TrackNewVec" << std::endl;
362  first = false;
363  }
364 # endif
365  return (new Type[len]);
366 }
367 
368 # else
369 
370 template <class Type>
372  const char *file ,
373  int line ,
374  size_t len ,
375  Type * /* oldptr */ )
376 {
379  "attempt to use TrackNewVec in parallel execution mode."
380  );
381  // try to allocate the new memrory
382  Type *newptr = CPPAD_NULL;
383  try
384  { newptr = new Type[len];
385  }
386  catch(...)
387  { TrackError("TrackNewVec", file, line,
388  "Cannot allocate sufficient memory"
389  );
390  }
391  // create tracking element
392  void *vptr = static_cast<void *>(newptr);
393  TrackElement *E = new TrackElement(file, line, vptr);
394 
395  // get the root
397 
398  // put this elemenent at the front of linked list
399  E->next = root->next;
400  root->next = E;
401 
402 # if CPPAD_TRACK_DEBUG
403  std::cout << "TrackNewVec: ";
405 # endif
406 
407  return newptr;
408 }
409 
410 # endif
411 
412 // TrackDelVec --------------------------------------------------------------
413 # ifdef NDEBUG
414 template <class Type>
415 inline void TrackDelVec(const char *file, int line, Type *oldptr)
416 {
417 # if CPPAD_TRACK_DEBUG
418  static bool first = true;
419  if( first )
420  { std::cout << "NDEBUG is defined in TrackDelVec" << std::endl;
421  first = false;
422  }
423 # endif
424  delete [] oldptr;
425 }
426 
427 # else
428 
429 template <class Type>
431  const char *file ,
432  int line ,
433  Type *oldptr )
434 {
437  "attempt to use TrackDelVec in parallel execution mode."
438  );
439  TrackElement *P;
440  TrackElement *E;
441 
442  // search list for pointer
443  P = TrackElement::Root();
444  E = P->next;
445  void *vptr = static_cast<void *>(oldptr);
446  while(E != CPPAD_NULL && E->ptr != vptr)
447  { P = E;
448  E = E->next;
449  }
450 
451  // check if pointer was not in list
452  if( E == CPPAD_NULL || E->ptr != vptr ) TrackError(
453  "TrackDelVec", file, line,
454  "Invalid value for the argument oldptr.\n"
455  "Possible linking of debug and NDEBUG compilations of CppAD."
456  );
457 
458 # if CPPAD_TRACK_DEBUG
459  std::cout << "TrackDelVec: ";
461 # endif
462 
463  // remove tracking element from list
464  P->next = E->next;
465 
466  // delete allocated pointer
467  delete [] oldptr;
468 
469  // delete tracking element
470  delete E;
471 
472  return;
473 }
474 
475 # endif
476 
477 // TrackExtend --------------------------------------------------------------
478 template <class Type>
480  const char *file ,
481  int line ,
482  size_t newlen ,
483  size_t ncopy ,
484  Type *oldptr )
485 {
488  "attempt to use TrackExtend in parallel execution mode."
489  );
490 
491 # if CPPAD_TRACK_DEBUG
492  using std::cout;
493  cout << "TrackExtend: file = " << file;
494  cout << ", line = " << line;
495  cout << ", newlen = " << newlen;
496  cout << ", ncopy = " << ncopy;
497  cout << ", oldptr = " << oldptr;
498  cout << std::endl;
499 # endif
501  ncopy <= newlen,
502  "TrackExtend: ncopy is greater than newlen."
503  );
504 
505  // allocate the new memrory
506  Type *newptr = TrackNewVec(file, line, newlen, oldptr);
507 
508  // copy the data
509  size_t i;
510  for(i = 0; i < ncopy; i++)
511  newptr[i] = oldptr[i];
512 
513  // delete the old vector
514  if( ncopy > 0 )
515  TrackDelVec(file, line, oldptr);
516 
517  return newptr;
518 }
519 
520 // TrackCount --------------------------------------------------------------
521 inline size_t TrackCount(const char *file, int line)
522 {
525  "attempt to use TrackCount in parallel execution mode."
526  );
527  size_t count = 0;
529  while( E->next != CPPAD_NULL )
530  { ++count;
531  E = E->next;
532  }
533  return count;
534 }
535 // ---------------------------------------------------------------------------
536 
537 } // End CppAD namespace
538 
539 // preprocessor symbols local to this file
540 # undef CPPAD_TRACK_DEBUG
541 
542 # endif
static void Print(void)
#define CPPAD_ASSERT_KNOWN(exp, msg)
Check that exp is true, if not print msg and terminate execution.
Define processor symbols and macros that are used by CppAD.
size_t TrackCount(const char *file, int line)
static bool in_parallel(void)
Are we in a parallel execution state; i.e., is it possible that other threads are currently executing...
TrackElement * next
Define the CppAD error checking macros (all of which begin with CPPAD_ASSERT_)
Type * TrackNewVec(const char *file, int line, size_t len, Type *)
void TrackError(const char *routine, const char *file, int line, const char *msg)
TrackElement(const char *f, int l, void *p)
Type * TrackExtend(const char *file, int line, size_t newlen, size_t ncopy, Type *oldptr)
#define CPPAD_ASSERT_UNKNOWN(exp)
Check that exp is true, if not terminate execution.
void TrackDelVec(const char *file, int line, Type *oldptr)
File used to define the CppAD multi-threading allocator class.
static void Print(TrackElement *E)
static TrackElement * Root(void)