@@ -23,6 +23,7 @@ template<class T, class Less = DefaultLess> struct OrderedSetOf {
23
23
using Slice = OrderedSliceOf<const T, Less>;
24
24
using AmendableSlice = SliceOf<T>;
25
25
using UnorderedSlice = SliceOf<const T>;
26
+ using MoveSlice = array19::MoveSliceOf<T>;
26
27
27
28
static_assert (std::is_trivial_v<T>, " Only works for trivial types!" );
28
29
@@ -34,39 +35,68 @@ template<class T, class Less = DefaultLess> struct OrderedSetOf {
34
35
Count m_capacity{};
35
36
36
37
public:
37
- OrderedSetOf () = default ;
38
- ~OrderedSetOf () noexcept {
38
+ constexpr OrderedSetOf () = default;
39
+ explicit constexpr OrderedSetOf (Slice ordered) noexcept
40
+ : m_pointer{Utils::allocate (ordered.count ())}
41
+ , m_count{ordered.count ()}
42
+ , m_capacity{ordered.count ()} {
43
+ Utils::copyAssign (m_pointer, ordered);
44
+ }
45
+ constexpr OrderedSetOf (const OrderedSetOf& o) noexcept
46
+ : m_pointer{Utils::allocate (o.m_count )}
47
+ , m_count{o.m_count }
48
+ , m_capacity{o.m_count } {
49
+ Utils::copyAssign (m_pointer, Slice{o});
50
+ }
51
+ constexpr OrderedSetOf (OrderedSetOf&& o) noexcept
52
+ : m_pointer{std::exchange (o.m_pointer , nullptr )}
53
+ , m_count{o.m_count }
54
+ , m_capacity{o.m_count } {}
55
+ constexpr auto operator =(const OrderedSetOf& o) noexcept -> OrderedSetOf& {
56
+ if (o.m_count > m_capacity) {
57
+ if (m_pointer) Utils::deallocate (SliceOf{m_pointer, m_capacity});
58
+ m_pointer = Utils::allocate (o.m_count );
59
+ m_capacity = o.m_count ;
60
+ }
61
+ Utils::copyAssign (m_pointer, Slice{o});
62
+ m_count = o.m_count ;
63
+ return *this ;
64
+ }
65
+ constexpr auto operator =(OrderedSetOf&& o) noexcept -> OrderedSetOf& {
66
+ if (m_pointer) Utils::deallocate (SliceOf{m_pointer, m_capacity});
67
+ m_pointer = std::exchange (o.m_pointer , nullptr );
68
+ m_count = o.m_count ;
69
+ m_capacity = o.m_capacity ;
70
+ return *this ;
71
+ }
72
+ constexpr ~OrderedSetOf () noexcept {
39
73
if (m_pointer) Utils::deallocate (SliceOf{m_pointer, m_capacity});
40
74
}
41
75
42
- [[nodiscard]] constexpr auto isEmpty () const noexcept -> bool { return m_count == 0 ; }
43
- [[nodiscard]] auto count () const -> Count { return m_count; }
44
- [[nodiscard]] auto totalCapacity () const -> Count { return m_capacity; }
45
- [[nodiscard]] auto unusedCapacity () const -> Count { return m_capacity - m_count; }
76
+ [[nodiscard]] constexpr auto isEmpty () const -> bool { return m_count == 0 ; }
77
+ [[nodiscard]] constexpr auto count () const -> Count { return m_count; }
78
+ [[nodiscard]] constexpr auto totalCapacity () const -> Count { return m_capacity; }
79
+ [[nodiscard]] constexpr auto unusedCapacity () const -> Count { return m_capacity - m_count; }
46
80
47
- [[nodiscard]] auto front () const -> const T& { return *begin (); }
48
- [[nodiscard]] auto back () const -> const T& { return *(begin () + m_count - 1 ); }
81
+ [[nodiscard]] constexpr auto front () const -> const T& { return *begin (); }
82
+ [[nodiscard]] constexpr auto back () const -> const T& { return *(begin () + m_count - 1 ); }
49
83
50
- [[nodiscard]] auto begin () const noexcept -> ConstIterator {
51
- return std::launder (reinterpret_cast <const T*>(m_pointer));
52
- }
53
- [[nodiscard]] auto end () const noexcept -> ConstIterator { return begin () + m_count; }
54
- [[nodiscard]] auto operator [](Index index) const noexcept -> const Element& {
55
- return *std::launder (reinterpret_cast <const T*>(m_pointer + index));
56
- }
57
- [[nodiscard]] operator Slice () const noexcept { return Slice{begin (), m_count}; }
84
+ [[nodiscard]] constexpr auto begin () const noexcept -> ConstIterator { return m_pointer; }
85
+ [[nodiscard]] constexpr auto end () const noexcept -> ConstIterator { return begin () + m_count; }
86
+ [[nodiscard]] constexpr auto operator [](Index index) const -> const Element& { return m_pointer[index]; }
87
+ [[nodiscard]] constexpr operator Slice () const { return Slice{m_pointer, m_count}; }
58
88
59
- void ensureCapacity (Count count) {
89
+ constexpr void ensureCapacity (Count count) {
60
90
if (totalCapacity () < count) growBy (static_cast <size_t >(count - totalCapacity ()));
61
91
}
62
- void ensureUnusedCapacity (Count count) {
92
+ constexpr void ensureUnusedCapacity (Count count) {
63
93
if (unusedCapacity () < count) growBy (static_cast <size_t >(count - unusedCapacity ()));
64
94
}
65
95
66
96
// / inserts a single value to the set if it is not yet present
67
97
// / note:
68
98
// / * if you want to insert muliple values use merge
69
- bool insert (T v) {
99
+ constexpr auto insert (T v) -> bool {
70
100
auto it = const_cast <Iterator>(static_cast <Slice>(*this ).lowerBound (v));
71
101
if (it != end () && *it == v) {
72
102
return false ;
@@ -76,12 +106,12 @@ template<class T, class Less = DefaultLess> struct OrderedSetOf {
76
106
auto nPtr = newStorage.begin ();
77
107
auto fCount = static_cast <size_t >(it - m_pointer);
78
108
if (0 != fCount ) {
79
- memcpy (nPtr, m_pointer, fCount );
109
+ Utils::moveConstruct (nPtr, MoveSlice{ m_pointer, fCount } );
80
110
nPtr += fCount ;
81
111
}
82
112
*nPtr++ = v;
83
113
if (fCount != m_count) {
84
- memcpy (nPtr, m_pointer + fCount , m_count - fCount );
114
+ Utils::moveConstruct (nPtr, MoveSlice{ m_pointer + fCount , m_count - fCount } );
85
115
}
86
116
Utils::deallocate (SliceOf{m_pointer, m_capacity});
87
117
m_pointer = newStorage.begin ();
@@ -90,7 +120,7 @@ template<class T, class Less = DefaultLess> struct OrderedSetOf {
90
120
return true ;
91
121
}
92
122
if (it != end ()) {
93
- memmove (it + 1 , it, static_cast <size_t >(end () - it));
123
+ Utils::moveAssignReverse (it + 1 , MoveSlice{ it, static_cast <size_t >(end () - it)} );
94
124
}
95
125
*it = v;
96
126
m_count++;
@@ -100,136 +130,142 @@ template<class T, class Less = DefaultLess> struct OrderedSetOf {
100
130
// / removes a single element from the set
101
131
// / preconditions:
102
132
// / * cIt has to point between begin() and before end()
103
- void remove (ConstIterator cIt) {
133
+ constexpr void remove (ConstIterator cIt) {
104
134
auto it = const_cast <Iterator>(cIt);
105
135
if (it + 1 != end ()) {
106
- memmove (it, it + 1 , static_cast <size_t >(end () - it - 1 ) );
136
+ Utils::moveAssignForward (it, MoveSlice{ it + 1 , static_cast <size_t >(end () - it)} );
107
137
}
108
138
m_count--;
109
139
}
110
140
111
141
// / adds multiple elements to the set if they are not already present
112
- // / note :
113
- // / * assumes that enough capacity for inserting all elements is required
114
- void merge (Slice elems) {
142
+ // / preconditions :
143
+ // / * assumes that elems are unique and ordered
144
+ constexpr void merge (Slice elems) {
115
145
if (elems.isEmpty ()) return ;
116
- auto less = Less{};
146
+ if (isEmpty ()) {
147
+ *this = OrderedSetOf{elems};
148
+ return ;
149
+ }
117
150
auto nCount = elems.count ();
118
- if (unusedCapacity () < nCount) { // merge into new storage
151
+ if (unusedCapacity () < nCount) {
119
152
auto newStorage = grownStorage (nCount);
120
- auto dPtr = newStorage.begin ();
121
- auto nPtr = elems.begin ();
122
- auto nEnd = elems.end ();
123
- if (isEmpty ()) {
124
- memcpy (dPtr, nPtr, nCount);
125
- Utils::deallocate (SliceOf{m_pointer, m_capacity});
126
- m_pointer = newStorage.begin ();
127
- m_capacity = newStorage.count ();
128
- m_count = nCount;
129
- return ;
130
- }
131
- auto n = *nPtr;
132
- auto oPtr = begin ();
133
- auto o = *oPtr;
134
- auto oEnd = end ();
135
- while (true ) {
136
- if (less (n, o)) {
137
- *dPtr++ = n;
138
- nPtr++;
139
- if (nPtr == nEnd) {
140
- memcpy (dPtr, oPtr, oEnd - oPtr);
141
- break ;
142
- }
143
- n = *nPtr;
144
- }
145
- else {
146
- *dPtr++ = o;
147
- oPtr++;
148
- if (!less (o, n)) {
149
- nPtr++;
150
- if (nPtr == nEnd) {
151
- if (oPtr != oEnd) memcpy (dPtr, oPtr, oEnd - oPtr);
152
- break ;
153
- }
154
- n = *nPtr;
155
- }
156
- if (oPtr == oEnd) {
157
- memcpy (dPtr, nPtr, nEnd - nPtr);
158
- break ;
159
- }
160
- o = *oPtr;
161
- }
162
- }
153
+ auto ptr = mergeInto (newStorage, elems);
163
154
Utils::deallocate (SliceOf{m_pointer, m_capacity});
164
155
m_pointer = newStorage.begin ();
165
156
m_capacity = newStorage.count ();
166
- m_count += nCount;
167
- return ;
157
+ m_count = static_cast <size_t >(ptr - m_pointer);
168
158
}
169
- if (isEmpty ()) {
170
- memcpy (m_pointer, elems.begin (), nCount);
171
- m_count = nCount;
172
- return ;
159
+ else {
160
+ m_count = mergeBackwards (elems);
173
161
}
174
- auto oBegin = m_pointer;
175
- auto oIt = oBegin + m_count - 1 ;
176
- auto o = *oIt;
177
- auto nBegin = elems.begin ();
162
+ }
163
+
164
+ private:
165
+ [[nodiscard]] constexpr auto grownStorage (size_t growBy) const -> AmendableSlice {
166
+ auto cur = m_capacity;
167
+ auto res = (cur << 1 ) - (cur >> 1 ) + (cur >> 4 ); // * 1.563
168
+ if (res < 5 ) res = 5 ;
169
+ if (res < m_capacity + growBy) res = m_capacity + growBy;
170
+ auto ptr = Utils::allocate (res);
171
+ return AmendableSlice{ptr, res};
172
+ }
173
+ constexpr void growBy (size_t by) {
174
+ auto newStorage = grownStorage (by);
175
+ Utils::moveConstruct (newStorage.begin (), MoveSlice{m_pointer, m_count});
176
+ Utils::deallocate (SliceOf{m_pointer, m_capacity});
177
+ m_pointer = newStorage.begin ();
178
+ m_capacity = newStorage.count ();
179
+ }
180
+ constexpr auto mergeInto (AmendableSlice storage, Slice elems) -> T* {
181
+ auto less = Less{};
182
+ auto dPtr = storage.begin ();
183
+ auto nPtr = elems.begin ();
184
+ auto const nEnd = elems.end ();
185
+ auto n = *nPtr;
186
+ auto oPtr = begin ();
187
+ auto o = *oPtr;
188
+ auto const oEnd = end ();
189
+ while (true ) {
190
+ if (less (n, o)) {
191
+ *dPtr++ = n;
192
+ nPtr++;
193
+ if (nPtr == nEnd) {
194
+ auto r = static_cast <size_t >(oEnd - oPtr);
195
+ Utils::copyAssign (dPtr, UnorderedSlice{oPtr, r});
196
+ return dPtr + r;
197
+ }
198
+ n = *nPtr;
199
+ }
200
+ else {
201
+ if (less (o, n)) {
202
+ *dPtr++ = o;
203
+ }
204
+ oPtr++;
205
+ if (oPtr == oEnd) {
206
+ auto r = static_cast <size_t >(nEnd - nPtr);
207
+ Utils::copyAssign (dPtr, UnorderedSlice{nPtr, r});
208
+ return dPtr + r;
209
+ }
210
+ o = *oPtr;
211
+ }
212
+ }
213
+ }
214
+ constexpr auto mergeBackwards (Slice elems) -> size_t {
215
+ auto less = Less{};
216
+ auto const oBegin = m_pointer;
217
+ auto const oCount = m_count;
218
+ auto const nBegin = elems.begin ();
219
+ auto const nCount = elems.count ();
220
+ auto oIt = oBegin + oCount - 1 ;
178
221
auto nIt = nBegin + nCount - 1 ;
179
- auto n = *nIt ;
180
- auto dIt = oBegin + m_count + nCount - 1 ;
222
+ auto dCount = oCount + nCount ;
223
+ auto dIt = oBegin + dCount - 1 ;
181
224
225
+ auto o = *oIt;
226
+ auto n = *nIt;
182
227
while (true ) {
183
228
if (less (o, n)) {
184
229
*dIt-- = n;
185
- nIt--;
186
230
if (nIt == nBegin) {
231
+ dIt++;
232
+ oIt++;
233
+ if (oIt != dIt) { // move by skipped elements
234
+ dCount -= (dIt - oIt);
235
+ Utils::moveAssignForward (oIt, MoveSlice{dIt, static_cast <size_t >(dCount - (oIt - oBegin))});
236
+ }
187
237
// remaining old values are in place
188
- break ;
238
+ return dCount ;
189
239
}
240
+ nIt--;
241
+ n = *nIt;
190
242
}
191
243
else {
192
- *dIt-- = o;
193
- oIt--;
194
- if (!less (n, o)) {
195
- nIt--;
196
- if (nIt == nBegin) {
197
- // remaining old values are in place
198
- break ;
199
- }
200
- n = *nIt;
244
+ if (less (n, o)) {
245
+ *dIt-- = o;
201
246
}
202
247
if (oIt == oBegin) {
203
- memcpy (oBegin, nBegin, nIt - nBegin);
204
- break ;
248
+ auto const remaining = static_cast <size_t >(nIt + 1 - nBegin);
249
+ Utils::copyAssign (oBegin, UnorderedSlice{nBegin, remaining});
250
+ dIt++;
251
+ if (oBegin + remaining != dIt) { // move by skipped elements
252
+ dCount -= (dIt - (oBegin + remaining));
253
+ Utils::moveAssignForward (
254
+ oBegin + remaining,
255
+ MoveSlice{dIt, static_cast <size_t >(dCount - remaining)});
256
+ }
257
+ return dCount;
205
258
}
259
+ oIt--;
206
260
o = *oIt;
207
261
}
208
262
}
209
- m_count += nCount;
210
- }
211
-
212
- private:
213
- [[nodiscard]] auto grownStorage (size_t growBy) const -> AmendableSlice {
214
- auto cur = m_capacity;
215
- auto res = (cur << 1 ) - (cur >> 1 ) + (cur >> 4 ); // * 1.563
216
- if (res < 5 ) res = 5 ;
217
- if (res < m_capacity + growBy) res = m_capacity + growBy;
218
- auto ptr = Utils::allocate (res);
219
- return AmendableSlice{ptr, res};
220
- }
221
- void growBy (size_t by) {
222
- auto newStorage = grownStorage (by);
223
- memcpy (newStorage.begin (), m_pointer, m_count);
224
- Utils::deallocate (SliceOf{m_pointer, m_capacity});
225
- m_pointer = newStorage.begin ();
226
- m_capacity = newStorage.count ();
227
263
}
228
264
};
229
265
230
266
// / deduce OrderedSliceOf from OrderedSetOf
231
267
// / usage:
232
- // / auto a = OrderedSetOf{1,2,3;
268
+ // / auto a = OrderedSetOf{1,2,3} ;
233
269
// / auto slice = OrderedSliceOf{a};
234
270
template <class T , class L > OrderedSliceOf (const OrderedSetOf<T, L>&) -> OrderedSliceOf<const T, L>;
235
271
0 commit comments