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