Sane C++ Libraries
C++ Platform Abstraction Libraries
Loading...
Searching...
No Matches
Segment.h
1// Copyright (c) Stefano Cristiano
2// SPDX-License-Identifier: MIT
3#pragma once
4#include "../Foundation/Assert.h"
5#include "../Foundation/Span.h"
6#include "../Memory/Memory.h"
7
8namespace SC
9{
12enum class SegmentAllocator
13{
14 Global = 0,
15 ThreadLocal = 1,
16};
17
18namespace detail
19{
20struct SC_MEMORY_EXPORT SegmentHeader;
21struct alignas(uint64_t) SegmentHeader
22{
23 static constexpr uint32_t MaxCapacity = (~static_cast<uint32_t>(0)) >> 1;
24
25 SegmentHeader(uint32_t capacity = 0, SegmentAllocator allocator = SegmentAllocator::Global)
26 {
27 sizeBytes = 0;
28 allocatorType = static_cast<uint32_t>(allocator);
29 capacityBytes = capacity;
30 hasInlineData = capacity > 0;
31 }
32 uint32_t sizeBytes : sizeof(uint32_t) * 8 - 1;
33 uint32_t allocatorType : 1;
34 uint32_t capacityBytes : sizeof(uint32_t) * 8 - 1;
35 uint32_t hasInlineData : 1;
36};
37
38struct SC_MEMORY_EXPORT SegmentHeaderOffset
39{
40 using PtrOffset = size_t;
41 SegmentHeader header;
42 PtrOffset offset = 0; // memory offset representing relative pointer to data from "this"
43};
44
45template <typename T>
46struct SC_MEMORY_EXPORT SegmentSelfRelativePointer : protected SegmentHeaderOffset
47{
48 // clang-format off
49 SC_COMPILER_FORCE_INLINE T* data() noexcept { return offset == 0 ? nullptr : toPtr(toOffset(this) + offset); }
50 SC_COMPILER_FORCE_INLINE const T* data() const noexcept { return offset == 0 ? nullptr : toPtr(toOffset(this) + offset); }
51 SC_COMPILER_FORCE_INLINE bool isInline() const noexcept { return (offset == sizeof(SegmentHeaderOffset) + sizeof(uint64_t)) and header.hasInlineData; }
52
53 protected:
54 struct InlineData : public SegmentHeaderOffset // Data layout corresponds to SmallBuffer, SmallVector etc.
55 {
56 uint64_t capacity; // Could use uint32_t but we need to align data to 64 bit anyway
57 ~InlineData() {}
58 union
59 {
60 T data[1]; // Accessing the whole class through volatile cast anyway so array size can be whatever
61 };
62 };
63 SC_COMPILER_FORCE_INLINE static auto toOffset(const volatile void* src) noexcept { return reinterpret_cast<PtrOffset>(src); }
64 SC_COMPILER_FORCE_INLINE static T* toPtr(PtrOffset src) noexcept { return reinterpret_cast<T*>(src); }
65 SC_COMPILER_FORCE_INLINE void setData(T* mem) noexcept { offset = mem == nullptr ? 0 : toOffset(mem) - toOffset(this); }
66 SC_COMPILER_FORCE_INLINE T* getInlineData() noexcept { return (T*)reinterpret_cast<volatile InlineData*>(this)->data; }
67 SC_COMPILER_FORCE_INLINE auto getInlineCapacity() noexcept { return reinterpret_cast<volatile InlineData*>(this)->capacity; }
68 // clang-format on
69};
70
72template <typename T>
73struct SC_MEMORY_EXPORT SegmentTrivial
74{
75 using Type = T;
76 inline static void destruct(Span<T> data) noexcept;
77 // clang-format off
78 template <typename U> inline static void copyConstructAs(Span<T> data, Span<const U> value) noexcept;
79 template <typename U> inline static void copyConstruct(Span<T> data, const U* src) noexcept;
80 template <typename U> inline static void copyAssign(Span<T> data, const U* src) noexcept;
81 template <typename U> inline static void copyInsert(Span<T> data, Span<const U> values) noexcept;
82 template <typename U> inline static void moveConstruct(Span<T> data, U* src) noexcept;
83 template <typename U> inline static void moveAssign(Span<T> data, U* src) noexcept;
84 // clang-format on
85 inline static void remove(Span<T> data, size_t numElements) noexcept;
86};
87
89template <typename ParentSegment, typename CommonParent, int N = 0,
90 SegmentAllocator Allocator = SegmentAllocator::ThreadLocal>
91struct SC_MEMORY_EXPORT SegmentCustom : public ParentSegment
92{
93 SegmentCustom() : ParentSegment(N, Allocator) {}
94 SegmentCustom(const CommonParent& other) : SegmentCustom() { CommonParent::operator=(other); }
95 SegmentCustom(CommonParent&& other) : SegmentCustom() { CommonParent::operator=(move(other)); }
96
97 SegmentCustom(const SegmentCustom& other) : SegmentCustom() { ParentSegment::operator=(other); }
98 SegmentCustom(SegmentCustom&& other) : SegmentCustom() { ParentSegment::operator=(move(other)); }
99 // clang-format off
100 SegmentCustom& operator=(const SegmentCustom& other) { ParentSegment::operator=(other); return *this; }
101 SegmentCustom& operator=(SegmentCustom&& other) { ParentSegment::operator=(move(other)); return *this; }
102 // clang-format on
103};
104} // namespace detail
105
112template <typename VTable>
113struct SC_MEMORY_EXPORT Segment : public VTable
114{
115 using VTable::data;
116 using T = typename VTable::Type;
117 Segment(uint32_t capacityInBytes, SegmentAllocator allocator = SegmentAllocator::Global) noexcept;
118
119 Segment() noexcept;
120 ~Segment() noexcept;
121 Segment(Segment&& other) noexcept;
122 Segment(const Segment& other) noexcept;
123 Segment& operator=(Segment&& other) noexcept;
124 Segment& operator=(const Segment& other) noexcept;
125
126 // clang-format off
127 template <typename U = T> Segment(Span<const U> span) noexcept : Segment() { SC_ASSERT_RELEASE(assign(span)); }
128 // clang-format on
129 Segment(std::initializer_list<T> list) noexcept;
130
133 [[nodiscard]] bool resizeWithoutInitializing(size_t newSize) noexcept;
134
136 [[nodiscard]] bool resize(size_t newSize, const T& value = T()) noexcept;
137
139 [[nodiscard]] bool reserve(size_t capacity) noexcept;
140
142 template <typename U = T>
143 [[nodiscard]] bool append(Span<const U> span) noexcept;
144
146 template <typename VTable2>
147 [[nodiscard]] bool appendMove(Segment<VTable2>&& other) noexcept;
148
151 [[nodiscard]] bool shrink_to_fit() noexcept;
152
154 void clear() noexcept;
155
158 template <typename U = T>
159 [[nodiscard]] bool assign(Span<const U> span) noexcept;
160
163 template <typename VTable2>
164 [[nodiscard]] bool assignMove(Segment<VTable2>&& other) noexcept;
165
167 [[nodiscard]] bool push_back(const T& value) noexcept { return resize(size() + 1, value); }
168
170 [[nodiscard]] bool push_back(T&& value) noexcept;
171
173 [[nodiscard]] bool push_front(const T& value) noexcept { return insert(0, value); }
174
178 [[nodiscard]] bool pop_back(T* removedValue = nullptr) noexcept;
179
183 [[nodiscard]] bool pop_front(T* removedValue = nullptr) noexcept;
184
185 // clang-format off
186 [[nodiscard]] T* begin() noexcept SC_LANGUAGE_LIFETIME_BOUND { return data(); }
187 [[nodiscard]] const T* begin() const noexcept SC_LANGUAGE_LIFETIME_BOUND { return data(); }
188 [[nodiscard]] T* end() noexcept SC_LANGUAGE_LIFETIME_BOUND { return data() + size(); }
189 [[nodiscard]] const T* end() const noexcept SC_LANGUAGE_LIFETIME_BOUND { return data() + size(); }
190
191 [[nodiscard]] T& back() noexcept SC_LANGUAGE_LIFETIME_BOUND { SC_ASSERT_RELEASE(not isEmpty()); return *(data() + size() - 1);}
192 [[nodiscard]] T& front() noexcept SC_LANGUAGE_LIFETIME_BOUND { SC_ASSERT_RELEASE(not isEmpty()); return *data();}
193 [[nodiscard]] const T& back() const noexcept SC_LANGUAGE_LIFETIME_BOUND { SC_ASSERT_RELEASE(not isEmpty()); return *(data() + size() - 1);}
194 [[nodiscard]] const T& front() const noexcept SC_LANGUAGE_LIFETIME_BOUND { SC_ASSERT_RELEASE(not isEmpty()); return *data();}
195
196 [[nodiscard]] T& operator[](size_t idx) noexcept SC_LANGUAGE_LIFETIME_BOUND { SC_ASSERT_DEBUG(idx < size()); return *(data() + idx);}
197 [[nodiscard]] const T& operator[](size_t idx) const noexcept SC_LANGUAGE_LIFETIME_BOUND { SC_ASSERT_DEBUG(idx < size()); return *(data() + idx);}
198 // clang-format on
199
201 [[nodiscard]] bool isEmpty() const noexcept { return VTable::header.sizeBytes == 0; }
202
204 [[nodiscard]] Span<T> toSpan() noexcept SC_LANGUAGE_LIFETIME_BOUND { return {data(), size()}; }
205
207 [[nodiscard]] Span<const T> toSpanConst() const noexcept SC_LANGUAGE_LIFETIME_BOUND { return {data(), size()}; }
208
210 [[nodiscard]] size_t size() const noexcept { return VTable::header.sizeBytes / sizeof(T); }
211
213 [[nodiscard]] size_t capacity() const noexcept { return VTable::header.capacityBytes / sizeof(T); }
214
219 [[nodiscard]] bool removeRange(size_t start, size_t length) noexcept;
220
224 [[nodiscard]] bool removeAt(size_t index) noexcept { return removeRange(index, 1); }
225
230 [[nodiscard]] bool insert(size_t index, Span<const T> data) noexcept;
231
232 protected:
233 template <typename VTable2>
234 friend struct Segment;
235 struct Internal;
236};
237
239} // namespace SC
#define SC_ASSERT_DEBUG(e)
Assert expression e to be true.
Definition Assert.h:63
#define SC_ASSERT_RELEASE(e)
Assert expression e to be true.
Definition Assert.h:48
#define SC_COMPILER_FORCE_INLINE
Macro for forcing inline functions.
Definition Compiler.h:46
constexpr T && move(T &value)
Converts an lvalue to an rvalue reference.
Definition Compiler.h:273
decltype(sizeof(0)) size_t
Platform independent unsigned size type.
Definition PrimitiveTypes.h:45
unsigned long long uint64_t
Platform independent (8) bytes unsigned int.
Definition PrimitiveTypes.h:33
unsigned int uint32_t
Platform independent (4) bytes unsigned int.
Definition PrimitiveTypes.h:29
A slice of contiguous memory, prefixed by and header containing size and capacity.
Definition Segment.h:114
size_t size() const noexcept
Returns current size.
Definition Segment.h:210
bool resize(size_t newSize, const T &value=T()) noexcept
Re-allocates to the requested new size, preserving its contents and setting new items to value.
size_t capacity() const noexcept
Returns current capacity (always >= of size())
Definition Segment.h:213
Span< T > toSpan() noexcept SC_LANGUAGE_LIFETIME_BOUND
Obtains a Span of internal contents.
Definition Segment.h:204
bool isEmpty() const noexcept
Check if is empty (size() == 0)
Definition Segment.h:201
bool removeRange(size_t start, size_t length) noexcept
Removes the range [start, start + length] from the segment.
bool push_front(const T &value) noexcept
Appends a single element to the start of the segment.
Definition Segment.h:173
bool removeAt(size_t index) noexcept
Removes the element at index.
Definition Segment.h:224
bool pop_back(T *removedValue=nullptr) noexcept
Removes the last element of the segment.
bool push_back(T &&value) noexcept
Moves a single element to the end of the segment.
bool insert(size_t index, Span< const T > data) noexcept
Insert a span at the given index.
bool resizeWithoutInitializing(size_t newSize) noexcept
Re-allocates to the requested new size, preserving its contents.
Span< const T > toSpanConst() const noexcept SC_LANGUAGE_LIFETIME_BOUND
Obtains a Span of internal contents.
Definition Segment.h:207
View over a contiguous sequence of items (pointer + size in elements).
Definition Span.h:29