sparrow 0.3.0
Loading...
Searching...
No Matches
buffer_adaptor.hpp
Go to the documentation of this file.
1// Copyright 2024 Man Group Operations Limited
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#pragma once
16
17#include <cmath>
18#include <ranges>
19#include <type_traits>
20
24
25namespace sparrow
26{
27 template <typename FromBufferRef, typename T>
28 concept BufferReference = std::ranges::contiguous_range<FromBufferRef> && std::is_reference_v<FromBufferRef>
29 && (sizeof(std::ranges::range_value_t<FromBufferRef>) <= sizeof(T));
30
31 template <typename FromBufferRef, typename T>
33
42 template <typename To, BufferReference<To> FromBufferRef>
45 {
46 public:
47
48 using value_type = To;
52 using const_pointer = const value_type*;
53 static constexpr bool is_const = std::is_const_v<To>;
54
55 using buffer_reference_value_type = std::remove_cvref_t<FromBufferRef>::value_type;
56 using buffer_reference = std::conditional_t<is_const, const FromBufferRef, FromBufferRef>;
57
58 using size_type = std::remove_cvref_t<buffer_reference>::size_type;
59 using difference_type = std::remove_cvref_t<buffer_reference>::difference_type;
62 using reverse_iterator = std::reverse_iterator<iterator>;
63 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
64
65 explicit buffer_adaptor(FromBufferRef buf)
66 requires(not is_const);
67 explicit buffer_adaptor(const FromBufferRef buf);
68
69 [[nodiscard]] constexpr pointer data() noexcept
70 requires(not is_const);
71 [[nodiscard]] constexpr const_pointer data() const noexcept;
72
73 // Element access
74
75 [[nodiscard]] constexpr reference operator[](size_type idx)
76 requires(not is_const);
77 [[nodiscard]] constexpr const_reference operator[](size_type idx) const;
78
79 [[nodiscard]] constexpr reference front()
80 requires(not is_const);
81 [[nodiscard]] constexpr const_reference front() const;
82
83 [[nodiscard]] constexpr reference back()
84 requires(not is_const);
85 [[nodiscard]] constexpr const_reference back() const;
86
87 // Iterators
88
89 [[nodiscard]] constexpr iterator begin() noexcept
90 requires(not is_const);
91 [[nodiscard]] constexpr iterator end() noexcept
92 requires(not is_const);
93
94 [[nodiscard]] constexpr const_iterator begin() const noexcept;
95 [[nodiscard]] constexpr const_iterator end() const noexcept;
96
97 [[nodiscard]] constexpr const_iterator cbegin() const noexcept;
98 [[nodiscard]] constexpr const_iterator cend() const noexcept;
99
100 [[nodiscard]] constexpr reverse_iterator rbegin() noexcept
101 requires(not is_const);
102 [[nodiscard]] constexpr reverse_iterator rend() noexcept
103 requires(not is_const);
104
105 [[nodiscard]] constexpr const_reverse_iterator rbegin() const noexcept;
106 [[nodiscard]] constexpr const_reverse_iterator rend() const noexcept;
107
108 [[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept;
109 [[nodiscard]] constexpr const_reverse_iterator crend() const noexcept;
110
111 // Capacity
112
113 [[nodiscard]] constexpr size_type size() const noexcept;
114 [[nodiscard]] constexpr size_type max_size() const noexcept;
115 [[nodiscard]] constexpr size_type capacity() const noexcept;
116 [[nodiscard]] constexpr bool empty() const noexcept;
117 constexpr void reserve(size_type new_cap)
118 requires(not is_const);
119 constexpr void shrink_to_fit()
120 requires(not is_const);
121
122 // Modifiers
123
124 constexpr void clear() noexcept
125 requires(not is_const);
126
127 constexpr iterator insert(const_iterator pos, const value_type& value)
128 requires(not is_const);
129 constexpr iterator insert(const_iterator pos, size_type count, const value_type& value)
130 requires(not is_const);
131
132 template <class InputIt>
133 requires std::input_iterator<InputIt>
134 constexpr iterator insert(const_iterator pos, InputIt first, InputIt last)
135 requires(not is_const);
136 constexpr iterator insert(const_iterator pos, std::initializer_list<value_type> ilist)
137 requires(not is_const);
138
139 template <class... Args>
140 constexpr iterator emplace(const_iterator pos, Args&&... args)
141 requires(not is_const);
142
144 requires(not is_const);
146 requires(not is_const);
147
148 constexpr void push_back(const value_type& value)
149 requires(not is_const);
150
151 constexpr void pop_back()
152 requires(not is_const);
153
154 constexpr void resize(size_type new_size)
155 requires(not is_const);
156
157 constexpr void resize(size_type new_size, const value_type& value)
158 requires(not is_const);
159
160 private:
161
162 static constexpr double m_from_to_size_ratio = static_cast<double>(sizeof(buffer_reference_value_type))
163 / static_cast<double>(sizeof(value_type));
164
165 static constexpr size_type m_to_from_size_ratio = static_cast<size_type>(1. / m_from_to_size_ratio);
166
167 [[nodiscard]] constexpr std::remove_cvref_t<buffer_reference>::size_type
168 index_for_buffer(size_type idx) const noexcept
169 {
170 return idx * m_to_from_size_ratio;
171 }
172
173 [[nodiscard]] std::remove_cvref_t<buffer_reference>::const_iterator
174 get_buffer_reference_iterator(const_iterator pos)
175 {
176 const difference_type index = std::distance(cbegin(), pos);
177 const auto idx_for_buffer = index_for_buffer(static_cast<size_type>(index));
178 SPARROW_ASSERT_TRUE(idx_for_buffer <= m_buffer.size());
179 return std::next(m_buffer.cbegin(), static_cast<difference_type>(idx_for_buffer));
180 }
181
182 buffer_reference m_buffer;
183 size_type m_max_size;
184 };
185
186 template <class T>
187 class holder
188 {
189 public:
190
191 template <class... Args>
192 holder(Args&&... args)
193 : value(std::forward<Args>(args)...)
194 {
195 }
196
198 };
199
200 template <typename To, BufferReference<To> FromBufferRef>
203 requires(not is_const)
204 : m_buffer(buf)
205 , m_max_size(m_buffer.max_size() / m_to_from_size_ratio)
206 {
207 }
208
209 template <typename To, BufferReference<To> FromBufferRef>
212 : m_buffer(buf)
213 , m_max_size(m_buffer.max_size() / m_to_from_size_ratio)
214 {
215 }
216
217 template <typename To, BufferReference<To> FromBufferRef>
218 requires T_is_const_if_FromBufferRef_is_const<FromBufferRef, To>
221 requires(not is_const)
222 {
223 return m_buffer.template data<value_type>();
224 }
225
226 template <typename To, BufferReference<To> FromBufferRef>
230 {
231 return m_buffer.template data<value_type>();
232 }
233
234 template <typename To, BufferReference<To> FromBufferRef>
238 requires(not is_const)
239 {
240 SPARROW_ASSERT_TRUE(idx < size());
241 return data()[idx];
242 }
243
244 template <typename To, BufferReference<To> FromBufferRef>
248 {
249 SPARROW_ASSERT_TRUE(idx < size());
250 return data()[idx];
251 }
252
253 template <typename To, BufferReference<To> FromBufferRef>
261
262 template <typename To, BufferReference<To> FromBufferRef>
270
271 template <typename To, BufferReference<To> FromBufferRef>
279
280 template <typename To, BufferReference<To> FromBufferRef>
284 {
286 return operator[](size() - 1);
287 }
288
289 template <typename To, BufferReference<To> FromBufferRef>
293 requires(not is_const)
294 {
295 return iterator(data());
296 }
297
298 template <typename To, BufferReference<To> FromBufferRef>
302 requires(not is_const)
303 {
304 return iterator(data() + size());
305 }
306
307 template <typename To, BufferReference<To> FromBufferRef>
311 {
312 return const_iterator(data());
313 }
314
315 template <typename To, BufferReference<To> FromBufferRef>
319 {
320 return const_iterator(data() + size());
321 }
322
323 template <typename To, BufferReference<To> FromBufferRef>
327 {
328 return begin();
329 }
330
331 template <typename To, BufferReference<To> FromBufferRef>
335 {
336 return end();
337 }
338
339 template <typename To, BufferReference<To> FromBufferRef>
343 requires(not is_const)
344 {
345 return reverse_iterator(end());
346 }
347
348 template <typename To, BufferReference<To> FromBufferRef>
352 requires(not is_const)
353 {
354 return reverse_iterator(begin());
355 }
356
357 template <typename To, BufferReference<To> FromBufferRef>
361 {
362 return const_reverse_iterator(end());
363 }
364
365 template <typename To, BufferReference<To> FromBufferRef>
369 {
371 }
372
373 template <typename To, BufferReference<To> FromBufferRef>
377 {
378 return rbegin();
379 }
380
381 template <typename To, BufferReference<To> FromBufferRef>
385 {
386 return rend();
387 }
388
389 // Capacity
390
391 template <typename To, BufferReference<To> FromBufferRef>
395 {
396 const double new_size = static_cast<double>(m_buffer.size()) * m_from_to_size_ratio;
398 std::trunc(new_size) == new_size,
399 "The size of the buffer is not a multiple of the size of the new type"
400 );
401 return static_cast<size_type>(new_size);
402 }
403
404 template <typename To, BufferReference<To> FromBufferRef>
408 {
409 return m_max_size;
410 }
411
412 template <typename To, BufferReference<To> FromBufferRef>
416 {
417 return m_buffer.capacity() / m_to_from_size_ratio;
418 }
419
420 template <typename To, BufferReference<To> FromBufferRef>
422 constexpr bool buffer_adaptor<To, FromBufferRef>::empty() const noexcept
423 {
424 return m_buffer.empty();
425 }
426
427 template <typename To, BufferReference<To> FromBufferRef>
430 requires(not is_const)
431 {
432 m_buffer.reserve(new_cap * m_to_from_size_ratio);
433 }
434
435 template <typename To, BufferReference<To> FromBufferRef>
438 requires(not is_const)
439 {
440 m_buffer.shrink_to_fit();
441 }
442
443 // Modifiers
444
445 template <typename To, BufferReference<To> FromBufferRef>
448 requires(not is_const)
449 {
450 m_buffer.clear();
451 }
452
453 template <typename To, BufferReference<To> FromBufferRef>
457 requires(not is_const)
458 {
459 SPARROW_ASSERT_TRUE(cbegin() <= pos);
460 SPARROW_ASSERT_TRUE(pos <= cend());
461 const difference_type index = std::distance(cbegin(), pos);
462 const auto buffer_pos = get_buffer_reference_iterator(pos);
463 m_buffer.insert(buffer_pos, m_to_from_size_ratio, 0);
464 operator[](static_cast<size_type>(index)) = value;
465 return std::next(begin(), index);
466 }
467
468 template <typename To, BufferReference<To> FromBufferRef>
472 requires(not is_const)
473 {
474 SPARROW_ASSERT_TRUE(cbegin() <= pos);
475 SPARROW_ASSERT_TRUE(pos <= cend());
476 const difference_type index = std::distance(cbegin(), pos);
477 const auto buffer_pos = get_buffer_reference_iterator(pos);
478 m_buffer.insert(buffer_pos, count * m_to_from_size_ratio, 0);
479 for (size_type i = 0; i < count; ++i)
480 {
481 data()[static_cast<size_t>(index) + i] = value;
482 }
483 return std::next(begin(), index);
484 }
485
486 template <typename To, BufferReference<To> FromBufferRef>
488 template <class InputIt>
489 requires std::input_iterator<InputIt>
492 requires(not is_const)
493 {
494 SPARROW_ASSERT_TRUE(cbegin() <= pos);
495 SPARROW_ASSERT_TRUE(pos <= cend());
496 const difference_type index = std::distance(cbegin(), pos);
497 const difference_type count = std::distance(first, last);
498 const auto buffer_pos = get_buffer_reference_iterator(pos);
499 m_buffer.insert(buffer_pos, static_cast<size_type>(count) * m_to_from_size_ratio, 0);
500 std::copy(first, last, data() + index);
501 return std::next(begin(), index);
502 }
503
504 template <typename To, BufferReference<To> FromBufferRef>
507 buffer_adaptor<To, FromBufferRef>::insert(const_iterator pos, std::initializer_list<value_type> ilist)
508 requires(not is_const)
509 {
510 return insert(pos, ilist.begin(), ilist.end());
511 }
512
513 template <typename To, BufferReference<To> FromBufferRef>
515 template <class... Args>
518 requires(not is_const)
519 {
520 SPARROW_ASSERT_TRUE(cbegin() <= pos);
521 SPARROW_ASSERT_TRUE(pos <= cend());
522 const difference_type index = std::distance(cbegin(), pos);
523 const auto buffer_pos = get_buffer_reference_iterator(pos);
524 m_buffer.insert(buffer_pos, m_to_from_size_ratio, 0);
525 data()[index] = value_type(std::forward<Args>(args)...);
526 return std::next(begin(), index);
527 }
528
529 template <typename To, BufferReference<To> FromBufferRef>
533 requires(not is_const)
534 {
535 SPARROW_ASSERT_TRUE(cbegin() <= pos);
536 SPARROW_ASSERT_TRUE(pos <= cend());
537 if (empty())
538 {
539 return begin();
540 }
541 const difference_type index = std::distance(cbegin(), pos);
542 const auto idx_for_buffer = index_for_buffer(static_cast<size_type>(index));
543 SPARROW_ASSERT_TRUE(idx_for_buffer < m_buffer.size());
544
545 m_buffer.erase(
546 std::next(m_buffer.cbegin(), static_cast<difference_type>(idx_for_buffer)),
547 std::next(m_buffer.cbegin(), static_cast<difference_type>(idx_for_buffer + m_to_from_size_ratio))
548 );
549 return std::next(begin(), index);
550 }
551
552 template <typename To, BufferReference<To> FromBufferRef>
556 requires(not is_const)
557 {
558 SPARROW_ASSERT_TRUE(cbegin() <= first);
559 SPARROW_ASSERT_TRUE(last <= cend());
560 if (empty())
561 {
562 return begin();
563 }
564 const difference_type index_first = std::distance(cbegin(), first);
565 const difference_type index_last = std::distance(cbegin(), last);
566 const auto idx_for_buffer_first = index_for_buffer(static_cast<size_type>(index_first));
567 SPARROW_ASSERT_TRUE(idx_for_buffer_first < m_buffer.size());
568 const auto idx_for_buffer_last = index_for_buffer(static_cast<size_type>(index_last));
569 SPARROW_ASSERT_TRUE(idx_for_buffer_last <= m_buffer.size());
570 m_buffer.erase(
571 std::next(m_buffer.cbegin(), static_cast<difference_type>(idx_for_buffer_first)),
572 std::next(m_buffer.cbegin(), static_cast<difference_type>(idx_for_buffer_last))
573 );
574 return std::next(begin(), index_first);
575 }
576
577 template <typename To, BufferReference<To> FromBufferRef>
580 requires(not is_const)
581 {
582 insert(cend(), value);
583 }
584
585 template <typename To, BufferReference<To> FromBufferRef>
588 requires(not is_const)
589 {
590 erase(std::prev(cend()));
591 }
592
593 template <typename To, BufferReference<To> FromBufferRef>
596 requires(not is_const)
597 {
598 const auto new_size_for_buffer = static_cast<size_type>(
599 static_cast<double>(new_size) / m_from_to_size_ratio
600 );
601 m_buffer.resize(new_size_for_buffer);
602 }
603
604 template <typename To, BufferReference<To> FromBufferRef>
607 requires(not is_const)
608 {
609 const size_type original_size = size();
610 const auto new_size_for_buffer = static_cast<size_type>(
611 static_cast<double>(new_size) / m_from_to_size_ratio
612 );
613 m_buffer.resize(new_size_for_buffer, 0);
614 for (size_type i = original_size; i < new_size; ++i)
615 {
616 operator[](i) = value;
617 }
618 }
619
620 template <typename To, class FromBufferRef>
621 auto make_buffer_adaptor(FromBufferRef& buf)
622 {
623 constexpr bool is_const = std::is_const_v<FromBufferRef>;
624 using RealToType = std::conditional_t<is_const, const To, To>;
626 }
627}
Class which have internally a reference to a contiguous container of a certain type and provides an A...
constexpr size_type capacity() const noexcept
std::remove_cvref_t< buffer_reference >::size_type size_type
const value_type & const_reference
constexpr const_iterator cbegin() const noexcept
constexpr const_iterator cend() const noexcept
pointer_iterator< pointer > iterator
constexpr pointer data() noexcept
constexpr reverse_iterator rbegin() noexcept
buffer_adaptor(FromBufferRef buf)
pointer_iterator< const_pointer > const_iterator
constexpr void push_back(const value_type &value)
constexpr size_type size() const noexcept
constexpr const_reverse_iterator crend() const noexcept
constexpr iterator emplace(const_iterator pos, Args &&... args)
buffer_adaptor(const FromBufferRef buf)
constexpr iterator erase(const_iterator pos)
std::remove_cvref_t< FromBufferRef >::value_type buffer_reference_value_type
constexpr reverse_iterator rend() noexcept
std::reverse_iterator< iterator > reverse_iterator
constexpr size_type max_size() const noexcept
std::conditional_t< is_const, const FromBufferRef, FromBufferRef > buffer_reference
std::remove_cvref_t< buffer_reference >::difference_type difference_type
constexpr const_reverse_iterator crbegin() const noexcept
constexpr iterator insert(const_iterator pos, const value_type &value)
constexpr reference operator[](size_type idx)
std::reverse_iterator< const_iterator > const_reverse_iterator
const value_type * const_pointer
holder(Args &&... args)
#define SPARROW_ASSERT_TRUE(expr__)
#define SPARROW_ASSERT(expr__, message__)
auto make_buffer_adaptor(FromBufferRef &buf)