/src/botan/build/include/internal/botan/internal/alignment_buffer.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Alignment buffer helper |
3 | | * (C) 2023 Jack Lloyd |
4 | | * 2023 René Meusel - Rohde & Schwarz Cybersecurity |
5 | | * |
6 | | * Botan is released under the Simplified BSD License (see license.txt) |
7 | | */ |
8 | | |
9 | | #ifndef BOTAN_ALIGNMENT_BUFFER_H_ |
10 | | #define BOTAN_ALIGNMENT_BUFFER_H_ |
11 | | |
12 | | #include <botan/concepts.h> |
13 | | #include <botan/mem_ops.h> |
14 | | #include <botan/internal/stl_util.h> |
15 | | |
16 | | #include <array> |
17 | | #include <optional> |
18 | | #include <span> |
19 | | |
20 | | namespace Botan { |
21 | | |
22 | | /** |
23 | | * Defines the strategy for handling the final block of input data in the |
24 | | * handle_unaligned_data() method of the AlignmentBuffer<>. |
25 | | * |
26 | | * - is_not_special: the final block is treated like any other block |
27 | | * - must_be_deferred: the final block is not emitted while bulk processing (typically add_data()) |
28 | | * but is deferred until manually consumed (typically final_result()) |
29 | | * |
30 | | * The AlignmentBuffer<> assumes data to be "the final block" if no further |
31 | | * input data is available in the BufferSlicer<>. This might result in some |
32 | | * performance overhead when using the must_be_deferred strategy. |
33 | | */ |
34 | | enum class AlignmentBufferFinalBlock : size_t { |
35 | | is_not_special = 0, |
36 | | must_be_deferred = 1, |
37 | | }; |
38 | | |
39 | | /** |
40 | | * @brief Alignment buffer helper |
41 | | * |
42 | | * Many algorithms have an intrinsic block size in which they consume input |
43 | | * data. When streaming arbitrary data chunks to such algorithms we must store |
44 | | * some data intermittently to honor the algorithm's alignment requirements. |
45 | | * |
46 | | * This helper encapsulates such an alignment buffer. The API of this class is |
47 | | * designed to minimize user errors in the algorithm implementations. Therefore, |
48 | | * it is strongly opinionated on its use case. Don't try to use it for anything |
49 | | * but the described circumstance. |
50 | | * |
51 | | * @tparam T the element type of the internal buffer |
52 | | * @tparam BLOCK_SIZE the buffer size to use for the alignment buffer |
53 | | * @tparam FINAL_BLOCK_STRATEGY defines whether the final input data block is |
54 | | * retained in handle_unaligned_data() and must be |
55 | | * manually consumed |
56 | | */ |
57 | | template <typename T, |
58 | | size_t BLOCK_SIZE, |
59 | | AlignmentBufferFinalBlock FINAL_BLOCK_STRATEGY = AlignmentBufferFinalBlock::is_not_special> |
60 | | requires(BLOCK_SIZE > 0) |
61 | | class AlignmentBuffer { |
62 | | public: |
63 | 146k | AlignmentBuffer() : m_position(0) {} Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)0>::AlignmentBuffer() Line | Count | Source | 63 | 141k | AlignmentBuffer() : m_position(0) {} |
Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)0>::AlignmentBuffer() Line | Count | Source | 63 | 5.24k | AlignmentBuffer() : m_position(0) {} |
Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)1>::AlignmentBuffer() Botan::AlignmentBuffer<unsigned char, 16ul, (Botan::AlignmentBufferFinalBlock)0>::AlignmentBuffer() Line | Count | Source | 63 | 340 | AlignmentBuffer() : m_position(0) {} |
Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)1>::AlignmentBuffer() Botan::AlignmentBuffer<unsigned char, 32ul, (Botan::AlignmentBufferFinalBlock)0>::AlignmentBuffer() Line | Count | Source | 63 | 52 | AlignmentBuffer() : m_position(0) {} |
|
64 | | |
65 | 173k | ~AlignmentBuffer() { secure_scrub_memory(m_buffer.data(), m_buffer.size()); } Botan::AlignmentBuffer<unsigned char, 32ul, (Botan::AlignmentBufferFinalBlock)0>::~AlignmentBuffer() Line | Count | Source | 65 | 52 | ~AlignmentBuffer() { secure_scrub_memory(m_buffer.data(), m_buffer.size()); } |
Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)0>::~AlignmentBuffer() Line | Count | Source | 65 | 168k | ~AlignmentBuffer() { secure_scrub_memory(m_buffer.data(), m_buffer.size()); } |
Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)0>::~AlignmentBuffer() Line | Count | Source | 65 | 5.24k | ~AlignmentBuffer() { secure_scrub_memory(m_buffer.data(), m_buffer.size()); } |
Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)1>::~AlignmentBuffer() Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)1>::~AlignmentBuffer() Botan::AlignmentBuffer<unsigned char, 16ul, (Botan::AlignmentBufferFinalBlock)0>::~AlignmentBuffer() Line | Count | Source | 65 | 340 | ~AlignmentBuffer() { secure_scrub_memory(m_buffer.data(), m_buffer.size()); } |
|
66 | | |
67 | | AlignmentBuffer(const AlignmentBuffer& other) = default; |
68 | | AlignmentBuffer(AlignmentBuffer&& other) noexcept = default; |
69 | | AlignmentBuffer& operator=(const AlignmentBuffer& other) = default; |
70 | | AlignmentBuffer& operator=(AlignmentBuffer&& other) noexcept = default; |
71 | | |
72 | 444k | void clear() { |
73 | 444k | clear_mem(m_buffer.data(), m_buffer.size()); |
74 | 444k | m_position = 0; |
75 | 444k | } Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)0>::clear() Line | Count | Source | 72 | 400k | void clear() { | 73 | 400k | clear_mem(m_buffer.data(), m_buffer.size()); | 74 | 400k | m_position = 0; | 75 | 400k | } |
Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)0>::clear() Line | Count | Source | 72 | 43.4k | void clear() { | 73 | 43.4k | clear_mem(m_buffer.data(), m_buffer.size()); | 74 | 43.4k | m_position = 0; | 75 | 43.4k | } |
Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)1>::clear() Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 16ul, (Botan::AlignmentBufferFinalBlock)0>::clear() Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)1>::clear() Botan::AlignmentBuffer<unsigned char, 32ul, (Botan::AlignmentBufferFinalBlock)0>::clear() Line | Count | Source | 72 | 52 | void clear() { | 73 | 52 | clear_mem(m_buffer.data(), m_buffer.size()); | 74 | 52 | m_position = 0; | 75 | 52 | } |
|
76 | | |
77 | | /** |
78 | | * Fills the currently unused bytes of the buffer with zero bytes |
79 | | */ |
80 | 314k | void fill_up_with_zeros() { |
81 | 314k | if(!ready_to_consume()) { |
82 | 314k | clear_mem(&m_buffer[m_position], elements_until_alignment()); |
83 | 314k | m_position = m_buffer.size(); |
84 | 314k | } |
85 | 314k | } Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)0>::fill_up_with_zeros() Line | Count | Source | 80 | 272k | void fill_up_with_zeros() { | 81 | 272k | if(!ready_to_consume()) { | 82 | 271k | clear_mem(&m_buffer[m_position], elements_until_alignment()); | 83 | 271k | m_position = m_buffer.size(); | 84 | 271k | } | 85 | 272k | } |
Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)0>::fill_up_with_zeros() Line | Count | Source | 80 | 41.7k | void fill_up_with_zeros() { | 81 | 41.7k | if(!ready_to_consume()) { | 82 | 41.7k | clear_mem(&m_buffer[m_position], elements_until_alignment()); | 83 | 41.7k | m_position = m_buffer.size(); | 84 | 41.7k | } | 85 | 41.7k | } |
Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)1>::fill_up_with_zeros() Botan::AlignmentBuffer<unsigned char, 16ul, (Botan::AlignmentBufferFinalBlock)0>::fill_up_with_zeros() Line | Count | Source | 80 | 453 | void fill_up_with_zeros() { | 81 | 453 | if(!ready_to_consume()) { | 82 | 453 | clear_mem(&m_buffer[m_position], elements_until_alignment()); | 83 | 453 | m_position = m_buffer.size(); | 84 | 453 | } | 85 | 453 | } |
Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)1>::fill_up_with_zeros() Botan::AlignmentBuffer<unsigned char, 32ul, (Botan::AlignmentBufferFinalBlock)0>::fill_up_with_zeros() Line | Count | Source | 80 | 52 | void fill_up_with_zeros() { | 81 | 52 | if(!ready_to_consume()) { | 82 | 52 | clear_mem(&m_buffer[m_position], elements_until_alignment()); | 83 | 52 | m_position = m_buffer.size(); | 84 | 52 | } | 85 | 52 | } |
|
86 | | |
87 | | /** |
88 | | * Appends the provided @p elements to the buffer. The user has to make |
89 | | * sure that @p elements fits in the remaining capacity of the buffer. |
90 | | */ |
91 | 656k | void append(std::span<const T> elements) { |
92 | 656k | BOTAN_ASSERT_NOMSG(elements.size() <= elements_until_alignment()); |
93 | 656k | std::copy(elements.begin(), elements.end(), m_buffer.begin() + m_position); |
94 | 656k | m_position += elements.size(); |
95 | 656k | } Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)0>::append(std::__1::span<unsigned char const, 18446744073709551615ul>) Line | Count | Source | 91 | 574k | void append(std::span<const T> elements) { | 92 | 574k | BOTAN_ASSERT_NOMSG(elements.size() <= elements_until_alignment()); | 93 | 574k | std::copy(elements.begin(), elements.end(), m_buffer.begin() + m_position); | 94 | 574k | m_position += elements.size(); | 95 | 574k | } |
Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)0>::append(std::__1::span<unsigned char const, 18446744073709551615ul>) Line | Count | Source | 91 | 81.5k | void append(std::span<const T> elements) { | 92 | 81.5k | BOTAN_ASSERT_NOMSG(elements.size() <= elements_until_alignment()); | 93 | 81.5k | std::copy(elements.begin(), elements.end(), m_buffer.begin() + m_position); | 94 | 81.5k | m_position += elements.size(); | 95 | 81.5k | } |
Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)1>::append(std::__1::span<unsigned char const, 18446744073709551615ul>) Botan::AlignmentBuffer<unsigned char, 16ul, (Botan::AlignmentBufferFinalBlock)0>::append(std::__1::span<unsigned char const, 18446744073709551615ul>) Line | Count | Source | 91 | 453 | void append(std::span<const T> elements) { | 92 | 453 | BOTAN_ASSERT_NOMSG(elements.size() <= elements_until_alignment()); | 93 | 453 | std::copy(elements.begin(), elements.end(), m_buffer.begin() + m_position); | 94 | 453 | m_position += elements.size(); | 95 | 453 | } |
Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)1>::append(std::__1::span<unsigned char const, 18446744073709551615ul>) Botan::AlignmentBuffer<unsigned char, 32ul, (Botan::AlignmentBufferFinalBlock)0>::append(std::__1::span<unsigned char const, 18446744073709551615ul>) Line | Count | Source | 91 | 52 | void append(std::span<const T> elements) { | 92 | 52 | BOTAN_ASSERT_NOMSG(elements.size() <= elements_until_alignment()); | 93 | 52 | std::copy(elements.begin(), elements.end(), m_buffer.begin() + m_position); | 94 | 52 | m_position += elements.size(); | 95 | 52 | } |
|
96 | | |
97 | | /** |
98 | | * Allows direct modification of the first @p elements in the buffer. |
99 | | * This is a low-level accessor that neither takes the buffer's current |
100 | | * capacity into account nor does it change the internal cursor. |
101 | | * Beware not to overwrite unconsumed bytes. |
102 | | */ |
103 | 138 | std::span<T> directly_modify_first(size_t elements) { |
104 | 138 | BOTAN_ASSERT_NOMSG(size() >= elements); |
105 | 138 | return std::span(m_buffer).first(elements); |
106 | 138 | } |
107 | | |
108 | | /** |
109 | | * Allows direct modification of the last @p elements in the buffer. |
110 | | * This is a low-level accessor that neither takes the buffer's current |
111 | | * capacity into account nor does it change the internal cursor. |
112 | | * Beware not to overwrite unconsumed bytes. |
113 | | */ |
114 | 280k | std::span<T> directly_modify_last(size_t elements) { |
115 | 280k | BOTAN_ASSERT_NOMSG(size() >= elements); |
116 | 280k | return std::span(m_buffer).last(elements); |
117 | 280k | } Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)0>::directly_modify_last(unsigned long) Line | Count | Source | 114 | 247k | std::span<T> directly_modify_last(size_t elements) { | 115 | 247k | BOTAN_ASSERT_NOMSG(size() >= elements); | 116 | 247k | return std::span(m_buffer).last(elements); | 117 | 247k | } |
Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)0>::directly_modify_last(unsigned long) Line | Count | Source | 114 | 33.0k | std::span<T> directly_modify_last(size_t elements) { | 115 | 33.0k | BOTAN_ASSERT_NOMSG(size() >= elements); | 116 | 33.0k | return std::span(m_buffer).last(elements); | 117 | 33.0k | } |
|
118 | | |
119 | | /** |
120 | | * Once the buffer reached alignment, this can be used to consume as many |
121 | | * input bytes from the given @p slider as possible. The output always |
122 | | * contains data elements that are a multiple of the intrinsic block size. |
123 | | * |
124 | | * @returns a view onto the aligned data from @p slicer and the number of |
125 | | * full blocks that are represented by this view. |
126 | | */ |
127 | 219k | [[nodiscard]] std::tuple<std::span<const uint8_t>, size_t> aligned_data_to_process(BufferSlicer& slicer) const { |
128 | 219k | BOTAN_ASSERT_NOMSG(in_alignment()); |
129 | | |
130 | | // When the final block is to be deferred, the last block must not be |
131 | | // selected for processing if there is no (unaligned) extra input data. |
132 | 219k | const size_t defer = (defers_final_block()) ? 1 : 0; |
133 | 219k | const size_t full_blocks_to_process = (slicer.remaining() - defer) / m_buffer.size(); |
134 | 219k | return {slicer.take(full_blocks_to_process * m_buffer.size()), full_blocks_to_process}; |
135 | 219k | } Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)0>::aligned_data_to_process(Botan::BufferSlicer&) const Line | Count | Source | 127 | 180k | [[nodiscard]] std::tuple<std::span<const uint8_t>, size_t> aligned_data_to_process(BufferSlicer& slicer) const { | 128 | 180k | BOTAN_ASSERT_NOMSG(in_alignment()); | 129 | | | 130 | | // When the final block is to be deferred, the last block must not be | 131 | | // selected for processing if there is no (unaligned) extra input data. | 132 | 180k | const size_t defer = (defers_final_block()) ? 1 : 0; | 133 | 180k | const size_t full_blocks_to_process = (slicer.remaining() - defer) / m_buffer.size(); | 134 | 180k | return {slicer.take(full_blocks_to_process * m_buffer.size()), full_blocks_to_process}; | 135 | 180k | } |
Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)0>::aligned_data_to_process(Botan::BufferSlicer&) const Line | Count | Source | 127 | 38.1k | [[nodiscard]] std::tuple<std::span<const uint8_t>, size_t> aligned_data_to_process(BufferSlicer& slicer) const { | 128 | 38.1k | BOTAN_ASSERT_NOMSG(in_alignment()); | 129 | | | 130 | | // When the final block is to be deferred, the last block must not be | 131 | | // selected for processing if there is no (unaligned) extra input data. | 132 | 38.1k | const size_t defer = (defers_final_block()) ? 1 : 0; | 133 | 38.1k | const size_t full_blocks_to_process = (slicer.remaining() - defer) / m_buffer.size(); | 134 | 38.1k | return {slicer.take(full_blocks_to_process * m_buffer.size()), full_blocks_to_process}; | 135 | 38.1k | } |
Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)1>::aligned_data_to_process(Botan::BufferSlicer&) const Botan::AlignmentBuffer<unsigned char, 16ul, (Botan::AlignmentBufferFinalBlock)0>::aligned_data_to_process(Botan::BufferSlicer&) const Line | Count | Source | 127 | 222 | [[nodiscard]] std::tuple<std::span<const uint8_t>, size_t> aligned_data_to_process(BufferSlicer& slicer) const { | 128 | 222 | BOTAN_ASSERT_NOMSG(in_alignment()); | 129 | | | 130 | | // When the final block is to be deferred, the last block must not be | 131 | | // selected for processing if there is no (unaligned) extra input data. | 132 | 222 | const size_t defer = (defers_final_block()) ? 1 : 0; | 133 | 222 | const size_t full_blocks_to_process = (slicer.remaining() - defer) / m_buffer.size(); | 134 | 222 | return {slicer.take(full_blocks_to_process * m_buffer.size()), full_blocks_to_process}; | 135 | 222 | } |
Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)1>::aligned_data_to_process(Botan::BufferSlicer&) const Botan::AlignmentBuffer<unsigned char, 32ul, (Botan::AlignmentBufferFinalBlock)0>::aligned_data_to_process(Botan::BufferSlicer&) const Line | Count | Source | 127 | 52 | [[nodiscard]] std::tuple<std::span<const uint8_t>, size_t> aligned_data_to_process(BufferSlicer& slicer) const { | 128 | 52 | BOTAN_ASSERT_NOMSG(in_alignment()); | 129 | | | 130 | | // When the final block is to be deferred, the last block must not be | 131 | | // selected for processing if there is no (unaligned) extra input data. | 132 | 52 | const size_t defer = (defers_final_block()) ? 1 : 0; | 133 | 52 | const size_t full_blocks_to_process = (slicer.remaining() - defer) / m_buffer.size(); | 134 | 52 | return {slicer.take(full_blocks_to_process * m_buffer.size()), full_blocks_to_process}; | 135 | 52 | } |
|
136 | | |
137 | | /** |
138 | | * Once the buffer reached alignment, this can be used to consume full |
139 | | * blocks from the input data represented by @p slicer. |
140 | | * |
141 | | * @returns a view onto the next full block from @p slicer or std::nullopt |
142 | | * if not enough data is available in @p slicer. |
143 | | */ |
144 | 1.23k | [[nodiscard]] std::optional<std::span<const uint8_t>> next_aligned_block_to_process(BufferSlicer& slicer) const { |
145 | 1.23k | BOTAN_ASSERT_NOMSG(in_alignment()); |
146 | | |
147 | | // When the final block is to be deferred, the last block must not be |
148 | | // selected for processing if there is no (unaligned) extra input data. |
149 | 1.23k | const size_t defer = (defers_final_block()) ? 1 : 0; |
150 | 1.23k | if(slicer.remaining() < m_buffer.size() + defer) { |
151 | 138 | return std::nullopt; |
152 | 138 | } |
153 | | |
154 | 1.10k | return slicer.take(m_buffer.size()); |
155 | 1.23k | } |
156 | | |
157 | | /** |
158 | | * Intermittently buffers potentially unaligned data provided in @p |
159 | | * slicer. If the internal buffer already contains some elements, data is |
160 | | * appended. Once a full block is collected, it is returned to the caller |
161 | | * for processing. |
162 | | * |
163 | | * @param slicer the input data source to be (partially) consumed |
164 | | * @returns a view onto a full block once enough data was collected, or |
165 | | * std::nullopt if no full block is available yet |
166 | | */ |
167 | 566k | [[nodiscard]] std::optional<std::span<const T>> handle_unaligned_data(BufferSlicer& slicer) { |
168 | | // When the final block is to be deferred, we would need to store and |
169 | | // hold a buffer that contains exactly one block until more data is |
170 | | // passed or it is explicitly consumed. |
171 | 566k | const size_t defer = (defers_final_block()) ? 1 : 0; |
172 | | |
173 | 566k | if(in_alignment() && slicer.remaining() >= m_buffer.size() + defer) { |
174 | | // We are currently in alignment and the passed-in data source |
175 | | // contains enough data to benefit from aligned processing. |
176 | | // Therefore, we don't copy anything into the intermittent buffer. |
177 | 190k | return std::nullopt; |
178 | 190k | } |
179 | | |
180 | | // Fill the buffer with as much input data as needed to reach alignment |
181 | | // or until the input source is depleted. |
182 | 375k | const auto elements_to_consume = std::min(m_buffer.size() - m_position, slicer.remaining()); |
183 | 375k | append(slicer.take(elements_to_consume)); |
184 | | |
185 | | // If we collected enough data, we push out one full block. When |
186 | | // deferring the final block is enabled, we additionally check that |
187 | | // more input data is available to continue processing a consecutive |
188 | | // block. |
189 | 375k | if(ready_to_consume() && (!defers_final_block() || !slicer.empty())) { |
190 | 28.9k | return consume(); |
191 | 346k | } else { |
192 | 346k | return std::nullopt; |
193 | 346k | } |
194 | 375k | } Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)0>::handle_unaligned_data(Botan::BufferSlicer&) Line | Count | Source | 167 | 478k | [[nodiscard]] std::optional<std::span<const T>> handle_unaligned_data(BufferSlicer& slicer) { | 168 | | // When the final block is to be deferred, we would need to store and | 169 | | // hold a buffer that contains exactly one block until more data is | 170 | | // passed or it is explicitly consumed. | 171 | 478k | const size_t defer = (defers_final_block()) ? 1 : 0; | 172 | | | 173 | 478k | if(in_alignment() && slicer.remaining() >= m_buffer.size() + defer) { | 174 | | // We are currently in alignment and the passed-in data source | 175 | | // contains enough data to benefit from aligned processing. | 176 | | // Therefore, we don't copy anything into the intermittent buffer. | 177 | 151k | return std::nullopt; | 178 | 151k | } | 179 | | | 180 | | // Fill the buffer with as much input data as needed to reach alignment | 181 | | // or until the input source is depleted. | 182 | 326k | const auto elements_to_consume = std::min(m_buffer.size() - m_position, slicer.remaining()); | 183 | 326k | append(slicer.take(elements_to_consume)); | 184 | | | 185 | | // If we collected enough data, we push out one full block. When | 186 | | // deferring the final block is enabled, we additionally check that | 187 | | // more input data is available to continue processing a consecutive | 188 | | // block. | 189 | 326k | if(ready_to_consume() && (!defers_final_block() || !slicer.empty())) { | 190 | 28.8k | return consume(); | 191 | 297k | } else { | 192 | 297k | return std::nullopt; | 193 | 297k | } | 194 | 326k | } |
Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)0>::handle_unaligned_data(Botan::BufferSlicer&) Line | Count | Source | 167 | 86.5k | [[nodiscard]] std::optional<std::span<const T>> handle_unaligned_data(BufferSlicer& slicer) { | 168 | | // When the final block is to be deferred, we would need to store and | 169 | | // hold a buffer that contains exactly one block until more data is | 170 | | // passed or it is explicitly consumed. | 171 | 86.5k | const size_t defer = (defers_final_block()) ? 1 : 0; | 172 | | | 173 | 86.5k | if(in_alignment() && slicer.remaining() >= m_buffer.size() + defer) { | 174 | | // We are currently in alignment and the passed-in data source | 175 | | // contains enough data to benefit from aligned processing. | 176 | | // Therefore, we don't copy anything into the intermittent buffer. | 177 | 38.0k | return std::nullopt; | 178 | 38.0k | } | 179 | | | 180 | | // Fill the buffer with as much input data as needed to reach alignment | 181 | | // or until the input source is depleted. | 182 | 48.4k | const auto elements_to_consume = std::min(m_buffer.size() - m_position, slicer.remaining()); | 183 | 48.4k | append(slicer.take(elements_to_consume)); | 184 | | | 185 | | // If we collected enough data, we push out one full block. When | 186 | | // deferring the final block is enabled, we additionally check that | 187 | | // more input data is available to continue processing a consecutive | 188 | | // block. | 189 | 48.4k | if(ready_to_consume() && (!defers_final_block() || !slicer.empty())) { | 190 | 25 | return consume(); | 191 | 48.4k | } else { | 192 | 48.4k | return std::nullopt; | 193 | 48.4k | } | 194 | 48.4k | } |
Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)1>::handle_unaligned_data(Botan::BufferSlicer&) Botan::AlignmentBuffer<unsigned char, 16ul, (Botan::AlignmentBufferFinalBlock)0>::handle_unaligned_data(Botan::BufferSlicer&) Line | Count | Source | 167 | 675 | [[nodiscard]] std::optional<std::span<const T>> handle_unaligned_data(BufferSlicer& slicer) { | 168 | | // When the final block is to be deferred, we would need to store and | 169 | | // hold a buffer that contains exactly one block until more data is | 170 | | // passed or it is explicitly consumed. | 171 | 675 | const size_t defer = (defers_final_block()) ? 1 : 0; | 172 | | | 173 | 675 | if(in_alignment() && slicer.remaining() >= m_buffer.size() + defer) { | 174 | | // We are currently in alignment and the passed-in data source | 175 | | // contains enough data to benefit from aligned processing. | 176 | | // Therefore, we don't copy anything into the intermittent buffer. | 177 | 222 | return std::nullopt; | 178 | 222 | } | 179 | | | 180 | | // Fill the buffer with as much input data as needed to reach alignment | 181 | | // or until the input source is depleted. | 182 | 453 | const auto elements_to_consume = std::min(m_buffer.size() - m_position, slicer.remaining()); | 183 | 453 | append(slicer.take(elements_to_consume)); | 184 | | | 185 | | // If we collected enough data, we push out one full block. When | 186 | | // deferring the final block is enabled, we additionally check that | 187 | | // more input data is available to continue processing a consecutive | 188 | | // block. | 189 | 453 | if(ready_to_consume() && (!defers_final_block() || !slicer.empty())) { | 190 | 0 | return consume(); | 191 | 453 | } else { | 192 | 453 | return std::nullopt; | 193 | 453 | } | 194 | 453 | } |
Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)1>::handle_unaligned_data(Botan::BufferSlicer&) Botan::AlignmentBuffer<unsigned char, 32ul, (Botan::AlignmentBufferFinalBlock)0>::handle_unaligned_data(Botan::BufferSlicer&) Line | Count | Source | 167 | 104 | [[nodiscard]] std::optional<std::span<const T>> handle_unaligned_data(BufferSlicer& slicer) { | 168 | | // When the final block is to be deferred, we would need to store and | 169 | | // hold a buffer that contains exactly one block until more data is | 170 | | // passed or it is explicitly consumed. | 171 | 104 | const size_t defer = (defers_final_block()) ? 1 : 0; | 172 | | | 173 | 104 | if(in_alignment() && slicer.remaining() >= m_buffer.size() + defer) { | 174 | | // We are currently in alignment and the passed-in data source | 175 | | // contains enough data to benefit from aligned processing. | 176 | | // Therefore, we don't copy anything into the intermittent buffer. | 177 | 52 | return std::nullopt; | 178 | 52 | } | 179 | | | 180 | | // Fill the buffer with as much input data as needed to reach alignment | 181 | | // or until the input source is depleted. | 182 | 52 | const auto elements_to_consume = std::min(m_buffer.size() - m_position, slicer.remaining()); | 183 | 52 | append(slicer.take(elements_to_consume)); | 184 | | | 185 | | // If we collected enough data, we push out one full block. When | 186 | | // deferring the final block is enabled, we additionally check that | 187 | | // more input data is available to continue processing a consecutive | 188 | | // block. | 189 | 52 | if(ready_to_consume() && (!defers_final_block() || !slicer.empty())) { | 190 | 0 | return consume(); | 191 | 52 | } else { | 192 | 52 | return std::nullopt; | 193 | 52 | } | 194 | 52 | } |
|
195 | | |
196 | | /** |
197 | | * Explicitly consume the currently collected block. It is the caller's |
198 | | * responsibility to ensure that the buffer is filled fully. After |
199 | | * consumption, the buffer is cleared and ready to collect new data. |
200 | | */ |
201 | 343k | [[nodiscard]] std::span<const T> consume() { |
202 | 343k | BOTAN_ASSERT_NOMSG(ready_to_consume()); |
203 | 343k | m_position = 0; |
204 | 343k | return m_buffer; |
205 | 343k | } Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)0>::consume() Line | Count | Source | 201 | 301k | [[nodiscard]] std::span<const T> consume() { | 202 | 301k | BOTAN_ASSERT_NOMSG(ready_to_consume()); | 203 | 301k | m_position = 0; | 204 | 301k | return m_buffer; | 205 | 301k | } |
Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)0>::consume() Line | Count | Source | 201 | 41.8k | [[nodiscard]] std::span<const T> consume() { | 202 | 41.8k | BOTAN_ASSERT_NOMSG(ready_to_consume()); | 203 | 41.8k | m_position = 0; | 204 | 41.8k | return m_buffer; | 205 | 41.8k | } |
Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)1>::consume() Botan::AlignmentBuffer<unsigned char, 16ul, (Botan::AlignmentBufferFinalBlock)0>::consume() Line | Count | Source | 201 | 453 | [[nodiscard]] std::span<const T> consume() { | 202 | 453 | BOTAN_ASSERT_NOMSG(ready_to_consume()); | 203 | 453 | m_position = 0; | 204 | 453 | return m_buffer; | 205 | 453 | } |
Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)1>::consume() Botan::AlignmentBuffer<unsigned char, 32ul, (Botan::AlignmentBufferFinalBlock)0>::consume() Line | Count | Source | 201 | 52 | [[nodiscard]] std::span<const T> consume() { | 202 | 52 | BOTAN_ASSERT_NOMSG(ready_to_consume()); | 203 | 52 | m_position = 0; | 204 | 52 | return m_buffer; | 205 | 52 | } |
|
206 | | |
207 | | /** |
208 | | * Explicitly consumes however many bytes are currently stored in the |
209 | | * buffer. After consumption, the buffer is cleared and ready to collect |
210 | | * new data. |
211 | | */ |
212 | | [[nodiscard]] std::span<const T> consume_partial() { |
213 | | const auto elements = elements_in_buffer(); |
214 | | m_position = 0; |
215 | | return std::span(m_buffer).first(elements); |
216 | | } |
217 | | |
218 | 280k | constexpr size_t size() const { return m_buffer.size(); } Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)0>::size() const Line | Count | Source | 218 | 247k | constexpr size_t size() const { return m_buffer.size(); } |
Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)0>::size() const Line | Count | Source | 218 | 33.0k | constexpr size_t size() const { return m_buffer.size(); } |
Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)1>::size() const |
219 | | |
220 | 138 | size_t elements_in_buffer() const { return m_position; } Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)1>::elements_in_buffer() const Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)0>::elements_in_buffer() const Line | Count | Source | 220 | 138 | size_t elements_in_buffer() const { return m_position; } |
Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)1>::elements_in_buffer() const |
221 | | |
222 | 1.53M | size_t elements_until_alignment() const { return m_buffer.size() - m_position; } Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)0>::elements_until_alignment() const Line | Count | Source | 222 | 1.34M | size_t elements_until_alignment() const { return m_buffer.size() - m_position; } |
Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)0>::elements_until_alignment() const Line | Count | Source | 222 | 189k | size_t elements_until_alignment() const { return m_buffer.size() - m_position; } |
Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)1>::elements_until_alignment() const Botan::AlignmentBuffer<unsigned char, 16ul, (Botan::AlignmentBufferFinalBlock)0>::elements_until_alignment() const Line | Count | Source | 222 | 906 | size_t elements_until_alignment() const { return m_buffer.size() - m_position; } |
Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)1>::elements_until_alignment() const Botan::AlignmentBuffer<unsigned char, 32ul, (Botan::AlignmentBufferFinalBlock)0>::elements_until_alignment() const Line | Count | Source | 222 | 104 | size_t elements_until_alignment() const { return m_buffer.size() - m_position; } |
|
223 | | |
224 | | /** |
225 | | * @returns true if the buffer is empty (i.e. contains no unaligned data) |
226 | | */ |
227 | 1.35M | bool in_alignment() const { return m_position == 0; } Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)0>::in_alignment() const Line | Count | Source | 227 | 1.13M | bool in_alignment() const { return m_position == 0; } |
Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)0>::in_alignment() const Line | Count | Source | 227 | 211k | bool in_alignment() const { return m_position == 0; } |
Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)1>::in_alignment() const Botan::AlignmentBuffer<unsigned char, 16ul, (Botan::AlignmentBufferFinalBlock)0>::in_alignment() const Line | Count | Source | 227 | 2.47k | bool in_alignment() const { return m_position == 0; } |
Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)1>::in_alignment() const Botan::AlignmentBuffer<unsigned char, 32ul, (Botan::AlignmentBufferFinalBlock)0>::in_alignment() const Line | Count | Source | 227 | 312 | bool in_alignment() const { return m_position == 0; } |
|
228 | | |
229 | | /** |
230 | | * @returns true if the buffer is full (i.e. a block is ready to be consumed) |
231 | | */ |
232 | 1.31M | bool ready_to_consume() const { return m_position == m_buffer.size(); } Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)0>::ready_to_consume() const Line | Count | Source | 232 | 1.14M | bool ready_to_consume() const { return m_position == m_buffer.size(); } |
Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)0>::ready_to_consume() const Line | Count | Source | 232 | 165k | bool ready_to_consume() const { return m_position == m_buffer.size(); } |
Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)1>::ready_to_consume() const Botan::AlignmentBuffer<unsigned char, 16ul, (Botan::AlignmentBufferFinalBlock)0>::ready_to_consume() const Line | Count | Source | 232 | 1.35k | bool ready_to_consume() const { return m_position == m_buffer.size(); } |
Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)1>::ready_to_consume() const Botan::AlignmentBuffer<unsigned char, 32ul, (Botan::AlignmentBufferFinalBlock)0>::ready_to_consume() const Line | Count | Source | 232 | 156 | bool ready_to_consume() const { return m_position == m_buffer.size(); } |
|
233 | | |
234 | 815k | constexpr bool defers_final_block() const { |
235 | 815k | return FINAL_BLOCK_STRATEGY == AlignmentBufferFinalBlock::must_be_deferred; |
236 | 815k | } Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)0>::defers_final_block() const Line | Count | Source | 234 | 689k | constexpr bool defers_final_block() const { | 235 | 689k | return FINAL_BLOCK_STRATEGY == AlignmentBufferFinalBlock::must_be_deferred; | 236 | 689k | } |
Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)0>::defers_final_block() const Line | Count | Source | 234 | 124k | constexpr bool defers_final_block() const { | 235 | 124k | return FINAL_BLOCK_STRATEGY == AlignmentBufferFinalBlock::must_be_deferred; | 236 | 124k | } |
Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 64ul, (Botan::AlignmentBufferFinalBlock)1>::defers_final_block() const Botan::AlignmentBuffer<unsigned char, 16ul, (Botan::AlignmentBufferFinalBlock)0>::defers_final_block() const Line | Count | Source | 234 | 897 | constexpr bool defers_final_block() const { | 235 | 897 | return FINAL_BLOCK_STRATEGY == AlignmentBufferFinalBlock::must_be_deferred; | 236 | 897 | } |
Unexecuted instantiation: Botan::AlignmentBuffer<unsigned char, 128ul, (Botan::AlignmentBufferFinalBlock)1>::defers_final_block() const Botan::AlignmentBuffer<unsigned char, 32ul, (Botan::AlignmentBufferFinalBlock)0>::defers_final_block() const Line | Count | Source | 234 | 156 | constexpr bool defers_final_block() const { | 235 | 156 | return FINAL_BLOCK_STRATEGY == AlignmentBufferFinalBlock::must_be_deferred; | 236 | 156 | } |
|
237 | | |
238 | | private: |
239 | | std::array<T, BLOCK_SIZE> m_buffer; |
240 | | size_t m_position; |
241 | | }; |
242 | | |
243 | | } // namespace Botan |
244 | | |
245 | | #endif |