CppAD: A C++ Algorithmic Differentiation Package  20130918
pod_vector.hpp
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines