4#include "../Foundation/Assert.h"
5#include "../Foundation/Limits.h"
6#include "../Foundation/Memory.h"
7#include "../Foundation/PrimitiveTypes.h"
8#include "Internal/Segment.h"
21struct SC::VectorAllocator
23 static SegmentHeader* reallocate(SegmentHeader* oldHeader,
size_t newSize);
25 static SegmentHeader* allocate(SegmentHeader* oldHeader,
size_t numNewBytes,
void* selfPointer);
27 static void release(SegmentHeader* oldHeader);
30 static T* getItems(SegmentHeader* header)
32 return reinterpret_cast<T*
>(
reinterpret_cast<char*
>(header) +
sizeof(SegmentHeader));
35 static const T* getItems(
const SegmentHeader* header)
37 return reinterpret_cast<T*
>(
reinterpret_cast<const char*
>(header) +
sizeof(SegmentHeader));
53 SegmentItems<T>* getSegmentItems()
const {
return SegmentItems<T>::getSegment(items); }
57 friend struct SmallStringTest;
58 friend struct VectorTest;
59 friend struct SmallVectorTest;
61 using Operations = SegmentOperations<VectorAllocator, T>;
69 Vector(std::initializer_list<T> list) : items(nullptr) { (void)
append({list.begin(), list.size()}); }
103 [[nodiscard]] T&
operator[](
size_t index) SC_LANGUAGE_LIFETIME_BOUND;
108 [[nodiscard]]
const T&
operator[](
size_t index)
const SC_LANGUAGE_LIFETIME_BOUND;
118 [[nodiscard]]
bool push_front(T&& element) {
return insertMove(0, {&element, 1}); }
123 [[nodiscard]]
bool push_back(
const T& element) {
return Operations::push_back(items, element); }
128 [[nodiscard]]
bool push_back(T&& element) {
return Operations::push_back(items,
move(element)); }
132 [[nodiscard]]
bool pop_back() {
return Operations::pop_back(items); }
136 [[nodiscard]]
bool pop_front() {
return Operations::pop_front(items); }
140 [[nodiscard]] T&
front() SC_LANGUAGE_LIFETIME_BOUND;
144 [[nodiscard]] const T&
front() const SC_LANGUAGE_LIFETIME_BOUND;
148 [[nodiscard]] T&
back() SC_LANGUAGE_LIFETIME_BOUND;
152 [[nodiscard]] const T&
back() const SC_LANGUAGE_LIFETIME_BOUND;
157 [[nodiscard]]
bool reserve(
size_t newCapacity);
163 [[nodiscard]]
bool resize(
size_t newSize, const T& value = T());
181 [[nodiscard]]
bool shrink_to_fit() {
return Operations::shrink_to_fit(items); }
185 [[nodiscard]]
bool isEmpty()
const {
return (items ==
nullptr) || getSegmentItems()->isEmpty(); }
189 [[nodiscard]]
size_t size()
const;
197 [[nodiscard]] T*
begin() SC_LANGUAGE_LIFETIME_BOUND {
return items; }
200 [[nodiscard]]
const T*
begin() const SC_LANGUAGE_LIFETIME_BOUND {
return items; }
203 [[nodiscard]] T*
end() SC_LANGUAGE_LIFETIME_BOUND {
return items +
size(); }
206 [[nodiscard]]
const T*
end() const SC_LANGUAGE_LIFETIME_BOUND {
return items +
size(); }
209 [[nodiscard]] T*
data() SC_LANGUAGE_LIFETIME_BOUND {
return items; }
212 [[nodiscard]]
const T*
data() const SC_LANGUAGE_LIFETIME_BOUND {
return items; }
228 template <
typename U>
235 template <
typename U>
244 template <
typename U>
245 [[nodiscard]]
bool contains(
const U& value,
size_t* foundIndex =
nullptr)
const;
252 template <
typename Lambda>
253 [[nodiscard]]
bool find(Lambda&& lambda,
size_t* foundIndex =
nullptr)
const;
258 [[nodiscard]]
bool removeAt(
size_t index) {
return Operations::removeAt(items, index); }
264 template <
typename Lambda>
271 template <
typename U>
272 [[nodiscard]]
bool remove(
const U& value);
275 [[nodiscard]]
bool insertMove(
size_t idx,
Span<T> data);
281 void moveAssign(
Vector&& other);
293inline SC::SegmentHeader* SC::VectorAllocator::reallocate(SegmentHeader* oldHeader,
size_t newSize)
295 if (newSize > SegmentHeader::MaxValue)
299 SegmentHeader* newHeader;
300 if (oldHeader->isSmallVector)
302 newHeader =
static_cast<SegmentHeader*
>(Memory::allocate(
sizeof(SegmentHeader) + newSize));
303 const auto minSize =
min(newSize,
static_cast<decltype(newSize)
>(oldHeader->sizeBytes));
304 ::memcpy(newHeader, oldHeader, minSize +
alignof(SegmentHeader));
305 newHeader->initDefaults();
306 newHeader->isFollowedBySmallVector =
true;
310 newHeader =
static_cast<SegmentHeader*
>(Memory::reallocate(oldHeader,
sizeof(SegmentHeader) + newSize));
314 newHeader->capacityBytes =
static_cast<SegmentHeader::SizeType
>(newSize);
319inline SC::SegmentHeader* SC::VectorAllocator::allocate(SegmentHeader* oldHeader,
size_t numNewBytes,
void* selfPointer)
321 if (numNewBytes > SegmentHeader::MaxValue)
325 if (oldHeader !=
nullptr)
327 if (oldHeader->isFollowedBySmallVector)
330 SegmentHeader* followingHeader =
331 reinterpret_cast<SegmentHeader*
>(
static_cast<char*
>(selfPointer) +
alignof(SegmentHeader));
332 if (followingHeader->isSmallVector && followingHeader->capacityBytes >= numNewBytes)
334 return followingHeader;
337 else if (oldHeader->isSmallVector)
339 if (oldHeader->capacityBytes >= numNewBytes)
346 SegmentHeader* newHeader =
static_cast<SegmentHeader*
>(Memory::allocate(
sizeof(SegmentHeader) + numNewBytes));
349 newHeader->capacityBytes =
static_cast<SegmentHeader::SizeType
>(numNewBytes);
350 newHeader->initDefaults();
351 if (oldHeader !=
nullptr && oldHeader->isSmallVector)
353 newHeader->isFollowedBySmallVector =
true;
359inline void SC::VectorAllocator::release(SegmentHeader* oldHeader)
361 if (oldHeader->isSmallVector)
363 oldHeader->sizeBytes = 0;
367 Memory::release(oldHeader);
377 static_assert(
sizeof(
Vector) ==
sizeof(
void*),
"sizeof(Vector)");
378 const size_t otherSize = other.
size();
391 moveAssign(forward<Vector>(other));
399 moveAssign(forward<Vector>(other));
409 const bool res = Operations::assign(items, other.
data(), other.
size());
433 const size_t numElements = size();
441 const size_t numElements = size();
449 const size_t numElements = size();
451 return items[numElements - 1];
457 const size_t numElements = size();
459 return items[numElements - 1];
465 return newCapacity > capacity() ? Operations::ensureCapacity(items, newCapacity, size()) :
true;
472 return Operations::template resizeInternal<IsTrivial, true>(items, newSize, &value);
479 return Operations::template resizeInternal<IsTrivial, false>(items, newSize,
nullptr);
485 if (items !=
nullptr)
487 Operations::clear(getSegmentItems());
494 if (items ==
nullptr)
495 SC_LANGUAGE_UNLIKELY {
return 0; }
498 return static_cast<size_t>(getSegmentItems()->sizeBytes /
sizeof(T));
505 if (items ==
nullptr)
506 SC_LANGUAGE_UNLIKELY {
return 0; }
509 return static_cast<size_t>(getSegmentItems()->capacityBytes /
sizeof(T));
516 return Operations::template insert<true>(items, idx, data.
data(), data.
sizeInElements());
522 return Operations::template insert<true>(items, size(), data.
data(), data.
sizeInElements());
529 if (appendMove({src.data(), src.size()}))
542 const auto oldSize = size();
547 if (not push_back(it))
566 items, 0, size(), [&](
const T& element) {
return element == value; }, foundIndex);
570template <
typename Lambda>
577template <
typename Lambda>
580 return SegmentItems<T>::removeAll(items, 0, size(), forward<Lambda>(criteria));
587 return SegmentItems<T>::removeAll(items, 0, size(), [&](
const auto& it) {
return it == value; });
593 if (items !=
nullptr)
595 Operations::destroy(getSegmentItems());
603 return Operations::template insert<false>(items, idx, data.data(), data.sizeInElements());
609 return Operations::template insert<false>(items, size(), data.data(), data.sizeInElements());
615 SegmentHeader* otherHeader = other.items !=
nullptr ? SegmentHeader::getSegmentHeader(other.items) : nullptr;
616 const bool otherIsSmallVector = otherHeader !=
nullptr && otherHeader->isSmallVector;
617 if (otherIsSmallVector)
621 (void)appendMove({other.items, other.size()});
626 const bool otherWasFollowedBySmallVector = otherHeader !=
nullptr && otherHeader->isFollowedBySmallVector;
627 if (otherHeader !=
nullptr)
630 const SegmentHeader* oldHeader = items !=
nullptr ? SegmentHeader::getSegmentHeader(items) : nullptr;
631 const bool shouldStillBeFollowedBySmallVector =
632 oldHeader !=
nullptr && (oldHeader->isFollowedBySmallVector || oldHeader->isSmallVector);
633 otherHeader->isFollowedBySmallVector = shouldStillBeFollowedBySmallVector;
638 if (otherWasFollowedBySmallVector)
645 otherHeader =
reinterpret_cast<SegmentHeader*
>(
reinterpret_cast<char*
>(&other) +
alignof(SegmentHeader));
646 other.items = otherHeader->getItems<T>();
650 other.items =
nullptr;
constexpr const T & min(const T &t1, const T &t2)
Finds the minimum of two values.
Definition: Compiler.h:300
constexpr ForwardIterator findIf(ForwardIterator first, ForwardIterator last, UnaryPredicate &&predicate)
Find item satisfying the given predicate.
Definition: AlgorithmFind.h:23
#define SC_ASSERT_DEBUG(e)
Assert expression e to be true.
Definition: Assert.h:82
#define SC_COMPILER_EXPORT
Macro for symbol visibility in non-MSVC compilers.
Definition: Compiler.h:78
#define SC_ASSERT_RELEASE(e)
Assert expression e to be true.
Definition: Assert.h:66
constexpr T && move(T &value)
Converts an lvalue to an rvalue reference.
Definition: Compiler.h:269
unsigned long size_t
Platform independent unsigned size type.
Definition: PrimitiveTypes.h:56
String with compile time configurable inline storage (small string optimization)
Definition: SmallString.h:21
View over a contiguous sequence of items (pointer + size in elements).
Definition: Span.h:21
constexpr const Type * data() const
Returns pointer to first element of the span.
Definition: Span.h:89
constexpr SizeType sizeInElements() const
Size of Span in elements.
Definition: Span.h:105
A non-modifiable owning string with associated encoding.
Definition: String.h:30
IsTriviallyCopyable evaluates to true if the type T can be trivially copied, false otherwise.
Definition: TypeTraits.h:60
A contiguous sequence of heap allocated elements.
Definition: Vector.h:51
bool resizeWithoutInitializing(size_t newSize)
Resizes this vector to newSize, preserving existing elements.
Definition: Vector.h:476
Vector()
Constructs an empty Vector.
Definition: Vector.h:65
bool append(Span< const T > data)
Appends a range of items copying them at the end of vector.
Definition: Vector.h:520
bool pop_back()
Removes the last element of the vector.
Definition: Vector.h:132
Vector(Vector &&other) noexcept
Moves vector contents into this vector.
Definition: Vector.h:388
T & operator[](size_t index) SC_LANGUAGE_LIFETIME_BOUND
Access item at index.
Definition: Vector.h:417
bool push_back(const T &element)
Appends an element copying it at the end of the Vector.
Definition: Vector.h:123
bool push_front(T &&element)
Moves an element in front of the Vector, at position 0.
Definition: Vector.h:118
bool appendMove(U &&src)
Appends another vector moving its contents at the end of vector.
Definition: Vector.h:527
bool removeAll(Lambda &&criteria)
Removes all items matching criteria given by Lambda.
Definition: Vector.h:578
void clear()
Removes all elements from container, calling destructor for each of them.
Definition: Vector.h:483
T * begin() SC_LANGUAGE_LIFETIME_BOUND
Gets pointer to first element of the vector.
Definition: Vector.h:197
bool shrink_to_fit()
Reallocates the vector so that size() == capacity().
Definition: Vector.h:181
bool find(Lambda &&lambda, size_t *foundIndex=nullptr) const
Finds the first item in vector matching criteria given by the lambda.
Definition: Vector.h:571
const T * begin() const SC_LANGUAGE_LIFETIME_BOUND
Gets pointer to first element of the vector.
Definition: Vector.h:200
size_t size() const
Gets size of the vector.
Definition: Vector.h:492
T & back() SC_LANGUAGE_LIFETIME_BOUND
Access the last element of the Vector.
Definition: Vector.h:447
size_t capacity() const
Gets capacity of the vector.
Definition: Vector.h:503
Vector(const Vector &other)
Copies vector into this vector.
Definition: Vector.h:375
Span< T > toSpan() SC_LANGUAGE_LIFETIME_BOUND
Returns a Span wrapping the entire of current vector.
Definition: Vector.h:98
void clearWithoutInitializing()
Sets size() to zero, without calling destructor on elements.
Definition: Vector.h:177
T & front() SC_LANGUAGE_LIFETIME_BOUND
Access the first element of the Vector.
Definition: Vector.h:431
Vector(std::initializer_list< T > list)
Constructs a Vector from an initializer list.
Definition: Vector.h:69
const T & operator[](size_t index) const SC_LANGUAGE_LIFETIME_BOUND
Access item at index.
Definition: Vector.h:424
bool append(Span< const U > src)
Appends a range of items copying them at the end of vector.
Definition: Vector.h:540
bool push_back(T &&element)
Appends an element moving it at the end of the Vector.
Definition: Vector.h:128
~Vector()
Destroys the Vector, releasing allocated memory.
Definition: Vector.h:72
bool remove(const U &value)
Removes all values equal to value
Definition: Vector.h:585
Vector & operator=(Vector &&other)
Move assigns another vector to this one.
Definition: Vector.h:395
bool resize(size_t newSize, const T &value=T())
Resizes this vector to newSize, preserving existing elements.
Definition: Vector.h:469
bool isEmpty() const
Check if the vector is empty.
Definition: Vector.h:185
const T * end() const SC_LANGUAGE_LIFETIME_BOUND
Gets pointer to one after last element of the vector.
Definition: Vector.h:206
bool reserve(size_t newCapacity)
Reserves memory for newCapacity elements, allocating memory if necessary.
Definition: Vector.h:463
const T * data() const SC_LANGUAGE_LIFETIME_BOUND
Gets pointer to first element of the vector.
Definition: Vector.h:212
bool insert(size_t idx, Span< const T > data)
Inserts a range of items copying them at given index.
Definition: Vector.h:514
T * end() SC_LANGUAGE_LIFETIME_BOUND
Gets pointer to one after last element of the vector.
Definition: Vector.h:203
bool removeAt(size_t index)
Removes an item at a given index.
Definition: Vector.h:258
bool push_front(const T &element)
Copies an element in front of the Vector, at position 0.
Definition: Vector.h:113
Vector & operator=(const Vector &other)
Copy assigns another vector to this one.
Definition: Vector.h:405
Span< const T > toSpanConst() const SC_LANGUAGE_LIFETIME_BOUND
Returns a Span wrapping the entire of current vector.
Definition: Vector.h:94
bool contains(const U &value, size_t *foundIndex=nullptr) const
Check if the current vector contains a given value.
Definition: Vector.h:563
bool pop_front()
Removes the first element of the vector.
Definition: Vector.h:136
T * data() SC_LANGUAGE_LIFETIME_BOUND
Gets pointer to first element of the vector.
Definition: Vector.h:209