|
|
@@ -0,0 +1,528 @@ |
|
|
|
// |
|
|
|
// ██████ ██ ██ ██████ ██████ |
|
|
|
// ██ ██ ██ ██ ██ ██ ** Clean Header-Only Classes ** |
|
|
|
// ██ ███████ ██ ██ ██ |
|
|
|
// ██ ██ ██ ██ ██ ██ https://github.com/Tracktion/choc |
|
|
|
// ██████ ██ ██ ██████ ██████ |
|
|
|
// |
|
|
|
// CHOC is (C)2021 Tracktion Corporation, and is offered under the terms of the ISC license: |
|
|
|
// |
|
|
|
// Permission to use, copy, modify, and/or distribute this software for any purpose with or |
|
|
|
// without fee is hereby granted, provided that the above copyright notice and this permission |
|
|
|
// notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL |
|
|
|
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY |
|
|
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR |
|
|
|
// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
|
|
|
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
|
|
|
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
|
|
|
|
|
|
#ifndef CHOC_SMALLVECTOR_HEADER_INCLUDED |
|
|
|
#define CHOC_SMALLVECTOR_HEADER_INCLUDED |
|
|
|
|
|
|
|
#include <algorithm> |
|
|
|
#include "choc_Span.h" |
|
|
|
|
|
|
|
namespace choc |
|
|
|
{ |
|
|
|
|
|
|
|
/** |
|
|
|
A std::vector-style container class, which uses some pre-allocated storage |
|
|
|
to avoid heap allocation when the number of elements is small. |
|
|
|
|
|
|
|
Inspired by LLVM's SmallVector, I've found this to be handy in many situations |
|
|
|
where you know there's only likely to be a small or fixed number of elements, |
|
|
|
and where performance is important. |
|
|
|
|
|
|
|
It retains most of the same basic methods as std::vector, but without some of |
|
|
|
the more exotic tricks that the std library uses, just to avoid things getting |
|
|
|
too complicated. |
|
|
|
*/ |
|
|
|
template <typename ElementType, size_t numPreallocatedElements> |
|
|
|
struct SmallVector |
|
|
|
{ |
|
|
|
using value_type = ElementType; |
|
|
|
using reference = ElementType&; |
|
|
|
using const_reference = const ElementType&; |
|
|
|
using iterator = ElementType*; |
|
|
|
using const_iterator = const ElementType*; |
|
|
|
using size_type = size_t; |
|
|
|
|
|
|
|
SmallVector() noexcept; |
|
|
|
~SmallVector() noexcept; |
|
|
|
|
|
|
|
SmallVector (SmallVector&&) noexcept; |
|
|
|
SmallVector (const SmallVector&); |
|
|
|
SmallVector& operator= (SmallVector&&) noexcept; |
|
|
|
SmallVector& operator= (const SmallVector&); |
|
|
|
|
|
|
|
/// Creates a SmallVector as a copy of some kind of iterable container. |
|
|
|
template <typename VectorType> |
|
|
|
SmallVector (const VectorType& initialContent); |
|
|
|
|
|
|
|
/// Replaces the contents of this vector with a copy of some kind of iterable container. |
|
|
|
template <typename VectorType> |
|
|
|
SmallVector& operator= (const VectorType&); |
|
|
|
|
|
|
|
reference operator[] (size_type index); |
|
|
|
const_reference operator[] (size_type index) const; |
|
|
|
|
|
|
|
value_type* data() const noexcept; |
|
|
|
|
|
|
|
const_iterator begin() const noexcept; |
|
|
|
const_iterator end() const noexcept; |
|
|
|
const_iterator cbegin() const noexcept; |
|
|
|
const_iterator cend() const noexcept; |
|
|
|
iterator begin() noexcept; |
|
|
|
iterator end() noexcept; |
|
|
|
|
|
|
|
const_reference front() const; |
|
|
|
reference front(); |
|
|
|
const_reference back() const; |
|
|
|
reference back(); |
|
|
|
|
|
|
|
bool empty() const noexcept; |
|
|
|
size_type size() const noexcept; |
|
|
|
size_type length() const noexcept; |
|
|
|
size_type capacity() const noexcept; |
|
|
|
|
|
|
|
bool contains (const ElementType&) const; |
|
|
|
|
|
|
|
void clear() noexcept; |
|
|
|
void resize (size_type newSize); |
|
|
|
void reserve (size_type requiredNumElements); |
|
|
|
|
|
|
|
void push_back (const value_type&); |
|
|
|
void push_back (value_type&&); |
|
|
|
|
|
|
|
/// Handy method to add multiple elements with a single push_back call. |
|
|
|
template <typename... Others> |
|
|
|
void push_back (const value_type& first, Others&&... others); |
|
|
|
|
|
|
|
template <typename... ConstructorArgs> |
|
|
|
void emplace_back (ConstructorArgs&&... args); |
|
|
|
|
|
|
|
void pop_back(); |
|
|
|
|
|
|
|
void insert (iterator insertPosition, const value_type& valueToInsert); |
|
|
|
void insert (iterator insertPosition, value_type&& valueToInsert); |
|
|
|
|
|
|
|
void erase (iterator startPosition); |
|
|
|
void erase (iterator startPosition, iterator endPosition); |
|
|
|
|
|
|
|
bool operator== (span<value_type>) const; |
|
|
|
bool operator!= (span<value_type>) const; |
|
|
|
|
|
|
|
private: |
|
|
|
value_type* elements; |
|
|
|
size_type numElements = 0, numAllocated = numPreallocatedElements; |
|
|
|
uint64_t internalStorage[(numPreallocatedElements * sizeof (value_type) + sizeof (uint64_t) - 1) / sizeof (uint64_t)]; |
|
|
|
|
|
|
|
void shrink (size_type); |
|
|
|
value_type* getInternalStorage() noexcept { return reinterpret_cast<value_type*> (internalStorage); } |
|
|
|
bool isUsingInternalStorage() const noexcept { return numAllocated <= numPreallocatedElements; } |
|
|
|
void resetToInternalStorage() noexcept; |
|
|
|
void freeHeapAndResetToInternalStorage() noexcept; |
|
|
|
|
|
|
|
static inline ElementType& _nullValue() noexcept { static ElementType e = {}; return e; } |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================== |
|
|
|
// _ _ _ _ |
|
|
|
// __| | ___ | |_ __ _ (_)| | ___ |
|
|
|
// / _` | / _ \| __| / _` || || |/ __| |
|
|
|
// | (_| || __/| |_ | (_| || || |\__ \ _ _ _ |
|
|
|
// \__,_| \___| \__| \__,_||_||_||___/(_)(_)(_) |
|
|
|
// |
|
|
|
// Code beyond this point is implementation detail... |
|
|
|
// |
|
|
|
//============================================================================== |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
SmallVector<ElementType, preSize>::SmallVector() noexcept : elements (getInternalStorage()) |
|
|
|
{ |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
SmallVector<ElementType, preSize>::~SmallVector() noexcept |
|
|
|
{ |
|
|
|
clear(); |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
SmallVector<ElementType, preSize>::SmallVector (const SmallVector& other) : SmallVector() |
|
|
|
{ |
|
|
|
operator= (other); |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
template <typename VectorType> |
|
|
|
SmallVector<ElementType, preSize>::SmallVector (const VectorType& initialContent) : SmallVector() |
|
|
|
{ |
|
|
|
reserve (initialContent.size()); |
|
|
|
|
|
|
|
for (auto& i : initialContent) |
|
|
|
emplace_back (i); |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
SmallVector<ElementType, preSize>::SmallVector (SmallVector&& other) noexcept |
|
|
|
{ |
|
|
|
if (other.isUsingInternalStorage()) |
|
|
|
{ |
|
|
|
elements = getInternalStorage(); |
|
|
|
numElements = other.numElements; |
|
|
|
|
|
|
|
for (size_type i = 0; i < numElements; ++i) |
|
|
|
new (elements + i) value_type (std::move (other.elements[i])); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
elements = other.elements; |
|
|
|
numElements = other.numElements; |
|
|
|
numAllocated = other.numAllocated; |
|
|
|
other.resetToInternalStorage(); |
|
|
|
other.numElements = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
SmallVector<ElementType, preSize>& SmallVector<ElementType, preSize>::operator= (SmallVector&& other) noexcept |
|
|
|
{ |
|
|
|
clear(); |
|
|
|
|
|
|
|
if (other.isUsingInternalStorage()) |
|
|
|
{ |
|
|
|
numElements = other.numElements; |
|
|
|
|
|
|
|
for (size_type i = 0; i < numElements; ++i) |
|
|
|
new (elements + i) value_type (std::move (other.elements[i])); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
elements = other.elements; |
|
|
|
numElements = other.numElements; |
|
|
|
numAllocated = other.numAllocated; |
|
|
|
other.resetToInternalStorage(); |
|
|
|
other.numElements = 0; |
|
|
|
} |
|
|
|
|
|
|
|
return *this; |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
SmallVector<ElementType, preSize>& SmallVector<ElementType, preSize>::operator= (const SmallVector& other) |
|
|
|
{ |
|
|
|
if (other.size() > numElements) |
|
|
|
{ |
|
|
|
reserve (other.size()); |
|
|
|
|
|
|
|
for (size_type i = 0; i < numElements; ++i) |
|
|
|
elements[i] = other.elements[i]; |
|
|
|
|
|
|
|
for (size_type i = numElements; i < other.size(); ++i) |
|
|
|
new (elements + i) value_type (other.elements[i]); |
|
|
|
|
|
|
|
numElements = other.size(); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
shrink (other.size()); |
|
|
|
|
|
|
|
for (size_type i = 0; i < numElements; ++i) |
|
|
|
elements[i] = other.elements[i]; |
|
|
|
} |
|
|
|
|
|
|
|
return *this; |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
template <typename VectorType> |
|
|
|
SmallVector<ElementType, preSize>& SmallVector<ElementType, preSize>::operator= (const VectorType& other) |
|
|
|
{ |
|
|
|
if (other.size() > numElements) |
|
|
|
{ |
|
|
|
reserve (other.size()); |
|
|
|
|
|
|
|
for (size_type i = 0; i < numElements; ++i) |
|
|
|
elements[i] = other[i]; |
|
|
|
|
|
|
|
for (size_type i = numElements; i < other.size(); ++i) |
|
|
|
new (elements + i) value_type (other[i]); |
|
|
|
|
|
|
|
numElements = other.size(); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
shrink (other.size()); |
|
|
|
|
|
|
|
for (size_type i = 0; i < numElements; ++i) |
|
|
|
elements[i] = other[i]; |
|
|
|
} |
|
|
|
|
|
|
|
return *this; |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
void SmallVector<ElementType, preSize>::resetToInternalStorage() noexcept |
|
|
|
{ |
|
|
|
elements = getInternalStorage(); |
|
|
|
numAllocated = preSize; |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
void SmallVector<ElementType, preSize>::freeHeapAndResetToInternalStorage() noexcept |
|
|
|
{ |
|
|
|
if (! isUsingInternalStorage()) |
|
|
|
{ |
|
|
|
delete[] reinterpret_cast<char*> (elements); |
|
|
|
resetToInternalStorage(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
typename SmallVector<ElementType, preSize>::reference SmallVector<ElementType, preSize>::operator[] (size_type index) |
|
|
|
{ |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN (index < numElements, _nullValue()); |
|
|
|
return elements[index]; |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
typename SmallVector<ElementType, preSize>::const_reference SmallVector<ElementType, preSize>::operator[] (size_type index) const |
|
|
|
{ |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN (index < numElements, _nullValue()); |
|
|
|
return elements[index]; |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
typename SmallVector<ElementType, preSize>::value_type* SmallVector<ElementType, preSize>::data() const noexcept { return elements; } |
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
typename SmallVector<ElementType, preSize>::const_iterator SmallVector<ElementType, preSize>::begin() const noexcept { return elements; } |
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
typename SmallVector<ElementType, preSize>::const_iterator SmallVector<ElementType, preSize>::end() const noexcept { return elements + numElements; } |
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
typename SmallVector<ElementType, preSize>::const_iterator SmallVector<ElementType, preSize>::cbegin() const noexcept { return elements; } |
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
typename SmallVector<ElementType, preSize>::const_iterator SmallVector<ElementType, preSize>::cend() const noexcept { return elements + numElements; } |
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
typename SmallVector<ElementType, preSize>::iterator SmallVector<ElementType, preSize>::begin() noexcept { return elements; } |
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
typename SmallVector<ElementType, preSize>::iterator SmallVector<ElementType, preSize>::end() noexcept { return elements + numElements; } |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
typename SmallVector<ElementType, preSize>::reference SmallVector<ElementType, preSize>::front() |
|
|
|
{ |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN (! empty(), _nullValue()); |
|
|
|
return elements[0]; |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
typename SmallVector<ElementType, preSize>::const_reference SmallVector<ElementType, preSize>::front() const |
|
|
|
{ |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN (! empty(), _nullValue()); |
|
|
|
return elements[0]; |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
typename SmallVector<ElementType, preSize>::reference SmallVector<ElementType, preSize>::back() |
|
|
|
{ |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN (! empty(), _nullValue()); |
|
|
|
return elements[numElements - 1]; |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
typename SmallVector<ElementType, preSize>::const_reference SmallVector<ElementType, preSize>::back() const |
|
|
|
{ |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN (! empty(), _nullValue()); |
|
|
|
return elements[numElements - 1]; |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
typename SmallVector<ElementType, preSize>::size_type SmallVector<ElementType, preSize>::size() const noexcept { return numElements; } |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
typename SmallVector<ElementType, preSize>::size_type SmallVector<ElementType, preSize>::length() const noexcept { return numElements; } |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
typename SmallVector<ElementType, preSize>::size_type SmallVector<ElementType, preSize>::capacity() const noexcept { return numAllocated; } |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
bool SmallVector<ElementType, preSize>::empty() const noexcept { return numElements == 0; } |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
bool SmallVector<ElementType, preSize>::contains (const ElementType& target) const |
|
|
|
{ |
|
|
|
for (size_t i = 0; i < numElements; ++i) |
|
|
|
if (elements[i] == target) |
|
|
|
return true; |
|
|
|
|
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
bool SmallVector<ElementType, preSize>::operator== (span<value_type> other) const { return span<value_type> (*this) == other; } |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
bool SmallVector<ElementType, preSize>::operator!= (span<value_type> other) const { return span<value_type> (*this) != other; } |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
void SmallVector<ElementType, preSize>::push_back (const value_type& item) |
|
|
|
{ |
|
|
|
reserve (numElements + 1); |
|
|
|
new (elements + numElements) value_type (item); |
|
|
|
++numElements; |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
void SmallVector<ElementType, preSize>::push_back (value_type&& item) |
|
|
|
{ |
|
|
|
reserve (numElements + 1); |
|
|
|
new (elements + numElements) value_type (std::move (item)); |
|
|
|
++numElements; |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
template <typename... Others> |
|
|
|
void SmallVector<ElementType, preSize>::push_back (const value_type& first, Others&&... others) |
|
|
|
{ |
|
|
|
reserve (numElements + 1 + sizeof... (others)); |
|
|
|
push_back (first); |
|
|
|
push_back (std::forward<Others> (others)...); |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
template <typename... ConstructorArgs> |
|
|
|
void SmallVector<ElementType, preSize>::emplace_back (ConstructorArgs&&... args) |
|
|
|
{ |
|
|
|
reserve (numElements + 1); |
|
|
|
new (elements + numElements) value_type (std::forward<ConstructorArgs> (args)...); |
|
|
|
++numElements; |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
void SmallVector<ElementType, preSize>::insert (iterator insertPos, const value_type& item) |
|
|
|
{ |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN (insertPos != nullptr && insertPos >= begin() && insertPos <= end(),); |
|
|
|
auto index = insertPos - begin(); |
|
|
|
push_back (item); |
|
|
|
std::rotate (begin() + index, end() - 1, end()); |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
void SmallVector<ElementType, preSize>::insert (iterator insertPos, value_type&& item) |
|
|
|
{ |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN (insertPos != nullptr && insertPos >= begin() && insertPos <= end(),); |
|
|
|
auto index = insertPos - begin(); |
|
|
|
push_back (std::move (item)); |
|
|
|
std::rotate (begin() + index, end() - 1, end()); |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
void SmallVector<ElementType, preSize>::pop_back() |
|
|
|
{ |
|
|
|
if (numElements == 1) |
|
|
|
{ |
|
|
|
clear(); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN (numElements > 0,); |
|
|
|
elements[--numElements].~value_type(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
void SmallVector<ElementType, preSize>::clear() noexcept |
|
|
|
{ |
|
|
|
for (size_type i = 0; i < numElements; ++i) |
|
|
|
elements[i].~value_type(); |
|
|
|
|
|
|
|
numElements = 0; |
|
|
|
freeHeapAndResetToInternalStorage(); |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
void SmallVector<ElementType, preSize>::resize (size_type newSize) |
|
|
|
{ |
|
|
|
if (newSize > numElements) |
|
|
|
{ |
|
|
|
reserve (newSize); |
|
|
|
|
|
|
|
while (numElements < newSize) |
|
|
|
new (elements + numElements++) value_type (value_type()); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
shrink (newSize); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
void SmallVector<ElementType, preSize>::shrink (size_type newSize) |
|
|
|
{ |
|
|
|
if (newSize == 0) |
|
|
|
return clear(); |
|
|
|
|
|
|
|
DISTRHO_SAFE_ASSERT_RETURN (newSize <= numElements,); |
|
|
|
|
|
|
|
while (newSize < numElements && numElements > 0) |
|
|
|
elements[--numElements].~value_type(); |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
void SmallVector<ElementType, preSize>::reserve (size_type requiredNumElements) |
|
|
|
{ |
|
|
|
if (requiredNumElements > numAllocated) |
|
|
|
{ |
|
|
|
requiredNumElements = static_cast<size_type> ((requiredNumElements + 15u) & ~(size_type) 15u); |
|
|
|
|
|
|
|
if (requiredNumElements > preSize) |
|
|
|
{ |
|
|
|
auto* newBuffer = reinterpret_cast<value_type*> (new char[requiredNumElements * sizeof (value_type)]); |
|
|
|
|
|
|
|
for (size_type i = 0; i < numElements; ++i) |
|
|
|
{ |
|
|
|
new (newBuffer + i) value_type (std::move (elements[i])); |
|
|
|
elements[i].~value_type(); |
|
|
|
} |
|
|
|
|
|
|
|
freeHeapAndResetToInternalStorage(); |
|
|
|
elements = newBuffer; |
|
|
|
} |
|
|
|
|
|
|
|
numAllocated = requiredNumElements; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
void SmallVector<ElementType, preSize>::erase (iterator startElement) |
|
|
|
{ |
|
|
|
erase (startElement, startElement + 1); |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ElementType, size_t preSize> |
|
|
|
void SmallVector<ElementType, preSize>::erase (iterator startElement, iterator endElement) |
|
|
|
{ |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN (startElement != nullptr && startElement >= begin() && startElement <= end(),); |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN (endElement != nullptr && endElement >= begin() && endElement <= end(),); |
|
|
|
|
|
|
|
if (startElement != endElement) |
|
|
|
{ |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN (startElement < endElement,); |
|
|
|
|
|
|
|
if (endElement == end()) |
|
|
|
return shrink (static_cast<size_type> (startElement - begin())); |
|
|
|
|
|
|
|
auto dest = startElement; |
|
|
|
|
|
|
|
for (auto src = endElement; src < end(); ++dest, ++src) |
|
|
|
*dest = std::move (*src); |
|
|
|
|
|
|
|
shrink (size() - static_cast<size_type> (endElement - startElement)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#endif // CHOC_SMALLVECTOR_HEADER_INCLUDED |