Simbody
3.4 (development)
|
00001 #ifndef SimTK_SimTKCOMMON_ARRAY_H_ 00002 #define SimTK_SimTKCOMMON_ARRAY_H_ 00003 00004 /* -------------------------------------------------------------------------- * 00005 * Simbody(tm): SimTKcommon * 00006 * -------------------------------------------------------------------------- * 00007 * This is part of the SimTK 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/home/simbody. * 00011 * * 00012 * Portions copyright (c) 2010-13 Stanford University and the Authors. * 00013 * Authors: Michael Sherman * 00014 * Contributors: * 00015 * * 00016 * Licensed under the Apache License, Version 2.0 (the "License"); you may * 00017 * not use this file except in compliance with the License. You may obtain a * 00018 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0. * 00019 * * 00020 * Unless required by applicable law or agreed to in writing, software * 00021 * distributed under the License is distributed on an "AS IS" BASIS, * 00022 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 00023 * See the License for the specific language governing permissions and * 00024 * limitations under the License. * 00025 * -------------------------------------------------------------------------- */ 00026 00033 #include "SimTKcommon/internal/common.h" 00034 #include "SimTKcommon/internal/ExceptionMacros.h" 00035 #include "SimTKcommon/internal/Serialize.h" 00036 00037 #include <algorithm> 00038 #include <iterator> 00039 #include <vector> 00040 #include <ostream> 00041 #include <climits> 00042 #include <typeinfo> 00043 00044 namespace SimTK { 00045 00046 // These are the classes defined in this header. 00047 template <class X> struct ArrayIndexTraits; 00048 template <class T, class X=unsigned> class ArrayViewConst_; 00049 template <class T, class X=unsigned> class ArrayView_; 00050 template <class T, class X=unsigned> class Array_; 00051 00052 00053 00054 //============================================================================== 00055 // CLASS ArrayIndexTraits 00056 //============================================================================== 00057 00100 template <class X> struct ArrayIndexTraits { 00103 typedef typename X::size_type size_type; 00106 typedef typename X::difference_type difference_type; 00109 static size_type max_size() {return X::max_size();} 00110 }; 00111 00114 template <> struct ArrayIndexTraits<unsigned> { 00115 typedef unsigned size_type; 00116 typedef int difference_type; 00117 static size_type max_size() {return (unsigned)INT_MAX;} 00118 }; 00119 00121 template <> struct ArrayIndexTraits<int> { 00122 typedef int size_type; 00123 typedef int difference_type; 00124 static size_type max_size() {return INT_MAX;} 00125 }; 00126 00134 template <> struct ArrayIndexTraits<unsigned long> { 00135 typedef unsigned long size_type; 00136 typedef long difference_type; 00137 static size_type max_size() {return (unsigned long)LONG_MAX;} 00138 }; 00139 00147 template <> struct ArrayIndexTraits<long> { 00148 typedef long size_type; 00149 typedef long difference_type; 00150 static size_type max_size() {return LONG_MAX;} 00151 }; 00152 00158 template <> struct ArrayIndexTraits<unsigned short> { 00159 typedef unsigned short size_type; 00160 typedef int difference_type; 00161 static size_type max_size() {return USHRT_MAX;} 00162 }; 00163 00168 template <> struct ArrayIndexTraits<short> { 00169 typedef short size_type; 00170 typedef short difference_type; 00171 static size_type max_size() {return SHRT_MAX;} 00172 }; 00173 00174 00179 template <> struct ArrayIndexTraits<unsigned char> { 00180 typedef unsigned char size_type; 00181 typedef short difference_type; 00182 static size_type max_size() {return UCHAR_MAX;} // not CHAR_MAX 00183 }; 00184 00190 template <> struct ArrayIndexTraits<signed char> { 00191 typedef signed char size_type; 00192 typedef signed char difference_type; 00193 static size_type max_size() {return SCHAR_MAX;} 00194 }; 00195 00202 template <> struct ArrayIndexTraits<char> { 00203 typedef char size_type; 00204 typedef signed char difference_type; 00205 static size_type max_size() {return (char)SCHAR_MAX;} 00206 }; 00207 00213 template <> struct ArrayIndexTraits<bool> { 00214 typedef unsigned char size_type; 00215 typedef signed char difference_type; 00216 static size_type max_size() {return 2;} 00217 }; 00218 00221 template <> struct ArrayIndexTraits<unsigned long long> { 00222 typedef unsigned long long size_type; 00223 typedef long long difference_type; 00224 static size_type max_size() 00225 {return (unsigned long long)LLONG_MAX;} 00226 }; 00227 00230 template <> struct ArrayIndexTraits<long long> { 00231 typedef long long size_type; 00232 typedef long long difference_type; 00233 static size_type max_size() {return LLONG_MAX;} 00234 }; 00235 00236 // Don't show this in Doxygen. 00238 // This helper class decides what integral type we should use to best pack 00239 // the index type's size_type representation. The idea is to pack the whole 00240 // Array_ structure into 8 bytes on a 32 bit machine, 16 bytes on a 64 bit 00241 // machine, using the largest integral type that will work, giving a layout 00242 // like this: | data pointer | 00243 // | nUsed | nAllocated | 00244 00245 // The default implementation just uses the integral type itself. 00246 template <class Integral, class is64Bit> struct ArrayIndexPackTypeHelper 00247 { typedef Integral packed_size_type;}; 00248 00249 // On 32 bit machine, pack anything smaller than a short into a short. 00250 template<> struct ArrayIndexPackTypeHelper<bool,FalseType> 00251 { typedef unsigned short packed_size_type;}; 00252 template<> struct ArrayIndexPackTypeHelper<char,FalseType> 00253 { typedef unsigned short packed_size_type;}; 00254 template<> struct ArrayIndexPackTypeHelper<unsigned char,FalseType> 00255 { typedef unsigned short packed_size_type;}; 00256 template<> struct ArrayIndexPackTypeHelper<signed char,FalseType> 00257 { typedef short packed_size_type;}; 00258 00259 // On 64 bit machine, pack anything smaller than an int into an int. 00260 template<> struct ArrayIndexPackTypeHelper<bool,TrueType> 00261 { typedef unsigned int packed_size_type;}; 00262 template<> struct ArrayIndexPackTypeHelper<char,TrueType> 00263 { typedef unsigned int packed_size_type;}; 00264 template<> struct ArrayIndexPackTypeHelper<unsigned char,TrueType> 00265 { typedef unsigned int packed_size_type;}; 00266 template<> struct ArrayIndexPackTypeHelper<signed char,TrueType> 00267 { typedef int packed_size_type;}; 00268 template<> struct ArrayIndexPackTypeHelper<unsigned short,TrueType> 00269 { typedef unsigned int packed_size_type;}; 00270 template<> struct ArrayIndexPackTypeHelper<short,TrueType> 00271 { typedef int packed_size_type;}; 00272 00273 template <class Integral> struct ArrayIndexPackType 00274 { typedef typename ArrayIndexPackTypeHelper<Integral,Is64BitPlatformType> 00275 ::packed_size_type packed_size_type;}; 00283 //============================================================================== 00284 // CLASS ArrayViewConst_ 00285 //============================================================================== 00312 template <class T, class X> class ArrayViewConst_ { 00313 public: 00314 00315 00316 //------------------------------------------------------------------------------ 00323 typedef T value_type; 00325 typedef X index_type; 00327 typedef T* pointer; 00329 typedef const T* const_pointer; 00331 typedef T& reference; 00333 typedef const T& const_reference; 00335 typedef T* iterator; 00337 typedef const T* const_iterator; 00339 typedef std::reverse_iterator<iterator> reverse_iterator; 00341 typedef std::reverse_iterator<const_iterator> const_reverse_iterator; 00343 typedef typename ArrayIndexTraits<X>::size_type size_type; 00346 typedef typename ArrayIndexTraits<X>::difference_type difference_type; 00348 typedef typename ArrayIndexPackType<size_type>::packed_size_type 00349 packed_size_type; 00353 //------------------------------------------------------------------------------ 00359 00361 ArrayViewConst_() : pData(0), nUsed(0), nAllocated(0) {} 00362 00372 ArrayViewConst_(const ArrayViewConst_& src) 00373 : pData(0), nUsed(src.nUsed), nAllocated(0) { 00374 if (nUsed) pData = const_cast<T*>(src.pData); 00375 } 00376 00377 // Copy assignment is suppressed. 00378 00401 ArrayViewConst_(const T* first, const T* last1) 00402 : pData(0),nUsed(0),nAllocated(0) { 00403 if (last1==first) return; // empty 00404 00405 SimTK_ERRCHK((first&&last1)||(first==last1), 00406 "ArrayViewConst_<T>(first,last1)", 00407 "One of the source pointers was null (0); either both must be" 00408 " non-null or both must be null."); 00409 00410 SimTK_ERRCHK3(this->isSizeOK(last1-first), 00411 "ArrayViewConst_<T>(first,last1)", 00412 "The source data's size %llu is too big for this array which" 00413 " is limited to %llu elements by its index type %s.", 00414 this->ull(last1-first), ullMaxSize(), indexName()); 00415 00416 pData = const_cast<T*>(first); 00417 nUsed = packed_size_type(last1-first); 00418 // nAllocated is already zero 00419 } 00420 00448 template <class A> 00449 ArrayViewConst_(const std::vector<T,A>& src) 00450 : pData(0),nUsed(0),nAllocated(0) { 00451 if (src.empty()) return; 00452 00453 SimTK_ERRCHK3(this->isSizeOK(src.size()), 00454 "ArrayViewConst_<T>::ctor(std::vector<T>)", 00455 "The source std::vector's size %llu is too big for this array which" 00456 " is limited to %llu elements by its index type %s.", 00457 this->ull(src.size()), ullMaxSize(), indexName()); 00458 00459 pData = const_cast<T*>(&src.front()); 00460 nUsed = packed_size_type(src.size()); 00461 // nAllocated is already zero 00462 } 00465 operator const ArrayView_<T,X>&() const 00466 { return *reinterpret_cast<const ArrayView_<T,X>*>(this); } 00469 operator const Array_<T,X>&() const 00470 { return *reinterpret_cast<const Array_<T,X>*>(this); } 00471 00477 void disconnect() { 00478 SimTK_ASSERT(nAllocated==0, 00479 "ArrayViewConst_::deallocate(): called on an owner Array_"); 00480 nUsed = 0; 00481 pData = 0; 00482 } 00483 00486 ~ArrayViewConst_() { 00487 disconnect(); 00488 } 00492 //------------------------------------------------------------------------------ 00499 00501 size_type size() const {return size_type(nUsed);} 00503 size_type max_size() const {return ArrayIndexTraits<X>::max_size();} 00506 bool empty() const {return nUsed==0;} 00511 size_type capacity() const {return size_type(nAllocated?nAllocated:nUsed);} 00515 size_type allocated() const {return size_type(nAllocated);} 00521 bool isOwner() const {return nAllocated || pData==0;} 00522 /*}*/ 00523 00524 00525 //------------------------------------------------------------------------------ 00532 00539 const T& operator[](index_type i) const { 00540 SimTK_INDEXCHECK(size_type(i),size(),"ArrayViewConst_<T>::operator[]()"); 00541 return pData[i]; 00542 } 00547 const T& at(index_type i) const { 00548 SimTK_INDEXCHECK_ALWAYS(size_type(i),size(),"ArrayViewConst_<T>::at()"); 00549 return pData[i]; 00550 } 00553 const T& getElt(index_type i) const { 00554 SimTK_INDEXCHECK(size_type(i),size(),"ArrayViewConst_<T>::getElt()"); 00555 return pData[i]; 00556 } 00562 const T& front() const 00563 { SimTK_ERRCHK(!empty(), "ArrayViewConst_<T>::front()", "Array was empty."); 00564 return pData[0]; } 00570 const T& back() const 00571 { SimTK_ERRCHK(!empty(), "ArrayViewConst_<T>::back()", "Array was empty."); 00572 return pData[nUsed-1]; } 00573 00592 ArrayViewConst_ operator()(index_type index, size_type length) const { 00593 const size_type ix(index); 00594 SimTK_ERRCHK2(isSizeInRange(ix, size()), "ArrayViewConst_<T>(index,length)", 00595 "For this operator, we must have 0 <= index <= size(), but" 00596 " index==%llu and size==%llu.", this->ull(ix), ullSize()); 00597 SimTK_ERRCHK2(isSizeInRange(length, size_type(size()-ix)), 00598 "ArrayViewConst_<T>(index,length)", 00599 "This operator requires 0 <= length <= size()-index, but" 00600 " length==%llu and size()-index==%llu.",this->ull(length),this->ull(size()-ix)); 00601 00602 return ArrayViewConst_(pData+ix, pData+ix+length); 00603 } 00606 ArrayViewConst_ getSubArray(index_type index, size_type length) const 00607 { return (*this)(index,length); } 00608 00612 //------------------------------------------------------------------------------ 00621 00626 const T* cbegin() const {return pData;} 00631 const T* cend() const {return pData + nUsed;} 00633 const T* begin() const {return pData;} 00635 const T* end() const {return pData + nUsed;} 00636 00639 const_reverse_iterator crbegin() const {return const_reverse_iterator(cend());} 00643 const_reverse_iterator crend() const {return const_reverse_iterator(cbegin());} 00645 const_reverse_iterator rbegin() const {return crbegin();} 00647 const_reverse_iterator rend() const {return crend();} 00648 00655 const T* cdata() const {return pData;} 00657 const T* data() const {return pData;} 00661 //------------------------------------------------------------------------------ 00662 protected: 00663 //------------------------------------------------------------------------------ 00664 // The remainder of this class is for the use of the ArrayView_<T,X> and 00665 // Array_<T,X> derived classes only and should not be documented for users to 00666 // see. 00667 00668 // Don't let doxygen see any of this. 00670 packed_size_type psize() const {return nUsed;} 00671 packed_size_type pallocated() const {return nAllocated;} 00672 00673 // These provide direct access to the data members for our trusted friends. 00674 void setData(const T* p) {pData = const_cast<T*>(p);} 00675 void setSize(size_type n) {nUsed = packed_size_type(n);} 00676 void incrSize() {++nUsed;} 00677 void decrSize() {--nUsed;} 00678 void setAllocated(size_type n) {nAllocated = packed_size_type(n);} 00679 00680 // Check whether a given size is the same as the current size of this array, 00681 // avoiding any compiler warnings due to mismatched integral types. 00682 template <class S> 00683 bool isSameSize(S sz) const 00684 { return ull(sz) == ullSize(); } 00685 00686 // Check that a source object's size will fit in the array being careful to 00687 // avoid overflow and warnings in the comparison. 00688 template <class S> 00689 bool isSizeOK(S srcSz) const 00690 { return ull(srcSz) <= ullMaxSize(); } 00691 00692 // This is identical in function to std::distance() (reports how many 00693 // elements lie between two iterators) but avoids any slow 00694 // Release-build bugcatchers that Microsoft may have felt compelled to add. 00695 // The implementation is specialized for random access iterators because 00696 // they can measure distance very fast. 00697 template<class Iter> static 00698 typename std::iterator_traits<Iter>::difference_type 00699 iterDistance(const Iter& first, const Iter& last1) { 00700 return iterDistanceImpl(first,last1, 00701 typename std::iterator_traits<Iter>::iterator_category()); 00702 } 00703 00704 // Generic slow implementation for non-random access iterators. This is fine 00705 // for forward and bidirectional iterators, but it will *consume* input 00706 // iterators so is useless for them. 00707 template<class Iter> static 00708 typename std::iterator_traits<Iter>::difference_type 00709 iterDistanceImpl(const Iter& first, const Iter& last1, std::input_iterator_tag) { 00710 typename std::iterator_traits<Iter>::difference_type d = 0; 00711 for (Iter src=first; src != last1; ++src, ++d) 00712 ; 00713 return d; 00714 } 00715 00716 // Fast specialization for random access iterators (including ordinary 00717 // pointers) -- just subtract. 00718 template<class Iter> static 00719 typename std::iterator_traits<Iter>::difference_type 00720 iterDistanceImpl(const Iter& first, const Iter& last1, 00721 std::random_access_iterator_tag) { 00722 return last1 - first; 00723 } 00724 00725 // This method attempts to determine whether any elements in the iterator range 00726 // [first,last1) overlap with the elements stored in this array. This is used 00727 // for error checks for operations where source is not permitted to overlap the 00728 // destination. For random access iterators (including ordinary pointers), we 00729 // can answer this question definitively because we expect the data to be 00730 // consecutive in memory. For other kinds of iterators, we will just assume 00731 // there is no overlap. Note that null ranges do not overlap even if the 00732 // pair of equal iterators points within the other range -- what matters is 00733 // the number of overlapping elements. 00734 template<class Iter> bool 00735 overlapsWithData(const Iter& first, const Iter& last1) { 00736 return overlapsWithDataImpl(first,last1, 00737 typename std::iterator_traits<Iter>::iterator_category()); 00738 } 00739 00740 // This is a partial specialization of the above where the data is given 00741 // with ordinary pointers. 00742 template <class T2> bool 00743 overlapsWithData(const T2* first, const T2* last1) { 00744 // Find the start and end+1 of the alleged overlap region. There is 00745 // overlap iff end+1 > start. Note that this works if either range 00746 // is [0,0) or [p,p), or if last1 is illegally less than first (we just 00747 // want to report no overlap in that case -- it is someone else's business 00748 // to complain). 00749 const T* obegin = std::max(cbegin(), (const T*)first); 00750 const T* oend1 = std::min(cend(), (const T*)last1); 00751 00752 return obegin < oend1; 00753 } 00754 00755 // This is the generic implementation for any type of input iterator other than 00756 // random access (i.e., bidirectional, forward, or input) -- assume no overlap. 00757 template<class Iter> bool 00758 overlapsWithDataImpl(const Iter&, const Iter&, std::input_iterator_tag) 00759 { return false; } 00760 00761 // Here we can actually test for overlap since we have random access iterators. 00762 // We convert them to pointers and then look for memory overlap. 00763 template<class Iter> bool 00764 overlapsWithDataImpl(const Iter& first, const Iter& last1, 00765 std::random_access_iterator_tag) { 00766 // We must check that the input iterators span a non-zero range before 00767 // assuming we can dereference them. 00768 if (last1 <= first) 00769 return false; // zero or malformed source range: no overlap 00770 00771 // We now know we can dereference first and last1-1 (can't safely 00772 // dereference last1 but we can use pointer arithmetic to point past 00773 // the (last-1)th element in memory). We then take the dereferenced 00774 // object's address to get ordinary pointers that we can use to 00775 // watch for illegal overlap. 00776 return overlapsWithData(&*first, &*(last1-1)); // use pointer overload 00777 } 00778 00779 // Cast an integral type to maximal-width unsigned long long to avoid accidental 00780 // overflows that might otherwise occur due to wraparound that can happen 00781 // with small index types. 00782 template <class S> 00783 static unsigned long long ull(S sz) 00784 { return (unsigned long long)sz; } 00785 00786 // Return size(), capacity(), and max_size() cast to unsigned long long. 00787 unsigned long long ullSize() const {return ull(size());} 00788 unsigned long long ullCapacity() const {return ull(capacity());} 00789 unsigned long long ullMaxSize() const {return ull(max_size());} 00790 00791 // Useful in error messages for explaining why something was too big. 00792 const char* indexName() const {return NiceTypeName<X>::name();} 00793 00796 private: 00797 //------------------------------------------------------------------------------ 00798 // DATA MEMBERS 00799 // These are the only data members and this layout is guaranteed not to change 00800 // from release to release. If data is null, then nUsed==nAllocated==0. 00801 00802 T* pData; // ptr to data referenced here, or 0 if none 00803 packed_size_type nUsed; // number of elements currently present (size) 00804 packed_size_type nAllocated; // heap allocation; 0 if pData is not owned 00805 00806 ArrayViewConst_& operator=(const ArrayViewConst_& src); // suppressed 00807 }; 00808 00809 00810 00811 00812 00813 00814 //============================================================================== 00815 // CLASS ArrayView_ 00816 //============================================================================== 00828 template <class T, class X> class ArrayView_ : public ArrayViewConst_<T,X> { 00829 typedef ArrayViewConst_<T,X> CBase; 00830 public: 00831 //------------------------------------------------------------------------------ 00836 /*{*/ 00837 typedef T value_type; 00838 typedef X index_type; 00839 typedef T* pointer; 00840 typedef const T* const_pointer; 00841 typedef T& reference; 00842 typedef const T& const_reference; 00843 typedef T* iterator; 00844 typedef const T* const_iterator; 00845 typedef std::reverse_iterator<iterator> reverse_iterator; 00846 typedef std::reverse_iterator<const_iterator> const_reverse_iterator; 00847 typedef typename ArrayIndexTraits<X>::size_type size_type; 00848 typedef typename ArrayIndexTraits<X>::difference_type difference_type; 00849 typedef typename ArrayIndexPackType<size_type>::packed_size_type 00850 packed_size_type; 00851 /*}*/ 00852 00853 00854 //------------------------------------------------------------------------------ 00860 00862 ArrayView_() : CBase() {} 00863 00865 ArrayView_(const ArrayView_& src) : CBase(src) {} 00866 00868 ArrayView_(T* first, const T* last1) : CBase(first,last1) {} 00869 00871 template <class A> 00872 ArrayView_(std::vector<T,A>& v) : CBase(v) {} 00873 00875 operator const Array_<T,X>&() const 00876 { return *reinterpret_cast<const Array_<T,X>*>(this); } 00877 00879 operator Array_<T,X>&() 00880 { return *reinterpret_cast<Array_<T,X>*>(this); } 00881 00884 void disconnect() {this->CBase::disconnect();} 00885 00888 ~ArrayView_() {this->CBase::disconnect();} 00892 //------------------------------------------------------------------------------ 00904 00906 ArrayView_& operator=(const ArrayView_& src) { 00907 if (&src != this) 00908 avAssignIteratorDispatch(src.cbegin(), src.cend(), 00909 std::random_access_iterator_tag(), 00910 "ArrayView_<T>::operator=(ArrayView_<T>)"); 00911 return *this; 00912 } 00913 00914 00917 template <class T2, class X2> 00918 ArrayView_& operator=(const ArrayViewConst_<T2,X2>& src) { 00919 if ((const void*)&src != (void*)this) 00920 avAssignIteratorDispatch(src.cbegin(), src.cend(), 00921 std::random_access_iterator_tag(), 00922 "ArrayView_<T>::operator=(Array_<T2>)"); 00923 return *this; 00924 } 00925 00926 // Help out dumb compilers struggling to match the template arguments and 00927 // promote the Array_ or ArrayView_ to ArrayConstView_ at the same time. 00928 00931 template <class T2, class X2> 00932 ArrayView_& operator=(const ArrayView_<T2,X2>& src) 00933 { return *this = static_cast<const ArrayViewConst_<T2,X2>&>(src); } 00936 template <class T2, class X2> 00937 ArrayView_& operator=(const Array_<T2,X2>& src) 00938 { return *this = static_cast<const ArrayViewConst_<T2,X2>&>(src); } 00939 00942 template <class T2, class A2> 00943 ArrayView_& operator=(const std::vector<T2,A2>& src) { 00944 avAssignIteratorDispatch(src.begin(), src.end(), 00945 std::random_access_iterator_tag(), 00946 "ArrayView_<T>::operator=(std::vector<T2>)"); 00947 return *this; 00948 } 00949 00951 ArrayView_& operator=(const T& fillValue) 00952 { fill(fillValue); return *this; } 00953 00959 ArrayView_& fill(const T& fillValue) { 00960 for (T* d = begin(); d != end(); ++d) 00961 *d = fillValue; // using T::operator=(T) 00962 return *this; 00963 } 00964 00968 void assign(size_type n, const T& fillValue) { 00969 SimTK_ERRCHK2(n == size(), "ArrayView_<T>::assign(n,value)", 00970 "Assignment to an ArrayView is permitted only if the source" 00971 " is the same size. Here n==%llu element(s) but the" 00972 " ArrayView has a fixed size of %llu.", 00973 this->ull(n), this->ull(size())); 00974 00975 fill(fillValue); 00976 } 00977 00995 template <class T2> 00996 void assign(const T2* first, const T2* last1) { 00997 const char* methodName = "ArrayView_<T>::assign(T2* first, T2* last1)"; 00998 SimTK_ERRCHK((first&&last1)||(first==last1), methodName, 00999 "One of the source pointers was null (0); either both must be" 01000 " non-null or both must be null."); 01001 // Valid pointers are random access iterators. 01002 avAssignIteratorDispatch(first, last1, std::random_access_iterator_tag(), 01003 methodName); 01004 } 01005 01035 // Watch out for integral types matching this signature -- they must be 01036 // forwarded to the assign(n, fillValue) signature instead. 01037 template <class Iter> 01038 void assign(const Iter& first, const Iter& last1) 01039 { avAssignDispatch(first,last1,typename IsIntegralType<Iter>::Result(), 01040 "ArrayView_<T>::assign(Iter first, Iter last1)"); } 01044 //------------------------------------------------------------------------------ 01051 01058 const T& operator[](index_type i) const {return this->CBase::operator[](i);} 01059 01067 T& operator[](index_type i) {return const_cast<T&>(this->CBase::operator[](i));} 01068 01073 const T& at(index_type i) const {return this->CBase::at(i);} 01074 01079 T& at(index_type i) {return const_cast<T&>(this->CBase::at(i));} 01080 01083 const T& getElt(index_type i) const {return this->CBase::getElt(i);} 01086 T& updElt(index_type i) {return const_cast<T&>(this->CBase::getElt(i));} 01087 01093 const T& front() const {return this->CBase::front();} 01094 01100 T& front() {return const_cast<T&>(this->CBase::front());} 01101 01107 const T& back() const {return this->CBase::back();} 01108 01114 T& back() {return const_cast<T&>(this->CBase::back());} 01115 01134 ArrayView_ operator()(index_type index, size_type length) { 01135 const size_type ix(index); 01136 SimTK_ERRCHK2(isSizeInRange(ix, size()), "ArrayView_<T>(index,length)", 01137 "For this operator, we must have 0 <= index <= size(), but" 01138 " index==%llu and size==%llu.", this->ull(ix), ullSize()); 01139 SimTK_ERRCHK2(isSizeInRange(length, size_type(size()-ix)), 01140 "ArrayView_<T>(index,length)", 01141 "This operator requires 0 <= length <= size()-index, but" 01142 " length==%llu and size()-index==%llu.",this->ull(length),this->ull(size()-ix)); 01143 01144 return ArrayView_(data()+ix, data()+ix+length); 01145 } 01148 ArrayView_ updSubArray(index_type index, size_type length) 01149 { return (*this)(index,length); } 01153 //------------------------------------------------------------------------------ 01162 01167 const T* cbegin() const {return this->CBase::cbegin();} 01169 const T* begin() const {return this->CBase::cbegin();} 01174 T* begin() {return const_cast<T*>(this->CBase::cbegin());} 01175 01180 const T* cend() const {return this->CBase::cend();} 01182 const T* end() const {return this->CBase::cend();} 01187 T* end() {return const_cast<T*>(this->CBase::cend());} 01188 01191 const_reverse_iterator crbegin() const {return this->CBase::crbegin();} 01193 const_reverse_iterator rbegin() const {return this->CBase::crbegin();} 01196 reverse_iterator rbegin() {return reverse_iterator(end());} 01197 01201 const_reverse_iterator crend() const {return this->CBase::crend();} 01203 const_reverse_iterator rend() const {return this->CBase::crend();} 01207 reverse_iterator rend() {return reverse_iterator(begin());} 01208 01215 const T* cdata() const {return this->CBase::cdata();} 01218 const T* data() const {return this->CBase::cdata();} 01222 T* data() {return const_cast<T*>(this->CBase::cdata());} 01226 //------------------------------------------------------------------------------ 01232 01233 // Note: these have to be explicitly forwarded to the base class methods 01234 // in order to keep gcc from complaining. Note that the "this->" is 01235 // apparently necessary in order to permit delayed definition of templatized 01236 // methods. Doxygen picks up the comments from the base class. 01237 01238 size_type size() const {return this->CBase::size();} 01239 size_type max_size() const {return this->CBase::max_size();} 01240 bool empty() const {return this->CBase::empty();} 01241 size_type capacity() const {return this->CBase::capacity();} 01242 size_type allocated() const {return this->CBase::allocated();} 01243 bool isOwner() const {return this->CBase::isOwner();} 01247 //------------------------------------------------------------------------------ 01248 private: 01249 //------------------------------------------------------------------------------ 01250 // no data members are allowed 01251 01252 //------------------------------------------------------------------------------ 01253 // ARRAY VIEW ASSIGN DISPATCH 01254 // This is the assign() implementation for ArrayView_ when the class that 01255 // matched the alleged InputIterator template argument turned out to be one of 01256 // the integral types in which case this should match the assign(n, fillValue) 01257 // signature. 01258 template <class IntegralType> 01259 void avAssignDispatch(IntegralType n, IntegralType v, TrueType isIntegralType, 01260 const char*) 01261 { assign(size_type(n), value_type(v)); } 01262 01263 // This is the assign() implementation for ArrayView_ when the class that 01264 // matched the alleged InputIterator template argument is NOT an integral type 01265 // and may very well be an iterator. 01266 template <class InputIterator> 01267 void avAssignDispatch(const InputIterator& first, const InputIterator& last1, 01268 FalseType isIntegralType, const char* methodName) 01269 { avAssignIteratorDispatch(first, last1, 01270 typename std::iterator_traits<InputIterator>::iterator_category(), 01271 methodName); } 01272 01273 // This is the assign() implementation for a plain input_iterator 01274 // (i.e., not a forward, bidirectional, or random access iterator). These 01275 // have the unfortunate property that we can't count the elements in advance. 01276 // Here we're going to complain if there aren't enough; but will simply stop 01277 // when we get size() elements and not insist that the input stream reached 01278 // the supplied last1 iterator. Semantics is elementwise assignment. 01279 template <class InputIterator> 01280 void avAssignIteratorDispatch(const InputIterator& first, 01281 const InputIterator& last1, 01282 std::input_iterator_tag, 01283 const char* methodName) 01284 { 01285 T* p = begin(); 01286 InputIterator src = first; 01287 while (src != last1 && p != end()) 01288 *p++ = *src++; // call T's assignment operator 01289 01290 // p now points just after the last element that was copied. 01291 const size_type nCopied = size_type(p - begin()); 01292 SimTK_ERRCHK2_ALWAYS(nCopied == size(), methodName, 01293 "The supplied input_iterator provided only %llu elements but this" 01294 " ArrayView has a fixed size of %llu elements.", 01295 this->ull(nCopied), ullSize()); 01296 01297 // We don't care if there are still more input elements available. 01298 } 01299 01300 // This is the assign() implementation that works for forward and bidirectional 01301 // iterators, but is not used for random_access_iterators. Here we'll count 01302 // the elements as we copy them and complain at the end if there were too 01303 // few or too many. 01304 template <class ForwardIterator> 01305 void avAssignIteratorDispatch(const ForwardIterator& first, 01306 const ForwardIterator& last1, 01307 std::forward_iterator_tag, 01308 const char* methodName) 01309 { 01310 T* p = begin(); 01311 ForwardIterator src = first; 01312 while (src != last1 && p != end()) 01313 *p++ = *src++; // call T's assignment operator 01314 01315 // p now points just after the last element that was copied. 01316 const size_type nCopied = size_type(p - begin()); 01317 SimTK_ERRCHK2_ALWAYS(nCopied == size(), methodName, 01318 "The supplied forward_ or bidirectional_iterator source range provided" 01319 " only %llu elements but this ArrayView has a fixed size of" 01320 " %llu elements.", this->ull(nCopied), ullSize()); 01321 01322 // Make sure we ran out of source elements. 01323 SimTK_ERRCHK1_ALWAYS(src == last1, methodName, 01324 "The supplied forward_ or bidirectional_iterator source range" 01325 " contained too many elements; this ArrayView has a fixed size of" 01326 " %llu elements.", ullSize()); 01327 } 01328 01329 // This is the assign() implementation that works for random_access_iterators 01330 // including ordinary pointers. Here we check the number of elements in advance 01331 // and complain if the source and destination aren't the same size. The 01332 // copying loop can be done faster in this case. 01333 template <class RandomAccessIterator> 01334 void avAssignIteratorDispatch(const RandomAccessIterator& first, 01335 const RandomAccessIterator& last1, 01336 std::random_access_iterator_tag, 01337 const char* methodName) 01338 { 01339 SimTK_ERRCHK2_ALWAYS(this->isSameSize(last1-first), methodName, 01340 "Assignment to an ArrayView is permitted only if the source" 01341 " is the same size. Here the source had %llu element(s) but the" 01342 " ArrayView has a fixed size of %llu.", 01343 this->ull(last1-first), this->ull(size())); 01344 01345 SimTK_ERRCHK_ALWAYS(!this->overlapsWithData(first,last1), methodName, 01346 "Source range can't overlap with the destination data."); 01347 01348 T* p = begin(); 01349 RandomAccessIterator src = first; 01350 while (p != end()) 01351 *p++ = *src++; // call T's assignment operator 01352 } 01353 01354 01355 //------------------------------------------------------------------------------ 01356 // The following private methods are protected methods in the ArrayViewConst_ 01357 // base class, so they should not need repeating here. However, we explicitly 01358 // forward to the base methods to avoid gcc errors. The gcc complaint 01359 // is due to their not depending on any template parameters; the "this->" 01360 // apparently fixes that problem. 01361 01362 packed_size_type psize() const {return this->CBase::psize();} 01363 packed_size_type pallocated() const {return this->CBase::pallocated();} 01364 01365 // This just cast sizes to unsigned long long so that we can do comparisons 01366 // without getting warnings. 01367 unsigned long long ullSize() const {return this->CBase::ullSize();} 01368 unsigned long long ullCapacity() const {return this->CBase::ullCapacity();} 01369 unsigned long long ullMaxSize() const {return this->CBase::ullMaxSize();} 01370 // This is the index type name and is handy for error messages to explain 01371 // why some size was too big. 01372 const char* indexName() const {return this->CBase::indexName();} 01373 }; 01374 01375 01376 01377 01378 01379 //============================================================================== 01380 // CLASS Array_ 01381 //============================================================================== 01484 template <class T, class X> class Array_ : public ArrayView_<T,X> { 01485 typedef ArrayView_<T,X> Base; 01486 typedef ArrayViewConst_<T,X> CBase; 01487 public: 01488 01489 01490 //------------------------------------------------------------------------------ 01496 // Doxygen picks up individual descriptions from the base class. 01497 /*{*/ 01498 typedef T value_type; 01499 typedef X index_type; 01500 typedef T* pointer; 01501 typedef const T* const_pointer; 01502 typedef T& reference; 01503 typedef const T& const_reference; 01504 typedef T* iterator; 01505 typedef const T* const_iterator; 01506 typedef std::reverse_iterator<iterator> reverse_iterator; 01507 typedef std::reverse_iterator<const_iterator> const_reverse_iterator; 01508 typedef typename ArrayIndexTraits<X>::size_type size_type; 01509 typedef typename ArrayIndexTraits<X>::difference_type difference_type; 01510 typedef typename ArrayIndexPackType<size_type>::packed_size_type 01511 packed_size_type; 01512 /*}*/ 01513 01514 //------------------------------------------------------------------------------ 01521 /*{*/ 01522 01524 Array_() : Base() {} 01525 01530 explicit Array_(size_type n) : Base() { 01531 SimTK_SIZECHECK(n, max_size(), "Array_<T>::ctor(n)"); 01532 allocateNoConstruct(n); 01533 defaultConstruct(data(), data()+n); 01534 setSize(n); 01535 } 01536 01540 Array_(size_type n, const T& initVal) : Base() { 01541 SimTK_SIZECHECK(n, max_size(), "Array_<T>::ctor(n,T)"); 01542 setSize(n); 01543 allocateNoConstruct(size()); 01544 fillConstruct(begin(), cend(), initVal); 01545 } 01561 template <class InputIter> 01562 Array_(const InputIter& first, const InputIter& last1) : Base() { 01563 ctorDispatch(first,last1,typename IsIntegralType<InputIter>::Result()); 01564 } 01565 01571 template <class T2> 01572 Array_(const T2* first, const T2* last1) : Base() { 01573 SimTK_ERRCHK((first&&last1)||(first==last1), "Array_<T>(first,last1)", 01574 "Pointers must be non-null unless they are both null."); 01575 SimTK_ERRCHK3(this->isSizeOK(last1-first), "Array_<T>(first,last1)", 01576 "Source has %llu elements but this array is limited to %llu" 01577 " elements by its index type %s.", 01578 this->ull(last1-first), ullMaxSize(), indexName()); 01579 01580 setSize(size_type(last1-first)); 01581 allocateNoConstruct(size()); 01582 copyConstruct(begin(), cend(), first); 01583 } 01584 01589 template <class T2> 01590 explicit Array_(const std::vector<T2>& v) : Base() { 01591 if (v.empty()) return; 01592 01593 SimTK_ERRCHK3(this->isSizeOK(v.size()), "Array_<T>::ctor(std::vector<T2>)", 01594 "The source std::vector's size %llu is too big for this array which" 01595 " is limited to %llu elements by its index type %s.", 01596 this->ull(v.size()), ullMaxSize(), indexName()); 01597 01598 // Call the above constructor, making sure to use pointers into the 01599 // vector's data rather than the iterators begin() and end() in case 01600 // they are different types. 01601 new (this) Array_(&v.front(), (&v.back())+1); 01602 } 01603 01608 Array_(const Array_& src) : Base() { 01609 setSize(src.size()); 01610 allocateNoConstruct(size()); 01611 copyConstruct(begin(), cend(), src.data()); 01612 } 01613 01620 template <class T2, class X2> 01621 Array_(const Array_<T2,X2>& src) : Base() { 01622 new (this) Array_(src.begin(), src.cend()); // see above 01623 } 01624 01654 Array_(T* first, const T* last1, const DontCopy&) : Base(first,last1) {} 01655 01683 template <class A> 01684 Array_(std::vector<T,A>& v, const DontCopy&) : Base(v) {} 01685 01689 ~Array_() { 01690 deallocate(); 01691 } 01692 01701 Array_& deallocate() { 01702 if (allocated()) { // owner with non-zero allocation 01703 clear(); // each element is destructed; size()=0; allocated() unchanged 01704 deallocateNoDestruct(); // free data(); allocated()=0 01705 } 01706 this->Base::disconnect(); // clear the handle 01707 return *this; 01708 } 01709 01713 //------------------------------------------------------------------------------ 01748 01766 void assign(size_type n, const T& fillValue) { 01767 SimTK_ERRCHK3(this->isSizeOK(n), "Array_<T>::assign(n,value)", 01768 "Requested size %llu is too big for this array which is limited" 01769 " to %llu elements by its index type %s.", 01770 this->ull(n), ullMaxSize(), indexName()); 01771 01772 SimTK_ERRCHK2(isOwner() || n==size(), "Array_<T>::assign(n,value)", 01773 "Requested size %llu is not allowed because this is a non-owner" 01774 " array of fixed size %llu.", this->ull(n), this->ull(size())); 01775 01776 if (!isOwner()) 01777 this->Base::fill(fillValue); 01778 else { 01779 clear(); // all elements destructed; allocation unchanged 01780 reallocateIfAdvisable(n); // change size if too small or too big 01781 fillConstruct(data(), cdata()+n, fillValue); 01782 setSize(n); 01783 } 01784 } 01785 01800 void fill(const T& fillValue) {this->Base::fill(fillValue);} 01801 01802 01824 template <class T2> 01825 void assign(const T2* first, const T2* last1) { 01826 const char* methodName = "Array_<T>::assign(T2* first, T2* last1)"; 01827 SimTK_ERRCHK((first&&last1)||(first==last1), methodName, 01828 "Pointers must be non-null unless they are both null."); 01829 SimTK_ERRCHK(!this->overlapsWithData(first,last1), methodName, 01830 "Source range can't overlap the current array contents."); 01831 // Pointers are random access iterators. 01832 assignIteratorDispatch(first,last1,std::random_access_iterator_tag(), 01833 methodName); 01834 } 01835 01836 01872 template <class Iter> 01873 void assign(const Iter& first, const Iter& last1) { 01874 assignDispatch(first,last1,typename IsIntegralType<Iter>::Result(), 01875 "Array_<T>::assign(Iter first, Iter last1)"); 01876 } 01877 01883 Array_& operator=(const Array_& src) { 01884 if (this != &src) 01885 assignIteratorDispatch(src.begin(), src.end(), 01886 std::random_access_iterator_tag(), 01887 "Array_<T>::operator=(Array_<T>)"); 01888 return *this; 01889 } 01890 01896 template <class T2, class X2> 01897 Array_& operator=(const Array_<T2,X2>& src) { 01898 assignIteratorDispatch(src.begin(), src.end(), 01899 std::random_access_iterator_tag(), 01900 "Array_<T>::operator=(Array_<T2,X2>)"); 01901 return *this; 01902 } 01903 01904 01909 template <class T2, class A> 01910 Array_& operator=(const std::vector<T2,A>& src) { 01911 assignIteratorDispatch(src.begin(), src.end(), 01912 std::random_access_iterator_tag(), 01913 "Array_<T>::operator=(std::vector)"); 01914 return *this; 01915 } 01916 01923 void swap(Array_& other) { 01924 T* const pTmp=data(); setData(other.data()); other.setData(pTmp); 01925 size_type nTmp=size(); setSize(other.size()); other.setSize(nTmp); 01926 nTmp=allocated(); setAllocated(other.allocated()); other.setAllocated(nTmp); 01927 } 01928 01934 Array_& adoptData(T* newData, size_type dataSize, 01935 size_type dataCapacity) 01936 { 01937 SimTK_SIZECHECK(dataCapacity, max_size(), "Array_<T>::adoptData()"); 01938 SimTK_ERRCHK2(dataSize <= dataCapacity, "Array_<T>::adoptData()", 01939 "Specified data size %llu was greater than the specified data" 01940 " capacity of %llu.", this->ull(dataSize), this->ull(dataCapacity)); 01941 SimTK_ERRCHK(newData || dataCapacity==0, "Array_<T>::adoptData()", 01942 "A null data pointer is allowed only if the size and capacity are" 01943 " specified as zero."); 01944 SimTK_ERRCHK(!this->overlapsWithData(newData, newData+dataSize), 01945 "Array_<T>::adoptData()", 01946 "The new data can't overlap with the old data."); 01947 01948 deallocate(); 01949 setData(newData); 01950 setSize(dataSize); 01951 setAllocated(dataCapacity); 01952 return *this; 01953 } 01956 Array_& adoptData(T* newData, size_type dataSize) 01957 { return adoptData(newData, dataSize, dataSize); } 01958 01959 01973 Array_& shareData(T* newData, size_type dataSize) { 01974 SimTK_SIZECHECK(dataSize, max_size(), "Array_<T>::shareData()"); 01975 SimTK_ERRCHK(newData || dataSize==0, "Array_<T>::shareData()", 01976 "A null data pointer is allowed only if the size is zero."); 01977 SimTK_ERRCHK(!this->overlapsWithData(newData, newData+dataSize), 01978 "Array_<T>::shareData()", 01979 "The new data can't overlap with the old data."); 01980 01981 deallocate(); 01982 setData(newData); 01983 setSize(dataSize); 01984 setAllocated(0); // indicates shared data 01985 return *this; 01986 } 01987 01990 Array_& shareData(T* first, const T* last1) { 01991 SimTK_ERRCHK3(this->isSizeOK(last1-first), "Array_<T>::shareData(first,last1)", 01992 "Requested size %llu is too big for this array which is limited" 01993 " to %llu elements by its index type %s.", 01994 this->ull(last1-first), ullMaxSize(), indexName()); 01995 return shareData(first, size_type(last1-first)); 01996 } 01997 02001 //------------------------------------------------------------------------------ 02007 02008 // Note: these have to be explicitly forwarded to the base class methods 02009 // in order to keep gcc from complaining. Note that the "this->" is 02010 // apparently necessary in order to permit delayed definition of templatized 02011 // methods. 02012 02014 size_type size() const {return this->CBase::size();} 02016 size_type max_size() const {return this->CBase::max_size();} 02019 bool empty() const {return this->CBase::empty();} 02024 size_type capacity() const {return this->CBase::capacity();} 02025 02030 void resize(size_type n) { 02031 if (n == size()) return; 02032 02033 SimTK_ERRCHK2(isOwner(), "Array_<T>::resize(n)", 02034 "Requested size change to %llu is not allowed because this is a" 02035 " non-owner array of fixed size %llu.", this->ull(n), this->ull(size())); 02036 02037 if (n < size()) { 02038 erase(data()+n, cend()); 02039 return; 02040 } 02041 // n > size() 02042 reserve(n); 02043 defaultConstruct(data()+size(), cdata()+n); // data() has changed 02044 setSize(n); 02045 } 02046 02051 void resize(size_type n, const T& initVal) { 02052 if (n == size()) return; 02053 02054 SimTK_ERRCHK2(isOwner(), "Array_<T>::resize(n,value)", 02055 "Requested size change to %llu is not allowed because this is a" 02056 " non-owner array of fixed size %llu.", this->ull(n), this->ull(size())); 02057 02058 if (n < size()) { 02059 erase(data()+n, cend()); 02060 return; 02061 } 02062 // n > size() 02063 reserve(n); 02064 fillConstruct(data()+size(), cdata()+n, initVal); 02065 setSize(n); 02066 } 02067 02074 void reserve(size_type n) { 02075 if (capacity() >= n) 02076 return; 02077 02078 SimTK_ERRCHK2(isOwner(), "Array_<T>::reserve()", 02079 "Requested capacity change to %llu is not allowed because this is a" 02080 " non-owner array of fixed size %llu.", this->ull(n), this->ull(size())); 02081 02082 T* newData = allocN(n); // no construction yet 02083 copyConstructThenDestructSource(newData, newData+size(), data()); 02084 freeN(data()); 02085 setData(newData); 02086 setAllocated(n); 02087 } 02088 02109 void shrink_to_fit() { 02110 // Allow 25% slop, but note that if size()==0 this will always reallocate 02111 // unless capacity is already zero. 02112 if (capacity() - size()/4 <= size()) // avoid overflow if size() near max 02113 return; 02114 T* newData = allocN(size()); 02115 copyConstructThenDestructSource(newData, newData+size(), data()); 02116 deallocateNoDestruct(); // data()=0, allocated()=0, size() unchanged 02117 setData(newData); 02118 setAllocated(size()); 02119 } 02120 02124 size_type allocated() const {return this->CBase::allocated();} 02130 bool isOwner() const {return this->CBase::isOwner();} 02134 //------------------------------------------------------------------------------ 02143 02148 const T* cbegin() const {return this->CBase::cbegin();} 02150 const T* begin() const {return this->CBase::cbegin();} 02155 T* begin() {return this->Base::begin();} 02156 02161 const T* cend() const {return this->CBase::cend();} 02163 const T* end() const {return this->CBase::cend();} 02168 T* end() {return this->Base::end();} 02169 02172 const_reverse_iterator crbegin() const {return this->CBase::crbegin();} 02174 const_reverse_iterator rbegin() const {return this->CBase::crbegin();} 02177 reverse_iterator rbegin() {return this->Base::rbegin();} 02178 02182 const_reverse_iterator crend() const {return this->CBase::crend();} 02184 const_reverse_iterator rend() const {return this->CBase::crend();} 02188 reverse_iterator rend() {return this->Base::rend();} 02189 02196 const T* cdata() const {return this->CBase::cdata();} 02199 const T* data() const {return this->CBase::cdata();} 02203 T* data() {return this->Base::data();} 02211 02218 const T& operator[](index_type i) const {return this->CBase::operator[](i);} 02219 02227 T& operator[](index_type i) {return this->Base::operator[](i);} 02228 02233 const T& at(index_type i) const {return this->CBase::at(i);} 02234 02239 T& at(index_type i) {return const_cast<T&>(this->Base::at(i));} 02240 02243 const T& getElt(index_type i) const {return this->CBase::getElt(i);} 02246 T& updElt(index_type i) {return this->Base::updElt(i);} 02247 02253 const T& front() const {return this->CBase::front();} 02254 02260 T& front() {return const_cast<T&>(this->Base::front());} 02261 02267 const T& back() const {return this->CBase::back();} 02268 02274 T& back() {return const_cast<T&>(this->Base::back());} 02275 02278 ArrayViewConst_<T,X> operator()(index_type index, size_type length) const 02279 { return CBase::operator()(index,length); } 02282 ArrayViewConst_<T,X> getSubArray(index_type index, size_type length) const 02283 { return CBase::getSubArray(index,length); } 02284 02287 ArrayView_<T,X> operator()(index_type index, size_type length) 02288 { return Base::operator()(index,length); } 02291 ArrayView_<T,X> updSubArray(index_type index, size_type length) 02292 { return Base::updSubArray(index,length); } 02296 //------------------------------------------------------------------------------ 02302 02329 void push_back(const T& value) { 02330 if (pallocated() == psize()) 02331 growAtEnd(1,"Array_<T>::push_back(value)"); 02332 copyConstruct(end(), value); 02333 incrSize(); 02334 } 02335 02349 void push_back() { 02350 if (pallocated() == psize()) 02351 growAtEnd(1,"Array_<T>::push_back()"); 02352 defaultConstruct(end()); 02353 incrSize(); 02354 } 02355 02371 T* raw_push_back() { 02372 if (pallocated() == psize()) 02373 growAtEnd(1,"Array_<T>::raw_push_back()"); 02374 T* const p = end(); 02375 incrSize(); 02376 return p; 02377 } 02378 02381 void pop_back() { 02382 SimTK_ERRCHK(!empty(), "Array_<T>::pop_back()", "Array was empty."); 02383 destruct(&back()); 02384 decrSize(); 02385 } 02386 02404 T* erase(T* first, const T* last1) { 02405 SimTK_ERRCHK(begin() <= first && first <= last1 && last1 <= end(), 02406 "Array<T>::erase(first,last1)", "Pointers out of range or out of order."); 02407 02408 const size_type nErased = size_type(last1-first); 02409 SimTK_ERRCHK(isOwner() || nErased==0, "Array<T>::erase(first,last1)", 02410 "No elements can be erased from a non-owner array."); 02411 02412 if (nErased) { 02413 destruct(first, last1); // Destruct the elements we're erasing. 02414 moveElementsDown(first+nErased, nErased); // Compress followers into the gap. 02415 setSize(size()-nErased); 02416 } 02417 return first; 02418 } 02419 02439 T* erase(T* p) { 02440 SimTK_ERRCHK(begin() <= p && p < end(), 02441 "Array<T>::erase(p)", "Pointer must point to a valid element."); 02442 SimTK_ERRCHK(isOwner(), "Array<T>::erase(p)", 02443 "No elements can be erased from a non-owner array."); 02444 02445 destruct(p); // Destruct the element we're erasing. 02446 moveElementsDown(p+1, 1); // Compress followers into the gap. 02447 decrSize(); 02448 return p; 02449 } 02450 02451 02472 T* eraseFast(T* p) { 02473 SimTK_ERRCHK(begin() <= p && p < end(), 02474 "Array<T>::eraseFast(p)", "Pointer must point to a valid element."); 02475 SimTK_ERRCHK(isOwner(), "Array<T>::eraseFast(p)", 02476 "No elements can be erased from a non-owner array."); 02477 02478 destruct(p); 02479 if (p+1 != end()) 02480 moveOneElement(p, &back()); 02481 decrSize(); 02482 return p; 02483 } 02484 02492 void clear() { 02493 SimTK_ERRCHK(isOwner() || empty(), "Array_<T>::clear()", 02494 "clear() is not allowed for a non-owner array."); 02495 destruct(begin(), end()); 02496 setSize(0); 02497 } 02498 02499 02526 T* insert(T* p, size_type n, const T& value) { 02527 T* const gap = insertGapAt(p, n, "Array<T>::insert(p,n,value)"); 02528 // Copy construct into the inserted elements and note the size change. 02529 fillConstruct(gap, gap+n, value); 02530 setSize(size()+n); 02531 return gap; 02532 } 02533 02538 T* insert(T* p, const T& value) { 02539 T* const gap = insertGapAt(p, 1, "Array<T>::insert(p,value)"); 02540 // Copy construct into the inserted element and note the size change. 02541 copyConstruct(gap, value); 02542 incrSize(); 02543 return gap; 02544 } 02545 02575 template <class T2> 02576 T* insert(T* p, const T2* first, const T2* last1) { 02577 const char* methodName = "Array_<T>::insert(T* p, T2* first, T2* last1)"; 02578 SimTK_ERRCHK((first&&last1) || (first==last1), methodName, 02579 "One of first or last1 was null; either both or neither must be null."); 02580 SimTK_ERRCHK(!this->overlapsWithData(first,last1), methodName, 02581 "Source range can't overlap with the current array contents."); 02582 // Pointers are random access iterators. 02583 return insertIteratorDispatch(p, first, last1, 02584 std::random_access_iterator_tag(), 02585 methodName); 02586 } 02587 02590 template <class Iter> 02591 T* insert(T* p, const Iter& first, const Iter& last1) { 02592 return insertDispatch(p, first, last1, 02593 typename IsIntegralType<Iter>::Result(), 02594 "Array_<T>::insert(T* p, Iter first, Iter last1)"); 02595 } 02600 //------------------------------------------------------------------------------ 02601 private: 02602 //------------------------------------------------------------------------------ 02603 02604 02605 // This method is used when we have already decided we need to make room for 02606 // some new elements by reallocation, by creating a gap somewhere within the 02607 // existing data. We'll issue an error message if this would violate the 02608 // max_size restriction (we can afford to do that even in a Release build since 02609 // we don't expect to grow very often). Otherwise we'll allocate some more space 02610 // and copy construct the existing elements into the new space, leaving a gap 02611 // where indicated. Note that this method does not change the current size but 02612 // does change the capacity. 02613 // 02614 // The gapPos must point within the existing data with null OK if the array 02615 // itself is null, and end() being OK any time although you should use the 02616 // more specialized growAtEnd() method if you know that's what's happening. 02617 // 02618 // Don't call this with a gapSz of zero. 02619 T* growWithGap(T* gapPos, size_type gapSz, const char* methodName) { 02620 assert(gapSz > 0); // <= 0 is a bug, not a user error 02621 02622 // Note that gapPos may be null if begin() and end() are also. 02623 SimTK_ERRCHK(begin() <= gapPos && gapPos <= end(), methodName, 02624 "Given insertion point is not valid for this array."); 02625 02626 // Get some new space of a reasonable size. 02627 setAllocated(calcNewCapacityForGrowthBy(gapSz, methodName)); 02628 T* newData = allocN(allocated()); 02629 02630 // How many elements will be before the gap? 02631 const size_type nBefore = (size_type)(gapPos-begin()); 02632 02633 // Locate the gap in the new space allocation. 02634 T* newGap = newData + nBefore; 02635 T* newGapEnd = newGap + gapSz; // one past the last element in the gap 02636 02637 // Copy elements before insertion point; destruct source as we go. 02638 copyConstructThenDestructSource(newData, newGap, data()); 02639 // Copy/destruct elements at and after insertion pt; leave gapSz gap. 02640 copyConstructThenDestructSource(newGapEnd, newData+size(), gapPos); 02641 02642 // Throw away the old data and switch to the new. 02643 freeN(data()); setData(newData); 02644 return newGap; 02645 } 02646 02647 // Same as growWithGap(end(), n, methodName); see above. 02648 void growAtEnd(size_type n, const char* methodName) { 02649 assert(n > 0); // <= 0 is a bug, not a user error 02650 // Get some new space of a reasonable size. 02651 setAllocated(calcNewCapacityForGrowthBy(n, methodName)); 02652 T* newData = allocN(allocated()); 02653 // Copy all the elements; destruct source as we go. 02654 copyConstructThenDestructSource(newData, newData+size(), data()); 02655 // Throw away the old data and switch to the new. 02656 freeN(data()); setData(newData); 02657 } 02658 02659 // This method determines how much we should increase the array's capacity 02660 // when asked to insert n elements, due to an insertion or push_back. We will 02661 // generally allocate more new space than requested, in anticipation of 02662 // further insertions. This has to be based on the current size so that only 02663 // log(n) reallocations are performed to insert n elements one at a time. Our 02664 // policy here is to at least double the capacity unless that would exceed 02665 // max_size(). There is also a minimum amount of allocation we'll do if the 02666 // current size is zero or very small. 02667 size_type calcNewCapacityForGrowthBy(size_type n, const char* methodName) const { 02668 SimTK_ERRCHK3_ALWAYS(isGrowthOK(n), methodName, 02669 "Can't grow this Array by %llu element(s) because it would" 02670 " then exceed the max_size of %llu set by its index type %s.", 02671 (unsigned long long)n, ullMaxSize(), indexName()); 02672 02673 // At this point we know that capacity()+n <= max_size(). 02674 const size_type mustHave = capacity() + n; 02675 02676 // Be careful not to overflow size_type as you could if you 02677 // double capacity() rather than halving max_size(). 02678 const size_type wantToHave = capacity() <= max_size()/2 02679 ? 2*capacity() 02680 : max_size(); 02681 02682 const size_type newCapacity = std::max(std::max(mustHave,wantToHave), 02683 minAlloc()); 02684 return newCapacity; 02685 } 02686 02687 // Insert an unconstructed gap of size n beginning at position p. The return 02688 // value is a pointer to the first element in the gap. It will be p if no 02689 // reallocation occurred, otherwise it will be pointing into the new data. 02690 // On return size() will be unchanged although allocated() may be bigger. 02691 T* insertGapAt(T* p, size_type n, const char* methodName) { 02692 // Note that p may be null if begin() and end() are also. 02693 SimTK_ERRCHK(begin() <= p && p <= end(), methodName, 02694 "Given insertion point is not valid for this Array."); 02695 02696 if (n==0) return p; // nothing to do 02697 02698 SimTK_ERRCHK_ALWAYS(isOwner(), methodName, 02699 "No elements can be inserted into a non-owner array."); 02700 02701 // Determine the number of elements before the insertion point and 02702 // the number at or afterwards (those must be moved up by one slot). 02703 const size_type before = (size_type)(p-begin()), after = (size_type)(end()-p); 02704 02705 // Grow the container if necessary. Note that if we have to grow we 02706 // can create the gap at the same time we copy the old elements over 02707 // to the new space. 02708 if (capacity() >= size()+n) { 02709 moveElementsUp(p, n); // leave a gap at p 02710 } else { // need to grow 02711 setAllocated(calcNewCapacityForGrowthBy(n, methodName)); 02712 T* newdata = allocN(allocated()); 02713 // Copy the elements before the insertion point, and destroy source. 02714 copyConstructThenDestructSource(newdata, newdata+before, data()); 02715 // Copy the elements at and after the insertion point, leaving a gap 02716 // of n elements. 02717 copyConstructThenDestructSource(newdata+before+n, 02718 newdata+before+n+after, 02719 p); // i.e., pData+before 02720 p = newdata + before; // points into newdata now 02721 freeN(data()); 02722 setData(newdata); 02723 } 02724 02725 return p; 02726 } 02727 02728 //------------------------------------------------------------------------------ 02729 // CTOR DISPATCH 02730 // This is the constructor implementation for when the class that matches 02731 // the alleged InputIterator type turns out to be one of the integral types 02732 // in which case this should be the ctor(n, initValue) constructor. 02733 template <class IntegralType> void 02734 ctorDispatch(IntegralType n, IntegralType v, TrueType isIntegralType) { 02735 new(this) Array_(size_type(n), value_type(v)); 02736 } 02737 02738 // This is the constructor implementation for when the class that matches 02739 // the alleged InputIterator type is NOT an integral type and may very well 02740 // be an iterator. In that case we split into iterators for which we can 02741 // determine the number of elements in advance (forward, bidirectional, 02742 // random access) and input iterators, for which we can't. Note: iterator 02743 // types are arranged hierarchically random->bi->forward->input with each 02744 // deriving from the one on its right, so the forward iterator tag also 02745 // matches bi and random. 02746 template <class InputIterator> void 02747 ctorDispatch(const InputIterator& first, const InputIterator& last1, 02748 FalseType isIntegralType) 02749 { ctorIteratorDispatch(first, last1, 02750 typename std::iterator_traits<InputIterator>::iterator_category()); } 02751 02752 // This is the slow generic ctor implementation for any iterator that can't 02753 // make it up to forward_iterator capability (that is, an input_iterator). 02754 // The issue here is that we can't advance the iterator to count the number 02755 // of elements before allocating because input_iterators are consumed when 02756 // reference so we can't go back to look. That means we may have to reallocate 02757 // memory log n times as we "push back" these elements onto the array. 02758 template <class InputIterator> void 02759 ctorIteratorDispatch(const InputIterator& first, const InputIterator& last1, 02760 std::input_iterator_tag) 02761 { 02762 InputIterator src = first; 02763 while (src != last1) { 02764 // We can afford to check this always since we are probably doing I/O. 02765 // Throwing an exception in a constructor is tricky, though -- this 02766 // won't go through the Array_ destructor although it will call the 02767 // Base (ArrayView_) destructor. Since we have already allocated 02768 // some space, we must call deallocate() manually. 02769 if (size() == max_size()) { 02770 deallocate(); 02771 SimTK_ERRCHK2_ALWAYS(!"too many elements", 02772 "Array_::ctor(InputIterator first, InputIterator last1)", 02773 "There were still source elements available when the array" 02774 " reached its maximum size of %llu as determined by its index" 02775 " type %s.", ullMaxSize(), indexName()); 02776 } 02777 push_back(*src++); 02778 } 02779 } 02780 02781 // This is the faster constructor implementation for iterator types for which 02782 // we can calculate the number of elements in advance. This will be optimal 02783 // for a random access iterator since we can count in constant time, but for 02784 // forward or bidirectional we'll have to advance n times to count and then 02785 // go back again to do the copy constructions. 02786 template <class ForwardIterator> void 02787 ctorIteratorDispatch(const ForwardIterator& first, const ForwardIterator& last1, 02788 std::forward_iterator_tag) 02789 { 02790 typedef typename std::iterator_traits<ForwardIterator>::difference_type 02791 difference_type; 02792 // iterDistance() is constant time for random access iterators, but 02793 // O(last1-first) for forward and bidirectional since it has to increment 02794 // to count how far apart they are. 02795 const difference_type nInput = this->iterDistance(first,last1); 02796 02797 SimTK_ERRCHK(nInput >= 0, 02798 "Array_(ForwardIterator first, ForwardIterator last1)", 02799 "Iterators were out of order."); 02800 02801 SimTK_ERRCHK3(this->isSizeOK(nInput), 02802 "Array_(ForwardIterator first, ForwardIterator last1)", 02803 "Source has %llu elements but this array is limited to %llu" 02804 " elements by its index type %s.", 02805 this->ull(nInput), ullMaxSize(), indexName()); 02806 02807 const size_type n = size_type(nInput); 02808 setSize(n); 02809 allocateNoConstruct(n); 02810 copyConstruct(data(), data()+n, first); 02811 } 02812 02813 //------------------------------------------------------------------------------ 02814 // INSERT DISPATCH 02815 // This is the insert() implementation for when the class that matches 02816 // the alleged InputIterator type turns out to be one of the integral types 02817 // in which case this should be the insert(p, n, initValue) constructor. 02818 template <class IntegralType> 02819 T* insertDispatch(T* p, IntegralType n, IntegralType v, 02820 TrueType isIntegralType, const char*) 02821 { return insert(p, size_type(n), value_type(v)); } 02822 02823 // This is the insert() implementation for when the class that matches 02824 // the alleged InputIterator type is NOT an integral type and may very well 02825 // be an iterator. See ctorDispatch() above for more information. 02826 template <class InputIterator> 02827 T* insertDispatch(T* p, const InputIterator& first, const InputIterator& last1, 02828 FalseType isIntegralType, const char* methodName) 02829 { return insertIteratorDispatch(p, first, last1, 02830 typename std::iterator_traits<InputIterator>::iterator_category(), 02831 methodName); } 02832 02833 // This is the slow generic insert implementation for any iterator that can't 02834 // make it up to forward_iterator capability (that is, an input_iterator). 02835 // See ctorIteratorDispatch() above for more information. 02836 template <class InputIterator> 02837 T* insertIteratorDispatch(T* p, InputIterator first, InputIterator last1, 02838 std::input_iterator_tag, const char* methodName) 02839 { 02840 size_type nInserted = 0; 02841 while (first != last1) { 02842 // We can afford to check this always since we are probably doing I/O. 02843 SimTK_ERRCHK2_ALWAYS(size() < max_size(), methodName, 02844 "There were still source elements available when the array" 02845 " reached its maximum size of %llu as determined by its index" 02846 " type %s.", ullMaxSize(), indexName()); 02847 p = insert(p, *first++); // p may now point to reallocated memory 02848 ++p; ++nInserted; 02849 } 02850 // p now points just after the last inserted element; subtract the 02851 // number inserted to get a pointer to the first inserted element. 02852 return p-nInserted; 02853 } 02854 02855 // This is the faster constructor implementation for iterator types for which 02856 // we can calculate the number of elements in advance. This will be optimal 02857 // for a random access iterator since we can count in constant time, but for 02858 // forward or bidirectional we'll have to advance n times to count and then 02859 // go back again to do the copy constructions. 02860 template <class ForwardIterator> 02861 T* insertIteratorDispatch(T* p, const ForwardIterator& first, 02862 const ForwardIterator& last1, 02863 std::forward_iterator_tag, 02864 const char* methodName) 02865 { 02866 typedef typename std::iterator_traits<ForwardIterator>::difference_type 02867 difference_type; 02868 // iterDistance() is constant time for random access iterators, but 02869 // O(last1-first) for forward and bidirectional since it has to increment 02870 // to count how far apart they are. 02871 const difference_type nInput = this->iterDistance(first,last1); 02872 02873 SimTK_ERRCHK(nInput >= 0, methodName, "Iterators were out of order."); 02874 02875 SimTK_ERRCHK3(isGrowthOK(nInput), methodName, 02876 "Source has %llu elements which would make this array exceed the %llu" 02877 " elements allowed by its index type %s.", 02878 this->ull(nInput), ullMaxSize(), indexName()); 02879 02880 const size_type n = size_type(nInput); 02881 p = insertGapAt(p, n, methodName); 02882 copyConstruct(p, p+n, first); 02883 setSize(size()+n); 02884 return p; 02885 } 02886 02887 //------------------------------------------------------------------------------ 02888 // ASSIGN DISPATCH 02889 // This is the assign() implementation for when the class that matches 02890 // the alleged InputIterator type turns out to be one of the integral types 02891 // in which case this should be the assign(n, initValue) constructor. 02892 template <class IntegralType> 02893 void assignDispatch(IntegralType n, IntegralType v, TrueType isIntegralType, 02894 const char* methodName) 02895 { assign(size_type(n), value_type(v)); } 02896 02897 // This is the assign() implementation for when the class that matches 02898 // the alleged InputIterator type is NOT an integral type and may very well 02899 // be an iterator. See ctorDispatch() above for more information. 02900 template <class InputIterator> 02901 void assignDispatch(const InputIterator& first, const InputIterator& last1, 02902 FalseType isIntegralType, const char* methodName) 02903 { assignIteratorDispatch(first, last1, 02904 typename std::iterator_traits<InputIterator>::iterator_category(), 02905 methodName); } 02906 02907 // This is the slow generic implementation for a plain input_iterator 02908 // (i.e., not a forward, bidirectional, or random access iterator). These 02909 // have the unfortunate property that we can't count the elements in advance. 02910 template <class InputIterator> 02911 void assignIteratorDispatch(const InputIterator& first, 02912 const InputIterator& last1, 02913 std::input_iterator_tag, 02914 const char* methodName) 02915 { 02916 // TODO: should probably allow this and just blow up when the size()+1st 02917 // element is seen. 02918 SimTK_ERRCHK_ALWAYS(isOwner(), methodName, 02919 "Assignment to a non-owner array can only be done from a source" 02920 " designated with forward iterators or pointers because we" 02921 " must be able to verify that the source and destination sizes" 02922 " are the same."); 02923 02924 clear(); // TODO: change space allocation here? 02925 InputIterator src = first; 02926 while (src != last1) { 02927 // We can afford to check this always since we are probably doing I/O. 02928 SimTK_ERRCHK2_ALWAYS(size() < max_size(), methodName, 02929 "There were still source elements available when the array" 02930 " reached its maximum size of %llu as determined by its index" 02931 " type %s.", ullMaxSize(), indexName()); 02932 02933 push_back(*src++); 02934 } 02935 } 02936 02937 // This is the faster implementation that works for forward, bidirectional, 02938 // and random access iterators including ordinary pointers. We can check here that the 02939 // iterators are in the right order, and that the source is not too big to 02940 // fit in this array. Null pointer checks should be done prior to calling, 02941 // however, since iterators in general aren't pointers. 02942 template <class ForwardIterator> 02943 void assignIteratorDispatch(const ForwardIterator& first, 02944 const ForwardIterator& last1, 02945 std::forward_iterator_tag, 02946 const char* methodName) 02947 { 02948 typedef typename std::iterator_traits<ForwardIterator>::difference_type 02949 IterDiffType; 02950 // iterDistance() is constant time for random access iterators, but 02951 // O(last1-first) for forward and bidirectional since it has to increment 02952 // to count how far apart they are. 02953 const IterDiffType nInput = this->iterDistance(first,last1); 02954 02955 SimTK_ERRCHK(nInput >= 0, methodName, "Iterators were out of order."); 02956 02957 SimTK_ERRCHK3(this->isSizeOK(nInput), methodName, 02958 "Source has %llu elements but this Array is limited to %llu" 02959 " elements by its index type %s.", 02960 this->ull(nInput), ullMaxSize(), indexName()); 02961 02962 const size_type n = size_type(nInput); 02963 if (isOwner()) { 02964 // This is an owner Array; assignment is considered deallocation 02965 // followed by copy construction. 02966 02967 clear(); // all elements destructed; allocation unchanged 02968 reallocateIfAdvisable(n); // change allocation if too small or too big 02969 copyConstruct(data(), cdata()+n, first); 02970 setSize(n); 02971 } else { 02972 // This is a non-owner Array. Assignment can occur only if the 02973 // source is the same size as the array, and the semantics are of 02974 // repeated assignment using T::operator=() not destruction followed 02975 // by copy construction. 02976 SimTK_ERRCHK2(n == size(), methodName, 02977 "Source has %llu elements which does not match the size %llu" 02978 " of the non-owner array it is being assigned into.", 02979 this->ull(n), ullSize()); 02980 02981 T* p = begin(); 02982 ForwardIterator src = first; 02983 while (src != last1) 02984 *p++ = *src++; // call T's assignment operator 02985 } 02986 } 02987 02988 // We are going to put a total of n elements into the Array (probably 02989 // because of an assignment or resize) and we want the space allocation 02990 // to be reasonable. That means of course that the allocation must be 02991 // *at least* n, but we also don't want it to be too big. Our policy 02992 // here is that if it is currently less than twice what we need we 02993 // won't reallocate, otherwise we'll shrink the space. When changing 02994 // the size to zero or something very small we'll treat the Array as 02995 // though its current size is minAlloc, meaning we won't reallocate 02996 // if the existing space is less than twice minAlloc. 02997 // nAllocated will be set appropriately; size() is not touched here. 02998 // No constructors or destructors are called. 02999 void reallocateIfAdvisable(size_type n) { 03000 if (allocated() < n || allocated()/2 > std::max(minAlloc(), n)) 03001 reallocateNoDestructOrConstruct(n); 03002 } 03003 03004 03005 void allocateNoConstruct(size_type n) 03006 { setData(allocN(n)); setAllocated(n); } // size() left unchanged 03007 void deallocateNoDestruct() 03008 { freeN(data()); setData(0); setAllocated(0); } // size() left unchanged 03009 void reallocateNoDestructOrConstruct(size_type n) 03010 { deallocateNoDestruct(); allocateNoConstruct(n); } 03011 03012 // This sets the smallest allocation we'll do when growing. 03013 size_type minAlloc() const 03014 { return std::min(max_size(), size_type(4)); } 03015 03016 // Allocate without construction. Returns a null pointer if asked 03017 // to allocate 0 elements. In Debug mode we'll fill memory with 03018 // all 1's as a bug catcher. 03019 static T* allocN(size_type n) { 03020 if (n==0) return 0; 03021 unsigned char* newdata = new unsigned char[n * sizeof(T)]; 03022 #ifndef NDEBUG 03023 unsigned char* b=newdata; 03024 const unsigned char* e=newdata+(n*sizeof(T)); 03025 while (b != e) *b++ = 0xff; 03026 #endif 03027 return reinterpret_cast<T*>(newdata); 03028 } 03029 03030 // Free memory without calling T's destructor. Nothing happens if passed 03031 // a null pointer. 03032 static void freeN(T* p) { 03033 delete[] reinterpret_cast<char*>(p); 03034 } 03035 03036 // default construct one element 03037 static void defaultConstruct(T* p) {new(p) T();} 03038 // default construct range [b,e) 03039 static void defaultConstruct(T* b, const T* e) 03040 { while (b!=e) new(b++) T(); } 03041 03042 // copy construct range [b,e) with repeats of a given value 03043 static void fillConstruct(T* b, const T* e, const T& v) 03044 { while(b!=e) new(b++) T(v); } 03045 03046 // copy construct one element from a given value 03047 static void copyConstruct(T* p, const T& v) {new(p) T(v);} 03048 // copy construct range [b,e) from sequence of source values 03049 static void copyConstruct(T* b, const T* e, T* src) 03050 { while(b!=e) new(b++) T(*src++); } 03051 // Templatized copy construct will work if the source elements are 03052 // assignment compatible with the destination elements. 03053 template <class InputIterator> 03054 static void copyConstruct(T* b, const T* e, InputIterator src) 03055 { while(b!=e) new(b++) T(*src++); } 03056 03057 // Copy construct range [b,e] from sequence of source values and 03058 // destruct the source after it is copied. It's better to alternate 03059 // copying and destructing than to do this in two passes since we 03060 // will already have touched the memory. 03061 static void copyConstructThenDestructSource(T* b, const T* e, T* src) 03062 { while(b!=e) {new(b++) T(*src); src++->~T();} } 03063 03064 // We have an element at from that we would like to move into the currently- 03065 // unconstructed slot at to. Both from and to are expected to be pointing to 03066 // elements within the currently allocated space. From's slot will be left 03067 // unconstructed. 03068 void moveOneElement(T* to, T* from) { 03069 assert(data() <= to && to < data()+allocated()); 03070 assert(data() <= from && from < data()+allocated()); 03071 copyConstruct(to, *from); 03072 destruct(from); 03073 } 03074 03075 03076 // Move elements from p to end() down by n>0 places to fill an unconstructed 03077 // gap beginning at p-n. Any leftover space at the end will be unconstructed. 03078 void moveElementsDown(T* p, size_type n) { 03079 assert(n > 0); 03080 for (; p != end(); ++p) 03081 moveOneElement(p-n,p); 03082 } 03083 03084 // Move elements from p to end() up by n>0 places to make an unconstructed gap 03085 // at [p,p+n). Note that this has to be done backwards so that we don't 03086 // write on any elements until after they've been copied. 03087 void moveElementsUp(T* p, size_type n) { 03088 assert(n > 0); 03089 T* src = end(); // points one past source element (begin()-1 not allowed) 03090 while (src != p) { 03091 --src; // now points to source 03092 moveOneElement(src+n, src);; 03093 } 03094 } 03095 03096 // destruct one element 03097 static void destruct(T* p) {p->~T();} 03098 // destruct range [b,e) 03099 static void destruct(T* b, const T* e) 03100 { while(b!=e) b++->~T(); } 03101 03102 // Check that growing this array by n elements wouldn't cause it to exceed 03103 // its allowable maximum size. 03104 template <class S> 03105 bool isGrowthOK(S n) const 03106 { return this->isSizeOK(ullCapacity() + this->ull(n)); } 03107 03108 // The following private methods are protected methods in the ArrayView base 03109 // class, so they should not need repeating here. Howevr, we explicitly 03110 // forward to the Base methods to avoid gcc errors. The gcc complaint 03111 // is due to their not depending on any template parameters; the "this->" 03112 // apparently fixes that problem. 03113 03114 // These provide direct access to the data members. 03115 packed_size_type psize() const {return this->CBase::psize();} 03116 packed_size_type pallocated() const {return this->CBase::pallocated();} 03117 03118 void setData(const T* p) {this->CBase::setData(p);} 03119 void setSize(size_type n) {this->CBase::setSize(n);} 03120 void incrSize() {this->CBase::incrSize();} 03121 void decrSize() {this->CBase::decrSize();} 03122 void setAllocated(size_type n) {this->CBase::setAllocated(n);} 03123 // This just cast sizes to unsigned long long so that we can do comparisons 03124 // without getting warnings. 03125 unsigned long long ullSize() const {return this->CBase::ullSize();} 03126 unsigned long long ullCapacity() const {return this->CBase::ullCapacity();} 03127 unsigned long long ullMaxSize() const {return this->CBase::ullMaxSize();} 03128 // This is the index type name and is handy for error messages to explain 03129 // why some size was too big. 03130 const char* indexName() const {return this->CBase::indexName();} 03131 }; 03132 03133 03134 // This "private" static method is used to implement ArrayView's 03135 // fillArrayViewFromStream() and Array's readArrayFromStream() namespace-scope 03136 // static methods, which are in turn used to implement ArrayView's and 03137 // Array's stream extraction operators ">>". This method has to be in the 03138 // header file so that we don't need to pass streams through the API, but it 03139 // is not intended for use by users and has no Doxygen presence, unlike 03140 // fillArrayFromStream() and readArrayFromStream() and (more commonly) 03141 // the extraction operators. 03142 template <class T, class X> static inline 03143 std::istream& readArrayFromStreamHelper 03144 (std::istream& in, bool isFixedSize, Array_<T,X>& out) 03145 { 03146 // If already failed, bad, or eof, set failed bit and return without 03147 // touching the Array. 03148 if (!in.good()) {in.setstate(std::ios::failbit); return in;} 03149 03150 // If the passed-in Array isn't an owner, then we have to treat it as 03151 // a fixed size ArrayView regardless of the setting of the isFixedSize 03152 // argument. 03153 if (!out.isOwner()) 03154 isFixedSize = true; // might be overriding the argument here 03155 03156 // numRequired will be ignored unless isFixedSize==true. 03157 const typename Array_<T,X>::size_type 03158 numRequired = isFixedSize ? out.size() : 0; 03159 03160 if (!isFixedSize) 03161 out.clear(); // We're going to replace the entire contents of the Array. 03162 03163 // Skip initial whitespace. If that results in eof this may be a successful 03164 // read of a 0-length, unbracketed Array. That is OK for either a 03165 // variable-length Array or a fixed-length ArrayView of length zero. 03166 std::ws(in); if (in.fail()) return in; 03167 if (in.eof()) { 03168 if (isFixedSize && numRequired != 0) 03169 in.setstate(std::ios_base::failbit); // zero elements not OK 03170 return in; 03171 } 03172 03173 // Here the stream is good and the next character is non-white. 03174 assert(in.good()); 03175 03176 // Use this for raw i/o (peeks and gets). 03177 typename std::iostream::int_type ch; 03178 const typename std::iostream::int_type EOFch = 03179 std::iostream::traits_type::eof(); 03180 03181 // Now see if the sequence is bare or surrounded by (), [], or {}. 03182 bool lookForCloser = true; 03183 char openBracket, closeBracket; 03184 ch = in.peek(); if (in.fail()) return in; 03185 assert(ch != EOFch); // we already checked above 03186 03187 openBracket = (char)ch; 03188 if (openBracket=='(') {in.get(); closeBracket = ')';} 03189 else if (openBracket=='[') {in.get(); closeBracket = ']';} 03190 else if (openBracket=='{') {in.get(); closeBracket = '}';} 03191 else lookForCloser = false; 03192 03193 // If lookForCloser is true, then closeBracket contains the terminating 03194 // delimiter, otherwise we're not going to quit until eof. 03195 03196 // Eat whitespace after the opening bracket to see what's next. 03197 if (in.good()) std::ws(in); 03198 03199 // If we're at eof now it must be because the open bracket was the 03200 // last non-white character in the stream, which is an error. 03201 if (!in.good()) { 03202 if (in.eof()) { 03203 assert(lookForCloser); // or we haven't read anything that could eof 03204 in.setstate(std::ios::failbit); 03205 } 03206 return in; 03207 } 03208 03209 // istream is good and next character is non-white; ready to read first 03210 // value or terminator. 03211 03212 // We need to figure out whether the elements are space- or comma- 03213 // separated and then insist on consistency. 03214 bool commaOK = true, commaRequired = false; 03215 bool terminatorSeen = false; 03216 X nextIndex(0); 03217 while (true) { 03218 char c; 03219 03220 // Here at the top of this loop, we have already successfully read 03221 // n=nextIndex values of type T. For fixed-size reads, it might be 03222 // the case that n==numRequired already, but we still may need to 03223 // look for a closing bracket before we can declare victory. 03224 // The stream is good() (not at eof) but it might be the case that 03225 // there is nothing but white space left; we don't know yet because 03226 // if we have satisfied the fixed-size count and are not expecting 03227 // a terminator then we should quit without absorbing the trailing 03228 // white space. 03229 assert(in.good()); 03230 03231 // Look for closing bracket before trying to read value. 03232 if (lookForCloser) { 03233 // Eat white space to find the closing bracket. 03234 std::ws(in); if (!in.good()) break; // eof? 03235 ch = in.peek(); assert(ch != EOFch); 03236 if (!in.good()) break; 03237 c = (char)ch; 03238 if (c == closeBracket) { 03239 in.get(); // absorb the closing bracket 03240 terminatorSeen = true; 03241 break; 03242 } 03243 // next char not a closing bracket; fall through 03244 } 03245 03246 // We didn't look or didn't find a closing bracket. The istream is good 03247 // but we might be looking at white space. 03248 03249 // If we already got all the elements we want, break for final checks. 03250 if (isFixedSize && (nextIndex == numRequired)) 03251 break; // that's a full count. 03252 03253 // Look for comma before value, except the first time. 03254 if (commaOK && nextIndex != 0) { 03255 // Eat white space to find the comma. 03256 std::ws(in); if (!in.good()) break; // eof? 03257 ch = in.peek(); assert(ch != EOFch); 03258 if (!in.good()) break; 03259 c = (char)ch; 03260 if (c == ',') { 03261 in.get(); // absorb comma 03262 commaRequired = true; // all commas from now on 03263 } else { // next char not a comma 03264 if (commaRequired) // bad, e.g.: v1, v2, v3 v4 03265 { in.setstate(std::ios::failbit); break; } 03266 else commaOK = false; // saw: v1 v2 (no commas now) 03267 } 03268 if (!in.good()) break; // might be eof 03269 } 03270 03271 // No closing bracket yet; don't have enough elements; skipped comma 03272 // if any; istream is good; might be looking at white space. 03273 assert(in.good()); 03274 03275 // Now read in an element of type T. 03276 // The extractor T::operator>>() will ignore leading white space. 03277 if (!isFixedSize) 03278 out.push_back(); // grow by one (default consructed) 03279 in >> out[nextIndex]; if (in.fail()) break; 03280 ++nextIndex; 03281 03282 if (!in.good()) break; // might be eof 03283 } 03284 03285 // We will get here under a number of circumstances: 03286 // - the fail bit is set in the istream, or 03287 // - we reached eof 03288 // - we saw a closing brace 03289 // - we got all the elements we wanted (for a fixed-size read) 03290 // Note that it is possible that we consumed everything except some 03291 // trailing white space (meaning we're not technically at eof), but 03292 // for consistency with built-in operator>>()'s we won't try to absorb 03293 // that trailing white space. 03294 03295 if (!in.fail()) { 03296 if (lookForCloser && !terminatorSeen) 03297 in.setstate(std::ios::failbit); // missing terminator 03298 03299 if (isFixedSize && nextIndex != numRequired) 03300 in.setstate(std::ios::failbit); // wrong number of values 03301 } 03302 03303 return in; 03304 } 03305 03306 03307 03308 //------------------------------------------------------------------------------ 03309 // RELATED GLOBAL OPERATORS 03310 //------------------------------------------------------------------------------ 03311 // These are logically part of the Array_<T,X> class but are not actually 03312 // class members; that is, they are in the SimTK namespace. 03313 03314 // Some of the serialization methods could have been member functions but 03315 // then an attempt to explicitly instantiate the whole Array_<T> class for 03316 // some type T would fail if T did not support the requisite I/O operations 03317 // even if those operations were never used. This came up when Chris Bruns was 03318 // trying to wrap Array objects for Python, which requires explicit 03319 // instantiation. 03320 03328 03332 template <class T, class X> inline void 03333 writeUnformatted(std::ostream& o, const Array_<T,X>& v) { 03334 for (X i(0); i < v.size(); ++i) { 03335 if (i != 0) o << " "; 03336 writeUnformatted(o, v[i]); 03337 } 03338 } 03339 03340 03344 template <class T, class X> inline void 03345 writeFormatted(std::ostream& o, const Array_<T,X>& v) { 03346 o << '('; 03347 for (X i(0); i < v.size(); ++i) { 03348 if (i != 0) o << ','; 03349 writeFormatted(o, v[i]); 03350 } 03351 o << ')'; 03352 } 03353 03360 template <class T, class X> inline 03361 std::ostream& 03362 operator<<(std::ostream& o, 03363 const ArrayViewConst_<T,X>& a) 03364 { 03365 o << '('; 03366 if (!a.empty()) { 03367 o << a.front(); 03368 for (const T* p = a.begin()+1; p != a.end(); ++p) 03369 o << ',' << *p; 03370 } 03371 return o << ')'; 03372 } 03373 03374 03378 template <class T, class X> inline bool 03379 readUnformatted(std::istream& in, Array_<T,X>& v) { 03380 v.clear(); 03381 T element; 03382 std::ws(in); // Make sure we're at eof if stream is all whitespace. 03383 while (!in.eof() && readUnformatted(in, element)) 03384 v.push_back(element); 03385 return !in.fail(); // eof is expected and ok 03386 } 03387 03392 template <class T, class X> inline bool 03393 readUnformatted(std::istream& in, ArrayView_<T,X>& v) { 03394 for (X i(0); i < v.size(); ++i) 03395 if (!readUnformatted(in, v[i])) return false; 03396 return true; 03397 } 03398 03399 03405 template <class T, class X> inline bool 03406 readFormatted(std::istream& in, Array_<T,X>& v) { 03407 return !readArrayFromStream(in,v).fail(); 03408 } 03409 03415 template <class T, class X> inline bool 03416 readFormatted(std::istream& in, ArrayView_<T,X>& v) { 03417 return !fillArrayViewFromStream(in,v).fail(); 03418 } 03419 03449 template <class T, class X> static inline 03450 std::istream& readArrayFromStream(std::istream& in, Array_<T,X>& out) 03451 { return readArrayFromStreamHelper<T,X>(in, false /*variable sizez*/, out); } 03452 03453 03454 03479 template <class T, class X> static inline 03480 std::istream& fillArrayFromStream(std::istream& in, Array_<T,X>& out) 03481 { return readArrayFromStreamHelper<T,X>(in, true /*fixed size*/, out); } 03482 03487 template <class T, class X> static inline 03488 std::istream& fillArrayViewFromStream(std::istream& in, ArrayView_<T,X>& out) 03489 { return readArrayFromStreamHelper<T,X>(in, true /*fixed size*/, out); } 03490 03491 03492 03493 03503 template <class T, class X> inline 03504 std::istream& operator>>(std::istream& in, Array_<T,X>& out) 03505 { return readArrayFromStream<T,X>(in, out); } 03506 03514 template <class T, class X> inline 03515 std::istream& operator>>(std::istream& in, ArrayView_<T,X>& out) 03516 { return fillArrayViewFromStream<T,X>(in, out); } 03517 03527 03530 template <class T1, class X1, class T2, class X2> inline bool 03531 operator==(const ArrayViewConst_<T1,X1>& a1, const ArrayViewConst_<T2,X2>& a2) { 03532 // Avoid warnings in size comparison by using common type. 03533 const ptrdiff_t sz1 = a1.end()-a1.begin(); 03534 const ptrdiff_t sz2 = a2.end()-a2.begin(); 03535 if (sz1 != sz2) return false; 03536 const T1* p1 = a1.begin(); 03537 const T2* p2 = a2.begin(); 03538 while (p1 != a1.end()) 03539 if (!(*p1++ == *p2++)) return false; 03540 return true; 03541 } 03544 template <class T1, class X1, class T2, class X2> inline bool 03545 operator!=(const ArrayViewConst_<T1,X1>& a1, const ArrayViewConst_<T2,X2>& a2) 03546 { return !(a1 == a2); } 03547 03552 template <class T1, class X1, class T2, class X2> inline bool 03553 operator<(const ArrayViewConst_<T1,X1>& a1, const ArrayViewConst_<T2,X2>& a2) { 03554 const T1* p1 = a1.begin(); 03555 const T2* p2 = a2.begin(); 03556 while (p1 != a1.end() && p2 != a2.end()) { 03557 if (!(*p1 == *p2)) 03558 return *p1 < *p2; // otherwise p1 > p2 03559 ++p1; ++p2; 03560 } 03561 // All elements were equal until one or both arrays ran out of elements. 03562 // a1 is less than a2 only if a1 ran out and a2 didn't. 03563 return p1 == a1.end() && p2 != a2.end(); 03564 } 03567 template <class T1, class X1, class T2, class X2> inline bool 03568 operator>=(const ArrayViewConst_<T1,X1>& a1, const ArrayViewConst_<T2,X2>& a2) 03569 { return !(a1 < a2); } 03573 template <class T1, class X1, class T2, class X2> inline bool 03574 operator>(const ArrayViewConst_<T1,X1>& a1, const ArrayViewConst_<T2,X2>& a2) 03575 { return a2 < a1; } 03578 template <class T1, class X1, class T2, class X2> inline bool 03579 operator<=(const ArrayViewConst_<T1,X1>& a1, const ArrayViewConst_<T2,X2>& a2) 03580 { return !(a1 > a2); } 03581 03585 template <class T1, class X1, class T2, class A2> inline bool 03586 operator==(const ArrayViewConst_<T1,X1>& a1, const std::vector<T2,A2>& v2) 03587 { return a1 == ArrayViewConst_<T2,size_t>(v2); } 03588 03592 template <class T1, class A1, class T2, class X2> inline bool 03593 operator==(const std::vector<T1,A1>& v1, const ArrayViewConst_<T2,X2>& a2) 03594 { return a2 == v1; } 03595 03598 template <class T1, class X1, class T2, class A2> inline bool 03599 operator!=(const ArrayViewConst_<T1,X1>& a1, const std::vector<T2,A2>& v2) 03600 { return !(a1 == v2); } 03603 template <class T1, class A1, class T2, class X2> inline bool 03604 operator!=(const std::vector<T1,A1>& v1, const ArrayViewConst_<T2,X2>& a2) 03605 { return !(a2 == v1); } 03606 03612 template <class T1, class X1, class T2, class A2> inline bool 03613 operator<(const ArrayViewConst_<T1,X1>& a1, const std::vector<T2,A2>& v2) 03614 { return a1 < ArrayViewConst_<T2,size_t>(v2); } 03615 03621 template <class T1, class A1, class T2, class X2> inline bool 03622 operator<(const std::vector<T1,A1>& v1, const ArrayViewConst_<T2,X2>& a2) 03623 { return ArrayViewConst_<T1,size_t>(v1) < a2; } 03624 03627 template <class T1, class X1, class T2, class A2> inline bool 03628 operator>=(const ArrayViewConst_<T1,X1>& a1, const std::vector<T2,A2>& v2) 03629 { return !(a1 < v2); } 03632 template <class T1, class A1, class T2, class X2> inline bool 03633 operator>=(const std::vector<T1,A1>& v1, const ArrayViewConst_<T2,X2>& a2) 03634 { return !(v1 < a2); } 03635 03639 template <class T1, class X1, class T2, class A2> inline bool 03640 operator>(const ArrayViewConst_<T1,X1>& a1, const std::vector<T2,A2>& v2) 03641 { return v2 < a1; } 03645 template <class T1, class A1, class T2, class X2> inline bool 03646 operator>(const std::vector<T1,A1>& v1, const ArrayViewConst_<T2,X2>& a2) 03647 { return a2 < v1; } 03648 03651 template <class T1, class X1, class T2, class A2> inline bool 03652 operator<=(const ArrayViewConst_<T1,X1>& a1, const std::vector<T2,A2>& v2) 03653 { return !(a1 > v2); } 03656 template <class T1, class A1, class T2, class X2> inline bool 03657 operator<=(const std::vector<T1,A1>& v1, const ArrayViewConst_<T2,X2>& a2) 03658 { return !(v1 > a2); } 03659 03662 } // namespace SimTK 03663 03664 namespace std { 03668 template <class T, class X> inline void 03669 swap(SimTK::Array_<T,X>& a1, SimTK::Array_<T,X>& a2) { 03670 a1.swap(a2); 03671 } 03672 03673 } // namespace std 03674 03675 #endif // SimTK_SimTKCOMMON_ARRAY_H_