|
|
@@ -24,11 +24,12 @@
|
|
|
|
|
|
#include "../Container/VectorBase.h"
|
|
|
|
|
|
+#include <algorithm>
|
|
|
#include <cassert>
|
|
|
#include <cstring>
|
|
|
-#include <algorithm>
|
|
|
#include <initializer_list>
|
|
|
#include <new>
|
|
|
+#include <type_traits>
|
|
|
#include <utility>
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
|
@@ -70,13 +71,24 @@ public:
|
|
|
/// Construct with initial data.
|
|
|
Vector(const T* data, unsigned size)
|
|
|
{
|
|
|
- DoInsertElements(0, data, data + size, CopyTag{});
|
|
|
+ if constexpr (std::is_trivial<T>::value && std::is_standard_layout<T>::value)
|
|
|
+ {
|
|
|
+ Resize(size);
|
|
|
+ CopyElements(Buffer(), data, size);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ DoInsertElements(0, data, data + size, CopyTag{});
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// Copy-construct from another vector.
|
|
|
Vector(const Vector<T>& vector)
|
|
|
{
|
|
|
- DoInsertElements(0, vector.Begin(), vector.End(), CopyTag{});
|
|
|
+ if constexpr (std::is_trivial<T>::value && std::is_standard_layout<T>::value)
|
|
|
+ *this = vector;
|
|
|
+ else
|
|
|
+ DoInsertElements(0, vector.Begin(), vector.End(), CopyTag{});
|
|
|
}
|
|
|
|
|
|
/// Copy-construct from another vector (iterator version).
|
|
|
@@ -103,7 +115,9 @@ public:
|
|
|
/// Destruct.
|
|
|
~Vector()
|
|
|
{
|
|
|
- DestructElements(Buffer(), size_);
|
|
|
+ if constexpr (!std::is_trivial<T>::value)
|
|
|
+ DestructElements(Buffer(), size_);
|
|
|
+
|
|
|
delete[] buffer_;
|
|
|
}
|
|
|
|
|
|
@@ -113,9 +127,18 @@ public:
|
|
|
// In case of self-assignment do nothing
|
|
|
if (&rhs != this)
|
|
|
{
|
|
|
- Vector<T> copy(rhs);
|
|
|
- Swap(copy);
|
|
|
+ if constexpr (std::is_trivial<T>::value && std::is_standard_layout<T>::value)
|
|
|
+ {
|
|
|
+ Resize(rhs.size_);
|
|
|
+ CopyElements(Buffer(), rhs.Buffer(), rhs.size_);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Vector<T> copy(rhs);
|
|
|
+ Swap(copy);
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
return *this;
|
|
|
}
|
|
|
|
|
|
@@ -239,14 +262,28 @@ public:
|
|
|
#ifndef COVERITY_SCAN_MODEL
|
|
|
void Push(const T& value)
|
|
|
{
|
|
|
- if (size_ < capacity_)
|
|
|
+ if constexpr (std::is_trivial<T>::value && std::is_standard_layout<T>::value)
|
|
|
{
|
|
|
- // Optimize common case
|
|
|
- ++size_;
|
|
|
- new (&Back()) T(value);
|
|
|
+ if (size_ < capacity_)
|
|
|
+ ++size_;
|
|
|
+ else
|
|
|
+ Resize(size_ + 1);
|
|
|
+
|
|
|
+ Back() = value;
|
|
|
}
|
|
|
else
|
|
|
- DoInsertElements(size_, &value, &value + 1, CopyTag{});
|
|
|
+ {
|
|
|
+ if (size_ < capacity_)
|
|
|
+ {
|
|
|
+ // Optimize common case
|
|
|
+ ++size_;
|
|
|
+ new (&Back()) T(value);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ DoInsertElements(size_, &value, &value + 1, CopyTag{});
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// Move-add an element at the end.
|
|
|
@@ -272,7 +309,21 @@ public:
|
|
|
#endif
|
|
|
|
|
|
/// Add another vector at the end.
|
|
|
- void Push(const Vector<T>& vector) { DoInsertElements(size_, vector.Begin(), vector.End(), CopyTag{}); }
|
|
|
+ void Push(const Vector<T>& vector)
|
|
|
+ {
|
|
|
+ if constexpr (std::is_trivial<T>::value && std::is_standard_layout<T>::value)
|
|
|
+ {
|
|
|
+ // Obtain the size before resizing, in case the other vector is another reference to this vector
|
|
|
+ unsigned thisSize = size_;
|
|
|
+ unsigned vectorSize = vector.size_;
|
|
|
+ Resize(thisSize + vectorSize);
|
|
|
+ CopyElements(Buffer() + thisSize, vector.Buffer(), vectorSize);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ DoInsertElements(size_, vector.Begin(), vector.End(), CopyTag{});
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
/// Remove the last element.
|
|
|
void Pop()
|
|
|
@@ -290,20 +341,58 @@ public:
|
|
|
/// Insert an element at position.
|
|
|
void Insert(unsigned pos, T && value)
|
|
|
{
|
|
|
- DoInsertElements(pos, &value, &value + 1, MoveTag{});
|
|
|
+ if constexpr (std::is_trivial<T>::value && std::is_standard_layout<T>::value)
|
|
|
+ {
|
|
|
+ if (pos > size_)
|
|
|
+ pos = size_;
|
|
|
+
|
|
|
+ unsigned oldSize = size_;
|
|
|
+ Resize(size_ + 1);
|
|
|
+ MoveRange(pos + 1, pos, oldSize - pos);
|
|
|
+ Buffer()[pos] = value;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ DoInsertElements(pos, &value, &value + 1, MoveTag{});
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// Insert another vector at position.
|
|
|
void Insert(unsigned pos, const Vector<T>& vector)
|
|
|
{
|
|
|
- DoInsertElements(pos, vector.Begin(), vector.End(), CopyTag{});
|
|
|
+ if constexpr (std::is_trivial<T>::value && std::is_standard_layout<T>::value)
|
|
|
+ {
|
|
|
+ if (pos > size_)
|
|
|
+ pos = size_;
|
|
|
+
|
|
|
+ unsigned oldSize = size_;
|
|
|
+ Resize(size_ + vector.size_);
|
|
|
+ MoveRange(pos + vector.size_, pos, oldSize - pos);
|
|
|
+ CopyElements(Buffer() + pos, vector.Buffer(), vector.size_);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ DoInsertElements(pos, vector.Begin(), vector.End(), CopyTag{});
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// Insert an element by iterator.
|
|
|
Iterator Insert(const Iterator& dest, const T& value)
|
|
|
{
|
|
|
- auto pos = (unsigned)(dest - Begin());
|
|
|
- return DoInsertElements(pos, &value, &value + 1, CopyTag{});
|
|
|
+ if constexpr (std::is_trivial<T>::value && std::is_standard_layout<T>::value)
|
|
|
+ {
|
|
|
+ auto pos = (unsigned)(dest - Begin());
|
|
|
+ if (pos > size_)
|
|
|
+ pos = size_;
|
|
|
+ Insert(pos, value);
|
|
|
+
|
|
|
+ return Begin() + pos;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ auto pos = (unsigned)(dest - Begin());
|
|
|
+ return DoInsertElements(pos, &value, &value + 1, CopyTag{});
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// Move-insert an element by iterator.
|
|
|
@@ -316,22 +405,67 @@ public:
|
|
|
/// Insert a vector by iterator.
|
|
|
Iterator Insert(const Iterator& dest, const Vector<T>& vector)
|
|
|
{
|
|
|
- auto pos = (unsigned)(dest - Begin());
|
|
|
- return DoInsertElements(pos, vector.Begin(), vector.End(), CopyTag{});
|
|
|
+ if constexpr (std::is_trivial<T>::value && std::is_standard_layout<T>::value)
|
|
|
+ {
|
|
|
+ auto pos = (unsigned)(dest - Begin());
|
|
|
+ if (pos > size_)
|
|
|
+ pos = size_;
|
|
|
+ Insert(pos, vector);
|
|
|
+
|
|
|
+ return Begin() + pos;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ auto pos = (unsigned)(dest - Begin());
|
|
|
+ return DoInsertElements(pos, vector.Begin(), vector.End(), CopyTag{});
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// Insert a vector partially by iterators.
|
|
|
Iterator Insert(const Iterator& dest, const ConstIterator& start, const ConstIterator& end)
|
|
|
{
|
|
|
- auto pos = (unsigned)(dest - Begin());
|
|
|
- return DoInsertElements(pos, start, end, CopyTag{});
|
|
|
+ if constexpr (std::is_trivial<T>::value && std::is_standard_layout<T>::value)
|
|
|
+ {
|
|
|
+ auto pos = (unsigned)(dest - Begin());
|
|
|
+ if (pos > size_)
|
|
|
+ pos = size_;
|
|
|
+ auto length = (unsigned)(end - start);
|
|
|
+ Resize(size_ + length);
|
|
|
+ MoveRange(pos + length, pos, size_ - pos - length);
|
|
|
+ CopyElements(Buffer() + pos, &(*start), length);
|
|
|
+
|
|
|
+ return Begin() + pos;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ auto pos = (unsigned)(dest - Begin());
|
|
|
+ return DoInsertElements(pos, start, end, CopyTag{});
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// Insert elements.
|
|
|
Iterator Insert(const Iterator& dest, const T* start, const T* end)
|
|
|
{
|
|
|
- auto pos = (unsigned)(dest - Begin());
|
|
|
- return DoInsertElements(pos, start, end, CopyTag{});
|
|
|
+ if constexpr (std::is_trivial<T>::value && std::is_standard_layout<T>::value)
|
|
|
+ {
|
|
|
+ auto pos = (unsigned)(dest - Begin());
|
|
|
+ if (pos > size_)
|
|
|
+ pos = size_;
|
|
|
+ auto length = (unsigned)(end - start);
|
|
|
+ Resize(size_ + length);
|
|
|
+ MoveRange(pos + length, pos, size_ - pos - length);
|
|
|
+
|
|
|
+ T* destPtr = Buffer() + pos;
|
|
|
+ for (const T* i = start; i != end; ++i)
|
|
|
+ *destPtr++ = *i;
|
|
|
+
|
|
|
+ return Begin() + pos;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ auto pos = (unsigned)(dest - Begin());
|
|
|
+ return DoInsertElements(pos, start, end, CopyTag{});
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// Erase a range of elements.
|
|
|
@@ -341,7 +475,15 @@ public:
|
|
|
if (pos + length > size_ || !length)
|
|
|
return;
|
|
|
|
|
|
- DoEraseElements(pos, length);
|
|
|
+ if constexpr (std::is_trivial<T>::value && std::is_standard_layout<T>::value)
|
|
|
+ {
|
|
|
+ MoveRange(pos, pos + length, size_ - pos - length);
|
|
|
+ Resize(size_ - length);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ DoEraseElements(pos, length);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// Erase a range of elements by swapping elements from the end of the array.
|
|
|
@@ -354,17 +496,35 @@ public:
|
|
|
|
|
|
unsigned newSize = size_ - length;
|
|
|
unsigned trailingCount = size_ - shiftStartIndex;
|
|
|
- if (trailingCount <= length)
|
|
|
+
|
|
|
+ if constexpr (std::is_trivial<T>::value && std::is_standard_layout<T>::value)
|
|
|
{
|
|
|
- // We're removing more elements from the array than exist past the end of the range being removed, so perform a normal shift and destroy
|
|
|
- DoEraseElements(pos, length);
|
|
|
+ if (trailingCount <= length)
|
|
|
+ {
|
|
|
+ // We're removing more elements from the array than exist past the end of the range being removed, so perform a normal shift and destroy
|
|
|
+ MoveRange(pos, shiftStartIndex, trailingCount);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // Swap elements from the end of the array into the empty space
|
|
|
+ CopyElements(Buffer() + pos, Buffer() + newSize, length);
|
|
|
+ }
|
|
|
+ Resize(newSize);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- // Swap elements from the end of the array into the empty space
|
|
|
- T* buffer = Buffer();
|
|
|
- std::move(buffer + newSize, buffer + size_, buffer + pos);
|
|
|
- Resize(newSize);
|
|
|
+ if (trailingCount <= length)
|
|
|
+ {
|
|
|
+ // We're removing more elements from the array than exist past the end of the range being removed, so perform a normal shift and destroy
|
|
|
+ DoEraseElements(pos, length);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // Swap elements from the end of the array into the empty space
|
|
|
+ T* buffer = Buffer();
|
|
|
+ std::move(buffer + newSize, buffer + size_, buffer + pos);
|
|
|
+ Resize(newSize);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -401,7 +561,9 @@ public:
|
|
|
return true;
|
|
|
}
|
|
|
else
|
|
|
+ {
|
|
|
return false;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// Erase an element by value by swapping with the last element. Return true if was found and erased.
|
|
|
@@ -414,20 +576,52 @@ public:
|
|
|
return true;
|
|
|
}
|
|
|
else
|
|
|
+ {
|
|
|
return false;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// Clear the vector.
|
|
|
void Clear() { Resize(0); }
|
|
|
|
|
|
/// Resize the vector.
|
|
|
- void Resize(unsigned newSize) { DoResize(newSize); }
|
|
|
+ void Resize(unsigned newSize)
|
|
|
+ {
|
|
|
+ if constexpr (std::is_trivial<T>::value && std::is_standard_layout<T>::value)
|
|
|
+ {
|
|
|
+ if (newSize > capacity_)
|
|
|
+ {
|
|
|
+ if (!capacity_)
|
|
|
+ capacity_ = newSize;
|
|
|
+ else
|
|
|
+ {
|
|
|
+ while (capacity_ < newSize)
|
|
|
+ capacity_ += (capacity_ + 1) >> 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ unsigned char* newBuffer = AllocateBuffer((unsigned)(capacity_ * sizeof(T)));
|
|
|
+ // Move the data into the new buffer and delete the old
|
|
|
+ if (buffer_)
|
|
|
+ {
|
|
|
+ CopyElements(reinterpret_cast<T*>(newBuffer), Buffer(), size_);
|
|
|
+ delete[] buffer_;
|
|
|
+ }
|
|
|
+ buffer_ = newBuffer;
|
|
|
+ }
|
|
|
+
|
|
|
+ size_ = newSize;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ DoResize(newSize);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
/// Resize the vector and fill new elements with default value.
|
|
|
void Resize(unsigned newSize, const T& value)
|
|
|
{
|
|
|
unsigned oldSize = Size();
|
|
|
- DoResize(newSize);
|
|
|
+ Resize(newSize);
|
|
|
for (unsigned i = oldSize; i < newSize; ++i)
|
|
|
At(i) = value;
|
|
|
}
|
|
|
@@ -438,22 +632,44 @@ public:
|
|
|
if (newCapacity < size_)
|
|
|
newCapacity = size_;
|
|
|
|
|
|
- if (newCapacity != capacity_)
|
|
|
+ if constexpr (std::is_trivial<T>::value && std::is_standard_layout<T>::value)
|
|
|
{
|
|
|
- T* newBuffer = nullptr;
|
|
|
- capacity_ = newCapacity;
|
|
|
+ if (newCapacity != capacity_)
|
|
|
+ {
|
|
|
+ unsigned char* newBuffer = nullptr;
|
|
|
+ capacity_ = newCapacity;
|
|
|
|
|
|
- if (capacity_)
|
|
|
+ if (capacity_)
|
|
|
+ {
|
|
|
+ newBuffer = AllocateBuffer((unsigned)(capacity_ * sizeof(T)));
|
|
|
+ // Move the data into the new buffer
|
|
|
+ CopyElements(reinterpret_cast<T*>(newBuffer), Buffer(), size_);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Delete the old buffer
|
|
|
+ delete[] buffer_;
|
|
|
+ buffer_ = newBuffer;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (newCapacity != capacity_)
|
|
|
{
|
|
|
- newBuffer = reinterpret_cast<T*>(AllocateBuffer((unsigned)(capacity_ * sizeof(T))));
|
|
|
- // Move the data into the new buffer
|
|
|
- ConstructElements(newBuffer, Begin(), End(), MoveTag{});
|
|
|
+ T* newBuffer = nullptr;
|
|
|
+ capacity_ = newCapacity;
|
|
|
+
|
|
|
+ if (capacity_)
|
|
|
+ {
|
|
|
+ newBuffer = reinterpret_cast<T*>(AllocateBuffer((unsigned)(capacity_ * sizeof(T))));
|
|
|
+ // Move the data into the new buffer
|
|
|
+ ConstructElements(newBuffer, Begin(), End(), MoveTag{});
|
|
|
+ }
|
|
|
+
|
|
|
+ // Delete the old buffer
|
|
|
+ DestructElements(Buffer(), size_);
|
|
|
+ delete[] buffer_;
|
|
|
+ buffer_ = reinterpret_cast<unsigned char*>(newBuffer);
|
|
|
}
|
|
|
-
|
|
|
- // Delete the old buffer
|
|
|
- DestructElements(Buffer(), size_);
|
|
|
- delete[] buffer_;
|
|
|
- buffer_ = reinterpret_cast<unsigned char*>(newBuffer);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -527,7 +743,7 @@ public:
|
|
|
return Buffer()[size_ - 1];
|
|
|
}
|
|
|
|
|
|
- /// Return size of vector.
|
|
|
+ /// Return number of elements.
|
|
|
unsigned Size() const { return size_; }
|
|
|
|
|
|
/// Return capacity of vector.
|
|
|
@@ -569,7 +785,9 @@ private:
|
|
|
static unsigned CalculateCapacity(unsigned size, unsigned capacity)
|
|
|
{
|
|
|
if (!capacity)
|
|
|
+ {
|
|
|
return size;
|
|
|
+ }
|
|
|
else
|
|
|
{
|
|
|
while (capacity < size)
|
|
|
@@ -583,7 +801,9 @@ private:
|
|
|
{
|
|
|
// If size shrinks, destruct the removed elements
|
|
|
if (newSize < size_)
|
|
|
+ {
|
|
|
DestructElements(Buffer() + newSize, size_ - newSize);
|
|
|
+ }
|
|
|
else
|
|
|
{
|
|
|
// Allocate new buffer if necessary and copy the current elements
|
|
|
@@ -679,518 +899,48 @@ private:
|
|
|
++dest;
|
|
|
}
|
|
|
}
|
|
|
-};
|
|
|
-
|
|
|
-/// %Vector template class for POD types. Does not call constructors or destructors and uses block move. Is intentionally (for performance reasons) unsafe for self-insertion.
|
|
|
-template <class T> class PODVector : public VectorBase
|
|
|
-{
|
|
|
-public:
|
|
|
- using ValueType = T;
|
|
|
- using Iterator = RandomAccessIterator<T>;
|
|
|
- using ConstIterator = RandomAccessConstIterator<T>;
|
|
|
-
|
|
|
- /// Construct empty.
|
|
|
- PODVector() noexcept = default;
|
|
|
-
|
|
|
- /// Construct with initial size.
|
|
|
- explicit PODVector(unsigned size)
|
|
|
- {
|
|
|
- Resize(size);
|
|
|
- }
|
|
|
-
|
|
|
- /// Construct with initial size and default value.
|
|
|
- PODVector(unsigned size, const T& value)
|
|
|
- {
|
|
|
- Resize(size);
|
|
|
- for (unsigned i = 0; i < size; ++i)
|
|
|
- At(i) = value;
|
|
|
- }
|
|
|
-
|
|
|
- /// Construct with initial data.
|
|
|
- PODVector(const T* data, unsigned size)
|
|
|
- {
|
|
|
- Resize(size);
|
|
|
- CopyElements(Buffer(), data, size);
|
|
|
- }
|
|
|
|
|
|
- /// Construct from another vector.
|
|
|
- PODVector(const PODVector<T>& vector)
|
|
|
- {
|
|
|
- *this = vector;
|
|
|
- }
|
|
|
- /// Aggregate initialization constructor.
|
|
|
- PODVector(const std::initializer_list<T>& list) : PODVector()
|
|
|
+ /// Move a range of elements within the vector. Only for PODVector.
|
|
|
+ void MoveRange(unsigned dest, unsigned src, unsigned count)
|
|
|
{
|
|
|
- for (auto it = list.begin(); it != list.end(); it++)
|
|
|
+ if constexpr (std::is_trivial<T>::value && std::is_standard_layout<T>::value)
|
|
|
{
|
|
|
- Push(*it);
|
|
|
+ if (count)
|
|
|
+ memmove(Buffer() + dest, Buffer() + src, count * sizeof(T));
|
|
|
}
|
|
|
- }
|
|
|
- /// Destruct.
|
|
|
- ~PODVector()
|
|
|
- {
|
|
|
- delete[] buffer_;
|
|
|
- }
|
|
|
-
|
|
|
- /// Assign from another vector.
|
|
|
- PODVector<T>& operator =(const PODVector<T>& rhs)
|
|
|
- {
|
|
|
- // In case of self-assignment do nothing
|
|
|
- if (&rhs != this)
|
|
|
+ else
|
|
|
{
|
|
|
- Resize(rhs.size_);
|
|
|
- CopyElements(Buffer(), rhs.Buffer(), rhs.size_);
|
|
|
+ static_assert(true);
|
|
|
}
|
|
|
- return *this;
|
|
|
- }
|
|
|
-
|
|
|
- /// Add-assign an element.
|
|
|
- PODVector<T>& operator +=(const T& rhs)
|
|
|
- {
|
|
|
- Push(rhs);
|
|
|
- return *this;
|
|
|
- }
|
|
|
-
|
|
|
- /// Add-assign another vector.
|
|
|
- PODVector<T>& operator +=(const PODVector<T>& rhs)
|
|
|
- {
|
|
|
- Push(rhs);
|
|
|
- return *this;
|
|
|
- }
|
|
|
-
|
|
|
- /// Add an element.
|
|
|
- PODVector<T> operator +(const T& rhs) const
|
|
|
- {
|
|
|
- PODVector<T> ret(*this);
|
|
|
- ret.Push(rhs);
|
|
|
- return ret;
|
|
|
- }
|
|
|
-
|
|
|
- /// Add another vector.
|
|
|
- PODVector<T> operator +(const PODVector<T>& rhs) const
|
|
|
- {
|
|
|
- PODVector<T> ret(*this);
|
|
|
- ret.Push(rhs);
|
|
|
- return ret;
|
|
|
}
|
|
|
|
|
|
- /// Test for equality with another vector.
|
|
|
- bool operator ==(const PODVector<T>& rhs) const
|
|
|
+ /// Copy elements from one buffer to another. Only for PODVector.
|
|
|
+ static void CopyElements(T* dest, const T* src, unsigned count)
|
|
|
{
|
|
|
- if (rhs.size_ != size_)
|
|
|
- return false;
|
|
|
-
|
|
|
- T* buffer = Buffer();
|
|
|
- T* rhsBuffer = rhs.Buffer();
|
|
|
- for (unsigned i = 0; i < size_; ++i)
|
|
|
+ if constexpr (std::is_trivial<T>::value && std::is_standard_layout<T>::value)
|
|
|
{
|
|
|
- if (buffer[i] != rhsBuffer[i])
|
|
|
- return false;
|
|
|
+ if (count)
|
|
|
+ memcpy(dest, src, count * sizeof(T));
|
|
|
}
|
|
|
-
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- /// Test for inequality with another vector.
|
|
|
- bool operator !=(const PODVector<T>& rhs) const
|
|
|
- {
|
|
|
- if (rhs.size_ != size_)
|
|
|
- return true;
|
|
|
-
|
|
|
- T* buffer = Buffer();
|
|
|
- T* rhsBuffer = rhs.Buffer();
|
|
|
- for (unsigned i = 0; i < size_; ++i)
|
|
|
+ else
|
|
|
{
|
|
|
- if (buffer[i] != rhsBuffer[i])
|
|
|
- return true;
|
|
|
+ static_assert(true);
|
|
|
}
|
|
|
-
|
|
|
- return false;
|
|
|
}
|
|
|
+};
|
|
|
|
|
|
- /// Return element at index.
|
|
|
- T& operator [](unsigned index)
|
|
|
- {
|
|
|
- assert(index < size_);
|
|
|
- return Buffer()[index];
|
|
|
- }
|
|
|
+/// For backwards compatibility.
|
|
|
+template <typename T>
|
|
|
+using PODVector = Vector<T>;
|
|
|
|
|
|
- /// Return const element at index.
|
|
|
- const T& operator [](unsigned index) const
|
|
|
- {
|
|
|
- assert(index < size_);
|
|
|
- return Buffer()[index];
|
|
|
- }
|
|
|
+template <class T> typename Urho3D::Vector<T>::ConstIterator begin(const Urho3D::Vector<T>& v) { return v.Begin(); }
|
|
|
|
|
|
- /// Return element at index.
|
|
|
- T& At(unsigned index)
|
|
|
- {
|
|
|
- assert(index < size_);
|
|
|
- return Buffer()[index];
|
|
|
- }
|
|
|
+template <class T> typename Urho3D::Vector<T>::ConstIterator end(const Urho3D::Vector<T>& v) { return v.End(); }
|
|
|
|
|
|
- /// Return const element at index.
|
|
|
- const T& At(unsigned index) const
|
|
|
- {
|
|
|
- assert(index < size_);
|
|
|
- return Buffer()[index];
|
|
|
- }
|
|
|
-
|
|
|
- /// Add an element at the end.
|
|
|
- void Push(const T& value)
|
|
|
- {
|
|
|
- if (size_ < capacity_)
|
|
|
- ++size_;
|
|
|
- else
|
|
|
- Resize(size_ + 1);
|
|
|
- Back() = value;
|
|
|
- }
|
|
|
-
|
|
|
- /// Add another vector at the end.
|
|
|
- void Push(const PODVector<T>& vector)
|
|
|
- {
|
|
|
- // Obtain the size before resizing, in case the other vector is another reference to this vector
|
|
|
- unsigned thisSize = size_;
|
|
|
- unsigned vectorSize = vector.size_;
|
|
|
- Resize(thisSize + vectorSize);
|
|
|
- CopyElements(Buffer() + thisSize, vector.Buffer(), vectorSize);
|
|
|
- }
|
|
|
-
|
|
|
- /// Remove the last element.
|
|
|
- void Pop()
|
|
|
- {
|
|
|
- if (size_)
|
|
|
- Resize(size_ - 1);
|
|
|
- }
|
|
|
-
|
|
|
- /// Insert an element at position.
|
|
|
- void Insert(unsigned pos, const T& value)
|
|
|
- {
|
|
|
- if (pos > size_)
|
|
|
- pos = size_;
|
|
|
-
|
|
|
- unsigned oldSize = size_;
|
|
|
- Resize(size_ + 1);
|
|
|
- MoveRange(pos + 1, pos, oldSize - pos);
|
|
|
- Buffer()[pos] = value;
|
|
|
- }
|
|
|
-
|
|
|
- /// Insert another vector at position.
|
|
|
- void Insert(unsigned pos, const PODVector<T>& vector)
|
|
|
- {
|
|
|
- if (pos > size_)
|
|
|
- pos = size_;
|
|
|
-
|
|
|
- unsigned oldSize = size_;
|
|
|
- Resize(size_ + vector.size_);
|
|
|
- MoveRange(pos + vector.size_, pos, oldSize - pos);
|
|
|
- CopyElements(Buffer() + pos, vector.Buffer(), vector.size_);
|
|
|
- }
|
|
|
-
|
|
|
- /// Insert an element by iterator.
|
|
|
- Iterator Insert(const Iterator& dest, const T& value)
|
|
|
- {
|
|
|
- auto pos = (unsigned)(dest - Begin());
|
|
|
- if (pos > size_)
|
|
|
- pos = size_;
|
|
|
- Insert(pos, value);
|
|
|
-
|
|
|
- return Begin() + pos;
|
|
|
- }
|
|
|
-
|
|
|
- /// Insert a vector by iterator.
|
|
|
- Iterator Insert(const Iterator& dest, const PODVector<T>& vector)
|
|
|
- {
|
|
|
- auto pos = (unsigned)(dest - Begin());
|
|
|
- if (pos > size_)
|
|
|
- pos = size_;
|
|
|
- Insert(pos, vector);
|
|
|
-
|
|
|
- return Begin() + pos;
|
|
|
- }
|
|
|
-
|
|
|
- /// Insert a vector partially by iterators.
|
|
|
- Iterator Insert(const Iterator& dest, const ConstIterator& start, const ConstIterator& end)
|
|
|
- {
|
|
|
- auto pos = (unsigned)(dest - Begin());
|
|
|
- if (pos > size_)
|
|
|
- pos = size_;
|
|
|
- auto length = (unsigned)(end - start);
|
|
|
- Resize(size_ + length);
|
|
|
- MoveRange(pos + length, pos, size_ - pos - length);
|
|
|
- CopyElements(Buffer() + pos, &(*start), length);
|
|
|
-
|
|
|
- return Begin() + pos;
|
|
|
- }
|
|
|
-
|
|
|
- /// Insert elements.
|
|
|
- Iterator Insert(const Iterator& dest, const T* start, const T* end)
|
|
|
- {
|
|
|
- auto pos = (unsigned)(dest - Begin());
|
|
|
- if (pos > size_)
|
|
|
- pos = size_;
|
|
|
- auto length = (unsigned)(end - start);
|
|
|
- Resize(size_ + length);
|
|
|
- MoveRange(pos + length, pos, size_ - pos - length);
|
|
|
-
|
|
|
- T* destPtr = Buffer() + pos;
|
|
|
- for (const T* i = start; i != end; ++i)
|
|
|
- *destPtr++ = *i;
|
|
|
-
|
|
|
- return Begin() + pos;
|
|
|
- }
|
|
|
-
|
|
|
- /// Erase a range of elements.
|
|
|
- void Erase(unsigned pos, unsigned length = 1)
|
|
|
- {
|
|
|
- // Return if the range is illegal
|
|
|
- if (!length || pos + length > size_)
|
|
|
- return;
|
|
|
-
|
|
|
- MoveRange(pos, pos + length, size_ - pos - length);
|
|
|
- Resize(size_ - length);
|
|
|
- }
|
|
|
-
|
|
|
- /// Erase an element by iterator. Return iterator to the next element.
|
|
|
- Iterator Erase(const Iterator& it)
|
|
|
- {
|
|
|
- auto pos = (unsigned)(it - Begin());
|
|
|
- if (pos >= size_)
|
|
|
- return End();
|
|
|
- Erase(pos);
|
|
|
-
|
|
|
- return Begin() + pos;
|
|
|
- }
|
|
|
-
|
|
|
- /// Erase a range by iterators. Return iterator to the next element.
|
|
|
- Iterator Erase(const Iterator& start, const Iterator& end)
|
|
|
- {
|
|
|
- auto pos = (unsigned)(start - Begin());
|
|
|
- if (pos >= size_)
|
|
|
- return End();
|
|
|
- auto length = (unsigned)(end - start);
|
|
|
- Erase(pos, length);
|
|
|
-
|
|
|
- return Begin() + pos;
|
|
|
- }
|
|
|
-
|
|
|
- /// Erase a range of elements by swapping elements from the end of the array.
|
|
|
- void EraseSwap(unsigned pos, unsigned length = 1)
|
|
|
- {
|
|
|
- unsigned shiftStartIndex = pos + length;
|
|
|
- // Return if the range is illegal
|
|
|
- if (shiftStartIndex > size_ || !length)
|
|
|
- return;
|
|
|
-
|
|
|
- unsigned newSize = size_ - length;
|
|
|
- unsigned trailingCount = size_ - shiftStartIndex;
|
|
|
- if (trailingCount <= length)
|
|
|
- {
|
|
|
- // We're removing more elements from the array than exist past the end of the range being removed, so perform a normal shift and destroy
|
|
|
- MoveRange(pos, shiftStartIndex, trailingCount);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- // Swap elements from the end of the array into the empty space
|
|
|
- CopyElements(Buffer() + pos, Buffer() + newSize, length);
|
|
|
- }
|
|
|
- Resize(newSize);
|
|
|
- }
|
|
|
-
|
|
|
- /// Erase an element by value. Return true if was found and erased.
|
|
|
- bool Remove(const T& value)
|
|
|
- {
|
|
|
- Iterator i = Find(value);
|
|
|
- if (i != End())
|
|
|
- {
|
|
|
- Erase(i);
|
|
|
- return true;
|
|
|
- }
|
|
|
- else
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- /// Erase an element by value by swapping with the last element. Return true if was found and erased.
|
|
|
- bool RemoveSwap(const T& value)
|
|
|
- {
|
|
|
- Iterator i = Find(value);
|
|
|
- if (i != End())
|
|
|
- {
|
|
|
- EraseSwap(i - Begin());
|
|
|
- return true;
|
|
|
- }
|
|
|
- else
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- /// Clear the vector.
|
|
|
- void Clear() { Resize(0); }
|
|
|
-
|
|
|
- /// Resize the vector.
|
|
|
- void Resize(unsigned newSize)
|
|
|
- {
|
|
|
- if (newSize > capacity_)
|
|
|
- {
|
|
|
- if (!capacity_)
|
|
|
- capacity_ = newSize;
|
|
|
- else
|
|
|
- {
|
|
|
- while (capacity_ < newSize)
|
|
|
- capacity_ += (capacity_ + 1) >> 1;
|
|
|
- }
|
|
|
-
|
|
|
- unsigned char* newBuffer = AllocateBuffer((unsigned)(capacity_ * sizeof(T)));
|
|
|
- // Move the data into the new buffer and delete the old
|
|
|
- if (buffer_)
|
|
|
- {
|
|
|
- CopyElements(reinterpret_cast<T*>(newBuffer), Buffer(), size_);
|
|
|
- delete[] buffer_;
|
|
|
- }
|
|
|
- buffer_ = newBuffer;
|
|
|
- }
|
|
|
-
|
|
|
- size_ = newSize;
|
|
|
- }
|
|
|
-
|
|
|
- /// Resize the vector and fill new elements with default value.
|
|
|
- void Resize(unsigned newSize, const T& value)
|
|
|
- {
|
|
|
- unsigned oldSize = Size();
|
|
|
- Resize(newSize);
|
|
|
- for (unsigned i = oldSize; i < newSize; ++i)
|
|
|
- At(i) = value;
|
|
|
- }
|
|
|
-
|
|
|
- /// Set new capacity.
|
|
|
- void Reserve(unsigned newCapacity)
|
|
|
- {
|
|
|
- if (newCapacity < size_)
|
|
|
- newCapacity = size_;
|
|
|
-
|
|
|
- if (newCapacity != capacity_)
|
|
|
- {
|
|
|
- unsigned char* newBuffer = nullptr;
|
|
|
- capacity_ = newCapacity;
|
|
|
-
|
|
|
- if (capacity_)
|
|
|
- {
|
|
|
- newBuffer = AllocateBuffer((unsigned)(capacity_ * sizeof(T)));
|
|
|
- // Move the data into the new buffer
|
|
|
- CopyElements(reinterpret_cast<T*>(newBuffer), Buffer(), size_);
|
|
|
- }
|
|
|
-
|
|
|
- // Delete the old buffer
|
|
|
- delete[] buffer_;
|
|
|
- buffer_ = newBuffer;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// Reallocate so that no extra memory is used.
|
|
|
- void Compact() { Reserve(size_); }
|
|
|
-
|
|
|
- /// Return iterator to value, or to the end if not found.
|
|
|
- Iterator Find(const T& value)
|
|
|
- {
|
|
|
- Iterator it = Begin();
|
|
|
- while (it != End() && *it != value)
|
|
|
- ++it;
|
|
|
- return it;
|
|
|
- }
|
|
|
-
|
|
|
- /// Return const iterator to value, or to the end if not found.
|
|
|
- ConstIterator Find(const T& value) const
|
|
|
- {
|
|
|
- ConstIterator it = Begin();
|
|
|
- while (it != End() && *it != value)
|
|
|
- ++it;
|
|
|
- return it;
|
|
|
- }
|
|
|
-
|
|
|
- /// Return index of value in vector, or size if not found.
|
|
|
- unsigned IndexOf(const T& value) const
|
|
|
- {
|
|
|
- return Find(value) - Begin();
|
|
|
- }
|
|
|
-
|
|
|
- /// Return whether contains a specific value.
|
|
|
- bool Contains(const T& value) const { return Find(value) != End(); }
|
|
|
-
|
|
|
- /// Return iterator to the beginning.
|
|
|
- Iterator Begin() { return Iterator(Buffer()); }
|
|
|
-
|
|
|
- /// Return const iterator to the beginning.
|
|
|
- ConstIterator Begin() const { return ConstIterator(Buffer()); }
|
|
|
-
|
|
|
- /// Return iterator to the end.
|
|
|
- Iterator End() { return Iterator(Buffer() + size_); }
|
|
|
-
|
|
|
- /// Return const iterator to the end.
|
|
|
- ConstIterator End() const { return ConstIterator(Buffer() + size_); }
|
|
|
-
|
|
|
- /// Return first element.
|
|
|
- T& Front() { return Buffer()[0]; }
|
|
|
-
|
|
|
- /// Return const first element.
|
|
|
- const T& Front() const { return Buffer()[0]; }
|
|
|
-
|
|
|
- /// Return last element.
|
|
|
- T& Back()
|
|
|
- {
|
|
|
- assert(size_);
|
|
|
- return Buffer()[size_ - 1];
|
|
|
- }
|
|
|
-
|
|
|
- /// Return const last element.
|
|
|
- const T& Back() const
|
|
|
- {
|
|
|
- assert(size_);
|
|
|
- return Buffer()[size_ - 1];
|
|
|
- }
|
|
|
-
|
|
|
- /// Return number of elements.
|
|
|
- unsigned Size() const { return size_; }
|
|
|
-
|
|
|
- /// Return capacity of vector.
|
|
|
- unsigned Capacity() const { return capacity_; }
|
|
|
-
|
|
|
- /// Return whether vector is empty.
|
|
|
- bool Empty() const { return size_ == 0; }
|
|
|
-
|
|
|
- /// Return the buffer with right type.
|
|
|
- T* Buffer() const { return reinterpret_cast<T*>(buffer_); }
|
|
|
-
|
|
|
-private:
|
|
|
- /// Move a range of elements within the vector.
|
|
|
- void MoveRange(unsigned dest, unsigned src, unsigned count)
|
|
|
- {
|
|
|
- if (count)
|
|
|
- memmove(Buffer() + dest, Buffer() + src, count * sizeof(T));
|
|
|
- }
|
|
|
-
|
|
|
- /// Copy elements from one buffer to another.
|
|
|
- static void CopyElements(T* dest, const T* src, unsigned count)
|
|
|
- {
|
|
|
- if (count)
|
|
|
- memcpy(dest, src, count * sizeof(T));
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-template <class T> typename Urho3D::Vector<T>::ConstIterator begin(const Urho3D::Vector<T>& v) { return v.Begin(); }
|
|
|
-
|
|
|
-template <class T> typename Urho3D::Vector<T>::ConstIterator end(const Urho3D::Vector<T>& v) { return v.End(); }
|
|
|
-
|
|
|
-template <class T> typename Urho3D::Vector<T>::Iterator begin(Urho3D::Vector<T>& v) { return v.Begin(); }
|
|
|
+template <class T> typename Urho3D::Vector<T>::Iterator begin(Urho3D::Vector<T>& v) { return v.Begin(); }
|
|
|
|
|
|
template <class T> typename Urho3D::Vector<T>::Iterator end(Urho3D::Vector<T>& v) { return v.End(); }
|
|
|
|
|
|
-template <class T> typename Urho3D::PODVector<T>::ConstIterator begin(const Urho3D::PODVector<T>& v) { return v.Begin(); }
|
|
|
-
|
|
|
-template <class T> typename Urho3D::PODVector<T>::ConstIterator end(const Urho3D::PODVector<T>& v) { return v.End(); }
|
|
|
-
|
|
|
-template <class T> typename Urho3D::PODVector<T>::Iterator begin(Urho3D::PODVector<T>& v) { return v.Begin(); }
|
|
|
-
|
|
|
-template <class T> typename Urho3D::PODVector<T>::Iterator end(Urho3D::PODVector<T>& v) { return v.End(); }
|
|
|
-
|
|
|
}
|
|
|
|
|
|
#ifdef _MSC_VER
|