Simbody

Array.h

Go to the documentation of this file.
00001 #ifndef SimTK_SimTKCOMMON_ARRAY_H_
00002 #define SimTK_SimTKCOMMON_ARRAY_H_
00003 
00004 /* -------------------------------------------------------------------------- *
00005  *                      SimTK Core: SimTKcommon                               *
00006  * -------------------------------------------------------------------------- *
00007  * This is part of the SimTK Core biosimulation toolkit originating from      *
00008  * Simbios, the NIH National Center for Physics-Based Simulation of           *
00009  * Biological Structures at Stanford, funded under the NIH Roadmap for        *
00010  * Medical Research, grant U54 GM072970. See https://simtk.org.               *
00011  *                                                                            *
00012  * Portions copyright (c) 2010 Stanford University and the Authors.           *
00013  * Authors: Michael Sherman                                                   *
00014  * Contributors:                                                              *
00015  *                                                                            *
00016  * Permission is hereby granted, free of charge, to any person obtaining a    *
00017  * copy of this software and associated documentation files (the "Software"), *
00018  * to deal in the Software without restriction, including without limitation  *
00019  * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
00020  * and/or sell copies of the Software, and to permit persons to whom the      *
00021  * Software is furnished to do so, subject to the following conditions:       *
00022  *                                                                            *
00023  * The above copyright notice and this permission notice shall be included in *
00024  * all copies or substantial portions of the Software.                        *
00025  *                                                                            *
00026  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
00027  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
00028  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
00029  * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,    *
00030  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR      *
00031  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE  *
00032  * USE OR OTHER DEALINGS IN THE SOFTWARE.                                     *
00033  * -------------------------------------------------------------------------- */
00034 
00041 #include "SimTKcommon/internal/common.h"
00042 #include "SimTKcommon/internal/ExceptionMacros.h"
00043 
00044 #include <algorithm>
00045 #include <iterator>
00046 #include <vector>
00047 #include <ostream>
00048 #include <climits>
00049 #include <typeinfo>
00050 
00051 namespace SimTK {
00052 
00053 // These are the classes defined in this header.
00054 template <class X>                   struct ArrayIndexTraits;
00055 template <class T, class X=unsigned> class  ArrayViewConst_;
00056 template <class T, class X=unsigned> class  ArrayView_;
00057 template <class T, class X=unsigned> class  Array_;
00058 
00059 
00060 
00061 //==============================================================================
00062 //                           CLASS ArrayIndexTraits
00063 //==============================================================================
00064 
00107 template <class X> struct ArrayIndexTraits {
00110     typedef typename X::size_type       size_type;
00113     typedef typename X::difference_type difference_type;
00116     static size_type max_size() {return X::max_size();}
00117 };
00118 
00121 template <> struct ArrayIndexTraits<unsigned> {
00122     typedef unsigned        size_type;
00123     typedef int             difference_type;
00124     static size_type        max_size() {return (unsigned)INT_MAX;}
00125 };
00126 
00128 template <> struct ArrayIndexTraits<int> {
00129     typedef int             size_type;
00130     typedef int             difference_type;
00131     static size_type        max_size() {return INT_MAX;}
00132 };
00133 
00141 template <> struct ArrayIndexTraits<unsigned long> {
00142     typedef unsigned long       size_type;
00143     typedef long                difference_type;
00144     static size_type            max_size() {return (unsigned long)LONG_MAX;}
00145 };
00146 
00154 template <> struct ArrayIndexTraits<long> {
00155     typedef long                size_type;
00156     typedef long                difference_type;
00157     static size_type            max_size() {return LONG_MAX;}
00158 };
00159 
00165 template <> struct ArrayIndexTraits<unsigned short> {
00166     typedef unsigned short      size_type;
00167     typedef int                 difference_type;
00168     static size_type            max_size() {return USHRT_MAX;}
00169 };
00170 
00175 template <> struct ArrayIndexTraits<short> {
00176     typedef short               size_type;
00177     typedef short               difference_type;
00178     static size_type            max_size() {return SHRT_MAX;}
00179 }; 
00180 
00181 
00186 template <> struct ArrayIndexTraits<unsigned char> {
00187     typedef unsigned char       size_type;
00188     typedef short               difference_type;
00189     static size_type            max_size() {return UCHAR_MAX;} // not CHAR_MAX
00190 };
00191 
00197 template <> struct ArrayIndexTraits<signed char> {
00198     typedef signed char         size_type;
00199     typedef signed char         difference_type;
00200     static size_type            max_size() {return SCHAR_MAX;}
00201 };
00202 
00209 template <> struct ArrayIndexTraits<char> {
00210     typedef char                size_type;
00211     typedef signed char         difference_type;
00212     static size_type            max_size() {return (char)SCHAR_MAX;}
00213 };
00214 
00220 template <> struct ArrayIndexTraits<bool> {
00221     typedef unsigned char       size_type;
00222     typedef signed char         difference_type;
00223     static size_type            max_size() {return 2;}
00224 };
00225 
00228 template <> struct ArrayIndexTraits<unsigned long long> {
00229     typedef unsigned long long  size_type;
00230     typedef long long           difference_type;
00231     static size_type            max_size() 
00232                                     {return (unsigned long long)LLONG_MAX;}
00233 };
00234 
00237 template <> struct ArrayIndexTraits<long long> {
00238     typedef long long           size_type;
00239     typedef long long           difference_type;
00240     static size_type            max_size() {return LLONG_MAX;}
00241 };
00242 
00243 // Don't show this in Doxygen.
00245 // This helper class decides what integral type we should use to best pack
00246 // the index type's size_type representation. The idea is to pack the whole
00247 // Array_ structure into 8 bytes on a 32 bit machine, 16 bytes on a 64 bit
00248 // machine, using the largest integral type that will work, giving a layout
00249 // like this:          |       data pointer     |
00250 //                     |   nUsed   | nAllocated |
00251 
00252 // The default implementation just uses the integral type itself.
00253 template <class Integral, class is64Bit> struct ArrayIndexPackTypeHelper 
00254 {   typedef Integral packed_size_type;};
00255 
00256 // On 32 bit machine, pack anything smaller than a short into a short.
00257 template<> struct ArrayIndexPackTypeHelper<bool,FalseType> 
00258 {   typedef unsigned short packed_size_type;};
00259 template<> struct ArrayIndexPackTypeHelper<char,FalseType> 
00260 {   typedef unsigned short packed_size_type;};
00261 template<> struct ArrayIndexPackTypeHelper<unsigned char,FalseType> 
00262 {   typedef unsigned short packed_size_type;};
00263 template<> struct ArrayIndexPackTypeHelper<signed char,FalseType> 
00264 {   typedef short packed_size_type;};
00265 
00266 // On 64 bit machine, pack anything smaller than an int into an int.
00267 template<> struct ArrayIndexPackTypeHelper<bool,TrueType> 
00268 {   typedef unsigned int packed_size_type;};
00269 template<> struct ArrayIndexPackTypeHelper<char,TrueType> 
00270 {   typedef unsigned int packed_size_type;};
00271 template<> struct ArrayIndexPackTypeHelper<unsigned char,TrueType> 
00272 {   typedef unsigned int packed_size_type;};
00273 template<> struct ArrayIndexPackTypeHelper<signed char,TrueType> 
00274 {   typedef int packed_size_type;};
00275 template<> struct ArrayIndexPackTypeHelper<unsigned short,TrueType> 
00276 {   typedef unsigned int packed_size_type;};
00277 template<> struct ArrayIndexPackTypeHelper<short,TrueType> 
00278 {   typedef int packed_size_type;};
00279 
00280 template <class Integral> struct ArrayIndexPackType
00281 {   typedef typename ArrayIndexPackTypeHelper<Integral,Is64BitPlatformType>
00282                         ::packed_size_type  packed_size_type;};
00290 //==============================================================================
00291 //                            CLASS ArrayViewConst_
00292 //==============================================================================
00319 template <class T, class X> class ArrayViewConst_ {
00320 public:
00321 
00322 
00323 //------------------------------------------------------------------------------
00330 typedef T           value_type;
00332 typedef X           index_type;
00334 typedef T*          pointer;
00336 typedef const T*    const_pointer;
00338 typedef T&          reference;
00340 typedef const T&    const_reference;
00342 typedef T*          iterator;
00344 typedef const T*    const_iterator;
00346 typedef std::reverse_iterator<iterator>                 reverse_iterator;
00348 typedef std::reverse_iterator<const_iterator>           const_reverse_iterator;
00350 typedef typename ArrayIndexTraits<X>::size_type         size_type;
00353 typedef typename ArrayIndexTraits<X>::difference_type   difference_type;
00355 typedef typename ArrayIndexPackType<size_type>::packed_size_type 
00356                                                         packed_size_type;
00360 //------------------------------------------------------------------------------
00366 
00368 ArrayViewConst_() : pData(0), nUsed(0), nAllocated(0) {}
00369 
00379 ArrayViewConst_(const ArrayViewConst_& src) 
00380 :   pData(0), nUsed(src.nUsed), nAllocated(0) {
00381     if (nUsed) pData = const_cast<T*>(src.pData);
00382 } 
00383 
00384 // Copy assignment is suppressed.
00385 
00408 ArrayViewConst_(const T* first, const T* last1) 
00409 :   pData(0),nUsed(0),nAllocated(0) { 
00410     if (last1==first) return; // empty
00411 
00412     const char* methodName = "ArrayViewConst_<T>::ctor(first,last1)";
00413 
00414     SimTK_ERRCHK((first&&last1)||(first==last1), methodName, 
00415         "One of the source pointers was null (0); either both must be"
00416         " non-null or both must be null.");
00417 
00418     SimTK_ERRCHK3(isSizeOK(last1-first), methodName, 
00419         "The source data's size %llu is too big for this array which"
00420         " is limited to %llu elements by its index type %s.",
00421         ull(last1-first), ullMaxSize(), indexName());
00422 
00423     pData = const_cast<T*>(first); 
00424     nUsed = packed_size_type(last1-first); 
00425     // nAllocated is already zero
00426 }
00427 
00455 template <class A>
00456 ArrayViewConst_(const std::vector<T,A>& src) 
00457 :   pData(0),nUsed(0),nAllocated(0) { 
00458     if (src.empty()) return;
00459 
00460     SimTK_ERRCHK3(isSizeOK(src.size()), 
00461         "ArrayViewConst_<T>::ctor(std::vector<T>)",
00462         "The source std::vector's size %llu is too big for this array which"
00463         " is limited to %llu elements by its index type %s.",
00464         ull(src.size()), ullMaxSize(), indexName());
00465 
00466     pData = const_cast<T*>(&src.front()); 
00467     nUsed = packed_size_type(src.size()); 
00468     // nAllocated is already zero
00469 }
00472 operator const ArrayView_<T,X>&() const
00473 {   return *reinterpret_cast<const ArrayView_<T,X>*>(this); }
00476 operator const Array_<T,X>&() const
00477 {   return *reinterpret_cast<const Array_<T,X>*>(this); }
00478 
00484 void disconnect() {
00485     SimTK_ASSERT(nAllocated==0,
00486         "ArrayViewConst_::deallocate(): called on an owner Array_");
00487     nUsed = 0;
00488     pData = 0;
00489 }
00490 
00493 ~ArrayViewConst_() {
00494     disconnect();
00495 }
00499 //------------------------------------------------------------------------------
00506 
00508 size_type size() const {return size_type(nUsed);}
00510 size_type max_size() const {return ArrayIndexTraits<X>::max_size();}
00513 bool empty() const {return nUsed==0;}
00518 size_type capacity() const {return size_type(nAllocated?nAllocated:nUsed);}
00522 size_type allocated() const {return size_type(nAllocated);}
00528 bool isOwner() const {return nAllocated || pData==0;}
00529 /*}*/
00530 
00531 
00532 //------------------------------------------------------------------------------
00539 
00546 const T& operator[](index_type i) const {
00547     SimTK_INDEXCHECK(size_type(i),size(),"ArrayViewConst_<T>::operator[]()");
00548     return pData[i];
00549 }
00554 const T& at(index_type i) const {
00555     SimTK_INDEXCHECK_ALWAYS(size_type(i),size(),"ArrayViewConst_<T>::at()");
00556     return pData[i];
00557 }
00560 const T& getElt(index_type i) const {
00561     SimTK_INDEXCHECK(size_type(i),size(),"ArrayViewConst_<T>::getElt()");
00562     return pData[i];
00563 }
00569 const T& front() const 
00570 {   SimTK_ERRCHK(!empty(), "ArrayViewConst_<T>::front()", "Array was empty.");
00571     return pData[0]; }
00577 const T& back() const 
00578 {   SimTK_ERRCHK(!empty(), "ArrayViewConst_<T>::back()", "Array was empty.");
00579     return pData[nUsed-1]; }
00580 
00599 ArrayViewConst_ operator()(index_type index, size_type length) const {
00600     const char* methodName = "ArrayViewConst_<T>(index,length)";
00601     const size_type ix(index);
00602     SimTK_ERRCHK2(isSizeInRange(ix, size()), methodName,
00603         "For this operator, we must have 0 <= index <= size(), but"
00604         " index==%llu and size==%llu.", ull(ix), ullSize());
00605     SimTK_ERRCHK2(isSizeInRange(length, size_type(size()-ix)), methodName, 
00606         "This operator requires 0 <= length <= size()-index, but"
00607         " length==%llu and size()-index==%llu.",ull(length),ull(size()-ix));
00608 
00609     return ArrayViewConst_(pData+ix, pData+ix+length);
00610 }
00613 ArrayViewConst_ getSubArray(index_type index, size_type length) const
00614 {   return (*this)(index,length); }
00615 
00619 //------------------------------------------------------------------------------
00628 
00633 const T* cbegin() const {return pData;}
00638 const T* cend() const {return pData + nUsed;}
00640 const T* begin() const {return pData;}
00642 const T* end() const {return pData + nUsed;}
00643 
00646 const_reverse_iterator crbegin() const {return const_reverse_iterator(cend());}
00650 const_reverse_iterator crend() const {return const_reverse_iterator(cbegin());}
00652 const_reverse_iterator rbegin() const {return crbegin();} 
00654 const_reverse_iterator rend() const {return crend();}
00655 
00662 const T* cdata() const {return pData;}
00664 const T* data() const {return pData;}
00668 //------------------------------------------------------------------------------
00669                                  protected:
00670 //------------------------------------------------------------------------------
00671 // The remainder of this class is for the use of the ArrayView_<T,X> and
00672 // Array_<T,X> derived classes only and should not be documented for users to 
00673 // see. 
00674                                      
00675 // Don't let doxygen see any of this.
00677 packed_size_type psize() const {return nUsed;}
00678 packed_size_type pallocated() const {return nAllocated;}
00679 
00680 // These provide direct access to the data members for our trusted friends.
00681 void setData(const T* p)        {pData = const_cast<T*>(p);}
00682 void setSize(size_type n)       {nUsed = packed_size_type(n);}
00683 void incrSize()                 {++nUsed;}
00684 void decrSize()                 {--nUsed;}
00685 void setAllocated(size_type n)  {nAllocated = packed_size_type(n);}
00686 
00687 // Check whether a given size is the same as the current size of this array,
00688 // avoiding any compiler warnings due to mismatched integral types.
00689 template <class S> 
00690 bool isSameSize(S sz) const
00691 {   return ull(sz) == ullSize(); }
00692 
00693 // Check that a source object's size will fit in the array being careful to
00694 // avoid overflow and warnings in the comparison.
00695 template <class S> 
00696 bool isSizeOK(S srcSz) const
00697 {   return ull(srcSz) <= ullMaxSize(); }
00698 
00699 // This is identical in function to std::distance() (reports how many 
00700 // elements lie between two iterators) but avoids any slow 
00701 // Release-build bugcatchers that Microsoft may have felt compelled to add.
00702 // The implementation is specialized for random access iterators because
00703 // they can measure distance very fast.
00704 template<class Iter> static
00705 typename std::iterator_traits<Iter>::difference_type
00706 iterDistance(const Iter& first, const Iter& last1) {
00707     return iterDistanceImpl(first,last1,
00708                 typename std::iterator_traits<Iter>::iterator_category());
00709 }
00710 
00711 // Generic slow implementation for non-random access iterators. This is fine
00712 // for forward and bidirectional iterators, but it will *consume* input
00713 // iterators so is useless for them.
00714 template<class Iter> static
00715 typename std::iterator_traits<Iter>::difference_type
00716 iterDistanceImpl(const Iter& first, const Iter& last1, std::input_iterator_tag) {
00717     typename std::iterator_traits<Iter>::difference_type d = 0;
00718     for (Iter src=first; src != last1; ++src, ++d)
00719         ;
00720     return d;
00721 }
00722 
00723 // Fast specialization for random access iterators (including ordinary
00724 // pointers) -- just subtract.
00725 template<class Iter> static
00726 typename std::iterator_traits<Iter>::difference_type
00727 iterDistanceImpl(const Iter& first, const Iter& last1, 
00728                  std::random_access_iterator_tag) {
00729     return last1 - first;
00730 }
00731 
00732 // This method attempts to determine whether any elements in the iterator range
00733 // [first,last1) overlap with the elements stored in this array. This is used 
00734 // for error checks for operations where source is not permitted to overlap the
00735 // destination. For random access iterators (including ordinary pointers), we 
00736 // can answer this question definitively because we expect the data to be 
00737 // consecutive in memory. For other kinds of iterators, we will just assume
00738 // there is no overlap. Note that null ranges do not overlap even if the
00739 // pair of equal iterators points within the other range -- what matters is
00740 // the number of overlapping elements.
00741 template<class Iter> bool
00742 overlapsWithData(const Iter& first, const Iter& last1) {
00743     return overlapsWithDataImpl(first,last1,
00744                 typename std::iterator_traits<Iter>::iterator_category());
00745 }
00746 
00747 // This is a partial specialization of the above where the data is given
00748 // with ordinary pointers.
00749 template <class T2> bool
00750 overlapsWithData(const T2* first, const T2* last1) {
00751     // Find the start and end+1 of the alleged overlap region. There is
00752     // overlap iff end+1 > start. Note that this works if either range 
00753     // is [0,0) or [p,p), or if last1 is illegally less than first (we just
00754     // want to report no overlap in that case -- it is someone else's business
00755     // to complain).
00756     const T* obegin = std::max(cbegin(), (const T*)first);
00757     const T* oend1  = std::min(cend(),   (const T*)last1);
00758 
00759     return obegin < oend1;
00760 }
00761 
00762 // This is the generic implementation for any type of input iterator other than
00763 // random access (i.e., bidirectional, forward, or input) -- assume no overlap.
00764 template<class Iter> bool
00765 overlapsWithDataImpl(const Iter&, const Iter&, std::input_iterator_tag) 
00766 {   return false; }
00767 
00768 // Here we can actually test for overlap since we have random access iterators.
00769 // We convert them to pointers and then look for memory overlap.
00770 template<class Iter> bool
00771 overlapsWithDataImpl(const Iter& first, const Iter& last1, 
00772                      std::random_access_iterator_tag) {
00773     // We must check that the input iterators span a non-zero range before
00774     // assuming we can dereference them.
00775     if (last1 <= first)
00776         return false; // zero or malformed source range: no overlap
00777 
00778     // We now know we can dereference first and last1-1 (can't safely 
00779     // dereference last1 but we can use pointer arithmetic to point past
00780     // the (last-1)th element in memory). We then take the dereferenced
00781     // object's address to get ordinary pointers that we can use to 
00782     // watch for illegal overlap.
00783     return overlapsWithData(&*first, &*(last1-1)); // use pointer overload
00784 }
00785 
00786 // Cast an integral type to maximal-width unsigned long long to avoid accidental
00787 // overflows that might otherwise occur due to wraparound that can happen 
00788 // with small index types.
00789 template <class S>
00790 static unsigned long long ull(S sz)
00791 {   return (unsigned long long)sz; }
00792 
00793 // Return size(), capacity(), and max_size() cast to unsigned long long.
00794 unsigned long long ullSize()     const {return ull(size());}
00795 unsigned long long ullCapacity() const {return ull(capacity());}
00796 unsigned long long ullMaxSize()  const {return ull(max_size());}
00797 
00798 // Useful in error messages for explaining why something was too big.
00799 const char* indexName() const {return NiceTypeName<X>::name();}
00800 
00803 private:
00804 //------------------------------------------------------------------------------
00805 //                               DATA MEMBERS
00806 // These are the only data members and this layout is guaranteed not to change
00807 // from release to release. If data is null, then nUsed==nAllocated==0.
00808 
00809 T*                  pData;      // ptr to data referenced here, or 0 if none
00810 packed_size_type    nUsed;      // number of elements currently present (size)
00811 packed_size_type    nAllocated; // heap allocation; 0 if pData is not owned
00812 
00813 ArrayViewConst_& operator=(const ArrayViewConst_& src); // suppressed
00814 };
00815 
00816 
00817 
00818 
00819 
00820 
00821 //==============================================================================
00822 //                            CLASS ArrayView_
00823 //==============================================================================
00835 template <class T, class X> class ArrayView_ : public ArrayViewConst_<T,X> {
00836 typedef ArrayViewConst_<T,X> CBase;
00837 public:
00838 //------------------------------------------------------------------------------
00843 /*{*/
00844 typedef T                                               value_type;
00845 typedef X                                               index_type;
00846 typedef T*                                              pointer;
00847 typedef const T*                                        const_pointer;
00848 typedef T&                                              reference;
00849 typedef const T&                                        const_reference;
00850 typedef T*                                              iterator;
00851 typedef const T*                                        const_iterator;
00852 typedef std::reverse_iterator<iterator>                 reverse_iterator;
00853 typedef std::reverse_iterator<const_iterator>           const_reverse_iterator;
00854 typedef typename ArrayIndexTraits<X>::size_type         size_type;
00855 typedef typename ArrayIndexTraits<X>::difference_type   difference_type;
00856 typedef typename ArrayIndexPackType<size_type>::packed_size_type 
00857                                                         packed_size_type;
00858 /*}*/
00859 
00860 
00861 //------------------------------------------------------------------------------
00867 
00869 ArrayView_() : CBase() {}
00870 
00872 ArrayView_(const ArrayView_& src) : CBase(src) {}
00873 
00875 ArrayView_(T* first, const T* last1) : CBase(first,last1) {} 
00876 
00878 template <class A>
00879 ArrayView_(std::vector<T,A>& v) : CBase(v) {}
00880 
00882 operator const Array_<T,X>&() const 
00883 {   return *reinterpret_cast<const Array_<T,X>*>(this); }  
00884 
00886 operator Array_<T,X>&() 
00887 {   return *reinterpret_cast<Array_<T,X>*>(this); } 
00888 
00891 void disconnect() {this->CBase::disconnect();}
00892 
00895 ~ArrayView_() {this->CBase::disconnect();}
00899 //------------------------------------------------------------------------------
00911 
00913 ArrayView_& operator=(const ArrayView_& src) {
00914     if (&src != this)
00915         avAssignIteratorDispatch(src.cbegin(), src.cend(),
00916                                  std::random_access_iterator_tag(),
00917                                  "ArrayView_<T>::operator=(ArrayView_<T>)");
00918     return *this;
00919 }
00920 
00921 
00924 template <class T2, class X2>
00925 ArrayView_& operator=(const ArrayViewConst_<T2,X2>& src) {
00926     if ((const void*)&src != (void*)this)
00927         avAssignIteratorDispatch(src.cbegin(), src.cend(),
00928                                  std::random_access_iterator_tag(),
00929                                  "ArrayView_<T>::operator=(Array_<T2>)");
00930     return *this;
00931 }
00932 
00933 // Help out dumb compilers struggling to match the template arguments and
00934 // promote the Array_ or ArrayView_ to ArrayConstView_ at the same time.
00935 
00938 template <class T2, class X2>
00939 ArrayView_& operator=(const ArrayView_<T2,X2>& src)
00940 {   return *this = static_cast<const ArrayViewConst_<T2,X2>&>(src); }
00943 template <class T2, class X2>
00944 ArrayView_& operator=(const Array_<T2,X2>& src)
00945 {   return *this = static_cast<const ArrayViewConst_<T2,X2>&>(src); }
00946 
00949 template <class T2, class A2>
00950 ArrayView_& operator=(const std::vector<T2,A2>& src) {
00951     avAssignIteratorDispatch(src.begin(), src.end(),
00952                              std::random_access_iterator_tag(),
00953                              "ArrayView_<T>::operator=(std::vector<T2>)");
00954     return *this;
00955 }
00956 
00958 ArrayView_& operator=(const T& fillValue) 
00959 {   fill(fillValue); return *this; }
00960 
00966 ArrayView_& fill(const T& fillValue) {
00967     for (T* d = begin(); d != end(); ++d)
00968         *d = fillValue; // using T::operator=(T)
00969     return *this;
00970 }
00971 
00975 void assign(size_type n, const T& fillValue) {
00976     SimTK_ERRCHK2(n == size(), "ArrayView_<T>::assign(n,value)",
00977         "Assignment to an ArrayView is permitted only if the source"
00978         " is the same size. Here n==%llu element(s) but the"
00979         " ArrayView has a fixed size of %llu.", 
00980         ull(n), ull(size()));
00981 
00982     fill(fillValue);
00983 }
00984 
01002 template <class T2>
01003 void assign(const T2* first, const T2* last1) {
01004     const char* methodName = "ArrayView_<T>::assign(T2* first, T2* last1)";
01005     SimTK_ERRCHK((first&&last1)||(first==last1), methodName, 
01006         "One of the source pointers was null (0); either both must be"
01007         " non-null or both must be null.");
01008     // Valid pointers are random access iterators.
01009     avAssignIteratorDispatch(first, last1, std::random_access_iterator_tag(),
01010                              methodName);
01011 }
01012 
01042 // Watch out for integral types matching this signature -- they must be
01043 // forwarded to the assign(n, fillValue) signature instead.
01044 template <class Iter>
01045 void assign(const Iter& first, const Iter& last1)
01046 {   avAssignDispatch(first,last1,typename IsIntegralType<Iter>::Result(),
01047                      "ArrayView_<T>::assign(Iter first, Iter last1)"); }
01051 //------------------------------------------------------------------------------
01058 
01065 const T& operator[](index_type i) const {return this->CBase::operator[](i);}
01066 
01074 T& operator[](index_type i) {return const_cast<T&>(this->CBase::operator[](i));}
01075 
01080 const T& at(index_type i) const {return this->CBase::at(i);}
01081 
01086 T& at(index_type i) {return const_cast<T&>(this->CBase::at(i));}
01087 
01090 const T& getElt(index_type i) const {return this->CBase::getElt(i);}
01093 T& updElt(index_type i) {return const_cast<T&>(this->CBase::getElt(i));}
01094 
01100 const T& front() const {return this->CBase::front();} 
01101 
01107 T& front() {return const_cast<T&>(this->CBase::front());}
01108 
01114 const T& back() const {return this->CBase::back();}
01115 
01121 T& back() {return const_cast<T&>(this->CBase::back());}
01122 
01141 ArrayView_ operator()(index_type index, size_type length) {
01142     const char* methodName = "ArrayView_<T>(index,length)";
01143     const size_type ix(index);
01144     SimTK_ERRCHK2(isSizeInRange(ix, size()), methodName,
01145         "For this operator, we must have 0 <= index <= size(), but"
01146         " index==%llu and size==%llu.", ull(ix), ullSize());
01147     SimTK_ERRCHK2(isSizeInRange(length, size_type(size()-ix)), methodName, 
01148         "This operator requires 0 <= length <= size()-index, but"
01149         " length==%llu and size()-index==%llu.",ull(length),ull(size()-ix));
01150 
01151     return ArrayView_(data()+ix, data()+ix+length);
01152 }
01155 ArrayView_ updSubArray(index_type index, size_type length)
01156 {   return (*this)(index,length); }
01160 //------------------------------------------------------------------------------
01169 
01174 const T* cbegin() const {return this->CBase::cbegin();}
01176 const T* begin() const {return this->CBase::cbegin();}
01181 T* begin() {return const_cast<T*>(this->CBase::cbegin());}
01182 
01187 const T* cend() const {return this->CBase::cend();}
01189 const T* end() const {return this->CBase::cend();}
01194 T* end() {return const_cast<T*>(this->CBase::cend());}
01195 
01198 const_reverse_iterator crbegin() const {return this->CBase::crbegin();}
01200 const_reverse_iterator rbegin() const {return this->CBase::crbegin();} 
01203 reverse_iterator rbegin() {return reverse_iterator(end());}
01204 
01208 const_reverse_iterator crend() const {return this->CBase::crend();}
01210 const_reverse_iterator rend() const {return this->CBase::crend();}
01214 reverse_iterator rend() {return reverse_iterator(begin());}
01215 
01222 const T* cdata() const {return this->CBase::cdata();}
01225 const T* data() const {return this->CBase::cdata();}
01229 T* data() {return const_cast<T*>(this->CBase::cdata());}
01233 //------------------------------------------------------------------------------
01239 
01240 // Note: these have to be explicitly forwarded to the base class methods
01241 // in order to keep gcc from complaining. Note that the "this->" is 
01242 // apparently necessary in order to permit delayed definition of templatized 
01243 // methods. Doxygen picks up the comments from the base class.
01244 
01245 size_type size()      const {return this->CBase::size();}
01246 size_type max_size()  const {return this->CBase::max_size();}
01247 bool      empty()     const {return this->CBase::empty();}
01248 size_type capacity()  const {return this->CBase::capacity();}
01249 size_type allocated() const {return this->CBase::allocated();}
01250 bool      isOwner()   const {return this->CBase::isOwner();}
01254 //------------------------------------------------------------------------------
01255                                    private:
01256 //------------------------------------------------------------------------------
01257 // no data members are allowed
01258 
01259 //------------------------------------------------------------------------------
01260 //                       ARRAY VIEW ASSIGN DISPATCH
01261 // This is the assign() implementation for ArrayView_ when the class that 
01262 // matched the alleged InputIterator template argument turned out to be one of 
01263 // the integral types in which case this should match the assign(n, fillValue) 
01264 // signature.
01265 template <class IntegralType>
01266 void avAssignDispatch(IntegralType n, IntegralType v, TrueType isIntegralType,
01267                       const char*) 
01268 {   assign(size_type(n), value_type(v)); }
01269 
01270 // This is the assign() implementation for ArrayView_ when the class that 
01271 // matched the alleged InputIterator template argument is NOT an integral type 
01272 // and may very well be an iterator. 
01273 template <class InputIterator> 
01274 void avAssignDispatch(const InputIterator& first, const InputIterator& last1, 
01275                       FalseType isIntegralType, const char* methodName) 
01276 {   avAssignIteratorDispatch(first, last1, 
01277         typename std::iterator_traits<InputIterator>::iterator_category(),
01278         methodName); }
01279 
01280 // This is the assign() implementation for a plain input_iterator
01281 // (i.e., not a forward, bidirectional, or random access iterator). These
01282 // have the unfortunate property that we can't count the elements in advance.
01283 // Here we're going to complain if there aren't enough; but will simply stop
01284 // when we get size() elements and not insist that the input stream reached
01285 // the supplied last1 iterator. Semantics is elementwise assignment.
01286 template <class InputIterator>
01287 void avAssignIteratorDispatch(const InputIterator& first, 
01288                               const InputIterator& last1, 
01289                               std::input_iterator_tag, 
01290                               const char* methodName) 
01291 {
01292     T* p = begin();
01293     InputIterator src = first;
01294     while (src != last1 && p != end())
01295         *p++ = *src++; // call T's assignment operator
01296 
01297     // p now points just after the last element that was copied.
01298     const size_type nCopied = size_type(p - begin());
01299     SimTK_ERRCHK2_ALWAYS(nCopied == size(), methodName,
01300         "The supplied input_iterator provided only %llu elements but this"
01301         " ArrayView has a fixed size of %llu elements.",
01302         ull(nCopied), ullSize());
01303 
01304     // We don't care if there are still more input elements available.
01305 }
01306 
01307 // This is the assign() implementation that works for forward and bidirectional
01308 // iterators, but is not used for random_access_iterators. Here we'll count
01309 // the elements as we copy them and complain at the end if there were too
01310 // few or too many.
01311 template <class ForwardIterator>
01312 void avAssignIteratorDispatch(const ForwardIterator& first, 
01313                               const ForwardIterator& last1,
01314                               std::forward_iterator_tag, 
01315                               const char* methodName) 
01316 {
01317     T* p = begin();
01318     ForwardIterator src = first;
01319     while (src != last1 && p != end())
01320         *p++ = *src++; // call T's assignment operator
01321 
01322     // p now points just after the last element that was copied.
01323     const size_type nCopied = size_type(p - begin());
01324     SimTK_ERRCHK2_ALWAYS(nCopied == size(), methodName,
01325         "The supplied forward_ or bidirectional_iterator source range provided"
01326         " only %llu elements but this ArrayView has a fixed size of"
01327         " %llu elements.", ull(nCopied), ullSize());
01328 
01329     // Make sure we ran out of source elements.
01330     SimTK_ERRCHK1_ALWAYS(src == last1, methodName,
01331         "The supplied forward_ or bidirectional_iterator source range"
01332         " contained too many elements; this ArrayView has a fixed size of"
01333         " %llu elements.", ullSize());
01334 }
01335 
01336 // This is the assign() implementation that works for random_access_iterators
01337 // including ordinary pointers. Here we check the number of elements in advance
01338 // and complain if the source and destination aren't the same size. The 
01339 // copying loop can be done faster in this case.
01340 template <class RandomAccessIterator>
01341 void avAssignIteratorDispatch(const RandomAccessIterator& first, 
01342                               const RandomAccessIterator& last1,
01343                               std::random_access_iterator_tag, 
01344                               const char* methodName) 
01345 {
01346     SimTK_ERRCHK2_ALWAYS(isSameSize(last1-first), methodName,
01347         "Assignment to an ArrayView is permitted only if the source"
01348         " is the same size. Here the source had %llu element(s) but the"
01349         " ArrayView has a fixed size of %llu.", 
01350         ull(last1-first), ull(size()));
01351 
01352     SimTK_ERRCHK_ALWAYS(!overlapsWithData(first,last1), methodName, 
01353         "Source range can't overlap with the destination data.");
01354 
01355     T* p = begin();
01356     RandomAccessIterator src = first;
01357     while (p != end())
01358         *p++ = *src++; // call T's assignment operator
01359 }
01360 
01361 
01362 //------------------------------------------------------------------------------
01363 // The following private methods are protected methods in the ArrayViewConst_ 
01364 // base class, so they should not need repeating here. However, we explicitly 
01365 // forward to the base methods to avoid gcc errors. The gcc complaint
01366 // is due to their not depending on any template parameters; the "this->"
01367 // apparently fixes that problem.
01368 
01369 packed_size_type psize()      const {return this->CBase::psize();}
01370 packed_size_type pallocated() const {return this->CBase::pallocated();}
01371 
01372 // This just cast sizes to unsigned long long so that we can do comparisons
01373 // without getting warnings.
01374 unsigned long long ullSize()     const {return this->CBase::ullSize();}
01375 unsigned long long ullCapacity() const {return this->CBase::ullCapacity();}
01376 unsigned long long ullMaxSize()  const {return this->CBase::ullMaxSize();}
01377 // This is the index type name and is handy for error messages to explain
01378 // why some size was too big.
01379 const char* indexName() const   {return this->CBase::indexName();}
01380 };
01381 
01382 
01383 
01384 
01385 
01386 //==============================================================================
01387 //                               CLASS Array_
01388 //==============================================================================
01491 template <class T, class X> class Array_ : public ArrayView_<T,X> {
01492     typedef ArrayView_<T,X>      Base;
01493     typedef ArrayViewConst_<T,X> CBase;
01494 public:
01495 
01496 
01497 //------------------------------------------------------------------------------
01503 // Doxygen picks up individual descriptions from the base class.
01504 /*{*/
01505 typedef T                                               value_type;
01506 typedef X                                               index_type;
01507 typedef T*                                              pointer;
01508 typedef const T*                                        const_pointer;
01509 typedef T&                                              reference;
01510 typedef const T&                                        const_reference;
01511 typedef T*                                              iterator;
01512 typedef const T*                                        const_iterator;
01513 typedef std::reverse_iterator<iterator>                 reverse_iterator;
01514 typedef std::reverse_iterator<const_iterator>           const_reverse_iterator;
01515 typedef typename ArrayIndexTraits<X>::size_type         size_type;
01516 typedef typename ArrayIndexTraits<X>::difference_type   difference_type;
01517 typedef typename ArrayIndexPackType<size_type>::packed_size_type 
01518                                                         packed_size_type;
01519 /*}*/
01520 
01521 //------------------------------------------------------------------------------
01528 /*{*/
01529 
01531 Array_() : Base() {}
01532 
01537 explicit Array_(size_type n) : Base() {
01538     SimTK_SIZECHECK(n, max_size(), "Array_<T>::ctor(n)");
01539     allocateNoConstruct(n);
01540     defaultConstruct(data(), data()+n);
01541     setSize(n);
01542 }
01543 
01547 Array_(size_type n, const T& initVal) : Base() {
01548     SimTK_SIZECHECK(n, max_size(), "Array_<T>::ctor(n,T)");
01549     setSize(n);
01550     allocateNoConstruct(size());
01551     fillConstruct(begin(), cend(), initVal);
01552 }
01568 template <class InputIter>
01569 Array_(const InputIter& first, const InputIter& last1) : Base() {
01570     ctorDispatch(first,last1,typename IsIntegralType<InputIter>::Result());
01571 }
01572 
01578 template <class T2>
01579 Array_(const T2* first, const T2* last1) : Base() {
01580     const char* methodName = "Array_<T>::ctor(first,last1)";
01581     SimTK_ERRCHK((first&&last1)||(first==last1), methodName, 
01582         "Pointers must be non-null unless they are both null.");
01583     SimTK_ERRCHK3(isSizeOK(last1-first), methodName,
01584         "Source has %llu elements but this array is limited to %llu"
01585         " elements by its index type %s.",
01586         ull(last1-first), ullMaxSize(), indexName());
01587 
01588     setSize(size_type(last1-first));
01589     allocateNoConstruct(size());
01590     copyConstruct(begin(), cend(), first);
01591 }
01592 
01597 template <class T2>
01598 explicit Array_(const std::vector<T2>& v) : Base() { 
01599     if (v.empty()) return;
01600 
01601     SimTK_ERRCHK3(isSizeOK(v.size()), "Array_<T>::ctor(std::vector<T2>)",
01602         "The source std::vector's size %llu is too big for this array which"
01603         " is limited to %llu elements by its index type %s.",
01604         ull(v.size()), ullMaxSize(), indexName());
01605 
01606     // Call the above constructor, making sure to use pointers into the
01607     // vector's data rather than the iterators begin() and end() in case
01608     // they are different types.
01609     new (this) Array_(&v.front(), (&v.back())+1);
01610 }
01611 
01616 Array_(const Array_& src) : Base() {
01617     setSize(src.size());
01618     allocateNoConstruct(size());
01619     copyConstruct(begin(), cend(), src.data());
01620 }
01621 
01628 template <class T2, class X2>
01629 Array_(const Array_<T2,X2>& src) : Base() {
01630     new (this) Array_(src.begin(), src.cend()); // see above
01631 }
01632 
01662 Array_(T* first, const T* last1, const DontCopy&) : Base(first,last1) {}
01663 
01691 template <class A>
01692 Array_(std::vector<T,A>& v, const DontCopy&) : Base(v) {}
01693 
01697 ~Array_() {
01698     deallocate();
01699 }
01700 
01709 Array_& deallocate() {
01710     if (allocated()) { // owner with non-zero allocation
01711         clear(); // each element is destructed; size()=0; allocated() unchanged
01712         deallocateNoDestruct(); // free data(); allocated()=0
01713     }
01714     this->Base::disconnect(); // clear the handle
01715     return *this;
01716 }
01717 
01721 //------------------------------------------------------------------------------
01756 
01774 void assign(size_type n, const T& fillValue) {
01775     const char* methodName = "Array_<T>::assign(n,value)";
01776     SimTK_ERRCHK3(isSizeOK(n), methodName,
01777         "Requested size %llu is too big for this array which is limited"
01778         " to %llu elements by its index type %s.",
01779         ull(n), ullMaxSize(), indexName());
01780 
01781     SimTK_ERRCHK2(isOwner() || n==size(), methodName,
01782         "Requested size %llu is not allowed because this is a non-owner"
01783         " array of fixed size %llu.", ull(n), ull(size()));
01784 
01785     if (!isOwner())
01786         this->Base::fill(fillValue);
01787     else {
01788         clear(); // all elements destructed; allocation unchanged
01789         reallocateIfAdvisable(n); // change size if too small or too big
01790         fillConstruct(data(), cdata()+n, fillValue);
01791         setSize(n);
01792     }
01793 }
01794 
01809 void fill(const T& fillValue) {this->Base::fill(fillValue);}
01810 
01811 
01833 template <class T2>
01834 void assign(const T2* first, const T2* last1) {
01835     const char* methodName = "Array_<T>::assign(T2* first, T2* last1)";
01836     SimTK_ERRCHK((first&&last1)||(first==last1), methodName, 
01837         "Pointers must be non-null unless they are both null.");
01838     SimTK_ERRCHK(!overlapsWithData(first,last1), methodName, 
01839         "Source range can't overlap the current array contents.");
01840     // Pointers are random access iterators.
01841     assignIteratorDispatch(first,last1,std::random_access_iterator_tag(),
01842                            methodName);
01843 }
01844 
01845 
01881 template <class Iter>
01882 void assign(const Iter& first, const Iter& last1) {
01883     assignDispatch(first,last1,typename IsIntegralType<Iter>::Result(),
01884                    "Array_<T>::assign(Iter first, Iter last1)");
01885 }
01886 
01892 Array_& operator=(const Array_& src) {
01893     if (this != &src)
01894         assignIteratorDispatch(src.begin(), src.end(), 
01895                                std::random_access_iterator_tag(),
01896                                "Array_<T>::operator=(Array_<T>)");
01897     return *this;
01898 }
01899 
01905 template <class T2, class X2>
01906 Array_& operator=(const Array_<T2,X2>& src) {
01907     assignIteratorDispatch(src.begin(), src.end(), 
01908                            std::random_access_iterator_tag(),
01909                            "Array_<T>::operator=(Array_<T2,X2>)");
01910     return *this;
01911 }
01912 
01913 
01918 template <class T2, class A>
01919 Array_& operator=(const std::vector<T2,A>& src) {
01920     assignIteratorDispatch(src.begin(), src.end(), 
01921                            std::random_access_iterator_tag(),
01922                            "Array_<T>::operator=(std::vector)");
01923     return *this;
01924 }
01925 
01932 void swap(Array_& other) {
01933     T* const pTmp=data(); setData(other.data()); other.setData(pTmp);
01934     size_type nTmp=size(); setSize(other.size()); other.setSize(nTmp);
01935     nTmp=allocated(); setAllocated(other.allocated()); other.setAllocated(nTmp);
01936 }
01937 
01943 Array_& adoptData(T* newData, size_type dataSize, 
01944                   size_type dataCapacity) 
01945 {
01946     const char* methodName = "Array_<T>::adoptData()";
01947     SimTK_SIZECHECK(dataCapacity, max_size(), methodName);
01948     SimTK_ERRCHK2(dataSize <= dataCapacity, methodName, 
01949         "Specified data size %llu was greater than the specified data"
01950         " capacity of %llu.", ull(dataSize), ull(dataCapacity));
01951     SimTK_ERRCHK(newData || dataCapacity==0, methodName,
01952         "A null data pointer is allowed only if the size and capacity are"
01953         " specified as zero.");
01954     SimTK_ERRCHK(!overlapsWithData(newData, newData+dataSize), methodName,
01955         "The new data can't overlap with the old data.");
01956 
01957     deallocate();
01958     setData(newData);
01959     setSize(dataSize);
01960     setAllocated(dataCapacity);
01961     return *this;
01962 }
01965 Array_& adoptData(T* newData, size_type dataSize) 
01966 {   return adoptData(newData, dataSize, dataSize); }
01967 
01968 
01982 Array_& shareData(T* newData, size_type dataSize) {
01983     const char* methodName = "Array_<T>::shareData()";
01984     SimTK_SIZECHECK(dataSize, max_size(), methodName);
01985     SimTK_ERRCHK(newData || dataSize==0, methodName,
01986         "A null data pointer is allowed only if the size is zero.");
01987     SimTK_ERRCHK(!overlapsWithData(newData, newData+dataSize), methodName,
01988         "The new data can't overlap with the old data.");
01989 
01990     deallocate();
01991     setData(newData);
01992     setSize(dataSize);
01993     setAllocated(0); // indicates shared data
01994     return *this;
01995 }
01996 
01999 Array_& shareData(T* first, const T* last1) {
02000     SimTK_ERRCHK3(isSizeOK(last1-first), "Array_<T>::shareData(first,last1)",
02001         "Requested size %llu is too big for this array which is limited"
02002         " to %llu elements by its index type %s.",
02003         ull(last1-first), ullMaxSize(), indexName());
02004     return shareData(first, size_type(last1-first));
02005 }
02006 
02010 //------------------------------------------------------------------------------
02016 
02017 // Note: these have to be explicitly forwarded to the base class methods
02018 // in order to keep gcc from complaining. Note that the "this->" is 
02019 // apparently necessary in order to permit delayed definition of templatized 
02020 // methods.
02021 
02023 size_type size() const {return this->CBase::size();}
02025 size_type max_size() const {return this->CBase::max_size();}
02028 bool empty() const {return this->CBase::empty();}
02033 size_type capacity() const {return this->CBase::capacity();}
02034 
02039 void resize(size_type n) {
02040     if (n == size()) return;
02041 
02042     SimTK_ERRCHK2(isOwner(), "Array_<T>::resize(n)",
02043         "Requested size change to %llu is not allowed because this is a"
02044         " non-owner array of fixed size %llu.", ull(n), ull(size()));
02045 
02046     if (n < size()) {
02047         erase(data()+n, cend());
02048         return;
02049     }
02050     // n > size()
02051     reserve(n);
02052     defaultConstruct(data()+size(), cdata()+n); // data() has changed
02053     setSize(n);
02054 }
02055 
02060 void resize(size_type n, const T& initVal) {
02061     if (n == size()) return;
02062 
02063     SimTK_ERRCHK2(isOwner(), "Array_<T>::resize(n,value)",
02064         "Requested size change to %llu is not allowed because this is a"
02065         " non-owner array of fixed size %llu.", ull(n), ull(size()));
02066 
02067     if (n < size()) {
02068         erase(data()+n, cend());
02069         return;
02070     }
02071     // n > size()
02072     reserve(n);
02073     fillConstruct(data()+size(), cdata()+n, initVal);
02074     setSize(n);
02075 }
02076 
02083 void reserve(size_type n) {
02084     if (capacity() >= n)
02085         return;
02086 
02087     SimTK_ERRCHK2(isOwner(), "Array_<T>::reserve()",
02088         "Requested capacity change to %llu is not allowed because this is a"
02089         " non-owner array of fixed size %llu.", ull(n), ull(size()));
02090 
02091     T* newData = allocN(n); // no construction yet
02092     copyConstructThenDestructSource(newData, newData+size(), data());
02093     freeN(data());
02094     setData(newData);
02095     setAllocated(n);
02096 }
02097 
02118 void shrink_to_fit() {
02119     // Allow 25% slop, but note that if size()==0 this will always reallocate
02120     // unless capacity is already zero.
02121     if (capacity() - size()/4 <= size()) // avoid overflow if size() near max
02122         return;
02123     T* newData = allocN(size());
02124     copyConstructThenDestructSource(newData, newData+size(), data());
02125     deallocateNoDestruct(); // data()=0, allocated()=0, size() unchanged
02126     setData(newData);
02127     setAllocated(size());
02128 }
02129 
02133 size_type allocated() const {return this->CBase::allocated();}
02139 bool isOwner() const {return this->CBase::isOwner();}
02143 //------------------------------------------------------------------------------
02152 
02157 const T* cbegin() const {return this->CBase::cbegin();}
02159 const T* begin() const {return this->CBase::cbegin();}
02164 T* begin() {return this->Base::begin();}
02165 
02170 const T* cend() const {return this->CBase::cend();}
02172 const T* end() const {return this->CBase::cend();}
02177 T* end() {return this->Base::end();}
02178 
02181 const_reverse_iterator crbegin() const {return this->CBase::crbegin();}
02183 const_reverse_iterator rbegin() const {return this->CBase::crbegin();} 
02186 reverse_iterator rbegin() {return this->Base::rbegin();}
02187 
02191 const_reverse_iterator crend() const {return this->CBase::crend();}
02193 const_reverse_iterator rend() const {return this->CBase::crend();}
02197 reverse_iterator rend() {return this->Base::rend();}
02198 
02205 const T* cdata() const {return this->CBase::cdata();}
02208 const T* data() const {return this->CBase::cdata();}
02212 T* data() {return this->Base::data();}
02220 
02227 const T& operator[](index_type i) const {return this->CBase::operator[](i);}
02228 
02236 T& operator[](index_type i) {return this->Base::operator[](i);}
02237 
02242 const T& at(index_type i) const {return this->CBase::at(i);}
02243 
02248 T& at(index_type i) {return const_cast<T&>(this->Base::at(i));}
02249 
02252 const T& getElt(index_type i) const {return this->CBase::getElt(i);}
02255 T& updElt(index_type i) {return this->Base::updElt(i);}
02256 
02262 const T& front() const {return this->CBase::front();} 
02263 
02269 T& front() {return const_cast<T&>(this->Base::front());}
02270 
02276 const T& back() const {return this->CBase::back();}
02277 
02283 T& back() {return const_cast<T&>(this->Base::back());}
02284 
02287 ArrayViewConst_<T,X> operator()(index_type index, size_type length) const
02288 {   return CBase::operator()(index,length); }
02291 ArrayViewConst_<T,X> getSubArray(index_type index, size_type length) const
02292 {   return CBase::getSubArray(index,length); }
02293 
02296 ArrayView_<T,X> operator()(index_type index, size_type length)
02297 {   return Base::operator()(index,length); }
02300 ArrayView_<T,X> updSubArray(index_type index, size_type length)
02301 {   return Base::updSubArray(index,length); }
02305 //------------------------------------------------------------------------------
02311 
02338 void push_back(const T& value) {
02339     if (pallocated() == psize())
02340         growAtEnd(1,"Array_<T>::push_back(value)");
02341     copyConstruct(end(), value);
02342     incrSize();
02343 }
02344 
02358 void push_back() {
02359     if (pallocated() == psize())
02360         growAtEnd(1,"Array_<T>::push_back()");
02361     defaultConstruct(end());
02362     incrSize();
02363 }
02364 
02380 T* raw_push_back() {
02381     if (pallocated() == psize())
02382         growAtEnd(1,"Array_<T>::raw_push_back()");
02383     T* const p = end();
02384     incrSize();
02385     return p;
02386 }
02387 
02390 void pop_back() {
02391     SimTK_ERRCHK(!empty(), "Array_<T>::pop_back()", "Array was empty.");
02392     destruct(&back());
02393     decrSize();
02394 }
02395 
02413 T* erase(T* first, const T* last1) {
02414     SimTK_ERRCHK(begin() <= first && first <= last1 && last1 <= end(),
02415     "Array<T>::erase(first,last1)", "Pointers out of range or out of order.");
02416 
02417     const size_type nErased = size_type(last1-first);
02418     SimTK_ERRCHK(isOwner() || nErased==0, "Array<T>::erase(first,last1)",
02419         "No elements can be erased from a non-owner array.");
02420 
02421     if (nErased) {
02422         destruct(first, last1); // Destruct the elements we're erasing.
02423         moveElementsDown(first+nErased, nErased); // Compress followers into the gap.
02424         setSize(size()-nErased);
02425     }
02426     return first;
02427 }
02428 
02448 T* erase(T* p) {
02449     SimTK_ERRCHK(begin() <= p && p < end(),
02450         "Array<T>::erase(p)", "Pointer must point to a valid element.");
02451     SimTK_ERRCHK(isOwner(), "Array<T>::erase(p)",
02452         "No elements can be erased from a non-owner array.");
02453 
02454     destruct(p);              // Destruct the element we're erasing.
02455     moveElementsDown(p+1, 1); // Compress followers into the gap.
02456     decrSize();
02457     return p;
02458 }
02459 
02460 
02481 T* eraseFast(T* p) {
02482     SimTK_ERRCHK(begin() <= p && p < end(),
02483         "Array<T>::eraseFast(p)", "Pointer must point to a valid element.");
02484     SimTK_ERRCHK(isOwner(), "Array<T>::eraseFast(p)",
02485         "No elements can be erased from a non-owner array.");
02486 
02487     destruct(p);
02488     if (p+1 != end()) 
02489         moveOneElement(p, &back());
02490     decrSize();
02491     return p;
02492 }
02493 
02501 void clear() {
02502     SimTK_ERRCHK(isOwner() || empty(), "Array_<T>::clear()", 
02503         "clear() is not allowed for a non-owner array.");
02504     destruct(begin(), end());
02505     setSize(0);
02506 }
02507 
02508 
02535 T* insert(T* p, size_type n, const T& value) {
02536     T* const gap = insertGapAt(p, n, "Array<T>::insert(p,n,value)");
02537     // Copy construct into the inserted elements and note the size change.
02538     fillConstruct(gap, gap+n, value);
02539     setSize(size()+n);
02540     return gap;
02541 }
02542 
02547 T* insert(T* p, const T& value)  {
02548     T* const gap = insertGapAt(p, 1, "Array<T>::insert(p,value)");
02549     // Copy construct into the inserted element and note the size change.
02550     copyConstruct(gap, value);
02551     incrSize();
02552     return gap;
02553 }
02554 
02584 template <class T2>
02585 T* insert(T* p, const T2* first, const T2* last1) {
02586     const char* methodName = "Array_<T>::insert(T* p, T2* first, T2* last1)";
02587     SimTK_ERRCHK((first&&last1) || (first==last1), methodName, 
02588         "One of first or last1 was null; either both or neither must be null.");
02589     SimTK_ERRCHK(!overlapsWithData(first,last1), methodName, 
02590         "Source range can't overlap with the current array contents.");
02591     // Pointers are random access iterators.
02592     return insertIteratorDispatch(p, first, last1,
02593                                   std::random_access_iterator_tag(),
02594                                   methodName);
02595 }
02596 
02599 template <class Iter>
02600 T* insert(T* p, const Iter& first, const Iter& last1) {
02601     return insertDispatch(p, first, last1,
02602                           typename IsIntegralType<Iter>::Result(),
02603                           "Array_<T>::insert(T* p, Iter first, Iter last1)");
02604 }
02609 //------------------------------------------------------------------------------
02610                                   private:
02611 //------------------------------------------------------------------------------
02612 
02613 
02614 // This method is used when we have already decided we need to make room for 
02615 // some new elements by reallocation, by creating a gap somewhere within the
02616 // existing data. We'll issue an error message if this would violate the  
02617 // max_size restriction (we can afford to do that even in a Release build since
02618 // we don't expect to grow very often). Otherwise we'll allocate some more space
02619 // and copy construct the existing elements into the new space, leaving a gap 
02620 // where indicated. Note that this method does not change the current size but
02621 // does change the capacity.
02622 //
02623 // The gapPos must point within the existing data with null OK if the array
02624 // itself is null, and end() being OK any time although you should use the
02625 // more specialized growAtEnd() method if you know that's what's happening.
02626 //
02627 // Don't call this with a gapSz of zero.
02628 T* growWithGap(T* gapPos, size_type gapSz, const char* methodName) {
02629     assert(gapSz > 0); // <= 0 is a bug, not a user error
02630 
02631     // Note that gapPos may be null if begin() and end() are also.
02632     SimTK_ERRCHK(begin() <= gapPos && gapPos <= end(), methodName, 
02633         "Given insertion point is not valid for this array.");
02634 
02635     // Get some new space of a reasonable size.
02636     setAllocated(calcNewCapacityForGrowthBy(gapSz, methodName));
02637     T* newData   = allocN(allocated());
02638 
02639     // How many elements will be before the gap?
02640     const size_type nBefore = (size_type)(gapPos-begin());
02641 
02642     // Locate the gap in the new space allocation.
02643     T* newGap    = newData + nBefore;
02644     T* newGapEnd = newGap  + gapSz; // one past the last element in the gap
02645 
02646     // Copy elements before insertion point; destruct source as we go.
02647     copyConstructThenDestructSource(newData,   newGap,        data());
02648     // Copy/destruct elements at and after insertion pt; leave gapSz gap.
02649     copyConstructThenDestructSource(newGapEnd, newData+size(), gapPos);
02650 
02651     // Throw away the old data and switch to the new.
02652     freeN(data()); setData(newData);
02653     return newGap;
02654 }
02655 
02656 // Same as growWithGap(end(), n, methodName); see above.
02657 void growAtEnd(size_type n, const char* methodName) {
02658     assert(n > 0); // <= 0 is a bug, not a user error
02659     // Get some new space of a reasonable size.
02660     setAllocated(calcNewCapacityForGrowthBy(n, methodName));
02661     T* newData   = allocN(allocated());
02662     // Copy all the elements; destruct source as we go.
02663     copyConstructThenDestructSource(newData, newData+size(), data());
02664     // Throw away the old data and switch to the new.
02665     freeN(data()); setData(newData);
02666 }
02667 
02668 // This method determines how much we should increase the array's capacity
02669 // when asked to insert n elements, due to an insertion or push_back. We will
02670 // generally allocate more new space than requested, in anticipation of
02671 // further insertions. This has to be based on the current size so that only
02672 // log(n) reallocations are performed to insert n elements one at a time. Our
02673 // policy here is to at least double the capacity unless that would exceed 
02674 // max_size(). There is also a minimum amount of allocation we'll do if the 
02675 // current size is zero or very small. 
02676 size_type calcNewCapacityForGrowthBy(size_type n, const char* methodName) const {
02677     SimTK_ERRCHK3_ALWAYS(isGrowthOK(n), methodName,
02678         "Can't grow this Array by %llu element(s) because it would"
02679         " then exceed the max_size of %llu set by its index type %s.",
02680         (unsigned long long)n, ullMaxSize(), indexName());
02681 
02682     // At this point we know that capacity()+n <= max_size().
02683     const size_type mustHave = capacity() + n;
02684 
02685     // Be careful not to overflow size_type as you could if you 
02686     // double capacity() rather than halving max_size().
02687     const size_type wantToHave = capacity() <= max_size()/2 
02688                                     ? 2*capacity() 
02689                                     : max_size();
02690 
02691     const size_type newCapacity = std::max(std::max(mustHave,wantToHave),
02692                                            minAlloc());
02693     return newCapacity;
02694 }
02695 
02696 // Insert an unconstructed gap of size n beginning at position p. The return
02697 // value is a pointer to the first element in the gap. It will be p if no
02698 // reallocation occurred, otherwise it will be pointing into the new data.
02699 // On return size() will be unchanged although allocated() may be bigger.
02700 T* insertGapAt(T* p, size_type n, const char* methodName) {
02701     // Note that p may be null if begin() and end() are also.
02702     SimTK_ERRCHK(begin() <= p && p <= end(), methodName, 
02703         "Given insertion point is not valid for this Array.");
02704 
02705     if (n==0) return p; // nothing to do
02706 
02707     SimTK_ERRCHK_ALWAYS(isOwner(), methodName,
02708         "No elements can be inserted into a non-owner array.");
02709 
02710     // Determine the number of elements before the insertion point and
02711     // the number at or afterwards (those must be moved up by one slot).
02712     const size_type before = (size_type)(p-begin()), after = (size_type)(end()-p);
02713 
02714     // Grow the container if necessary. Note that if we have to grow we
02715     // can create the gap at the same time we copy the old elements over
02716     // to the new space.
02717     if (capacity() >= size()+n) {
02718         moveElementsUp(p, n); // leave a gap at p
02719     } else { // need to grow
02720         setAllocated(calcNewCapacityForGrowthBy(n, methodName));
02721         T* newdata = allocN(allocated());
02722         // Copy the elements before the insertion point, and destroy source.
02723         copyConstructThenDestructSource(newdata, newdata+before, data());
02724         // Copy the elements at and after the insertion point, leaving a gap
02725         // of n elements.
02726         copyConstructThenDestructSource(newdata+before+n,
02727                                         newdata+before+n+after,
02728                                         p); // i.e., pData+before
02729         p = newdata + before; // points into newdata now
02730         freeN(data());
02731         setData(newdata);
02732     }
02733 
02734     return p;
02735 }
02736 
02737 //------------------------------------------------------------------------------
02738 //                           CTOR DISPATCH
02739 // This is the constructor implementation for when the class that matches
02740 // the alleged InputIterator type turns out to be one of the integral types
02741 // in which case this should be the ctor(n, initValue) constructor.
02742 template <class IntegralType> void
02743 ctorDispatch(IntegralType n, IntegralType v, TrueType isIntegralType) {
02744     new(this) Array_(size_type(n), value_type(v));
02745 }
02746 
02747 // This is the constructor implementation for when the class that matches
02748 // the alleged InputIterator type is NOT an integral type and may very well
02749 // be an iterator. In that case we split into iterators for which we can
02750 // determine the number of elements in advance (forward, bidirectional,
02751 // random access) and input iterators, for which we can't. Note: iterator
02752 // types are arranged hierarchically random->bi->forward->input with each
02753 // deriving from the one on its right, so the forward iterator tag also
02754 // matches bi and random.
02755 template <class InputIterator> void
02756 ctorDispatch(const InputIterator& first, const InputIterator& last1, 
02757              FalseType isIntegralType) 
02758 {   ctorIteratorDispatch(first, last1, 
02759         typename std::iterator_traits<InputIterator>::iterator_category()); }
02760 
02761 // This is the slow generic ctor implementation for any iterator that can't
02762 // make it up to forward_iterator capability (that is, an input_iterator).
02763 // The issue here is that we can't advance the iterator to count the number
02764 // of elements before allocating because input_iterators are consumed when
02765 // reference so we can't go back to look. That means we may have to reallocate
02766 // memory log n times as we "push back" these elements onto the array.
02767 template <class InputIterator> void
02768 ctorIteratorDispatch(const InputIterator& first, const InputIterator& last1, 
02769                      std::input_iterator_tag) 
02770 {
02771     InputIterator src = first;
02772     while (src != last1) {
02773         // We can afford to check this always since we are probably doing I/O.
02774         // Throwing an exception in a constructor is tricky, though -- this
02775         // won't go through the Array_ destructor although it will call the
02776         // Base (ArrayView_) destructor. Since we have already allocated
02777         // some space, we must call deallocate() manually.
02778         if (size() == max_size()) {
02779             deallocate();
02780             SimTK_ERRCHK2_ALWAYS(!"too many elements",
02781                 "Array_::ctor(InputIterator first, InputIterator last1)",
02782                 "There were still source elements available when the array"
02783                 " reached its maximum size of %llu as determined by its index"
02784                 " type %s.", ullMaxSize(), indexName());
02785         }
02786         push_back(*src++);
02787     }
02788 }
02789 
02790 // This is the faster constructor implementation for iterator types for which
02791 // we can calculate the number of elements in advance. This will be optimal
02792 // for a random access iterator since we can count in constant time, but for
02793 // forward or bidirectional we'll have to advance n times to count and then
02794 // go back again to do the copy constructions.
02795 template <class ForwardIterator> void
02796 ctorIteratorDispatch(const ForwardIterator& first, const ForwardIterator& last1, 
02797                      std::forward_iterator_tag) 
02798 {
02799     const char* methodName = 
02800         "Array_::ctor(ForwardIterator first, ForwardIterator last1)";
02801     typedef typename std::iterator_traits<ForwardIterator>::difference_type
02802         difference_type;
02803     // iterDistance() is constant time for random access iterators, but 
02804     // O(last1-first) for forward and bidirectional since it has to increment 
02805     // to count how far apart they are.
02806     const difference_type nInput = iterDistance(first,last1);
02807 
02808     SimTK_ERRCHK(nInput >= 0, methodName, "Iterators were out of order.");
02809 
02810     SimTK_ERRCHK3(isSizeOK(nInput), methodName,
02811         "Source has %llu elements but this array is limited to %llu"
02812         " elements by its index type %s.",
02813         ull(nInput), ullMaxSize(), indexName());
02814 
02815     const size_type n = size_type(nInput);
02816     setSize(n);
02817     allocateNoConstruct(n);
02818     copyConstruct(data(), data()+n, first);
02819 }
02820 
02821 //------------------------------------------------------------------------------
02822 //                           INSERT DISPATCH
02823 // This is the insert() implementation for when the class that matches
02824 // the alleged InputIterator type turns out to be one of the integral types
02825 // in which case this should be the insert(p, n, initValue) constructor.
02826 template <class IntegralType> 
02827 T* insertDispatch(T* p, IntegralType n, IntegralType v, 
02828                   TrueType isIntegralType, const char*) 
02829 {   return insert(p, size_type(n), value_type(v)); }
02830 
02831 // This is the insert() implementation for when the class that matches
02832 // the alleged InputIterator type is NOT an integral type and may very well
02833 // be an iterator. See ctorDispatch() above for more information.
02834 template <class InputIterator> 
02835 T* insertDispatch(T* p, const InputIterator& first, const InputIterator& last1, 
02836                   FalseType isIntegralType, const char* methodName) 
02837 {   return insertIteratorDispatch(p, first, last1, 
02838         typename std::iterator_traits<InputIterator>::iterator_category(),
02839         methodName); }
02840 
02841 // This is the slow generic insert implementation for any iterator that can't
02842 // make it up to forward_iterator capability (that is, an input_iterator).
02843 // See ctorIteratorDispatch() above for more information.
02844 template <class InputIterator> 
02845 T* insertIteratorDispatch(T* p, InputIterator first, InputIterator last1, 
02846                           std::input_iterator_tag, const char* methodName) 
02847 {
02848     size_type nInserted = 0;
02849     while (first != last1) {
02850         // We can afford to check this always since we are probably doing I/O.
02851         SimTK_ERRCHK2_ALWAYS(size() < max_size(), methodName,
02852             "There were still source elements available when the array"
02853             " reached its maximum size of %llu as determined by its index"
02854             " type %s.", ullMaxSize(), indexName());
02855         p = insert(p, *first++);  // p may now point to reallocated memory
02856         ++p; ++nInserted;
02857     }
02858     // p now points just after the last inserted element; subtract the
02859     // number inserted to get a pointer to the first inserted element.
02860     return p-nInserted;
02861 }
02862 
02863 // This is the faster constructor implementation for iterator types for which
02864 // we can calculate the number of elements in advance. This will be optimal
02865 // for a random access iterator since we can count in constant time, but for
02866 // forward or bidirectional we'll have to advance n times to count and then
02867 // go back again to do the copy constructions.
02868 template <class ForwardIterator>
02869 T* insertIteratorDispatch(T* p, const ForwardIterator& first, 
02870                                 const ForwardIterator& last1,
02871                                 std::forward_iterator_tag,
02872                                 const char* methodName) 
02873 {
02874     typedef typename std::iterator_traits<ForwardIterator>::difference_type
02875         difference_type;
02876     // iterDistance() is constant time for random access iterators, but 
02877     // O(last1-first) for forward and bidirectional since it has to increment 
02878     // to count how far apart they are.
02879     const difference_type nInput = iterDistance(first,last1);
02880 
02881     SimTK_ERRCHK(nInput >= 0, methodName, "Iterators were out of order.");
02882 
02883     SimTK_ERRCHK3(isGrowthOK(nInput), methodName,
02884         "Source has %llu elements which would make this array exceed the %llu"
02885         " elements allowed by its index type %s.",
02886         ull(nInput), ullMaxSize(), indexName());
02887 
02888     const size_type n = size_type(nInput);
02889     p = insertGapAt(p, n, methodName);
02890     copyConstruct(p, p+n, first);
02891     setSize(size()+n);
02892     return p;
02893 }
02894 
02895 //------------------------------------------------------------------------------
02896 //                           ASSIGN DISPATCH
02897 // This is the assign() implementation for when the class that matches
02898 // the alleged InputIterator type turns out to be one of the integral types
02899 // in which case this should be the assign(n, initValue) constructor.
02900 template <class IntegralType>
02901 void assignDispatch(IntegralType n, IntegralType v, TrueType isIntegralType,
02902                     const char* methodName) 
02903 {   assign(size_type(n), value_type(v)); }
02904 
02905 // This is the assign() implementation for when the class that matches
02906 // the alleged InputIterator type is NOT an integral type and may very well
02907 // be an iterator. See ctorDispatch() above for more information.
02908 template <class InputIterator> 
02909 void assignDispatch(const InputIterator& first, const InputIterator& last1, 
02910                     FalseType isIntegralType, const char* methodName) 
02911 {   assignIteratorDispatch(first, last1, 
02912         typename std::iterator_traits<InputIterator>::iterator_category(),
02913         methodName); }
02914 
02915 // This is the slow generic implementation for a plain input_iterator
02916 // (i.e., not a forward, bidirectional, or random access iterator). These
02917 // have the unfortunate property that we can't count the elements in advance.
02918 template <class InputIterator>
02919 void assignIteratorDispatch(const InputIterator& first, 
02920                             const InputIterator& last1, 
02921                             std::input_iterator_tag, 
02922                             const char* methodName) 
02923 {
02924     // TODO: should probably allow this and just blow up when the size()+1st
02925     // element is seen.
02926     SimTK_ERRCHK_ALWAYS(isOwner(), methodName,
02927         "Assignment to a non-owner array can only be done from a source"
02928         " designated with forward iterators or pointers because we"
02929         " must be able to verify that the source and destination sizes"
02930         " are the same.");
02931 
02932     clear(); // TODO: change space allocation here?
02933     InputIterator src = first;
02934     while (src != last1) {
02935         // We can afford to check this always since we are probably doing I/O.
02936         SimTK_ERRCHK2_ALWAYS(size() < max_size(), methodName,
02937             "There were still source elements available when the array"
02938             " reached its maximum size of %llu as determined by its index"
02939             " type %s.", ullMaxSize(), indexName());
02940 
02941         push_back(*src++);
02942     }
02943 }
02944 
02945 // This is the faster implementation that works for forward, bidirectional,
02946 // and random access iterators including ordinary pointers. We can check here that the 
02947 // iterators are in the right order, and that the source is not too big to
02948 // fit in this array. Null pointer checks should be done prior to calling,
02949 // however, since iterators in general aren't pointers.
02950 template <class ForwardIterator>
02951 void assignIteratorDispatch(const ForwardIterator& first, 
02952                             const ForwardIterator& last1,
02953                             std::forward_iterator_tag, 
02954                             const char* methodName) 
02955 {
02956     typedef typename std::iterator_traits<ForwardIterator>::difference_type
02957         IterDiffType;
02958     // iterDistance() is constant time for random access iterators, but 
02959     // O(last1-first) for forward and bidirectional since it has to increment 
02960     // to count how far apart they are.
02961     const IterDiffType nInput = iterDistance(first,last1);
02962 
02963     SimTK_ERRCHK(nInput >= 0, methodName, "Iterators were out of order.");
02964 
02965     SimTK_ERRCHK3(isSizeOK(nInput), methodName,
02966         "Source has %llu elements but this Array is limited to %llu"
02967         " elements by its index type %s.",
02968         ull(nInput), ullMaxSize(), indexName());
02969 
02970     const size_type n = size_type(nInput);
02971     if (isOwner()) {
02972         // This is an owner Array; assignment is considered deallocation
02973         // followed by copy construction.
02974 
02975         clear(); // all elements destructed; allocation unchanged
02976         reallocateIfAdvisable(n); // change allocation if too small or too big
02977         copyConstruct(data(), cdata()+n, first);
02978         setSize(n);
02979     } else {
02980         // This is a non-owner Array. Assignment can occur only if the
02981         // source is the same size as the array, and the semantics are of
02982         // repeated assignment using T::operator=() not destruction followed
02983         // by copy construction.
02984         SimTK_ERRCHK2(n == size(), methodName,
02985             "Source has %llu elements which does not match the size %llu"
02986             " of the non-owner array it is being assigned into.",
02987             ull(n), ullSize());
02988 
02989         T* p = begin();
02990         ForwardIterator src = first;
02991         while (src != last1)
02992             *p++ = *src++; // call T's assignment operator
02993     }
02994 }
02995 
02996 // We are going to put a total of n elements into the Array (probably
02997 // because of an assignment or resize) and we want the space allocation
02998 // to be reasonable. That means of course that the allocation must be 
02999 // *at least* n, but we also don't want it to be too big. Our policy
03000 // here is that if it is currently less than twice what we need we
03001 // won't reallocate, otherwise we'll shrink the space. When changing
03002 // the size to zero or something very small we'll treat the Array as
03003 // though its current size is minAlloc, meaning we won't reallocate
03004 // if the existing space is less than twice minAlloc.
03005 // nAllocated will be set appropriately; size() is not touched here.
03006 // No constructors or destructors are called.
03007 void reallocateIfAdvisable(size_type n) {
03008     if (allocated() < n || allocated()/2 > std::max(minAlloc(), n)) 
03009         reallocateNoDestructOrConstruct(n);
03010 }
03011 
03012 
03013 void allocateNoConstruct(size_type n) 
03014 {   setData(allocN(n)); setAllocated(n); } // size() left unchanged
03015 void deallocateNoDestruct() 
03016 {   freeN(data()); setData(0); setAllocated(0); } // size() left unchanged
03017 void reallocateNoDestructOrConstruct(size_type n)
03018 {   deallocateNoDestruct(); allocateNoConstruct(n); }
03019 
03020 // This sets the smallest allocation we'll do when growing.
03021 size_type minAlloc() const 
03022 {   return std::min(max_size(), size_type(4)); }
03023 
03024 // Allocate without construction. Returns a null pointer if asked
03025 // to allocate 0 elements. In Debug mode we'll fill memory with 
03026 // all 1's as a bug catcher.
03027 static T* allocN(size_type n) {
03028     if (n==0) return 0;
03029     unsigned char* newdata = new unsigned char[n * sizeof(T)];
03030     #ifndef NDEBUG
03031         unsigned char* b=newdata; 
03032         const unsigned char* e=newdata+(n*sizeof(T));
03033         while (b != e) *b++ = 0xff;
03034     #endif
03035     return reinterpret_cast<T*>(newdata);
03036 }
03037 
03038 // Free memory without calling T's destructor. Nothing happens if passed
03039 // a null pointer.
03040 static void freeN(T* p) {
03041     delete[] reinterpret_cast<char*>(p);
03042 }
03043 
03044 // default construct one element
03045 static void defaultConstruct(T* p) {new(p) T();}
03046 // default construct range [b,e)
03047 static void defaultConstruct(T* b, const T* e) 
03048 {   while (b!=e) new(b++) T(); }
03049 
03050 // copy construct range [b,e) with repeats of a given value
03051 static void fillConstruct(T* b, const T* e, const T& v)
03052 {   while(b!=e) new(b++) T(v); }
03053 
03054 // copy construct one element from a given value
03055 static void copyConstruct(T* p, const T& v) {new(p) T(v);}
03056 // copy construct range [b,e) from sequence of source values
03057 static void copyConstruct(T* b, const T* e, T* src)
03058 {   while(b!=e) new(b++) T(*src++); }
03059 // Templatized copy construct will work if the source elements are
03060 // assignment compatible with the destination elements.
03061 template <class InputIterator>
03062 static void copyConstruct(T* b, const T* e, InputIterator src)
03063 {   while(b!=e) new(b++) T(*src++); }
03064 
03065 // Copy construct range [b,e] from sequence of source values and
03066 // destruct the source after it is copied. It's better to alternate
03067 // copying and destructing than to do this in two passes since we
03068 // will already have touched the memory.
03069 static void copyConstructThenDestructSource(T* b, const T* e, T* src)
03070 {   while(b!=e) {new(b++) T(*src); src++->~T();} }
03071 
03072 // We have an element at from that we would like to move into the currently-
03073 // unconstructed slot at to. Both from and to are expected to be pointing to
03074 // elements within the currently allocated space. From's slot will be left
03075 // unconstructed.
03076 void moveOneElement(T* to, T* from) {
03077     assert(data() <= to   && to   < data()+allocated());
03078     assert(data() <= from && from < data()+allocated());
03079     copyConstruct(to, *from); 
03080     destruct(from);
03081 }
03082 
03083 
03084 // Move elements from p to end() down by n>0 places to fill an unconstructed 
03085 // gap beginning at p-n. Any leftover space at the end will be unconstructed.
03086 void moveElementsDown(T* p, size_type n) {
03087     assert(n > 0);
03088     for (; p != end(); ++p)
03089         moveOneElement(p-n,p);
03090 }
03091 
03092 // Move elements from p to end() up by n>0 places to make an unconstructed gap
03093 // at [p,p+n). Note that this has to be done backwards so that we don't
03094 // write on any elements until after they've been copied.
03095 void moveElementsUp(T* p, size_type n) {
03096     assert(n > 0);
03097     T* src = end(); // points one past source element (begin()-1 not allowed)
03098     while (src != p) {
03099         --src; // now points to source
03100         moveOneElement(src+n, src);;
03101     }
03102 }
03103 
03104 // destruct one element
03105 static void destruct(T* p) {p->~T();}
03106 // destruct range [b,e)
03107 static void destruct(T* b, const T* e)
03108 {   while(b!=e) b++->~T(); }
03109 
03110 // Check that growing this array by n elements wouldn't cause it to exceed
03111 // its allowable maximum size.
03112 template <class S>
03113 bool isGrowthOK(S n) const
03114 {   return isSizeOK(ullCapacity() + ull(n)); }
03115 
03116 // The following private methods are protected methods in the ArrayView base 
03117 // class, so they should not need repeating here. Howevr, we explicitly 
03118 // forward to the Base methods to avoid gcc errors. The gcc complaint
03119 // is due to their not depending on any template parameters; the "this->"
03120 // apparently fixes that problem.
03121 
03122 // These provide direct access to the data members.
03123 packed_size_type psize()      const {return this->CBase::psize();}
03124 packed_size_type pallocated() const {return this->CBase::pallocated();}
03125 
03126 void setData(const T* p)        {this->CBase::setData(p);}
03127 void setSize(size_type n)       {this->CBase::setSize(n);}
03128 void incrSize()                 {this->CBase::incrSize();}
03129 void decrSize()                 {this->CBase::decrSize();}
03130 void setAllocated(size_type n)  {this->CBase::setAllocated(n);}
03131 // This just cast sizes to unsigned long long so that we can do comparisons
03132 // without getting warnings.
03133 unsigned long long ullSize()     const {return this->CBase::ullSize();}
03134 unsigned long long ullCapacity() const {return this->CBase::ullCapacity();}
03135 unsigned long long ullMaxSize()  const {return this->CBase::ullMaxSize();}
03136 // This is the index type name and is handy for error messages to explain
03137 // why some size was too big.
03138 const char* indexName() const   {return this->CBase::indexName();}
03139 };
03140 
03141 
03142 // This "private" static method is used to implement ArrayView's 
03143 // fillArrayViewFromStream() and Array's readArrayFromStream() namespace-scope
03144 // static methods, which are in turn used to implement ArrayView's and 
03145 // Array's stream extraction operators ">>". This method has to be in the 
03146 // header file so that we don't need to pass streams through the API, but it 
03147 // is not intended for use by users and has no Doxygen presence, unlike 
03148 // fillArrayFromStream() and readArrayFromStream() and (more commonly)
03149 // the extraction operators.
03150 template <class T, class X> static inline 
03151 std::istream& readArrayFromStreamHelper
03152    (std::istream& in, bool isFixedSize, Array_<T,X>& out)
03153 {
03154     // If already failed, bad, or eof, set failed bit and return without 
03155     // touching the Array.
03156     if (!in.good()) {in.setstate(std::ios::failbit); return in;}
03157 
03158     // If the passed-in Array isn't an owner, then we have to treat it as
03159     // a fixed size ArrayView regardless of the setting of the isFixedSize
03160     // argument.
03161     if (!out.isOwner())
03162         isFixedSize = true; // might be overriding the argument here
03163 
03164     // numRequired will be ignored unless isFixedSize==true.
03165     const typename Array_<T,X>::size_type 
03166         numRequired = isFixedSize ? out.size() : 0;
03167 
03168     if (!isFixedSize)
03169         out.clear(); // We're going to replace the entire contents of the Array.
03170 
03171     // Skip initial whitespace. If that results in eof this may be a successful
03172     // read of a 0-length, unbracketed Array. That is OK for either a
03173     // variable-length Array or a fixed-length ArrayView of length zero.
03174     std::ws(in); if (in.fail()) return in;
03175     if (in.eof()) {
03176         if (isFixedSize && numRequired != 0)
03177             in.setstate(std::ios_base::failbit); // zero elements not OK
03178         return in;
03179     }
03180     
03181     // Here the stream is good and the next character is non-white.
03182     assert(in.good());
03183 
03184     // Use this for raw i/o (peeks and gets).
03185     typename       std::iostream::int_type ch;
03186     const typename std::iostream::int_type EOFch = 
03187         std::iostream::traits_type::eof();
03188 
03189     // Now see if the sequence is bare or surrounded by (), [], or {}.
03190     bool lookForCloser = true;
03191     char openBracket, closeBracket;
03192     ch = in.peek(); if (in.fail()) return in;
03193     assert(ch != EOFch); // we already checked above
03194 
03195     openBracket = (char)ch;
03196     if      (openBracket=='(') {in.get(); closeBracket = ')';}
03197     else if (openBracket=='[') {in.get(); closeBracket = ']';}
03198     else if (openBracket=='{') {in.get(); closeBracket = '}';}
03199     else lookForCloser = false;
03200 
03201     // If lookForCloser is true, then closeBracket contains the terminating
03202     // delimiter, otherwise we're not going to quit until eof.
03203 
03204     // Eat whitespace after the opening bracket to see what's next.
03205     if (in.good()) std::ws(in);
03206 
03207     // If we're at eof now it must be because the open bracket was the
03208     // last non-white character in the stream, which is an error.
03209     if (!in.good()) {
03210         if (in.eof()) {
03211             assert(lookForCloser); // or we haven't read anything that could eof
03212             in.setstate(std::ios::failbit);
03213         }
03214         return in;
03215     }
03216 
03217     // istream is good and next character is non-white; ready to read first
03218     // value or terminator.
03219 
03220     // We need to figure out whether the elements are space- or comma-
03221     // separated and then insist on consistency.
03222     bool commaOK = true, commaRequired = false;
03223     bool terminatorSeen = false;
03224     X nextIndex(0);
03225     while (true) {
03226         char c;
03227 
03228         // Here at the top of this loop, we have already successfully read 
03229         // n=nextIndex values of type T. For fixed-size reads, it might be
03230         // the case that n==numRequired already, but we still may need to
03231         // look for a closing bracket before we can declare victory.
03232         // The stream is good() (not at eof) but it might be the case that 
03233         // there is nothing but white space left; we don't know yet because
03234         // if we have satisfied the fixed-size count and are not expecting
03235         // a terminator then we should quit without absorbing the trailing
03236         // white space.
03237         assert(in.good());
03238 
03239         // Look for closing bracket before trying to read value.
03240         if (lookForCloser) {
03241             // Eat white space to find the closing bracket.
03242             std::ws(in); if (!in.good()) break; // eof?
03243             ch = in.peek(); assert(ch != EOFch);
03244             if (!in.good()) break;
03245             c = (char)ch;
03246             if (c == closeBracket) {   
03247                 in.get(); // absorb the closing bracket
03248                 terminatorSeen = true; 
03249                 break; 
03250             }
03251             // next char not a closing bracket; fall through
03252         }
03253 
03254         // We didn't look or didn't find a closing bracket. The istream is good 
03255         // but we might be looking at white space.
03256 
03257         // If we already got all the elements we want, break for final checks.
03258         if (isFixedSize && (nextIndex == numRequired))
03259             break; // that's a full count.
03260 
03261         // Look for comma before value, except the first time.
03262         if (commaOK && nextIndex != 0) {
03263             // Eat white space to find the comma.
03264             std::ws(in); if (!in.good()) break; // eof?
03265             ch = in.peek(); assert(ch != EOFch);
03266             if (!in.good()) break;
03267             c = (char)ch;
03268             if (c == ',') {
03269                 in.get(); // absorb comma
03270                 commaRequired = true; // all commas from now on
03271             } else { // next char not a comma
03272                 if (commaRequired) // bad, e.g.: v1, v2, v3 v4 
03273                 {   in.setstate(std::ios::failbit); break; }
03274                 else commaOK = false; // saw: v1 v2 (no commas now)
03275             }
03276             if (!in.good()) break; // might be eof
03277         }
03278 
03279         // No closing bracket yet; don't have enough elements; skipped comma 
03280         // if any; istream is good; might be looking at white space.
03281         assert(in.good());
03282 
03283         // Now read in an element of type T.
03284         // The extractor T::operator>>() will ignore leading white space.
03285         if (!isFixedSize)
03286             out.push_back(); // grow by one (default consructed)
03287         in >> out[nextIndex]; if (in.fail()) break;
03288         ++nextIndex;
03289 
03290         if (!in.good()) break; // might be eof
03291     }
03292 
03293     // We will get here under a number of circumstances:
03294     //  - the fail bit is set in the istream, or
03295     //  - we reached eof
03296     //  - we saw a closing brace
03297     //  - we got all the elements we wanted (for a fixed-size read)
03298     // Note that it is possible that we consumed everything except some
03299     // trailing white space (meaning we're not technically at eof), but
03300     // for consistency with built-in operator>>()'s we won't try to absorb
03301     // that trailing white space.
03302 
03303     if (!in.fail()) {
03304         if (lookForCloser && !terminatorSeen)
03305             in.setstate(std::ios::failbit); // missing terminator
03306 
03307         if (isFixedSize && nextIndex != numRequired)
03308             in.setstate(std::ios::failbit); // wrong number of values
03309     }
03310 
03311     return in;
03312 }
03313 
03314 
03315 
03316 //------------------------------------------------------------------------------
03317 //                          RELATED GLOBAL OPERATORS
03318 //------------------------------------------------------------------------------
03319 // These are logically part of the Array_<T,X> class but are not actually 
03320 // class members; that is, they are in the SimTK namespace.
03321 
03322 // Some of the serialization methods could have been member functions but 
03323 // then an attempt to explicitly instantiate the whole Array_<T> class for
03324 // some type T would fail if T did not support the requisite I/O operations
03325 // even if those operations were never used. This came up when Chris Bruns was
03326 // trying to wrap Array objects for Python, which requires explicit 
03327 // instantiation.
03328 
03336 
03343 template <class T, class X> inline 
03344 std::ostream&
03345 operator<<(std::ostream& o, 
03346            const ArrayViewConst_<T,X>& a) 
03347 {
03348     o << '(';
03349     if (!a.empty()) {
03350         o << a.front();
03351         for (const T* p = a.begin()+1; p != a.end(); ++p)
03352             o << ',' << *p;
03353     }
03354     return o << ')';
03355 } 
03356 
03357 
03387 template <class T, class X> static inline 
03388 std::istream& readArrayFromStream(std::istream& in, Array_<T,X>& out)
03389 {   return readArrayFromStreamHelper<T,X>(in, false /*variable sizez*/, out); }
03390 
03391 
03392 
03417 template <class T, class X> static inline 
03418 std::istream& fillArrayFromStream(std::istream& in, Array_<T,X>& out)
03419 {   return readArrayFromStreamHelper<T,X>(in, true /*fixed size*/, out); }
03420 
03425 template <class T, class X> static inline 
03426 std::istream& fillArrayViewFromStream(std::istream& in, ArrayView_<T,X>& out)
03427 {   return readArrayFromStreamHelper<T,X>(in, true /*fixed size*/, out); }
03428 
03429 
03430 
03431 
03441 template <class T, class X> inline
03442 std::istream& operator>>(std::istream& in, Array_<T,X>& out) 
03443 {   return readArrayFromStream<T,X>(in, out); }
03444 
03452 template <class T, class X> inline
03453 std::istream& operator>>(std::istream& in, ArrayView_<T,X>& out) 
03454 {   return fillArrayViewFromStream<T,X>(in, out); }
03455 
03465 
03468 template <class T1, class X1, class T2, class X2> inline bool 
03469 operator==(const ArrayViewConst_<T1,X1>& a1, const ArrayViewConst_<T2,X2>& a2) {
03470     // Avoid warnings in size comparison by using common type.
03471     const ptrdiff_t sz1 = a1.end()-a1.begin();
03472     const ptrdiff_t sz2 = a2.end()-a2.begin();
03473     if (sz1 != sz2) return false;
03474     const T1* p1 = a1.begin();
03475     const T2* p2 = a2.begin();
03476     while (p1 != a1.end())
03477         if (!(*p1++ == *p2++)) return false;
03478     return true;
03479 }
03482 template <class T1, class X1, class T2, class X2> inline bool 
03483 operator!=(const ArrayViewConst_<T1,X1>& a1, const ArrayViewConst_<T2,X2>& a2)
03484 {   return !(a1 == a2); }
03485 
03490 template <class T1, class X1, class T2, class X2> inline bool 
03491 operator<(const ArrayViewConst_<T1,X1>& a1, const ArrayViewConst_<T2,X2>& a2) {
03492     const T1* p1 = a1.begin();
03493     const T2* p2 = a2.begin();
03494     while (p1 != a1.end() && p2 != a2.end()) {
03495         if (!(*p1 == *p2))
03496             return *p1 < *p2; // otherwise p1 > p2
03497         ++p1; ++p2;
03498     }
03499     // All elements were equal until one or both arrays ran out of elements.
03500     // a1 is less than a2 only if a1 ran out and a2 didn't.
03501     return p1 == a1.end() && p2 != a2.end();
03502 }
03505 template <class T1, class X1, class T2, class X2> inline bool 
03506 operator>=(const ArrayViewConst_<T1,X1>& a1, const ArrayViewConst_<T2,X2>& a2)
03507 {   return !(a1 < a2); }
03511 template <class T1, class X1, class T2, class X2> inline bool 
03512 operator>(const ArrayViewConst_<T1,X1>& a1, const ArrayViewConst_<T2,X2>& a2)
03513 {   return a2 < a1; }
03516 template <class T1, class X1, class T2, class X2> inline bool 
03517 operator<=(const ArrayViewConst_<T1,X1>& a1, const ArrayViewConst_<T2,X2>& a2)
03518 {   return !(a1 > a2); }
03519 
03523 template <class T1, class X1, class T2, class A2> inline bool 
03524 operator==(const ArrayViewConst_<T1,X1>& a1, const std::vector<T2,A2>& v2)
03525 {   return a1 == ArrayViewConst_<T2,size_t>(v2); }
03526 
03530 template <class T1, class A1, class T2, class X2> inline bool 
03531 operator==(const std::vector<T1,A1>& v1, const ArrayViewConst_<T2,X2>& a2)
03532 {   return a2 == v1; }
03533 
03536 template <class T1, class X1, class T2, class A2> inline bool 
03537 operator!=(const ArrayViewConst_<T1,X1>& a1, const std::vector<T2,A2>& v2)
03538 {   return !(a1 == v2); }
03541 template <class T1, class A1, class T2, class X2> inline bool 
03542 operator!=(const std::vector<T1,A1>& v1, const ArrayViewConst_<T2,X2>& a2)
03543 {   return !(a2 == v1); }
03544 
03550 template <class T1, class X1, class T2, class A2> inline bool 
03551 operator<(const ArrayViewConst_<T1,X1>& a1, const std::vector<T2,A2>& v2)
03552 {   return a1 < ArrayViewConst_<T2,size_t>(v2); }
03553 
03559 template <class T1, class A1, class T2, class X2> inline bool 
03560 operator<(const std::vector<T1,A1>& v1, const ArrayViewConst_<T2,X2>& a2)
03561 {   return ArrayViewConst_<T1,size_t>(v1) < a2; }
03562 
03565 template <class T1, class X1, class T2, class A2> inline bool 
03566 operator>=(const ArrayViewConst_<T1,X1>& a1, const std::vector<T2,A2>& v2)
03567 {   return !(a1 < v2); }
03570 template <class T1, class A1, class T2, class X2> inline bool 
03571 operator>=(const std::vector<T1,A1>& v1, const ArrayViewConst_<T2,X2>& a2)
03572 {   return !(v1 < a2); }
03573 
03577 template <class T1, class X1, class T2, class A2> inline bool 
03578 operator>(const ArrayViewConst_<T1,X1>& a1, const std::vector<T2,A2>& v2)
03579 {   return v2 < a1; }
03583 template <class T1, class A1, class T2, class X2> inline bool 
03584 operator>(const std::vector<T1,A1>& v1, const ArrayViewConst_<T2,X2>& a2)
03585 {   return a2 < v1; }
03586 
03589 template <class T1, class X1, class T2, class A2> inline bool 
03590 operator<=(const ArrayViewConst_<T1,X1>& a1, const std::vector<T2,A2>& v2)
03591 {   return !(a1 > v2); }
03594 template <class T1, class A1, class T2, class X2> inline bool 
03595 operator<=(const std::vector<T1,A1>& v1, const ArrayViewConst_<T2,X2>& a2)
03596 {   return !(v1 > a2); }
03597 
03600 } // namespace SimTK
03601 
03602 namespace std {
03606 template <class T, class X> inline void
03607 swap(SimTK::Array_<T,X>& a1, SimTK::Array_<T,X>& a2) {
03608     a1.swap(a2);
03609 }
03610 
03611 } // namespace std
03612   
03613 #endif // SimTK_SimTKCOMMON_ARRAY_H_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines