diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2014-03-26 19:21:20 +0000 |
---|---|---|
committer | <> | 2014-05-08 15:03:54 +0000 |
commit | fb123f93f9f5ce42c8e5785d2f8e0edaf951740e (patch) | |
tree | c2103d76aec5f1f10892cd1d3a38e24f665ae5db /include/iprt/cpp/list.h | |
parent | 58ed4748338f9466599adfc8a9171280ed99e23f (diff) | |
download | VirtualBox-fb123f93f9f5ce42c8e5785d2f8e0edaf951740e.tar.gz |
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2.HEADVirtualBox-4.3.10master
Diffstat (limited to 'include/iprt/cpp/list.h')
-rw-r--r-- | include/iprt/cpp/list.h | 506 |
1 files changed, 306 insertions, 200 deletions
diff --git a/include/iprt/cpp/list.h b/include/iprt/cpp/list.h index 97c1a193..ca8c8f3c 100644 --- a/include/iprt/cpp/list.h +++ b/include/iprt/cpp/list.h @@ -3,7 +3,7 @@ */ /* - * Copyright (C) 2011 Oracle Corporation + * Copyright (C) 2011-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -29,6 +29,7 @@ #include <iprt/cpp/meta.h> #include <iprt/mem.h> #include <iprt/string.h> /* for memcpy */ +#include <iprt/assert.h> #include <new> /* For std::bad_alloc */ @@ -133,16 +134,13 @@ class RTCListHelper public: static inline void set(T2 *p, size_t i, const T1 &v) { p[i] = v; } static inline T1 & at(T2 *p, size_t i) { return p[i]; } - static inline size_t find(T2 *p, const T1 &v, size_t cSize) + static inline size_t find(T2 *p, const T1 &v, size_t cElements) { - size_t i = 0; - while(i < cSize) - { + size_t i = cElements; + while (i-- > 0) if (p[i] == v) - break; - ++i; - } - return i; + return i; + return cElements; } static inline void copyTo(T2 *p, T2 *const p1 , size_t iTo, size_t cSize) { @@ -162,16 +160,13 @@ class RTCListHelper<T1, T1*> public: static inline void set(T1 **p, size_t i, const T1 &v) { p[i] = new T1(v); } static inline T1 & at(T1 **p, size_t i) { return *p[i]; } - static inline size_t find(T1 **p, const T1 &v, size_t cSize) + static inline size_t find(T1 **p, const T1 &v, size_t cElements) { - size_t i = 0; - while(i < cSize) - { + size_t i = cElements; + while (i-- > 0) if (*p[i] == v) - break; - ++i; - } - return i; + return i; + return cElements; } static inline void copyTo(T1 **p, T1 **const p1 , size_t iTo, size_t cSize) { @@ -179,10 +174,10 @@ public: p[iTo + i] = new T1(*p1[i]); } static inline void erase(T1 **p, size_t i) { delete p[i]; } - static inline void eraseRange(T1 **p, size_t cFrom, size_t cSize) + static inline void eraseRange(T1 **p, size_t iFrom, size_t cItems) { - for (size_t i = cFrom; i < cFrom + cSize; ++i) - delete p[i]; + while (cItems-- > 0) + delete p[iFrom++]; } }; @@ -194,15 +189,17 @@ public: template <class T, typename ITYPE, bool MT> class RTCListBase { - /** - * Traits + /** @name Traits. * * Defines the return type of most of the getter methods. If the internal * used type is a pointer, we return a reference. If not we return by * value. + * + * @{ */ typedef typename RTCIfPtr<ITYPE, T&, T>::result GET_RTYPE; typedef typename RTCIfPtr<ITYPE, const T&, T>::result GET_CRTYPE; + /** @} */ public: /** @@ -213,13 +210,13 @@ public: * @param cCapacitiy The initial capacity the list has. * @throws std::bad_alloc */ - RTCListBase(size_t cCapacity = DefaultCapacity) - : m_pArray(0) - , m_cSize(0) - , m_cCapacity(0) + RTCListBase(size_t cCapacity = kDefaultCapacity) + : m_pArray(0) + , m_cElements(0) + , m_cCapacity(0) { if (cCapacity > 0) - realloc_grow(cCapacity); + growArray(cCapacity); } /** @@ -232,13 +229,18 @@ public: * @throws std::bad_alloc */ RTCListBase(const RTCListBase<T, ITYPE, MT>& other) - : m_pArray(0) - , m_cSize(0) - , m_cCapacity(0) + : m_pArray(0) + , m_cElements(0) + , m_cCapacity(0) { - realloc_no_elements_clean(other.m_cSize); - RTCListHelper<T, ITYPE>::copyTo(m_pArray, other.m_pArray, 0, other.m_cSize); - m_cSize = other.m_cSize; + other.m_guard.enterRead(); + + size_t const cElementsOther = other.m_cElements; + resizeArrayNoErase(cElementsOther); + RTCListHelper<T, ITYPE>::copyTo(m_pArray, other.m_pArray, 0, cElementsOther); + m_cElements = cElementsOther; + + other.m_guard.leaveRead(); } /** @@ -246,16 +248,20 @@ public: */ ~RTCListBase() { - RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cSize); + RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cElements); if (m_pArray) + { RTMemFree(m_pArray); + m_pArray = NULL; + } + m_cElements = m_cCapacity = 0; } /** * Sets a new capacity within the list. * * If the new capacity is bigger than the old size, it will be simply - * preallocated more space for the new items. If the new capacity is + * preallocated more space for the new items. If the new capacity is * smaller than the previous size, items at the end of the list will be * deleted. * @@ -265,7 +271,7 @@ public: void setCapacity(size_t cCapacity) { m_guard.enterWrite(); - realloc(cCapacity); + resizeArray(cCapacity); m_guard.leaveWrite(); } @@ -274,26 +280,47 @@ public: * * @return The actual capacity. */ - size_t capacity() const { return m_cCapacity; } + size_t capacity() const + { + m_guard.enterRead(); + size_t cRet = m_cCapacity; + m_guard.leaveRead(); + return cRet; + } /** * Check if an list contains any items. * * @return True if there is more than zero items, false otherwise. */ - bool isEmpty() const { return m_cSize == 0; } + bool isEmpty() const + { + m_guard.enterRead(); + bool fEmpty = m_cElements == 0; + m_guard.leaveRead(); + return fEmpty; + } /** * Return the current count of elements within the list. * * @return The current element count. */ - size_t size() const { return m_cSize; } + size_t size() const + { + m_guard.enterRead(); + size_t cRet = m_cElements; + m_guard.leaveRead(); + return cRet; + } /** * Inserts an item to the list at position @a i. * - * @param i The position of the new item. + * @param i The position of the new item. The must be within or at the + * exact end of the list. Indexes specified beyond the end of + * the list will be changed to an append() operation and strict + * builds will raise an assert. * @param val The new item. * @return a reference to this list. * @throws std::bad_alloc @@ -301,13 +328,56 @@ public: RTCListBase<T, ITYPE, MT> &insert(size_t i, const T &val) { m_guard.enterWrite(); - if (m_cSize == m_cCapacity) - realloc_grow(m_cCapacity + DefaultCapacity); - memmove(&m_pArray[i + 1], &m_pArray[i], (m_cSize - i) * sizeof(ITYPE)); + + AssertMsgStmt(i <= m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements); + + if (m_cElements == m_cCapacity) + growArray(m_cCapacity + kDefaultCapacity); + + memmove(&m_pArray[i + 1], &m_pArray[i], (m_cElements - i) * sizeof(ITYPE)); RTCListHelper<T, ITYPE>::set(m_pArray, i, val); - ++m_cSize; + ++m_cElements; + m_guard.leaveWrite(); + return *this; + } + + /** + * Inserts a list to the list at position @a i. + * + * @param i The position of the new item. The must be within or at the + * exact end of the list. Indexes specified beyond the end of + * the list will be changed to an append() operation and strict + * builds will raise an assert. + * @param other The other list. This MUST not be the same as the destination + * list, will assert and return without doing anything if this + * happens. + * @return a reference to this list. + * @throws std::bad_alloc + */ + RTCListBase<T, ITYPE, MT> &insert(size_t i, const RTCListBase<T, ITYPE, MT> &other) + { + AssertReturn(this != &other, *this); + + other.m_guard.enterRead(); + m_guard.enterWrite(); + + AssertMsgStmt(i <= m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements); + size_t cElementsOther = other.m_cElements; + if (RT_LIKELY(cElementsOther > 0)) + { + if (m_cCapacity - m_cElements < cElementsOther) + growArray(m_cCapacity + (cElementsOther - (m_cCapacity - m_cElements))); + if (i < m_cElements) + memmove(&m_pArray[i + cElementsOther], &m_pArray[i], (m_cElements - i) * sizeof(ITYPE)); + + RTCListHelper<T, ITYPE>::copyTo(&m_pArray[i], other.m_pArray, 0, cElementsOther); + m_cElements += cElementsOther; + } + + m_guard.leaveWrite(); + other.m_guard.leaveRead(); return *this; } @@ -332,15 +402,7 @@ public: */ RTCListBase<T, ITYPE, MT> &prepend(const RTCListBase<T, ITYPE, MT> &other) { - m_guard.enterWrite(); - if (m_cCapacity - m_cSize < other.m_cSize) - realloc_grow(m_cCapacity + (other.m_cSize - (m_cCapacity - m_cSize))); - memmove(&m_pArray[other.m_cSize], &m_pArray[0], m_cSize * sizeof(ITYPE)); - RTCListHelper<T, ITYPE>::copyTo(m_pArray, other.m_pArray, 0, other.m_cSize); - m_cSize += other.m_cSize; - m_guard.leaveWrite(); - - return *this; + return insert(0, other); } /** @@ -353,10 +415,10 @@ public: RTCListBase<T, ITYPE, MT> &append(const T &val) { m_guard.enterWrite(); - if (m_cSize == m_cCapacity) - realloc_grow(m_cCapacity + DefaultCapacity); - RTCListHelper<T, ITYPE>::set(m_pArray, m_cSize, val); - ++m_cSize; + if (m_cElements == m_cCapacity) + growArray(m_cCapacity + kDefaultCapacity); + RTCListHelper<T, ITYPE>::set(m_pArray, m_cElements, val); + ++m_cElements; m_guard.leaveWrite(); return *this; @@ -365,28 +427,29 @@ public: /** * Append a list of type T to the list. * - * @param other The list to append. + * @param other The list to append. Must not be the same as the destination + * list, will assert and return without doing anything. * @return a reference to this list. * @throws std::bad_alloc */ RTCListBase<T, ITYPE, MT> &append(const RTCListBase<T, ITYPE, MT> &other) { + AssertReturn(this != &other, *this); + + other.m_guard.enterRead(); m_guard.enterWrite(); - if (RT_LIKELY(other.m_cSize > 0)) - { - if (m_cCapacity - m_cSize < other.m_cSize) - realloc_grow(m_cCapacity + (other.m_cSize - (m_cCapacity - m_cSize))); - RTCListHelper<T, ITYPE>::copyTo(m_pArray, other.m_pArray, m_cSize, other.m_cSize); - m_cSize += other.m_cSize; - } - m_guard.leaveWrite(); + insert(m_cElements, other); + + m_guard.leaveWrite(); + other.m_guard.leaveRead(); return *this; } /** - * Copy the items of the other list into this list. All previous items of - * this list are deleted. + * Copy the items of the other list into this list. + * + * All previous items of this list are deleted. * * @param other The list to copy. * @return a reference to this list. @@ -397,51 +460,61 @@ public: if (RT_UNLIKELY(this == &other)) return *this; + other.m_guard.enterRead(); m_guard.enterWrite(); + /* Delete all items. */ - RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cSize); + RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cElements); + /* Need we to realloc memory. */ - if (other.m_cSize != m_cCapacity) - realloc_no_elements_clean(other.m_cSize); - m_cSize = other.m_cSize; + if (other.m_cElements != m_cCapacity) + resizeArrayNoErase(other.m_cElements); + m_cElements = other.m_cElements; + /* Copy new items. */ - RTCListHelper<T, ITYPE>::copyTo(m_pArray, other.m_pArray, 0, other.m_cSize); - m_guard.leaveWrite(); + RTCListHelper<T, ITYPE>::copyTo(m_pArray, other.m_pArray, 0, other.m_cElements); + m_guard.leaveWrite(); + other.m_guard.leaveRead(); return *this; } /** * Replace an item in the list. * - * @note No boundary checks are done. Make sure @a i is equal or greater zero - * and smaller than RTCList::size. - * - * @param i The position of the item to replace. + * @param i The position of the item to replace. If this is out of range, + * the request will be ignored, strict builds will assert. * @param val The new value. * @return a reference to this list. */ RTCListBase<T, ITYPE, MT> &replace(size_t i, const T &val) { m_guard.enterWrite(); - RTCListHelper<T, ITYPE>::erase(m_pArray, i); - RTCListHelper<T, ITYPE>::set(m_pArray, i, val); - m_guard.leaveWrite(); + if (i < m_cElements) + { + RTCListHelper<T, ITYPE>::erase(m_pArray, i); + RTCListHelper<T, ITYPE>::set(m_pArray, i, val); + } + else + AssertMsgFailed(("i=%zu m_cElements=%zu\n", i, m_cElements)); + + m_guard.leaveWrite(); return *this; } /** * Return the first item as constant object. * - * @note No boundary checks are done. Make sure there is at least one - * element. + * @return A reference or pointer to the first item. * - * @return The first item. + * @note No boundary checks are done. Make sure there is at least one + * element. */ GET_CRTYPE first() const { m_guard.enterRead(); + Assert(m_cElements > 0); GET_CRTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, 0); m_guard.leaveRead(); return res; @@ -450,14 +523,15 @@ public: /** * Return the first item. * - * @note No boundary checks are done. Make sure there is at least one - * element. + * @return A reference or pointer to the first item. * - * @return The first item. + * @note No boundary checks are done. Make sure there is at least one + * element. */ GET_RTYPE first() { m_guard.enterRead(); + Assert(m_cElements > 0); GET_RTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, 0); m_guard.leaveRead(); return res; @@ -466,15 +540,16 @@ public: /** * Return the last item as constant object. * - * @note No boundary checks are done. Make sure there is at least one - * element. + * @return A reference or pointer to the last item. * - * @return The last item. + * @note No boundary checks are done. Make sure there is at least one + * element. */ GET_CRTYPE last() const { m_guard.enterRead(); - GET_CRTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, m_cSize - 1); + Assert(m_cElements > 0); + GET_CRTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, m_cElements - 1); m_guard.leaveRead(); return res; } @@ -482,15 +557,16 @@ public: /** * Return the last item. * - * @note No boundary checks are done. Make sure there is at least one - * element. + * @return A reference or pointer to the last item. * - * @return The last item. + * @note No boundary checks are done. Make sure there is at least one + * element. */ GET_RTYPE last() { m_guard.enterRead(); - GET_RTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, m_cSize - 1); + Assert(m_cElements > 0); + GET_RTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, m_cElements - 1); m_guard.leaveRead(); return res; } @@ -498,15 +574,16 @@ public: /** * Return the item at position @a i as constant object. * - * @note No boundary checks are done. Make sure @a i is equal or greater zero - * and smaller than RTCList::size. - * - * @param i The position of the item to return. + * @param i The position of the item to return. This better not be out of + * bounds, however should it be the last element of the array + * will be return and strict builds will raise an assertion. + * Should the array be empty, a crash is very likely. * @return The item at position @a i. */ GET_CRTYPE at(size_t i) const { m_guard.enterRead(); + AssertMsgStmt(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements - 1); GET_CRTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, i); m_guard.leaveRead(); return res; @@ -515,15 +592,16 @@ public: /** * Return the item at position @a i. * - * @note No boundary checks are done. Make sure @a i is equal or greater zero - * and smaller than RTCList::size. - * - * @param i The position of the item to return. + * @param i The position of the item to return. This better not be out of + * bounds, however should it be the last element of the array + * will be return and strict builds will raise an assertion. + * Should the array be empty, a crash is very likely. * @return The item at position @a i. */ GET_RTYPE at(size_t i) { m_guard.enterRead(); + AssertMsgStmt(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements - 1); GET_RTYPE res = RTCListHelper<T, ITYPE>::at(m_pArray, i); m_guard.leaveRead(); return res; @@ -532,31 +610,31 @@ public: /** * Return the item at position @a i as mutable reference. * - * @note No boundary checks are done. Make sure @a i is equal or greater zero - * and smaller than RTCList::size. - * - * @param i The position of the item to return. + * @param i The position of the item to return. This better not be out of + * bounds, however should it be the last element of the array + * will be return and strict builds will raise an assertion. + * Should the array be empty, a crash is very likely. * @return The item at position @a i. */ T &operator[](size_t i) { m_guard.enterRead(); + AssertMsgStmt(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements), i = m_cElements - 1); T &res = RTCListHelper<T, ITYPE>::at(m_pArray, i); m_guard.leaveRead(); return res; } /** - * Return the item at position @a i. If @a i isn't valid within the list a - * default value is returned. + * Return the item at position @a i or default value if out of range. * * @param i The position of the item to return. - * @return The item at position @a i. + * @return The item at position @a i or default value. */ T value(size_t i) const { m_guard.enterRead(); - if (RT_UNLIKELY(i >= m_cSize)) + if (RT_UNLIKELY(i >= m_cElements)) { m_guard.leaveRead(); return T(); @@ -567,17 +645,16 @@ public: } /** - * Return the item at position @a i. If @a i isn't valid within the list - * @a defaultVal is returned. + * Return the item at position @a i, or @a defaultVal if out of range. * * @param i The position of the item to return. * @param defaultVal The value to return in case @a i is invalid. - * @return The item at position @a i. + * @return The item at position @a i or @a defaultVal. */ T value(size_t i, const T &defaultVal) const { m_guard.enterRead(); - if (RT_UNLIKELY(i >= m_cSize)) + if (RT_UNLIKELY(i >= m_cElements)) { m_guard.leaveRead(); return defaultVal; @@ -596,16 +673,16 @@ public: bool contains(const T &val) const { m_guard.enterRead(); - bool res = RTCListHelper<T, ITYPE>::find(m_pArray, val, m_cSize) != m_cSize; + bool fRc = RTCListHelper<T, ITYPE>::find(m_pArray, val, m_cElements) < m_cElements; m_guard.leaveRead(); - return res; + return fRc; } /** * Remove the first item. * - * @note No boundary checks are done. Make sure there is at least one - * element. + * @note You should make sure the list isn't empty. Strict builds will assert. + * The other builds will quietly ignore the request. */ void removeFirst() { @@ -615,51 +692,52 @@ public: /** * Remove the last item. * - * @note No boundary checks are done. Make sure there is at least one - * element. + * @note You should make sure the list isn't empty. Strict builds will assert. + * The other builds will quietly ignore the request. */ void removeLast() { - removeAt(m_cSize - 1); + m_guard.enterWrite(); + removeAtLocked(m_cElements - 1); + m_guard.leaveWrite(); } /** * Remove the item at position @a i. * - * @note No boundary checks are done. Make sure @a i is equal or greater zero - * and smaller than RTCList::size. - * - * @param i The position of the item to remove. + * @param i The position of the item to remove. Out of bounds values will + * be ignored and an assertion will be raised in strict builds. */ void removeAt(size_t i) { m_guard.enterWrite(); - RTCListHelper<T, ITYPE>::erase(m_pArray, i); - /* Not last element? */ - if (i < m_cSize - 1) - memmove(&m_pArray[i], &m_pArray[i + 1], (m_cSize - i - 1) * sizeof(ITYPE)); - --m_cSize; + removeAtLocked(i); m_guard.leaveWrite(); } /** * Remove a range of items from the list. * - * @note No boundary checks are done. Make sure @a iFrom is equal or - * greater zero and smaller than RTCList::size. @a iTo has to be - * greater than @a iFrom and equal or smaller than RTCList::size. - * - * @param iFrom The start position of the items to remove. - * @param iTo The end position of the items to remove (excluded). + * @param iStart The start position of the items to remove. + * @param iEnd The end position of the items to remove (excluded). */ - void removeRange(size_t iFrom, size_t iTo) + void removeRange(size_t iStart, size_t iEnd) { + AssertReturnVoid(iStart <= iEnd); m_guard.enterWrite(); - RTCListHelper<T, ITYPE>::eraseRange(m_pArray, iFrom, iTo - iFrom); - /* Not last elements? */ - if (m_cSize - iTo > 0) - memmove(&m_pArray[iFrom], &m_pArray[iTo], (m_cSize - iTo) * sizeof(ITYPE)); - m_cSize -= iTo - iFrom; + + AssertMsgStmt(iEnd <= m_cElements, ("iEnd=%zu m_cElements=%zu\n", iEnd, m_cElements), iEnd = m_cElements); + AssertMsgStmt(iStart < m_cElements, ("iStart=%zu m_cElements=%zu\n", iStart, m_cElements), iStart = m_cElements); + size_t const cElements = iEnd - iStart; + if (cElements > 0) + { + Assert(iStart < m_cElements); + RTCListHelper<T, ITYPE>::eraseRange(m_pArray, iStart, cElements); + if (m_cElements > iEnd) + memmove(&m_pArray[iStart], &m_pArray[iEnd], (m_cElements - iEnd) * sizeof(ITYPE)); + m_cElements -= cElements; + } + m_guard.leaveWrite(); } @@ -669,18 +747,21 @@ public: void clear() { m_guard.enterWrite(); + /* Values cleanup */ - RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cSize); - if (m_cSize != DefaultCapacity) - realloc_no_elements_clean(DefaultCapacity); - m_cSize = 0; + RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cElements); + if (m_cElements != kDefaultCapacity) + resizeArrayNoErase(kDefaultCapacity); + m_cElements = 0; + m_guard.leaveWrite(); } /** - * Return the raw array. For native types this is a pointer to continuous - * memory of the items. For pointer types this is a continuous memory of - * pointers to the items. + * Return the raw array. + * + * For native types this is a pointer to continuous memory of the items. For + * pointer types this is a continuous memory of pointers to the items. * * @warning If you change anything in the underlaying list, this memory * will very likely become invalid. So take care when using this @@ -688,12 +769,12 @@ public: * * @returns the raw memory. */ - ITYPE* raw() const + ITYPE *raw() const { m_guard.enterRead(); - ITYPE* res = m_pArray; + ITYPE *pRet = m_pArray; m_guard.leaveRead(); - return res; + return pRet; } RTCListBase<T, ITYPE, MT> &operator<<(const T &val) @@ -707,89 +788,114 @@ public: /** * The default capacity of the list. This is also used as grow factor. */ - static const size_t DefaultCapacity; + static const size_t kDefaultCapacity; protected: /** - * Generic realloc, which does some kind of boundary checking. + * Generic resizes the array, surplus elements are erased. + * + * @param cElementsNew The new array size. + * @throws std::bad_alloc. */ - void realloc(size_t cNewSize) + void resizeArray(size_t cElementsNew) { /* Same size? */ - if (cNewSize == m_cCapacity) + if (cElementsNew == m_cCapacity) return; /* If we get smaller we have to delete some of the objects at the end of the list. */ - if ( cNewSize < m_cSize + if ( cElementsNew < m_cElements && m_pArray) - RTCListHelper<T, ITYPE>::eraseRange(m_pArray, cNewSize, m_cSize - cNewSize); - realloc_no_elements_clean(cNewSize); + RTCListHelper<T, ITYPE>::eraseRange(m_pArray, cElementsNew, m_cElements - cElementsNew); + + resizeArrayNoErase(cElementsNew); } - void realloc_no_elements_clean(size_t cNewSize) + /** + * Resizes the array without doing the erase() thing on surplus elements. + * + * @param cElementsNew The new array size. + * @throws std::bad_alloc. + */ + void resizeArrayNoErase(size_t cElementsNew) { /* Same size? */ - if (cNewSize == m_cCapacity) + if (cElementsNew == m_cCapacity) return; - /* If we get smaller we have to delete some of the objects at the end - of the list. */ - if ( cNewSize < m_cSize - && m_pArray) - m_cSize -= m_cSize - cNewSize; - - /* If we get zero we delete the array it self. */ - if ( cNewSize == 0 - && m_pArray) - { - RTMemFree(m_pArray); - m_pArray = 0; - } - m_cCapacity = cNewSize; - /* Resize the array. */ - if (cNewSize > 0) + if (cElementsNew > 0) { - m_pArray = static_cast<ITYPE*>(RTMemRealloc(m_pArray, sizeof(ITYPE) * cNewSize)); - if (!m_pArray) + void *pvNew = RTMemRealloc(m_pArray, sizeof(ITYPE) * cElementsNew); + if (!pvNew) { - /** @todo you leak memory. */ - m_cCapacity = 0; - m_cSize = 0; #ifdef RT_EXCEPTIONS_ENABLED throw std::bad_alloc(); #endif + return; } + m_pArray = static_cast<ITYPE*>(pvNew); + } + /* If we get zero we delete the array it self. */ + else if (m_pArray) + { + RTMemFree(m_pArray); + m_pArray = NULL; } + + m_cCapacity = cElementsNew; + if (m_cElements > cElementsNew) + m_cElements = cElementsNew; } /** * Special realloc method which require that the array will grow. * + * @param cElementsNew The new array size. + * @throws std::bad_alloc. * @note No boundary checks are done! */ - void realloc_grow(size_t cNewSize) + void growArray(size_t cElementsNew) { - /* Resize the array. */ - m_cCapacity = cNewSize; - m_pArray = static_cast<ITYPE*>(RTMemRealloc(m_pArray, sizeof(ITYPE) * cNewSize)); - if (!m_pArray) + Assert(cElementsNew > m_cCapacity); + void *pvNew = RTMemRealloc(m_pArray, sizeof(ITYPE) * cElementsNew); + if (pvNew) + { + m_cCapacity = cElementsNew; + m_pArray = static_cast<ITYPE*>(pvNew); + } + else { - /** @todo you leak memory. */ - m_cCapacity = 0; - m_cSize = 0; #ifdef RT_EXCEPTIONS_ENABLED throw std::bad_alloc(); #endif } } + /** + * Remove the item at position @a i. + * + * @param i The position of the item to remove. Out of bounds values will + * be ignored and an assertion will be raised in strict builds. + * @remarks + */ + void removeAtLocked(size_t i) + { + AssertMsgReturnVoid(i < m_cElements, ("i=%zu m_cElements=%zu\n", i, m_cElements)); + + RTCListHelper<T, ITYPE>::erase(m_pArray, i); + if (i < m_cElements - 1) + memmove(&m_pArray[i], &m_pArray[i + 1], (m_cElements - i - 1) * sizeof(ITYPE)); + --m_cElements; + } + + /** The internal list array. */ ITYPE *m_pArray; /** The current count of items in use. */ - size_t m_cSize; + size_t m_cElements; /** The current capacity of the internal array. */ size_t m_cCapacity; /** The guard used to serialize the access to the items. */ @@ -797,7 +903,7 @@ protected: }; template <class T, typename ITYPE, bool MT> -const size_t RTCListBase<T, ITYPE, MT>::DefaultCapacity = 10; +const size_t RTCListBase<T, ITYPE, MT>::kDefaultCapacity = 10; /** * Template class which automatically determines the type of list to use. @@ -819,11 +925,11 @@ public: * @param cCapacitiy The initial capacity the list has. * @throws std::bad_alloc */ - RTCList(size_t cCapacity = BASE::DefaultCapacity) - : BASE(cCapacity) {} + RTCList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} RTCList(const BASE &other) - : BASE(other) {} + : BASE(other) {} /* Define our own new and delete. */ RTMEMEF_NEW_AND_DELETE_OPERATORS(); @@ -850,8 +956,8 @@ public: * @param cCapacitiy The initial capacity the list has. * @throws std::bad_alloc */ - RTCList(size_t cCapacity = BASE::DefaultCapacity) - : BASE(cCapacity) {} + RTCList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} /* Define our own new and delete. */ RTMEMEF_NEW_AND_DELETE_OPERATORS(); @@ -878,8 +984,8 @@ public: * @param cCapacitiy The initial capacity the list has. * @throws std::bad_alloc */ - RTCList(size_t cCapacity = BASE::DefaultCapacity) - : BASE(cCapacity) {} + RTCList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} /* Define our own new and delete. */ RTMEMEF_NEW_AND_DELETE_OPERATORS(); |