/src/botan/build/include/botan/internal/stl_util.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * STL Utility Functions |
3 | | * (C) 1999-2007 Jack Lloyd |
4 | | * (C) 2015 Simon Warta (Kullo GmbH) |
5 | | * |
6 | | * Botan is released under the Simplified BSD License (see license.txt) |
7 | | */ |
8 | | |
9 | | #ifndef BOTAN_STL_UTIL_H_ |
10 | | #define BOTAN_STL_UTIL_H_ |
11 | | |
12 | | #include <map> |
13 | | #include <set> |
14 | | #include <span> |
15 | | #include <string> |
16 | | #include <tuple> |
17 | | #include <variant> |
18 | | #include <vector> |
19 | | |
20 | | #include <botan/concepts.h> |
21 | | #include <botan/secmem.h> |
22 | | #include <botan/strong_type.h> |
23 | | |
24 | | namespace Botan { |
25 | | |
26 | 0 | inline std::vector<uint8_t> to_byte_vector(std::string_view s) { return std::vector<uint8_t>(s.cbegin(), s.cend()); } |
27 | | |
28 | 0 | inline std::string to_string(const secure_vector<uint8_t>& bytes) { return std::string(bytes.cbegin(), bytes.cend()); } |
29 | | |
30 | | /** |
31 | | * Return the keys of a map as a std::set |
32 | | */ |
33 | | template <typename K, typename V> |
34 | | std::set<K> map_keys_as_set(const std::map<K, V>& kv) { |
35 | | std::set<K> s; |
36 | | for(auto&& i : kv) { |
37 | | s.insert(i.first); |
38 | | } |
39 | | return s; |
40 | | } |
41 | | |
42 | | /** |
43 | | * Return the keys of a multimap as a std::set |
44 | | */ |
45 | | template <typename K, typename V> |
46 | | std::set<K> map_keys_as_set(const std::multimap<K, V>& kv) { |
47 | | std::set<K> s; |
48 | | for(auto&& i : kv) { |
49 | | s.insert(i.first); |
50 | | } |
51 | | return s; |
52 | | } |
53 | | |
54 | | /* |
55 | | * Searching through a std::map |
56 | | * @param mapping the map to search |
57 | | * @param key is what to look for |
58 | | * @param null_result is the value to return if key is not in mapping |
59 | | * @return mapping[key] or null_result |
60 | | */ |
61 | | template <typename K, typename V> |
62 | | inline V search_map(const std::map<K, V>& mapping, const K& key, const V& null_result = V()) { |
63 | | auto i = mapping.find(key); |
64 | | if(i == mapping.end()) |
65 | | return null_result; |
66 | | return i->second; |
67 | | } |
68 | | |
69 | | template <typename K, typename V, typename R> |
70 | | inline R search_map(const std::map<K, V>& mapping, const K& key, const R& null_result, const R& found_result) { |
71 | | auto i = mapping.find(key); |
72 | | if(i == mapping.end()) |
73 | | return null_result; |
74 | | return found_result; |
75 | | } |
76 | | |
77 | | /* |
78 | | * Insert a key/value pair into a multimap |
79 | | */ |
80 | | template <typename K, typename V> |
81 | | void multimap_insert(std::multimap<K, V>& multimap, const K& key, const V& value) { |
82 | | multimap.insert(std::make_pair(key, value)); |
83 | | } |
84 | | |
85 | | /** |
86 | | * Existence check for values |
87 | | */ |
88 | | template <typename T, typename OT> |
89 | | bool value_exists(const std::vector<T>& vec, const OT& val) { |
90 | | for(size_t i = 0; i != vec.size(); ++i) |
91 | | if(vec[i] == val) |
92 | | return true; |
93 | | return false; |
94 | | } |
95 | | |
96 | | template <typename T, typename Pred> |
97 | | void map_remove_if(Pred pred, T& assoc) { |
98 | | auto i = assoc.begin(); |
99 | | while(i != assoc.end()) { |
100 | | if(pred(i->first)) |
101 | | assoc.erase(i++); |
102 | | else |
103 | | i++; |
104 | | } |
105 | | } |
106 | | |
107 | | /** |
108 | | * Helper class to ease unmarshalling of concatenated fixed-length values |
109 | | */ |
110 | | class BufferSlicer final { |
111 | | public: |
112 | 0 | BufferSlicer(std::span<const uint8_t> buffer) : m_remaining(buffer) {} |
113 | | |
114 | | template <concepts::contiguous_container ContainerT> |
115 | 0 | auto copy(const size_t count) { |
116 | 0 | const auto result = take(count); |
117 | 0 | return ContainerT(result.begin(), result.end()); |
118 | 0 | } Unexecuted instantiation: auto Botan::BufferSlicer::copy<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >(unsigned long) Unexecuted instantiation: auto Botan::BufferSlicer::copy<std::__1::vector<unsigned char, Botan::secure_allocator<unsigned char> > >(unsigned long) |
119 | | |
120 | 0 | auto copy_as_vector(const size_t count) { return copy<std::vector<uint8_t>>(count); } |
121 | | |
122 | 0 | auto copy_as_secure_vector(const size_t count) { return copy<secure_vector<uint8_t>>(count); } |
123 | | |
124 | 0 | std::span<const uint8_t> take(const size_t count) { |
125 | 0 | BOTAN_STATE_CHECK(remaining() >= count); |
126 | 0 | auto result = m_remaining.first(count); |
127 | 0 | m_remaining = m_remaining.subspan(count); |
128 | 0 | return result; |
129 | 0 | } |
130 | | |
131 | | template <concepts::contiguous_strong_type T> |
132 | | StrongSpan<const T> take(const size_t count) { |
133 | | return StrongSpan<const T>(take(count)); |
134 | | } |
135 | | |
136 | 0 | void copy_into(std::span<uint8_t> sink) { |
137 | 0 | const auto data = take(sink.size()); |
138 | 0 | std::copy(data.begin(), data.end(), sink.begin()); |
139 | 0 | } |
140 | | |
141 | 0 | void skip(const size_t count) { take(count); } |
142 | | |
143 | 0 | size_t remaining() const { return m_remaining.size(); } |
144 | | |
145 | 0 | bool empty() const { return m_remaining.empty(); } |
146 | | |
147 | | private: |
148 | | std::span<const uint8_t> m_remaining; |
149 | | }; |
150 | | |
151 | | /** |
152 | | * @brief Helper class to ease in-place marshalling of concatenated fixed-length |
153 | | * values. |
154 | | * |
155 | | * The size of the final buffer must be known from the start, reallocations are |
156 | | * not performed. |
157 | | */ |
158 | | class BufferStuffer { |
159 | | public: |
160 | 0 | BufferStuffer(std::span<uint8_t> buffer) : m_buffer(buffer) {} |
161 | | |
162 | | /** |
163 | | * @returns a span for the next @p bytes bytes in the concatenated buffer. |
164 | | * Checks that the buffer is not exceded. |
165 | | */ |
166 | 0 | std::span<uint8_t> next(size_t bytes) { |
167 | 0 | BOTAN_STATE_CHECK(m_buffer.size() >= bytes); |
168 | 0 |
|
169 | 0 | auto result = m_buffer.first(bytes); |
170 | 0 | m_buffer = m_buffer.subspan(bytes); |
171 | 0 | return result; |
172 | 0 | } |
173 | | |
174 | | template <concepts::contiguous_strong_type StrongT> |
175 | | StrongSpan<StrongT> next(size_t bytes) { |
176 | | return StrongSpan<StrongT>(next(bytes)); |
177 | | } |
178 | | |
179 | 0 | void append(std::span<const uint8_t> buffer) { |
180 | 0 | auto sink = next(buffer.size()); |
181 | 0 | std::copy(buffer.begin(), buffer.end(), sink.begin()); |
182 | 0 | } |
183 | | |
184 | 0 | bool full() const { return m_buffer.empty(); } |
185 | | |
186 | 0 | size_t remaining_capacity() const { return m_buffer.size(); } |
187 | | |
188 | | private: |
189 | | std::span<uint8_t> m_buffer; |
190 | | }; |
191 | | |
192 | | /** |
193 | | * Concatenate an arbitrary number of buffers. |
194 | | * @return the concatenation of \p buffers as the container type of the first buffer |
195 | | */ |
196 | | template <typename... Ts> |
197 | | decltype(auto) concat(Ts&&... buffers) { |
198 | | static_assert(sizeof...(buffers) > 0, "concat requires at least one buffer"); |
199 | | |
200 | | using result_t = std::remove_cvref_t<std::tuple_element_t<0, std::tuple<Ts...>>>; |
201 | | result_t result; |
202 | | result.reserve((buffers.size() + ...)); |
203 | | (result.insert(result.end(), buffers.begin(), buffers.end()), ...); |
204 | | return result; |
205 | | } |
206 | | |
207 | | /** |
208 | | * Concatenate an arbitrary number of buffers and define the output buffer |
209 | | * type as a mandatory template parameter. |
210 | | * @return the concatenation of \p buffers as the user-defined container type |
211 | | */ |
212 | | template <typename ResultT, typename... Ts> |
213 | | ResultT concat_as(Ts&&... buffers) { |
214 | | return concat(ResultT(), std::forward<Ts>(buffers)...); |
215 | | } |
216 | | |
217 | | template <typename... Alts, typename... Ts> |
218 | | constexpr bool holds_any_of(const std::variant<Ts...>& v) noexcept { |
219 | | return (std::holds_alternative<Alts>(v) || ...); |
220 | | } |
221 | | |
222 | | template <typename GeneralVariantT, typename SpecialT> |
223 | | constexpr bool is_generalizable_to(const SpecialT&) noexcept { |
224 | | return std::is_constructible_v<GeneralVariantT, SpecialT>; |
225 | | } |
226 | | |
227 | | template <typename GeneralVariantT, typename... SpecialTs> |
228 | | constexpr bool is_generalizable_to(const std::variant<SpecialTs...>&) noexcept { |
229 | | return (std::is_constructible_v<GeneralVariantT, SpecialTs> && ...); |
230 | | } |
231 | | |
232 | | /** |
233 | | * @brief Converts a given variant into another variant-ish whose type states |
234 | | * are a super set of the given variant. |
235 | | * |
236 | | * This is useful to convert restricted variant types into more general |
237 | | * variants types. |
238 | | */ |
239 | | template <typename GeneralVariantT, typename SpecialT> |
240 | | constexpr GeneralVariantT generalize_to(SpecialT&& specific) noexcept |
241 | | requires(std::is_constructible_v<GeneralVariantT, std::decay_t<SpecialT>>) |
242 | | { |
243 | | return std::forward<SpecialT>(specific); |
244 | | } |
245 | | |
246 | | /** |
247 | | * @brief Converts a given variant into another variant-ish whose type states |
248 | | * are a super set of the given variant. |
249 | | * |
250 | | * This is useful to convert restricted variant types into more general |
251 | | * variants types. |
252 | | */ |
253 | | template <typename GeneralVariantT, typename... SpecialTs> |
254 | | constexpr GeneralVariantT generalize_to(std::variant<SpecialTs...> specific) noexcept { |
255 | | static_assert( |
256 | | is_generalizable_to<GeneralVariantT>(specific), |
257 | | "Desired general type must be implicitly constructible by all types of the specialized std::variant<>"); |
258 | | return std::visit([](auto s) -> GeneralVariantT { return s; }, std::move(specific)); |
259 | | } |
260 | | |
261 | | // This is a helper utility to emulate pattern matching with std::visit. |
262 | | // See https://en.cppreference.com/w/cpp/utility/variant/visit for more info. |
263 | | template <class... Ts> |
264 | | struct overloaded : Ts... { |
265 | | using Ts::operator()...; |
266 | | }; |
267 | | // explicit deduction guide (not needed as of C++20) |
268 | | template <class... Ts> |
269 | | overloaded(Ts...) -> overloaded<Ts...>; |
270 | | |
271 | | } // namespace Botan |
272 | | |
273 | | #endif |