Line data Source code
1 : /**
2 : Copyright (c) 2017-2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #ifndef STAPPLER_CORE_MEMORY_SPMEMSTORAGEMEM_H_
25 : #define STAPPLER_CORE_MEMORY_SPMEMSTORAGEMEM_H_
26 :
27 : #include "SPMemStorageMemImpl.h"
28 : #include "SPMemPointerIterator.h"
29 :
30 : namespace STAPPLER_VERSIONIZED stappler::memory {
31 :
32 : template <typename Type>
33 : struct mem_sso_test {
34 : static constexpr bool value = std::is_scalar<Type>::value;
35 : };
36 :
37 : template <typename Type, size_t Extra = 0>
38 : class storage_mem_soo : public impl::mem_soo_iface<Type, Extra, mem_sso_test<Type>::value> {
39 : public:
40 : using base = impl::mem_soo_iface<Type, Extra, mem_sso_test<Type>::value>;
41 : using self = storage_mem_soo<Type, Extra>;
42 : using pointer = Type *;
43 : using const_pointer = const Type *;
44 : using reference = Type &;
45 : using const_reference = const Type &;
46 :
47 : using size_type = size_t;
48 : using allocator = Allocator<Type>;
49 :
50 : using iterator = pointer_iterator<Type, pointer, reference>;
51 : using const_iterator = pointer_iterator<Type, const_pointer, const_reference>;
52 :
53 : using reverse_iterator = std::reverse_iterator<iterator>;
54 : using const_reverse_iterator = std::reverse_iterator<const_iterator>;
55 :
56 : using base::get_soo_size;
57 :
58 : // default init with current context allocator or specified allocator
59 28518031 : storage_mem_soo(const allocator &alloc = allocator()) noexcept : base(alloc) { }
60 :
61 : storage_mem_soo(pointer p, size_type s, const allocator &alloc) noexcept : storage_mem_soo(alloc) {
62 : assign(p, s);
63 : }
64 :
65 4514900 : storage_mem_soo(const_pointer p, size_type s, const allocator &alloc = allocator()) noexcept : storage_mem_soo(alloc) {
66 4514898 : assign(p, s);
67 4514901 : }
68 :
69 125 : storage_mem_soo(const self &other, size_type pos, size_type len, const allocator &alloc = allocator()) noexcept
70 125 : : storage_mem_soo(alloc) {
71 125 : if (pos < other.size()) {
72 100 : assign(other.data() + pos, min(len, other.size() - pos));
73 : }
74 125 : }
75 :
76 : // copy-construct
77 9840300 : storage_mem_soo(const self &other, const allocator &alloc = allocator()) noexcept
78 9840300 : : storage_mem_soo(alloc) {
79 9840298 : assign(other);
80 9840297 : }
81 :
82 : // move
83 : // we steal memory block from other, it lifetime is same, or make copy
84 8320757 : storage_mem_soo(self &&other, const allocator &alloc = allocator()) noexcept
85 8320757 : : storage_mem_soo(alloc) {
86 8320759 : if (other._allocator == _allocator) {
87 : // lifetime is same, steal allocated memory
88 8320284 : perform_move(std::move(other));
89 : } else {
90 475 : assign(other);
91 : }
92 8320754 : other.clear_dealloc(_allocator);
93 8320752 : }
94 :
95 5492 : storage_mem_soo & operator = (const self &other) noexcept {
96 5492 : assign(other);
97 5492 : return *this;
98 : }
99 :
100 44852 : storage_mem_soo & operator = (self &&other) noexcept {
101 44852 : if (other._allocator == _allocator) {
102 : // clear and deallocate our memory, self-move-assignment is UB
103 44427 : clear_dealloc(_allocator);
104 44427 : perform_move(std::move(other));
105 : } else {
106 425 : assign(other);
107 : }
108 44852 : other.clear_dealloc(_allocator);
109 44852 : return *this;
110 : }
111 :
112 : using base::assign;
113 : using base::assign_weak;
114 : using base::assign_mem;
115 : using base::is_weak;
116 :
117 9848543 : void assign(const self &other) {
118 9848543 : assign(other.data(), other.size());
119 9848542 : }
120 :
121 25 : void assign(const self &other, size_type pos, size_type len) {
122 25 : assign(other.data() + pos, min(len, other.size() - pos));
123 25 : }
124 :
125 : template <typename ...Args>
126 47290830 : reference emplace_back(Args && ...args) {
127 47290830 : reserve(size() + 1, true); // reserve should switch mode if required
128 47230205 : return emplace_back_unsafe(std::forward<Args>(args)...);
129 : }
130 :
131 3718583 : void pop_back() {
132 3718583 : if (size() > 0) {
133 3718585 : const auto size = modify_size(-1);
134 3718586 : auto ptr = data() + size;
135 3718587 : _allocator.destroy(ptr);
136 3718585 : memset((void *)ptr, 0, sizeof(Type));
137 : }
138 3718585 : }
139 :
140 : template <typename ...Args>
141 546415224 : reference emplace_back_unsafe(Args && ...args) {
142 546415224 : const auto s = modify_size(1);
143 546420256 : auto ptr = data() + s - 1;
144 546428012 : _allocator.construct(data() + s - 1, std::forward<Args>(args)...);
145 546463646 : return *ptr;
146 : }
147 :
148 : template <typename... Args>
149 118251 : iterator emplace( const_iterator it, Args&&... args ) {
150 118251 : const auto _size = size();
151 118251 : auto _ptr = data();
152 118251 : size_type pos = it - _ptr;
153 118251 : if (_size == 0 || pos == _size) {
154 5240 : emplace_back(std::forward<Args>(args)...);
155 5240 : return iterator(data() + size() - 1);
156 : } else {
157 113011 : _ptr = reserve(_size + 1, true);
158 113011 : _allocator.move(_ptr + pos + 1, _ptr + pos, _size - pos);
159 113011 : _allocator.construct(_ptr + pos, std::forward<Args>(args)...);
160 113011 : modify_size(1);
161 113011 : return iterator(_ptr + pos);
162 : }
163 : }
164 :
165 : template <typename... Args>
166 10984 : iterator emplace_safe( const_iterator it, Args&&... args ) {
167 10984 : const auto _used = size();
168 10984 : auto _ptr = data();
169 10984 : size_type pos = it - _ptr;
170 10984 : if (_used == 0 || pos == _used) {
171 6060 : emplace_back(std::forward<Args>(args)...);
172 6060 : return iterator(data() + size() - 1);
173 : } else {
174 4924 : _ptr = reserve(_used + 2, true);
175 4924 : _allocator.construct(_ptr + _used + 1, std::forward<Args>(args)...);
176 4924 : _allocator.move(_ptr + pos + 1, _ptr + pos, _used - pos);
177 4924 : _allocator.move(_ptr + pos, _ptr + _used + 1, 1);
178 4924 : modify_size(1);
179 4924 : return iterator(_ptr + pos);
180 : }
181 : }
182 :
183 494137350 : void insert_back(const_pointer ptr, size_type s) {
184 494137350 : const auto _used = size();
185 494137350 : auto _ptr = reserve(_used + s, true);
186 494137349 : _allocator.copy(_ptr + _used, ptr, s);
187 494137349 : modify_size(s);
188 494137350 : }
189 :
190 19675 : void insert_back(const self &other) {
191 19675 : insert_back(other.data(), other.size());
192 19675 : }
193 :
194 25 : void insert_back(const self &other, size_type pos, size_type len) {
195 25 : insert_back(other.data() + pos, std::min(other.size() - pos, len));
196 25 : }
197 :
198 200 : void insert(size_type pos, const_pointer ptr, size_type s) {
199 200 : const auto _used = size();
200 200 : auto _ptr = reserve(_used + s, true);
201 200 : _allocator.move(_ptr + pos + s, _ptr + pos, _used - pos);
202 200 : _allocator.copy(_ptr + pos, ptr, s);
203 200 : modify_size(s);
204 200 : }
205 :
206 25 : void insert(size_type pos, const self &other) {
207 25 : insert(pos, other.data(), other.size());
208 25 : }
209 :
210 25 : void insert(size_type spos, const self &other, size_type pos, size_type len) {
211 25 : insert(spos, other.data() + pos, min(other.size() - pos, len));
212 25 : }
213 :
214 : template< class... Args >
215 75 : void insert(size_type pos, size_type s, Args && ... args) {
216 75 : const auto _used = size();
217 75 : auto _ptr = reserve(_used + s, true);
218 75 : _allocator.move(_ptr + pos + s, _ptr + pos, _used - pos);
219 175 : for (size_type i = pos; i < pos + s; i++) {
220 100 : _allocator.construct(_ptr + i, std::forward<Args>(args)...);
221 : }
222 75 : modify_size(s);
223 75 : }
224 :
225 : template< class... Args >
226 50 : iterator insert(const_iterator it, size_type len, Args && ... args) {
227 50 : size_type pos = it - data();
228 50 : insert(pos, len, std::forward<Args>(args)...);
229 50 : return iterator(data() + pos);
230 : }
231 :
232 : template< class InputIt >
233 11150 : iterator insert( const_iterator it, InputIt first, InputIt last ) {
234 11150 : auto _ptr = data();
235 11150 : const auto _used = size();
236 11150 : auto pos = it - _ptr;
237 11150 : auto size = std::distance(first, last);
238 11150 : _ptr = reserve(_used + size, true);
239 11150 : if (pos - _used > 0) {
240 0 : _allocator.move(_ptr + pos + size, _ptr + pos, _used - pos);
241 : }
242 11150 : auto i = pos;
243 78050 : for (auto it = first; it != last; ++ it, ++ i) {
244 66900 : _allocator.construct(_ptr + i, *it);
245 : }
246 11150 : modify_size(size);
247 11150 : return iterator(_ptr + pos);
248 : }
249 :
250 50 : void erase(size_type pos, size_type len) {
251 50 : auto _ptr = data();
252 50 : const auto _used = size();
253 50 : len = min(len, _used - pos);
254 50 : _allocator.destroy(_ptr + pos, len); // удаляем указанный блок
255 50 : if (pos + len < _used) { // смещаем остаток
256 25 : _allocator.move(_ptr + pos, _ptr + pos + len, _used - pos - len);
257 : }
258 50 : auto s = modify_size(-len);
259 50 : memset((void *)(_ptr + s), 0, len * sizeof(Type));
260 50 : }
261 :
262 34094 : iterator erase(const_iterator it) {
263 34094 : auto _ptr = data();
264 34095 : const auto _used = size();
265 34095 : auto pos = it - _ptr;
266 34095 : _allocator.destroy(const_cast<pointer>( & (*it) ));
267 34095 : if (pos < _used - 1) {
268 350 : _allocator.move(_ptr + pos, _ptr + pos + 1, _used - pos - 1);
269 : }
270 34095 : auto s = modify_size(-1);
271 34095 : memset((void *)(_ptr + s), 0, sizeof(Type));
272 34095 : return iterator(_ptr + pos);
273 : }
274 :
275 : iterator erase(const_iterator first, const_iterator last) {
276 : auto _ptr = data();
277 : auto pos = first - _ptr;
278 : auto len = last - first;
279 : erase(pos, len);
280 : return iterator(_ptr + pos);
281 : }
282 :
283 50 : pointer prepare_replace(size_type pos, size_type len, size_type nlen) {
284 50 : const auto _used = size();
285 50 : auto _ptr = reserve(_used - len + nlen, true);
286 50 : _allocator.destroy(_ptr + pos, len);
287 50 : if (pos + len < _used) {
288 50 : _allocator.move(_ptr + pos + nlen, _ptr + pos + len, _used - pos - len); // смещаем данные
289 : }
290 50 : return _ptr + pos;
291 : }
292 :
293 25 : void replace(size_type pos, size_type len, const_pointer ptr, size_type nlen) {
294 25 : const auto _used = size();
295 25 : len = min(len, _used - pos);
296 25 : _allocator.copy(prepare_replace(pos, len, nlen), ptr, nlen);
297 :
298 25 : const auto s = modify_size(nlen - len);
299 :
300 25 : if (nlen < len) {
301 25 : memset((void *)(data() + s), 0, (len - nlen) * sizeof(Type));
302 : }
303 25 : }
304 :
305 : void replace(size_type pos, size_type len, const self &other) {
306 : replace(pos, len, other.data(), other.size());
307 : }
308 : void replace(size_type pos, size_type len, const self &other, size_type npos, size_type nlen) {
309 : replace(pos, len, other.data() + npos, MIN(other.size() - npos, nlen));
310 : }
311 :
312 25 : void replace(size_type pos, size_type len, size_type nlen, Type t) {
313 25 : const auto _used = size();
314 25 : len = min(len, _used - pos);
315 25 : prepare_replace(pos, len, nlen);
316 25 : auto _ptr = data();
317 50 : for (size_type i = pos; i < pos + nlen; i++) {
318 25 : _allocator.construct(_ptr + i, t);
319 : }
320 :
321 25 : const auto s = modify_size(nlen - len);
322 :
323 25 : if (nlen < len) {
324 25 : memset((void *)(data() + s), 0, (len - nlen) * sizeof(Type));
325 : }
326 25 : }
327 :
328 : template< class InputIt >
329 : iterator replace( const_iterator first, const_iterator last, InputIt first2, InputIt last2 ) {
330 : auto pos = size_t(first - data());
331 : auto len = size_t(last - first);
332 : auto nlen = std::distance(first2, last2);
333 :
334 : prepare_replace(pos, len, nlen);
335 : auto i = pos;
336 : auto _ptr = data();
337 : for (auto it = first2; it != last2; it ++, i++) {
338 : _allocator.construct(_ptr + i, *it);
339 : }
340 :
341 : const auto s = modify_size(nlen - len);
342 :
343 : if (nlen < len) {
344 : memset((void *)(data() + s), 0, (len - nlen) * sizeof(Type));
345 : }
346 : return iterator(pos);
347 : }
348 :
349 : template <typename ...Args>
350 75 : void fill(size_type s, Args && ... args) {
351 75 : clear();
352 75 : auto _ptr = reserve(s, true);
353 350 : for (size_type i = 0; i < s; i++) {
354 275 : _allocator.construct(_ptr + i, std::forward<Args>(args)...);
355 : }
356 :
357 75 : set_size(s);
358 75 : }
359 :
360 : template <typename ...Args>
361 8181617 : void resize(size_type n, Args && ... args) {
362 8181617 : auto _ptr = reserve(n, true);
363 :
364 8181612 : const auto _used = size();
365 8181615 : if (n < _used) {
366 3729 : if (_ptr) {
367 3729 : _allocator.destroy(_ptr + n, _used - n);
368 : }
369 8177886 : } else if (n > _used) {
370 1170520576 : for (size_type i = _used; i < n; i++) {
371 1162665191 : _allocator.construct(_ptr + i, std::forward<Args>(args)...);
372 : }
373 : }
374 :
375 8181598 : set_size(n);
376 8181620 : }
377 :
378 : using base::reserve;
379 : using base::clear;
380 : using base::extract;
381 :
382 : using base::empty;
383 : using base::data;
384 : using base::size;
385 : using base::capacity;
386 :
387 221125139 : reference at(size_type s) noexcept {
388 221125139 : return data()[s];
389 : }
390 :
391 781741 : const_reference at(size_type s) const noexcept {
392 781741 : return data()[s];
393 : }
394 :
395 3358780 : reference back() noexcept { return *(data() + (size() - 1)); }
396 1061736 : const_reference back() const noexcept { return *(data() + (size() - 1)); }
397 :
398 179119 : reference front() noexcept { return *data(); }
399 703089 : const_reference front() const noexcept { return *data(); }
400 :
401 51266157 : iterator begin() noexcept { return iterator(data()); }
402 55691442 : iterator end() noexcept { return iterator(data() + size()); }
403 :
404 12685751 : const_iterator begin() const noexcept { return const_iterator(data()); }
405 12956678 : const_iterator end() const noexcept { return const_iterator(data() + size()); }
406 :
407 200 : const_iterator cbegin() const noexcept { return const_iterator(data()); }
408 75 : const_iterator cend() const noexcept { return const_iterator(data() + size()); }
409 :
410 : reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
411 : reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
412 :
413 : const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
414 : const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
415 :
416 : const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(cend()); }
417 : const_reverse_iterator crend() const noexcept { return const_reverse_iterator(cbegin()); }
418 :
419 25 : void shrink_to_fit() noexcept {
420 25 : if (size() == 0) {
421 25 : clear_dealloc(_allocator);
422 : }
423 25 : }
424 :
425 4991 : const allocator & get_allocator() const noexcept { return _allocator; }
426 :
427 : private:
428 : using base::perform_move;
429 : using base::clear_dealloc;
430 : using base::modify_size;
431 : using base::set_size;
432 :
433 : using base::_allocator;
434 : };
435 :
436 : template <typename Type, size_t Extra = 0>
437 : using storage_mem = storage_mem_soo<Type, Extra>;
438 :
439 : }
440 :
441 : #endif /* STAPPLER_CORE_MEMORY_SPMEMSTORAGEMEM_H_ */
|