CppAD: A C++ Algorithmic Differentiation Package
20130918
|
00001 /* $Id$ */ 00002 # ifndef CPPAD_POD_VECTOR_INCLUDED 00003 # define CPPAD_POD_VECTOR_INCLUDED 00004 00005 /* -------------------------------------------------------------------------- 00006 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-14 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 # include <algorithm> 00017 # include <cppad/thread_alloc.hpp> 00018 # include <cppad/local/cppad_assert.hpp> 00019 # include <cppad/local/op_code.hpp> 00020 00021 namespace CppAD { // BEGIN_CPPAD_NAMESPACE 00022 /*! 00023 \file pod_vector.hpp 00024 File used to define pod_vector class 00025 */ 00026 00027 /* 00028 A list of which Types pod_vector<Type> consideres to be plain old data 00029 */ 00030 /// default value is false 00031 template <class Type> inline bool is_pod(void) { return false; } 00032 /// system pod types so far: 00033 template <> inline bool is_pod<bool>(void) { return true; } 00034 template <> inline bool is_pod<char>(void) { return true; } 00035 template <> inline bool is_pod<float>(void) { return true; } 00036 template <> inline bool is_pod<double>(void) { return true; } 00037 template <> inline bool is_pod<unsigned char>(void) { return true; } 00038 template <> inline bool is_pod<unsigned short int>(void) { return true; } 00039 template <> inline bool is_pod<unsigned int>(void) { return true; } 00040 # if ! CPPAD_SIZE_T_SAME_UNSIGNED_INT 00041 template <> inline bool is_pod<size_t>(void) { return true; } 00042 # endif 00043 /// CppAD pod types so far: 00044 template <> inline bool is_pod<OpCode>(void) { return true; } 00045 00046 // --------------------------------------------------------------------------- 00047 /*! 00048 A vector class with Type element that does not use element constructors 00049 or destructors when Type is Plain Old Data (pod). 00050 */ 00051 template <class Type> 00052 class pod_vector { 00053 private: 00054 /// maximum number of elements that should ever be in this vector 00055 size_t max_length_; 00056 /// number of elements currently in this vector 00057 size_t length_; 00058 /// maximum number of Type elements current allocation can hold 00059 size_t capacity_; 00060 /// pointer to the first type elements 00061 /// (not defined and should not be used when capacity_ = 0) 00062 Type *data_; 00063 /// do not use the copy constructor 00064 explicit pod_vector(const pod_vector& ) 00065 { CPPAD_ASSERT_UNKNOWN(false); } 00066 public: 00067 /// Constructors set capacity, length, and data to zero. 00068 /// 00069 /// \param max_length 00070 /// value for maximum number of elements in this vector. 00071 inline pod_vector( 00072 size_t max_length = std::numeric_limits<size_t>::max() 00073 ) 00074 : max_length_(max_length), length_(0), capacity_(0), data_(CPPAD_NULL) 00075 { } 00076 // ---------------------------------------------------------------------- 00077 /// Destructor: returns allocated memory to \c thread_alloc; 00078 /// see \c extend. If this is not plain old data, 00079 /// the destructor for each element is called. 00080 ~pod_vector(void) 00081 { if( capacity_ > 0 ) 00082 { void* v_ptr = reinterpret_cast<void*>( data_ ); 00083 if( ! is_pod<Type>() ) 00084 { // call destructor for each element 00085 size_t i; 00086 for(i = 0; i < capacity_; i++) 00087 (data_ + i)->~Type(); 00088 } 00089 thread_alloc::return_memory(v_ptr); 00090 } 00091 } 00092 // ---------------------------------------------------------------------- 00093 /// current number of elements in this vector. 00094 inline size_t size(void) const 00095 { return length_; } 00096 /// current capacity (amount of allocated storage) for this vector. 00097 inline size_t capacity(void) const 00098 { return capacity_; } 00099 /// current data pointer, no longer valid after any of the following: 00100 /// extend, erase, operator=, and ~pod_vector. 00101 /// Take extreem care when using this function. 00102 inline Type* data(void) 00103 { return data_; } 00104 /// const version of \c data pointer 00105 inline const Type* data(void) const 00106 { return data_; } 00107 // ---------------------------------------------------------------------- 00108 /*! 00109 Increase the number of elements the end of this vector. 00110 00111 \param n 00112 is the number of elements to add to end of this vector. 00113 00114 \return 00115 is the number of elements in the vector before \c extend was extended. 00116 00117 - If \c Type is plain old data, new elements are not initialized; 00118 i.e., their constructor is not called. Otherwise, the constructor 00119 is called for each new element. 00120 00121 - This is the only routine that allocates memory for \c pod_vector. 00122 and it uses thread_alloc for this allocation, hence this determines 00123 which thread corresponds to this vector (when in parallel mode). 00124 00125 - If the resulting length of the vector would be more than \c max_length_, 00126 and \c NDEBUG is not defined, a CPPAD_ASSERT is generated. 00127 */ 00128 inline size_t extend(size_t n) 00129 { size_t old_length = length_; 00130 length_ += n; 00131 CPPAD_ASSERT_KNOWN( 00132 length_ <= max_length_ , 00133 "pod_vector.hpp: attempt to create to large a vector.\n" 00134 "If Type is CPPAD_TYPE_ADDR_TYPE, tape is too long for Type." 00135 ); 00136 // check if we can use current memory 00137 if( capacity_ >= length_ ) 00138 return old_length; 00139 00140 // save more old information 00141 size_t old_capacity = capacity_; 00142 Type* old_data = data_; 00143 00144 // get new memory and set capacity 00145 size_t length_bytes = length_ * sizeof(Type); 00146 size_t capacity_bytes; 00147 void* v_ptr = thread_alloc::get_memory(length_bytes, capacity_bytes); 00148 capacity_ = capacity_bytes / sizeof(Type); 00149 data_ = reinterpret_cast<Type*>(v_ptr); 00150 CPPAD_ASSERT_UNKNOWN( length_ <= capacity_ ); 00151 00152 size_t i; 00153 if( ! is_pod<Type>() ) 00154 { // call constructor for each new element 00155 for(i = 0; i < capacity_; i++) 00156 new(data_ + i) Type(); 00157 } 00158 00159 // copy old data to new data 00160 for(i = 0; i < old_length; i++) 00161 data_[i] = old_data[i]; 00162 00163 // return old memory to available pool 00164 if( old_capacity > 0 ) 00165 { v_ptr = reinterpret_cast<void*>( old_data ); 00166 if( ! is_pod<Type>() ) 00167 { for(i = 0; i < old_capacity; i++) 00168 (old_data + i)->~Type(); 00169 } 00170 thread_alloc::return_memory(v_ptr); 00171 } 00172 00173 // return value for extend(n) is the old length 00174 return old_length; 00175 } 00176 // ---------------------------------------------------------------------- 00177 /// non-constant element access; i.e., we can change this element value 00178 Type& operator[]( 00179 /// element index, must be less than length 00180 size_t i 00181 ) 00182 { CPPAD_ASSERT_UNKNOWN( i < length_ ); 00183 return data_[i]; 00184 } 00185 // ---------------------------------------------------------------------- 00186 /// constant element access; i.e., we cannot change this element value 00187 const Type& operator[]( 00188 /// element index, must be less than length 00189 size_t i 00190 ) const 00191 { CPPAD_ASSERT_UNKNOWN( i < length_ ); 00192 return data_[i]; 00193 } 00194 // ---------------------------------------------------------------------- 00195 /*! 00196 Remove all the elements from this vector but leave the capacity 00197 and data pointer as is. 00198 00199 */ 00200 void erase(void) 00201 { length_ = 0; 00202 return; 00203 } 00204 // ---------------------------------------------------------------------- 00205 /*! 00206 Remove all the elements from this vector and delete its memory. 00207 */ 00208 void free(void) 00209 { if( capacity_ > 0 ) 00210 { void* v_ptr = reinterpret_cast<void*>( data_ ); 00211 if( ! is_pod<Type>() ) 00212 { // call destructor for each element 00213 size_t i; 00214 for(i = 0; i < capacity_; i++) 00215 (data_ + i)->~Type(); 00216 } 00217 thread_alloc::return_memory(v_ptr); 00218 } 00219 data_ = CPPAD_NULL; 00220 capacity_ = 0; 00221 length_ = 0; 00222 } 00223 /// vector assignment operator 00224 /// If the resulting length of the vector would be more than 00225 /// \c max_length_, and \c NDEBUG is not defined, 00226 /// a CPPAD_ASSERT is generated. 00227 void operator=( 00228 /// right hand size of the assingment operation 00229 const pod_vector& x 00230 ) 00231 { size_t i; 00232 00233 if( x.length_ <= capacity_ ) 00234 { // use existing allocation for this vector 00235 length_ = x.length_; 00236 CPPAD_ASSERT_KNOWN( 00237 length_ <= max_length_ , 00238 "pod_vector.hpp: attempt to create to large a vector.\n" 00239 "If Type is CPPAD_TYPE_ADDR_TYPE, tape long for Type." 00240 ); 00241 } 00242 else 00243 { // free old memory and get new memory of sufficient length 00244 if( capacity_ > 0 ) 00245 { void* v_ptr = reinterpret_cast<void*>( data_ ); 00246 if( ! is_pod<Type>() ) 00247 { // call destructor for each element 00248 for(i = 0; i < capacity_; i++) 00249 (data_ + i)->~Type(); 00250 } 00251 thread_alloc::return_memory(v_ptr); 00252 } 00253 length_ = capacity_ = 0; 00254 extend( x.length_ ); 00255 } 00256 CPPAD_ASSERT_UNKNOWN( length_ == x.length_ ); 00257 for(i = 0; i < length_; i++) 00258 { data_[i] = x.data_[i]; } 00259 } 00260 /*! 00261 Swap all properties of this vector with another. 00262 00263 \param other 00264 is the other vector that we are swapping this vector with. 00265 */ 00266 void swap(pod_vector& other) 00267 { std::swap(capacity_, other.capacity_); 00268 std::swap(length_, other.length_); 00269 std::swap(data_, other.data_); 00270 } 00271 }; 00272 00273 } // END_CPPAD_NAMESPACE 00274 # endif