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