sparrow 0.9.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{
33 template <typename FromBufferRef, typename T>
34 concept BufferReference = std::ranges::contiguous_range<FromBufferRef> && std::is_reference_v<FromBufferRef>
35 && (sizeof(std::ranges::range_value_t<FromBufferRef>) <= sizeof(T));
36
43 template <typename FromBufferRef, typename T>
45
55 template <typename To, BufferReference<To> FromBufferRef>
58 {
59 public:
60
61 using value_type = To;
65 using const_pointer = const value_type*;
66 static constexpr bool is_const = std::is_const_v<To>;
67
68 using buffer_reference_value_type = std::remove_cvref_t<FromBufferRef>::value_type;
69 using buffer_reference = std::conditional_t<is_const, const FromBufferRef, FromBufferRef>;
70
71 using size_type = std::remove_cvref_t<buffer_reference>::size_type;
72 using difference_type = std::remove_cvref_t<buffer_reference>::difference_type;
75 using reverse_iterator = std::reverse_iterator<iterator>;
76 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
77
83 constexpr explicit buffer_adaptor(FromBufferRef buf)
84 requires(not is_const);
85
91 constexpr explicit buffer_adaptor(const FromBufferRef buf);
92
98 [[nodiscard]] constexpr pointer data() noexcept
99 requires(not is_const);
100
106 [[nodiscard]] constexpr const_pointer data() const noexcept;
107
108 // Element access
109
116 [[nodiscard]] constexpr reference operator[](size_type idx)
117 requires(not is_const);
118
125 [[nodiscard]] constexpr const_reference operator[](size_type idx) const;
126
132 [[nodiscard]] constexpr reference front()
133 requires(not is_const);
134
140 [[nodiscard]] constexpr const_reference front() const;
141
147 [[nodiscard]] constexpr reference back()
148 requires(not is_const);
149
155 [[nodiscard]] constexpr const_reference back() const;
156
157 // Iterators
158
164 [[nodiscard]] constexpr iterator begin() noexcept
165 requires(not is_const);
166
172 [[nodiscard]] constexpr iterator end() noexcept
173 requires(not is_const);
174
180 [[nodiscard]] constexpr const_iterator begin() const noexcept;
181
187 [[nodiscard]] constexpr const_iterator end() const noexcept;
188
194 [[nodiscard]] constexpr const_iterator cbegin() const noexcept;
195
201 [[nodiscard]] constexpr const_iterator cend() const noexcept;
202
208 [[nodiscard]] constexpr reverse_iterator rbegin() noexcept
209 requires(not is_const);
210
216 [[nodiscard]] constexpr reverse_iterator rend() noexcept
217 requires(not is_const);
218
224 [[nodiscard]] constexpr const_reverse_iterator rbegin() const noexcept;
225
231 [[nodiscard]] constexpr const_reverse_iterator rend() const noexcept;
232
238 [[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept;
239
245 [[nodiscard]] constexpr const_reverse_iterator crend() const noexcept;
246
247 // Capacity
248
254 [[nodiscard]] constexpr size_type size() const noexcept(!SPARROW_CONTRACTS_THROW_ON_FAILURE);
260 [[nodiscard]] constexpr size_type max_size() const noexcept;
261
267 [[nodiscard]] constexpr size_type capacity() const noexcept;
268
274 [[nodiscard]] constexpr bool empty() const noexcept;
275
281 constexpr void reserve(size_type new_cap)
282 requires(not is_const);
283
287 constexpr void shrink_to_fit()
288 requires(not is_const);
289
290 // Modifiers
291
295 constexpr void clear() noexcept
296 requires(not is_const);
297
305 constexpr iterator insert(const_iterator pos, const value_type& value)
306 requires(not is_const);
307
316 constexpr iterator insert(const_iterator pos, size_type count, const value_type& value)
317 requires(not is_const);
318
328 template <class InputIt>
329 requires std::input_iterator<InputIt>
330 constexpr iterator insert(const_iterator pos, InputIt first, InputIt last)
331 requires(not is_const);
332
340 constexpr iterator insert(const_iterator pos, std::initializer_list<value_type> ilist)
341 requires(not is_const);
342
351 template <class... Args>
352 constexpr iterator emplace(const_iterator pos, Args&&... args)
353 requires(not is_const);
354
362 requires(not is_const);
363
372 requires(not is_const);
373
379 constexpr void push_back(const value_type& value)
380 requires(not is_const);
381
385 constexpr void pop_back()
386 requires(not is_const);
387
393 constexpr void resize(size_type new_size)
394 requires(not is_const);
395
402 constexpr void resize(size_type new_size, const value_type& value)
403 requires(not is_const);
404
405 private:
406
408 static constexpr double m_from_to_size_ratio = static_cast<double>(sizeof(buffer_reference_value_type))
409 / static_cast<double>(sizeof(value_type));
410
412 static constexpr size_type m_to_from_size_ratio = static_cast<size_type>(1. / m_from_to_size_ratio);
413
420 [[nodiscard]] constexpr std::remove_cvref_t<buffer_reference>::size_type
421 index_for_buffer(size_type idx) const noexcept
422 {
423 return idx * m_to_from_size_ratio;
424 }
425
432 [[nodiscard]] std::remove_cvref_t<buffer_reference>::const_iterator
433 get_buffer_reference_iterator(const_iterator pos)
434 {
435 const difference_type index = std::distance(cbegin(), pos);
436 const auto idx_for_buffer = index_for_buffer(static_cast<size_type>(index));
437 SPARROW_ASSERT_TRUE(idx_for_buffer <= m_buffer.size());
438 return std::next(m_buffer.cbegin(), static_cast<difference_type>(idx_for_buffer));
439 }
440
441 buffer_reference m_buffer;
442 size_type m_max_size;
443 };
444
445 template <class T>
446 class holder
447 {
448 public:
449
450 template <class... Args>
451 holder(Args&&... args)
452 : value(std::forward<Args>(args)...)
453 {
454 }
455
457 };
458
459 template <typename To, BufferReference<To> FromBufferRef>
462 requires(not is_const)
463 : m_buffer(buf)
464 , m_max_size(m_buffer.max_size() / m_to_from_size_ratio)
465 {
466 }
467
468 template <typename To, BufferReference<To> FromBufferRef>
470 constexpr buffer_adaptor<To, FromBufferRef>::buffer_adaptor(const FromBufferRef buf)
471 : m_buffer(buf)
472 , m_max_size(m_buffer.max_size() / m_to_from_size_ratio)
473 {
474 }
475
476 template <typename To, BufferReference<To> FromBufferRef>
477 requires T_is_const_if_FromBufferRef_is_const<FromBufferRef, To>
480 requires(not is_const)
481 {
482 return m_buffer.template data<value_type>();
483 }
484
485 template <typename To, BufferReference<To> FromBufferRef>
489 {
490 return m_buffer.template data<value_type>();
491 }
492
493 template <typename To, BufferReference<To> FromBufferRef>
497 requires(not is_const)
498 {
499 SPARROW_ASSERT_TRUE(idx < size());
500 return data()[idx];
501 }
502
503 template <typename To, BufferReference<To> FromBufferRef>
507 {
508 SPARROW_ASSERT_TRUE(idx < size());
509 return data()[idx];
510 }
511
512 template <typename To, BufferReference<To> FromBufferRef>
520
521 template <typename To, BufferReference<To> FromBufferRef>
529
530 template <typename To, BufferReference<To> FromBufferRef>
538
539 template <typename To, BufferReference<To> FromBufferRef>
543 {
545 return operator[](size() - 1);
546 }
547
548 template <typename To, BufferReference<To> FromBufferRef>
552 requires(not is_const)
553 {
554 return iterator(data());
555 }
556
557 template <typename To, BufferReference<To> FromBufferRef>
561 requires(not is_const)
562 {
563 return iterator(data() + size());
564 }
565
566 template <typename To, BufferReference<To> FromBufferRef>
570 {
571 return const_iterator(data());
572 }
573
574 template <typename To, BufferReference<To> FromBufferRef>
578 {
579 return const_iterator(data() + size());
580 }
581
582 template <typename To, BufferReference<To> FromBufferRef>
586 {
587 return begin();
588 }
589
590 template <typename To, BufferReference<To> FromBufferRef>
594 {
595 return end();
596 }
597
598 template <typename To, BufferReference<To> FromBufferRef>
602 requires(not is_const)
603 {
604 return reverse_iterator(end());
605 }
606
607 template <typename To, BufferReference<To> FromBufferRef>
611 requires(not is_const)
612 {
613 return reverse_iterator(begin());
614 }
615
616 template <typename To, BufferReference<To> FromBufferRef>
620 {
621 return const_reverse_iterator(end());
622 }
623
624 template <typename To, BufferReference<To> FromBufferRef>
628 {
630 }
631
632 template <typename To, BufferReference<To> FromBufferRef>
636 {
637 return rbegin();
638 }
639
640 template <typename To, BufferReference<To> FromBufferRef>
644 {
645 return rend();
646 }
647
648 // Capacity
649
650 template <typename To, BufferReference<To> FromBufferRef>
654 {
655 const double new_size = static_cast<double>(m_buffer.size()) * m_from_to_size_ratio;
657 std::trunc(new_size) == new_size,
658 "The size of the buffer is not a multiple of the size of the new type"
659 );
660 return static_cast<size_type>(new_size);
661 }
662
663 template <typename To, BufferReference<To> FromBufferRef>
667 {
668 return m_max_size;
669 }
670
671 template <typename To, BufferReference<To> FromBufferRef>
675 {
676 return m_buffer.capacity() / m_to_from_size_ratio;
677 }
678
679 template <typename To, BufferReference<To> FromBufferRef>
681 constexpr bool buffer_adaptor<To, FromBufferRef>::empty() const noexcept
682 {
683 return m_buffer.empty();
684 }
685
686 template <typename To, BufferReference<To> FromBufferRef>
689 requires(not is_const)
690 {
691 m_buffer.reserve(new_cap * m_to_from_size_ratio);
692 }
693
694 template <typename To, BufferReference<To> FromBufferRef>
697 requires(not is_const)
698 {
699 m_buffer.shrink_to_fit();
700 }
701
702 // Modifiers
703
704 template <typename To, BufferReference<To> FromBufferRef>
707 requires(not is_const)
708 {
709 m_buffer.clear();
710 }
711
712 template <typename To, BufferReference<To> FromBufferRef>
716 requires(not is_const)
717 {
718 SPARROW_ASSERT_TRUE(cbegin() <= pos);
719 SPARROW_ASSERT_TRUE(pos <= cend());
720 const difference_type index = std::distance(cbegin(), pos);
721 const auto buffer_pos = get_buffer_reference_iterator(pos);
722 m_buffer.insert(buffer_pos, m_to_from_size_ratio, 0);
723 operator[](static_cast<size_type>(index)) = value;
724 return std::next(begin(), index);
725 }
726
727 template <typename To, BufferReference<To> FromBufferRef>
731 requires(not is_const)
732 {
733 SPARROW_ASSERT_TRUE(cbegin() <= pos);
734 SPARROW_ASSERT_TRUE(pos <= cend());
735 const difference_type index = std::distance(cbegin(), pos);
736 const auto buffer_pos = get_buffer_reference_iterator(pos);
737 m_buffer.insert(buffer_pos, count * m_to_from_size_ratio, 0);
738 for (size_type i = 0; i < count; ++i)
739 {
740 data()[static_cast<size_t>(index) + i] = value;
741 }
742 return std::next(begin(), index);
743 }
744
745 template <typename To, BufferReference<To> FromBufferRef>
747 template <class InputIt>
748 requires std::input_iterator<InputIt>
751 requires(not is_const)
752 {
753 SPARROW_ASSERT_TRUE(cbegin() <= pos);
754 SPARROW_ASSERT_TRUE(pos <= cend());
755 const difference_type index = std::distance(cbegin(), pos);
756 const difference_type count = std::distance(first, last);
757 const auto buffer_pos = get_buffer_reference_iterator(pos);
758 m_buffer.insert(buffer_pos, static_cast<size_type>(count) * m_to_from_size_ratio, 0);
759 std::copy(first, last, data() + index);
760 return std::next(begin(), index);
761 }
762
763 template <typename To, BufferReference<To> FromBufferRef>
766 buffer_adaptor<To, FromBufferRef>::insert(const_iterator pos, std::initializer_list<value_type> ilist)
767 requires(not is_const)
768 {
769 return insert(pos, ilist.begin(), ilist.end());
770 }
771
772 template <typename To, BufferReference<To> FromBufferRef>
774 template <class... Args>
777 requires(not is_const)
778 {
779 SPARROW_ASSERT_TRUE(cbegin() <= pos);
780 SPARROW_ASSERT_TRUE(pos <= cend());
781 const difference_type index = std::distance(cbegin(), pos);
782 const auto buffer_pos = get_buffer_reference_iterator(pos);
783 m_buffer.insert(buffer_pos, m_to_from_size_ratio, 0);
784 data()[index] = value_type(std::forward<Args>(args)...);
785 return std::next(begin(), index);
786 }
787
788 template <typename To, BufferReference<To> FromBufferRef>
792 requires(not is_const)
793 {
794 SPARROW_ASSERT_TRUE(cbegin() <= pos);
795 SPARROW_ASSERT_TRUE(pos <= cend());
796 if (empty())
797 {
798 return begin();
799 }
800 const difference_type index = std::distance(cbegin(), pos);
801 const auto idx_for_buffer = index_for_buffer(static_cast<size_type>(index));
802 SPARROW_ASSERT_TRUE(idx_for_buffer < m_buffer.size());
803
804 m_buffer.erase(
805 std::next(m_buffer.cbegin(), static_cast<difference_type>(idx_for_buffer)),
806 std::next(m_buffer.cbegin(), static_cast<difference_type>(idx_for_buffer + m_to_from_size_ratio))
807 );
808 return std::next(begin(), index);
809 }
810
811 template <typename To, BufferReference<To> FromBufferRef>
815 requires(not is_const)
816 {
817 SPARROW_ASSERT_TRUE(cbegin() <= first);
818 SPARROW_ASSERT_TRUE(last <= cend());
819 if (empty())
820 {
821 return begin();
822 }
823 const difference_type index_first = std::distance(cbegin(), first);
824 const difference_type index_last = std::distance(cbegin(), last);
825 const auto idx_for_buffer_first = index_for_buffer(static_cast<size_type>(index_first));
826 SPARROW_ASSERT_TRUE(idx_for_buffer_first < m_buffer.size());
827 const auto idx_for_buffer_last = index_for_buffer(static_cast<size_type>(index_last));
828 SPARROW_ASSERT_TRUE(idx_for_buffer_last <= m_buffer.size());
829 m_buffer.erase(
830 std::next(m_buffer.cbegin(), static_cast<difference_type>(idx_for_buffer_first)),
831 std::next(m_buffer.cbegin(), static_cast<difference_type>(idx_for_buffer_last))
832 );
833 return std::next(begin(), index_first);
834 }
835
836 template <typename To, BufferReference<To> FromBufferRef>
839 requires(not is_const)
840 {
841 insert(cend(), value);
842 }
843
844 template <typename To, BufferReference<To> FromBufferRef>
847 requires(not is_const)
848 {
849 erase(std::prev(cend()));
850 }
851
852 template <typename To, BufferReference<To> FromBufferRef>
855 requires(not is_const)
856 {
857 const auto new_size_for_buffer = static_cast<size_type>(
858 static_cast<double>(new_size) / m_from_to_size_ratio
859 );
860 m_buffer.resize(new_size_for_buffer);
861 }
862
863 template <typename To, BufferReference<To> FromBufferRef>
866 requires(not is_const)
867 {
868 const size_type original_size = size();
869 const auto new_size_for_buffer = static_cast<size_type>(
870 static_cast<double>(new_size) / m_from_to_size_ratio
871 );
872 m_buffer.resize(new_size_for_buffer, 0);
873 for (size_type i = original_size; i < new_size; ++i)
874 {
875 operator[](i) = value;
876 }
877 }
878
879 template <typename To, class FromBufferRef>
880 auto make_buffer_adaptor(FromBufferRef& buf)
881 {
882 constexpr bool is_const = std::is_const_v<FromBufferRef>;
883 using RealToType = std::conditional_t<is_const, const To, To>;
885 }
886}
Class which has internally a reference to a contiguous container of a certain type and provides an AP...
constexpr size_type capacity() const noexcept
constexpr size_type size() const noexcept(!SPARROW_CONTRACTS_THROW_ON_FAILURE)
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
Returns a pointer to the underlying data.
constexpr reverse_iterator rbegin() noexcept
constexpr buffer_adaptor(FromBufferRef buf)
Constructs a buffer adaptor with a non-const buffer reference.
constexpr buffer_adaptor(const FromBufferRef buf)
Constructs a buffer adaptor with a const buffer reference.
pointer_iterator< const_pointer > const_iterator
constexpr void push_back(const value_type &value)
constexpr const_reverse_iterator crend() const noexcept
constexpr iterator emplace(const_iterator pos, Args &&... args)
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)
Returns a reference to the element at the specified index.
std::reverse_iterator< const_iterator > const_reverse_iterator
const value_type * const_pointer
holder(Args &&... args)
Concept that checks if a type is a buffer reference suitable for adaptation.
Concept that ensures T is const if FromBufferRef is const.
Concept for matching qualifier requirements.
#define SPARROW_ASSERT_TRUE(expr__)
#define SPARROW_ASSERT(expr__, message__)
#define SPARROW_CONTRACTS_THROW_ON_FAILURE
Definition contracts.hpp:24
auto make_buffer_adaptor(FromBufferRef &buf)