Coverage Report

Created: 2025-04-11 06:34

/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