/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2016, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Teigha(R) software pursuant to a license // agreement with Open Design Alliance. // Teigha(R) Copyright (C) 2002-2016 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// #ifndef OdVector_H_INCLUDED #define OdVector_H_INCLUDED #include #include "TD_PackPush.h" #include "OdArrayMemAlloc.h" #include "OdAlloc.h" template , class Mm = OdrxMemoryManager> class OdVector; /** \details This template class implements dynamic Array objects within Teigha. \remarks Methods are provided to access Array elements via both array indices and array pointers (iterators). Some definitions are in order: 1. Logical Length or Size -- The number of entries in the array. Initially zero. 2. Physical Length -- The maximum Logical Length of the array before it automatically grows. 3. Grow Length -- The number of entries by which the Physical Length will grow as required. \sa Db */ template class OdVector { public: typedef typename A::size_type size_type; typedef T* iterator; typedef const T* const_iterator; // compatibility with OdArray typedef T value_type; typedef const T& const_reference; typedef T& reference; private: static T* allocate(size_type physicalLength); void release(); void reallocate(size_type physicalLength, bool isUseRealloc = false, bool isForcePhysicalLength = false); bool isValid(size_type index) const; void assertValid(size_type index) const; static void riseError(OdResult res); const_iterator begin_const() const; iterator begin_non_const(); const_iterator end_const() const; iterator end_non_const(); public: /** \param physicalLength [in] Initial physical length. \param growLength [in] Initial grow length. */ explicit OdVector(size_type physicalLength, int growLength = 8); OdVector(); OdVector(const OdVector& vec); ~OdVector(); OdVector& operator=(const OdVector& vec); /** \details Returns an iterator that references the first element in this Array object. */ iterator begin(); const_iterator begin() const; iterator end(); const_iterator end() const; /** \details Inserts an element, number of elements, or range of elements, into this Array object. \param before [in] Position where first element is to be inserted. \param first [in] Position of first element to be inserted. \param afterLast [in] Position of first element after the last element to be inserted. \remarks The range of elements may be from another Array object. */ void insert(iterator before, const_iterator first, const_iterator afterLast); /** \param numElem [in] Number of elements to insert. \param value [in] Value to insert. */ iterator insert(iterator before, size_type numElem, const T& value); iterator insert(iterator before, const T& value = T()); /** \details Inserts the specified value into this Array object at the specified index. \param index [in] Array index. \param value [in] Value to insert. \remarks 0 <= index <= length() Elements starting at index will have their indices incremented. Returns a reference to this Array object. */ OdVector& insertAt(size_type index, const T& value); /** \details Removes the element at the specified index from this Array object. \param index [in] Array index. \remarks 0 <= index < length() Elements starting at index+1 will have their indices decremented. Returns a reference to this Array object. */ OdVector& removeAt(size_type index); /** \details Removes the specified elements from this Array object. \param startIndex [in] Start index. \param endIndex [in] End index. \remarks Elements from startIndex through endIndex inclusive will be removed. Returns a reference to this Array object. */ OdVector& removeSubArray(size_type startIndex, size_type endIndex); /** \details Removes the element with the specified value from this Array object. \param value [in] Value for which to search. \param startIndex [in] Starting index of search. \remarks Removes the first occurance of value starting at startIndex. Returns true if and only if an element was removed. */ bool remove(const T& value, size_type startIndex = 0); /** \details Specifies the logical length for this Array object. \param logicalLength [in] Logical length. \param value [in] Value for the elements added to obtain the new logical length. */ void resize(size_type logicalLength, const T& value); void resize(size_type logicalLength); /** \details Returns the logical length of this Array object. */ size_type size() const; /** \details Returns true if and only if this Array is empty. */ bool empty() const; /** \details Returns the physical length of this Array object. */ size_type capacity() const; /** \details Sets the physical length of this Array object to the specified reserve length if the reserve length is greater than its physical length. \param reserveLength [in] Minimum physical length. */ void reserve(size_type reserveLength); /** \details Assigns the specified range of elements to this Array object. \param first [in] Position of first element to be assigned. \param afterLast [in] Position of first element after the last element to be assigned. \remarks After this Array object is cleared, this function assigns the specified range of elements from another Array object. */ void assign(const_iterator first, const_iterator afterLast); /** \details Removes the specified element or range of elements from this Array object. \param first [in] Position of first element to be assigned. \param afterLast [in] Position of first element after the last element to be assigned. */ iterator erase(iterator first, iterator afterLast); /** \param where [in] Element to remove. */ iterator erase(iterator where); /** \details Removes all elements from this Array object. */ void clear(); /** \details Appends an element to the end of this Array object. */ void push_back(const T& value); /** \details Returns true if and only if this Array object contains ths specified value. \param value [in] Value for which to search. \param startIndex [in] Starting index of search. */ bool contains(const T& value, size_type startIndex = 0) const; /** \details Returns the number of elements in this Array object. */ size_type length() const; /** \details Returns true if and only if this Array is empty. */ bool isEmpty() const; /** \details Returns the logical length of this Array object. */ size_type logicalLength() const; /** \details Returns the physical length of this Array object. */ size_type physicalLength() const; /** \details Returns the grow length of this Array object. */ int growLength() const; /** \details Returns the data buffer of this Array object. */ const T* asArrayPtr() const; /** \details Returns the data buffer of this Array object. */ const T* getPtr() const; T* asArrayPtr(); /** \remarks For convenient access to the data. */ const T& operator[](size_type index) const; T& operator[](size_type index); /** \details Returns the element of this Array object at the specified index. \param arrayIndex [in] Array index. */ T& at(size_type index); const T& at(size_type index) const; /** \details Sets the element of this Array object at the specified index. \param arrayIndex [in] Array index. \param value [in] Value. */ OdVector& setAt(size_type index, const T& value); /** \details Returns the element of this Array object at the specified position. \param arrayIndex [in] Array index. */ const T& getAt(size_type index) const; /** \details Returns the first element of this Array object. */ T& first(); const T& first() const; /** \details Returns the last element of this Array object. */ T& last(); const T& last() const; size_type append(const T& value); iterator append(); /** \details Appends the specified value or Array object to the end of this Array object. \param vec [in] Array to append. \param value [in] Value to append. \remarks If called with otherArray, returns a reference to this Array object. If called with value, returns the index of the new last element. If called with no arguments, returns an interator (pointer) to the first element after the last element in the array. */ OdVector& append(const OdVector& vec); /** \details Removes the first element in this Array object. */ OdVector& removeFirst(); /** \details Removes the last element in this Array object. */ OdVector& removeLast(); bool operator==(const OdVector& vec) const; /** \details Sets all the elements in this Array object to the specified value. \param value [in] Value to assign. */ OdVector& setAll(const T& value); /** \details Returns true if and only if this Array object contains ths specified value. \param value [in] Value for which to search. \param index [out] Receives the index of the found value. \param startIndex [in] Starting index of search. \remarks Returns the index at which the element was found. */ bool find(const T& value, size_type& index, size_type startIndex = 0) const; /** \details Sets the logical length of this Array object. \param logicalLength [in] Logical length. \remarks The physical length is increased as required. */ OdVector& setLogicalLength(size_type logicalLength); /** \details Sets the physical length of this Array object. \param physicalLength [in] Physical length. \remarks The logical length is decreased as required. */ OdVector& setPhysicalLength(size_type physicalLength); /** \details Sets the grow length of this Array object. \param growLength [in] Grow length. */ OdVector& setGrowLength(int growLength); /** \details Reverses the order of the elements in this Array object. */ OdVector& reverse(); /** \details Swaps the specified elements in this Array object. \param firstIndex [in] Index of first element. \param secondIndex [in] Index of second element. */ OdVector& swap(size_type firstIndex, size_type secondIndex); private: T* m_pData; size_type m_physicalLength; size_type m_logicalLength; int m_growLength; }; #define VEC_SIZE_TYPE typename OdVector::size_type #define VEC_ITERATOR typename OdVector::iterator #define VEC_CONST_ITERATOR typename OdVector::const_iterator template inline OdVector::OdVector(VEC_SIZE_TYPE physicalLength, int growLength) : m_pData(NULL), m_physicalLength(physicalLength), m_logicalLength(0) , m_growLength(growLength) { if(m_growLength == 0) { ODA_FAIL(); m_growLength = -200; } if (m_physicalLength) { m_pData = allocate(m_physicalLength); } } template inline OdVector::OdVector() : m_pData(NULL), m_physicalLength(0), m_logicalLength(0), m_growLength(-200) { } template inline OdVector::OdVector(const OdVector& vec) : m_pData(NULL), m_physicalLength(vec.m_physicalLength) , m_logicalLength(vec.m_logicalLength), m_growLength(vec.m_growLength) { if(m_physicalLength > 0) { m_pData = allocate(m_physicalLength); A::copy(m_pData, vec.m_pData, m_logicalLength); } } template inline OdVector::~OdVector() { release(); } template inline OdVector& OdVector::operator=(const OdVector& vec) { if(this != &vec) { if(m_physicalLength < vec.m_logicalLength) { release(); m_pData = allocate(vec.m_logicalLength); m_physicalLength = vec.m_logicalLength; } m_logicalLength = vec.m_logicalLength; A::copy(m_pData, vec.m_pData, m_logicalLength); } return *this; } template inline T* OdVector::allocate(VEC_SIZE_TYPE physicalLength) { ODA_ASSERT(physicalLength != 0); const VEC_SIZE_TYPE numByte = physicalLength*sizeof(T); ODA_ASSERT(numByte >= physicalLength); // size_type overflow T* pData = ((numByte >= physicalLength) ? reinterpret_cast(Mm::Alloc(numByte)) : NULL); if(pData == NULL) throw OdError(eOutOfMemory); return pData; } template inline void OdVector::release() { if(m_pData != NULL) { A::destroy(m_pData, m_logicalLength); Mm::Free(m_pData); m_pData = NULL; m_physicalLength = 0; } } template inline void OdVector::reallocate(VEC_SIZE_TYPE physicalLength, bool isUseRealloc, bool isForcePhysicalLength) { T* pOldData = m_pData; VEC_SIZE_TYPE newPhysicalLength = physicalLength; if(!isForcePhysicalLength) { if(m_growLength > 0) { newPhysicalLength = ((newPhysicalLength + m_growLength - 1)/m_growLength) * m_growLength; } else { newPhysicalLength = m_logicalLength + (-m_growLength)*m_logicalLength/100; if(newPhysicalLength < physicalLength) newPhysicalLength = physicalLength; } } if(isUseRealloc && A::useRealloc() && m_logicalLength > 0 && m_pData != NULL) { m_pData = reinterpret_cast(Mm::Realloc(pOldData, newPhysicalLength*sizeof(T), m_physicalLength*sizeof(T))); if (!m_pData) throw OdError(eOutOfMemory); m_physicalLength = newPhysicalLength; if(physicalLength < m_logicalLength) m_logicalLength = physicalLength; } else { T* pNewData = allocate(newPhysicalLength); const VEC_SIZE_TYPE newLogicalLength = odmin(m_logicalLength, physicalLength); A::constructn(pNewData, pOldData, newLogicalLength); release(); m_pData = pNewData; m_physicalLength = newPhysicalLength; m_logicalLength = newLogicalLength; } } template inline bool OdVector::isValid(VEC_SIZE_TYPE index) const { // index is unsigned here, no need >= 0 check return (index < m_logicalLength); } template inline void OdVector::assertValid(VEC_SIZE_TYPE index) const { if(!isValid(index)) { ODA_FAIL(); throw OdError_InvalidIndex(); } } template inline void OdVector::riseError(OdResult res) { ODA_FAIL(); throw OdError(res); } template inline VEC_CONST_ITERATOR OdVector::begin_const() const { return begin(); } template inline VEC_ITERATOR OdVector::begin_non_const() { return begin(); } template inline VEC_CONST_ITERATOR OdVector::end_const() const { return end(); } template inline VEC_ITERATOR OdVector::end_non_const() { return end(); } template inline VEC_ITERATOR OdVector::begin() { return (!isEmpty() ? m_pData : NULL); } template inline VEC_CONST_ITERATOR OdVector::begin() const { return (!isEmpty() ? m_pData : NULL); } template inline VEC_ITERATOR OdVector::end() { return (!isEmpty() ? m_pData + m_logicalLength : NULL); } template inline VEC_CONST_ITERATOR OdVector::end() const { return (!isEmpty() ? m_pData + m_logicalLength : NULL); } template inline void OdVector::insert(VEC_ITERATOR before, VEC_CONST_ITERATOR first, VEC_CONST_ITERATOR afterLast) { const VEC_SIZE_TYPE oldLogicalLength = m_logicalLength; const VEC_SIZE_TYPE index = (VEC_SIZE_TYPE)(before - begin_const()); if(index <= m_logicalLength && afterLast >= first) { if(afterLast > first) { const VEC_SIZE_TYPE numElem = (VEC_SIZE_TYPE)(afterLast - first); const VEC_SIZE_TYPE newLogicalLength = oldLogicalLength + numElem; if(newLogicalLength > m_physicalLength) reallocate(newLogicalLength, first < begin() || first >= end()); A::constructn(m_pData + oldLogicalLength, first, numElem); m_logicalLength = newLogicalLength; T* pData = m_pData + index; if(index != oldLogicalLength) A::move(pData + numElem, pData, oldLogicalLength - index); A::copy(pData, first, numElem); } } else riseError(eInvalidInput); } template inline VEC_ITERATOR OdVector::insert(VEC_ITERATOR before, VEC_SIZE_TYPE numElem, const T& value) { const VEC_SIZE_TYPE oldLogicalLength = m_logicalLength; const VEC_SIZE_TYPE newLogicalLength = oldLogicalLength + numElem; const VEC_SIZE_TYPE index = (VEC_SIZE_TYPE)(before - begin_const()); if(newLogicalLength > m_physicalLength) reallocate(newLogicalLength, &value < begin() || &value >= end()); A::constructn(m_pData + oldLogicalLength, numElem, value); m_logicalLength = newLogicalLength; T* pData = m_pData + index; if(index != oldLogicalLength) A::move(pData + numElem, pData, oldLogicalLength - index); while(numElem--) pData[numElem] = value; return (begin_non_const() + index); } template inline VEC_ITERATOR OdVector::insert(VEC_ITERATOR before, const T& value) { const VEC_SIZE_TYPE index = (VEC_SIZE_TYPE)(before - begin_const()); insertAt(index, value); return (begin_non_const() + index); } template inline OdVector& OdVector::insertAt(VEC_SIZE_TYPE index, const T& value) { const VEC_SIZE_TYPE oldLogicalLength = m_logicalLength; const VEC_SIZE_TYPE newLogicalLength = oldLogicalLength + 1; if(index == oldLogicalLength) resize(newLogicalLength, value); else if(index < oldLogicalLength) { if(newLogicalLength > m_physicalLength) reallocate(newLogicalLength, &value < begin() || &value >= end()); A::construct(m_pData + oldLogicalLength); ++m_logicalLength; T* pData = m_pData + index; A::move(pData + 1, pData, oldLogicalLength - index); m_pData[index] = value; } else riseError(eInvalidIndex); return *this; } template inline OdVector& OdVector::removeAt(VEC_SIZE_TYPE index) { assertValid(index); const VEC_SIZE_TYPE newLogicalLength = m_logicalLength - 1; if(index < newLogicalLength) { T* pData = m_pData + index; A::move(pData, pData + 1, newLogicalLength - index); } resize(newLogicalLength); return *this; } template inline OdVector& OdVector::removeSubArray(VEC_SIZE_TYPE startIndex, VEC_SIZE_TYPE endIndex) { if(!isValid(startIndex) || startIndex > endIndex) riseError(eInvalidIndex); const VEC_SIZE_TYPE oldLogicalLength = m_logicalLength; T* pData = m_pData; ++endIndex; const VEC_SIZE_TYPE numElem = endIndex - startIndex; A::move(pData + startIndex, pData + endIndex, oldLogicalLength - endIndex); A::destroy(pData + oldLogicalLength - numElem, numElem); m_logicalLength -= numElem; return *this; } template inline bool OdVector::remove(const T& value, VEC_SIZE_TYPE startIndex) { VEC_SIZE_TYPE index = 0; if(find(value, index, startIndex)) { removeAt(index); return true; } return false; } template inline void OdVector::resize(VEC_SIZE_TYPE logicalLength, const T& value) { const VEC_SIZE_TYPE oldLogicalLength = m_logicalLength; const int lengthDiff = logicalLength - oldLogicalLength; if(lengthDiff > 0) { if(logicalLength > m_physicalLength) reallocate(logicalLength, &value < begin() || &value >= end()); A::constructn(m_pData + oldLogicalLength, lengthDiff, value); } else if(lengthDiff < 0) A::destroy(m_pData + logicalLength, -lengthDiff); m_logicalLength = logicalLength; } template inline void OdVector::resize(VEC_SIZE_TYPE logicalLength) { const VEC_SIZE_TYPE oldLogicalLength = m_logicalLength; const int lengthDiff = logicalLength - oldLogicalLength; if(lengthDiff > 0) { if(logicalLength > m_physicalLength) reallocate(logicalLength, true); A::constructn(m_pData + oldLogicalLength, lengthDiff); } else if(lengthDiff < 0) A::destroy(m_pData + logicalLength, -lengthDiff); m_logicalLength = logicalLength; } template inline VEC_SIZE_TYPE OdVector::size() const { return m_logicalLength; } template inline bool OdVector::empty() const { return (m_logicalLength == 0); } template inline VEC_SIZE_TYPE OdVector::capacity() const { return m_physicalLength; } template inline void OdVector::reserve(VEC_SIZE_TYPE reserveLength) { if(m_physicalLength < reserveLength) setPhysicalLength(reserveLength); } template inline void OdVector::assign(VEC_CONST_ITERATOR first, VEC_CONST_ITERATOR afterLast) { erase(begin_non_const(), end_non_const()); insert(begin_non_const(), first, afterLast); } template inline VEC_ITERATOR OdVector::erase(VEC_ITERATOR first, VEC_ITERATOR afterLast) { const VEC_SIZE_TYPE index = (VEC_SIZE_TYPE)(first - begin_const()); if(first != afterLast) removeSubArray(index, (VEC_SIZE_TYPE)(afterLast - begin_const() - 1)); return (begin_non_const() + index); } template inline VEC_ITERATOR OdVector::erase(VEC_ITERATOR it) { const VEC_SIZE_TYPE index = (VEC_SIZE_TYPE)(it - begin_const()); removeAt(index); return (begin_non_const() + index); } template inline void OdVector::clear() { erase(begin_non_const(), end_non_const()); } template inline void OdVector::push_back(const T& value) { insertAt(m_logicalLength, value); } template inline bool OdVector::contains(const T& value, VEC_SIZE_TYPE startIndex) const { VEC_SIZE_TYPE index; return find(value, index, startIndex); } template inline VEC_SIZE_TYPE OdVector::length() const { return m_logicalLength; } template inline bool OdVector::isEmpty() const { return (m_logicalLength == 0); } template inline VEC_SIZE_TYPE OdVector::logicalLength() const { return m_logicalLength; } template inline VEC_SIZE_TYPE OdVector::physicalLength() const { return m_physicalLength; } template inline int OdVector::growLength() const { return m_growLength; } template inline const T* OdVector::asArrayPtr() const { return m_pData; } template inline const T* OdVector::getPtr() const { return m_pData; } template inline T* OdVector::asArrayPtr() { // OdArray::asArrayPtr invokes non-const version of data() method which checks length and return null. // Constant version of asArrayPtr and getPtr will return m_pData as is for OdArray too. return (length()) ? m_pData : NULL; } template inline const T& OdVector::operator[](VEC_SIZE_TYPE index) const { assertValid(index); return m_pData[index]; } template inline T& OdVector::operator[](VEC_SIZE_TYPE index) { assertValid(index); return m_pData[index]; } template inline T& OdVector::at(VEC_SIZE_TYPE index) { assertValid(index); return m_pData[index]; } template inline const T& OdVector::at(VEC_SIZE_TYPE index) const { assertValid(index); return m_pData[index]; } template inline OdVector& OdVector::setAt(VEC_SIZE_TYPE index, const T& value) { assertValid(index); m_pData[index] = value; return *this; } template inline const T& OdVector::getAt(VEC_SIZE_TYPE index) const { assertValid(index); return m_pData[index]; } template inline T& OdVector::first() { return m_pData[0]; } template inline const T& OdVector::first() const { return m_pData[0]; } template inline T& OdVector::last() { return m_pData[m_logicalLength - 1]; } template inline const T& OdVector::last() const { return m_pData[m_logicalLength - 1]; } template inline VEC_SIZE_TYPE OdVector::append(const T& value) { insertAt(m_logicalLength, value); return (m_logicalLength - 1); } template inline VEC_ITERATOR OdVector::append() { const VEC_SIZE_TYPE index = append(T()); return (begin_non_const() + index); } template inline OdVector& OdVector::append(const OdVector& vec) { insert(end_non_const(), vec.begin(), vec.end()); return *this; } template inline OdVector& OdVector::removeFirst() { return removeAt(0); } template inline OdVector& OdVector::removeLast() { return removeAt(m_logicalLength - 1); } template inline bool OdVector::operator==(const OdVector& vec) const { if(m_logicalLength == vec.m_logicalLength) { for(VEC_SIZE_TYPE i = 0; i < m_logicalLength; ++i) { if(m_pData[i] != vec.m_pData[i]) return false; } return true; } return false; } template inline OdVector& OdVector::setAll(const T& value) { for(VEC_SIZE_TYPE i = 0; i < m_logicalLength; ++i) m_pData[i] = value; return *this; } template inline bool OdVector::find(const T& value, VEC_SIZE_TYPE& index, VEC_SIZE_TYPE startIndex) const { if(!isEmpty()) { assertValid(startIndex); for(VEC_SIZE_TYPE i = startIndex; i < m_logicalLength; ++i) { if(m_pData[i] == value) { index = i; return true; } } } return false; } template inline OdVector& OdVector::setLogicalLength(VEC_SIZE_TYPE logicalLength) { resize(logicalLength); return *this; } template inline OdVector& OdVector::setPhysicalLength(VEC_SIZE_TYPE physicalLength) { if(physicalLength == 0) { release(); m_pData = NULL; m_physicalLength = 0; } else if(physicalLength != m_physicalLength) reallocate(physicalLength, true, true); if(m_physicalLength < m_logicalLength) m_logicalLength = m_physicalLength; return *this; } template inline OdVector& OdVector::setGrowLength(int growLength) { if(growLength != 0) m_growLength = growLength; else ODA_FAIL(); return *this; } template inline OdVector& OdVector::reverse() { if(!isEmpty()) { T value; VEC_ITERATOR it1 = begin_non_const(); VEC_ITERATOR it2 = end_non_const(); --it2; while(it1 < it2) { value = *it1; *it1 = *it2; *it2 = value; ++it1; --it2; } } return *this; } template inline OdVector& OdVector::swap(VEC_SIZE_TYPE firstIndex, VEC_SIZE_TYPE secondIndex) { if(!isValid(firstIndex) || !isValid(secondIndex)) riseError(eInvalidIndex); if(firstIndex != secondIndex) { const T value = m_pData[firstIndex]; m_pData[firstIndex] = m_pData[secondIndex]; m_pData[secondIndex] = value; } return *this; } #include "TD_PackPop.h" typedef OdVector > OdIntVector; typedef OdVector > OdUInt32Vector; typedef OdVector > OdInt32Vector; typedef OdVector > OdUInt8Vector; typedef OdVector > OdUInt64Vector; #ifdef OD_GEPNT3D_H typedef OdVector > OdGePoint3dVector; #endif #ifdef OD_GEVEC3D_H typedef OdVector > OdGeVector3dVector; #endif #endif // OdVector_H_INCLUDED