libsidplayfp 3.0.0
core.hpp
1// ReSharper disable CppUseTypeTraitAlias
2#ifndef HASHLIB_ALL_IN_ONE
3#pragma once
4#include "config.hpp"
5#include <algorithm>
6#ifdef __cpp_lib_endian
7#include <bit>
8#endif
9#include <array>
10#include <cassert>
11#include <cstddef>
12#include <cstdint>
13#include <cstring>
14#include <iterator>
15#include <string>
16#include <type_traits>
17#include <utility>
18#endif
19
20
21namespace hashlib {
22 namespace detail {
23 template<bool C>
24 using bool_constant = std::integral_constant<bool, C>;
25
26 template<bool C, typename T = void>
27 using enable_if_t = typename std::enable_if<C, T>::type;
28
29 template<bool C, typename T, typename U>
30 using conditional_t = typename std::conditional<C, T, U>::type;
31
32 template<typename...>
33 using void_t = void;
34
35 template<typename T>
36 using remove_const_t = typename std::remove_const<T>::type;
37
38 template<typename T>
39 using remove_reference_t = typename std::remove_reference<T>::type;
40
41 template<typename T>
42 using remove_pointer_t = typename std::remove_pointer<T>::type;
43
44 template<typename T>
45 using remove_cv_t = typename std::remove_cv<T>::type;
46
47 template<typename T>
48 using remove_cvref_t = remove_cv_t<remove_reference_t<T>>;
49
50 template<typename T>
51 using add_pointer_t = typename std::add_pointer<T>::type;
52
53 template <typename T>
55 using type = T;
56 };
57
58 template<typename T>
59 using type_identity_t = typename type_identity<T>::type;
60
61 template<typename...>
62 struct conjunction : std::true_type {};
63
64 template<typename B1>
65 struct conjunction<B1> : B1 {};
66
67 template<typename B1, typename... Bn>
68 struct conjunction<B1, Bn...> : conditional_t<bool(B1::value), conjunction<Bn...>, B1> {};
69
70 template<typename...>
71 struct disjunction : std::false_type {};
72
73 template<typename B1>
74 struct disjunction<B1> : B1 {};
75
76 template<typename B1, typename... Bn>
77 struct disjunction<B1, Bn...> : conditional_t<bool(B1::value), B1, disjunction<Bn...>> {};
78
79 template<typename B>
80 struct negation : bool_constant<!bool(B::value)> {};
81
82 template<typename T, typename U>
83 using is_derived_from = conjunction<std::is_base_of<U, T>, std::is_convertible<T*, U*>>;
84
85 template<typename T>
86 using iter_reference_t = decltype(*std::declval<T&>());
87
88 template<typename T>
89 using iter_value_t = remove_cvref_t<iter_reference_t<T>>;
90
91#ifndef __cpp_lib_nonmember_container_access
92 template<typename C>
93 HASHLIB_CXX17_CONSTEXPR auto data(C& c) -> decltype(c.data()) {
94 return c.data();
95 }
96
97 template<typename C>
98 HASHLIB_CXX17_CONSTEXPR auto data(const C& c) -> decltype(c.data()) {
99 return c.data();
100 }
101
102 template<typename T, std::size_t N>
103 HASHLIB_CXX17_CONSTEXPR auto data(T(&array)[N]) noexcept -> T* {
104 return array;
105 }
106
107 template<typename E>
108 HASHLIB_CXX17_CONSTEXPR auto data(std::initializer_list<E> il) noexcept -> const E* {
109 return il.begin();
110 }
111#else
112 using std::data;
113#endif
114
115 template<typename T>
116 using iter_cat_t = typename std::iterator_traits<T>::iterator_category;
117
118 template<typename, typename, typename = void>
119 struct is_iterator_impl : std::false_type {};
120
121 template<typename T, typename Tag>
122 struct is_iterator_impl<T, Tag, void_t<iter_cat_t<T>>> : is_derived_from<iter_cat_t<T>, Tag> {};
123
124 template<typename, typename, typename = void>
125 struct is_sentinel_for_impl : std::false_type {};
126
127 template<typename T, typename It>
128 struct is_sentinel_for_impl<T, It, void_t<decltype(std::declval<It&&>() != std::declval<T&&>())>> : std::true_type {};
129
130 template<typename T>
131 using range_iter_t = decltype(std::begin(std::declval<T&>()));
132
133 template<typename T>
134 using range_sent_t = decltype(std::end(std::declval<T&>()));
135
136 template<typename T>
137 using range_reference_t = iter_reference_t<range_iter_t<T>>;
138
139 template<typename T>
140 using range_value_t = iter_value_t<range_iter_t<T>>;
141
142 template<typename, typename, typename = void>
143 struct is_range_impl : std::false_type {};
144
145 template<typename T, typename Tag>
146 struct is_range_impl<T, Tag, enable_if_t<
147 is_iterator_impl<range_iter_t<T>, Tag>::value &&
148 is_sentinel_for_impl<range_sent_t<T>, range_iter_t<T>>::value
149 >> : std::true_type {};
150
151 template<typename, typename = void>
152 struct is_contiguous_range_impl : std::false_type {};
153
154 template<typename T>
155 struct is_contiguous_range_impl<T, enable_if_t<
156 is_range_impl<T, std::random_access_iterator_tag>::value &&
157 std::is_same<
158 decltype(data(std::declval<T&>())), // use ADL
159 add_pointer_t<iter_reference_t<range_iter_t<T>>>
160 >::value
161 >> : std::true_type {};
162
163 template<typename T>
164 using is_output_iterator = is_iterator_impl<T, std::output_iterator_tag>;
165
166 template<typename T>
167 using is_input_iterator = is_iterator_impl<T, std::input_iterator_tag>;
168
169 template<typename T>
170 using is_forward_iterator = is_iterator_impl<T, std::forward_iterator_tag>;
171
172 template<typename T>
173 using is_bidirectional_iterator = is_iterator_impl<T, std::bidirectional_iterator_tag>;
174
175 template<typename T>
176 using is_random_access_iterator = is_iterator_impl<T, std::random_access_iterator_tag>;
177
178 template<typename T, typename It>
179 using is_sentinel_for = is_sentinel_for_impl<T, It>;
180
181 template<typename T>
182 using is_input_range = is_range_impl<T, std::input_iterator_tag>;
183
184 template<typename T>
185 using is_forward_range = is_range_impl<T, std::forward_iterator_tag>;
186
187 template<typename T>
188 using is_bidirectional_range = is_range_impl<T, std::bidirectional_iterator_tag>;
189
190 template<typename T>
191 using is_random_access_range = is_range_impl<T, std::random_access_iterator_tag>;
192
193 template<typename T>
194 using is_contiguous_range = is_contiguous_range_impl<T>;
195
196#ifdef __cpp_lib_endian
197 using std::endian;
198#else
199 enum class endian {
200#if defined(_MSC_VER) && !defined(__clang__)
201 little = 0,
202 big = 1,
203 native = little
204#else
205 little = __ORDER_LITTLE_ENDIAN__,
206 big = __ORDER_BIG_ENDIAN__,
207 native = __BYTE_ORDER__
208#endif
209 };
210#endif
211
212 static_assert(endian::native == endian::big || endian::native == endian::little, "unsupported mixed-endian.");
213
214 constexpr auto is_little_endian() noexcept -> bool {
215 return endian::native == endian::little;
216 }
217 }
218
219 HASHLIB_MOD_EXPORT using byte = unsigned char;
220
221 HASHLIB_MOD_EXPORT HASHLIB_CXX17_INLINE constexpr std::size_t dynamic_extent = static_cast<std::size_t>(-1);
222
223 template<typename T, std::size_t N = dynamic_extent>
224 class span;
225
226 namespace detail {
227 template<typename>
228 struct is_span: std::false_type {};
229
230 template<typename T, std::size_t N>
231 struct is_span<span<T, N>> : std::true_type {};
232
233 template<typename>
234 struct is_std_array : std::false_type {};
235
236 template<typename T, size_t N>
237 struct is_std_array<std::array<T, N>> : std::true_type {};
238 }
239
240 HASHLIB_MOD_EXPORT template<typename T, std::size_t N>
241 class span {
242 public:
243 using element_type = T;
244 using value_type = detail::remove_cv_t<T>;
245 using size_type = std::size_t;
246 using difference_type = std::ptrdiff_t;
247 using pointer = T*;
248 using const_pointer = const T*;
249 using reference = T&;
250 using const_reference = const T&;
251 using iterator = T*;
252 using const_iterator = const T*;
253 using reverse_iterator = std::reverse_iterator<iterator>;
254 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
255
256 public:
257 span() = default;
258
259 HASHLIB_CXX17_CONSTEXPR span(pointer data, size_type size) noexcept : data_(data), size_(size) {
260 assert(data_ || size_ == 0);
261 }
262
263 template<size_type M, detail::enable_if_t<N == dynamic_extent || M == N>* = nullptr>
264 HASHLIB_CXX17_CONSTEXPR span(detail::type_identity_t<T>(&array)[M]) noexcept : span(array, N) {}
265
266 template<size_type M, detail::enable_if_t<N == dynamic_extent || M == N>* = nullptr>
267 HASHLIB_CXX17_CONSTEXPR span(std::array<value_type, M>& array) noexcept : span(array.data(), N) {}
268
269 template<size_type M, detail::enable_if_t<
270 std::is_const<T>::value &&
271 (N == dynamic_extent || M == N)
272 >* = nullptr>
273 HASHLIB_CXX17_CONSTEXPR span(const std::array<value_type, M>& array) noexcept : span(array.data(), N) {}
274
275 template<typename U, detail::enable_if_t<
276 std::is_const<T>::value &&
277 std::is_same<U, detail::remove_const_t<T>>::value>
278 * = nullptr>
279 HASHLIB_CXX17_CONSTEXPR span(span<U> other) : span(other.data(), other.size()) {}
280
281 template<typename Range, detail::enable_if_t<
282 detail::is_contiguous_range<Range>::value &&
283 std::is_same<detail::range_value_t<Range>, value_type>::value &&
286 std::is_convertible<decltype(detail::data(std::declval<Range&>())), pointer>::value
287 >* = nullptr>
288 HASHLIB_CXX17_CONSTEXPR span(Range& rng): span(detail::data(rng), std::distance(std::begin(rng), std::end(rng))) {}
289
290 HASHLIB_CXX17_CONSTEXPR span(const span& other) noexcept = default;
291
292 span& operator= (const span& other) noexcept = default;
293
294 ~span() = default;
295
296 HASHLIB_CXX17_CONSTEXPR auto first(size_type count) const noexcept -> span {
297 assert(count <= size_);
298 return span(data_, count);
299 }
300
301 HASHLIB_CXX17_CONSTEXPR auto last(size_type count) const noexcept -> span {
302 assert(count <= size_);
303 return span(data_ + (size_ - count), count);
304 }
305
306 HASHLIB_CXX17_CONSTEXPR auto subspan(size_type pos, size_type count = dynamic_extent) const noexcept -> span {
307 assert(pos <= size_);
308 assert(count == dynamic_extent || count <= size_ - pos);
309 return span(
310 data_ + pos,
311 count == dynamic_extent ? size_ - pos : count
312 );
313 }
314
315 HASHLIB_CXX17_CONSTEXPR auto size() const noexcept -> size_type {
316 return size_;
317 }
318
319 HASHLIB_CXX17_CONSTEXPR auto size_bytes() const noexcept -> size_type {
320 return size() * sizeof(T);
321 }
322
323 HASHLIB_CXX17_CONSTEXPR auto empty() const noexcept -> bool {
324 return size_ == 0;
325 }
326
327 HASHLIB_CXX17_CONSTEXPR auto operator[](size_type index) const noexcept -> T& {
328 assert(index < size_);
329 return data_[index];
330 }
331
332 HASHLIB_CXX17_CONSTEXPR auto front() const noexcept -> T& {
333 assert(!empty());
334 return *data();
335 }
336
337 HASHLIB_CXX17_CONSTEXPR auto back() const noexcept -> T& {
338 assert(!empty());
339 return *(data() + size() - 1);
340 }
341
342 HASHLIB_CXX17_CONSTEXPR auto data() const noexcept -> T* {
343 return static_cast<T*>(data_);
344 }
345
346 HASHLIB_CXX17_CONSTEXPR auto begin() const noexcept -> iterator {
347 return static_cast<T*>(data_);
348 }
349
350 HASHLIB_CXX17_CONSTEXPR auto end() const noexcept -> iterator {
351 return begin() + size_;
352 }
353
354 HASHLIB_CXX17_CONSTEXPR auto cbegin() const noexcept -> const_iterator {
355 return begin();
356 }
357
358 HASHLIB_CXX17_CONSTEXPR auto cend() const noexcept -> const_iterator {
359 return end();
360 }
361
362 HASHLIB_CXX17_CONSTEXPR auto rbegin() const noexcept -> reverse_iterator {
363 return reverse_iterator(end());
364 }
365
366 HASHLIB_CXX17_CONSTEXPR auto rend() const noexcept -> reverse_iterator {
367 return reverse_iterator(begin());
368 }
369
370 HASHLIB_CXX17_CONSTEXPR auto crbegin() const noexcept -> const_reverse_iterator {
371 return const_reverse_iterator(cend());
372 }
373
374 HASHLIB_CXX17_CONSTEXPR auto crend() const noexcept -> const_reverse_iterator {
375 return const_reverse_iterator(cbegin());
376 }
377
378 private:
379 pointer data_{};
380 size_type size_{};
381 };
382
383 HASHLIB_MOD_EXPORT template<typename T>
384 HASHLIB_NODISCARD auto as_bytes(span<T> s) noexcept -> span<const byte> {
385 return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
386 }
387
388 HASHLIB_MOD_EXPORT template<typename T, detail::enable_if_t<!std::is_const<T>::value>* = nullptr>
389 HASHLIB_NODISCARD auto as_writable_bytes(span<T> s) noexcept -> span<byte> {
390 return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
391 }
392
393
394 namespace detail {
395 template<typename T>
396 class auto_restorer {
397 static_assert(std::is_same<T, remove_cvref_t<T>>::value, "`T` shall be a non-cv-qualified, non-reference type");
398 static_assert(
399 std::is_move_constructible<T>::value && std::is_move_assignable<T>::value &&
400 std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
401 "`T` shall be a copyable type"
402 );
403 public:
404 HASHLIB_CXX20_CONSTEXPR explicit auto_restorer(T& target) noexcept(std::is_nothrow_copy_constructible<T>::value) : ref_(target), old_(target) {}
405
406 auto_restorer(const auto_restorer&) = delete;
407
408 HASHLIB_CXX20_CONSTEXPR ~auto_restorer() {
409 ref_ = std::move(old_);
410 }
411
412 auto operator= (const auto_restorer&) -> auto_restorer& = delete;
413
414 private:
415 T& ref_;
416 T old_;
417 };
418
419 template<typename T>
420 using is_byte_like = disjunction<
421 std::is_same<remove_const_t<T>, char>,
422 std::is_same<remove_const_t<T>, unsigned char>,
423 std::is_same<remove_const_t<T>, signed char>
424#ifdef __cpp_lib_byte
425 ,std::is_same<remove_const_t<T>, std::byte>
426#endif
427 >;
428
429 HASHLIB_CXX17_INLINE constexpr char hex_table[] = "0123456789abcdef";
430 }
431
432
433 HASHLIB_MOD_EXPORT template<typename Base>
434 class context : private Base {
435 public:
436 using Base::digest_size;
437 using Base::update;
438
439 context() = default;
440
441 explicit context(span<const byte> bytes) : context() {
442 this->update(bytes);
443 }
444
445 template<typename InputIt, typename Sentinel, detail::enable_if_t<
446 detail::is_input_iterator<InputIt>::value &&
447 detail::is_sentinel_for<Sentinel, InputIt>::value &&
448 detail::is_byte_like<detail::iter_value_t<InputIt>>::value
449 >* = nullptr>
450 explicit context(InputIt first, Sentinel last) : context() {
451 this->update(std::move(first), std::move(last));
452 }
453
454 template<typename Range, detail::enable_if_t<
455 detail::is_input_range<Range>::value &&
456 detail::is_byte_like<detail::range_value_t<Range>>::value
457 >* = nullptr>
458 explicit context(Range&& rng) : context(std::begin(rng), std::end(rng)) {}
459
460 template<typename Range, detail::enable_if_t<
461 detail::is_input_range<Range>::value &&
462 detail::is_byte_like<detail::range_value_t<Range>>::value
463 >* = nullptr>
464 auto update(Range&& rng) -> void {
465 this->update(std::begin(rng), std::end(rng));
466 }
467
468 HASHLIB_NODISCARD auto digest() noexcept -> std::array<byte, digest_size> {
469 std::array<byte, digest_size> result;
470 std::size_t i = 0;
471 static_assert(digest_size <= sizeof(decltype(this->do_digest())), "what the f**k?");
472 for (auto unit : this->do_digest()) {
473 if (i == digest_size) break;
474 for (auto byte_ : this->unit_to_bytes(unit)) {
475 result[i++] = byte_;
476 }
477 }
478 assert(i == digest_size);
479 return result;
480 }
481
482 HASHLIB_NODISCARD auto hexdigest() -> std::string {
483 std::string result;
484 result.resize(2 * digest_size);
485 std::size_t i = 0;
486 for (auto byte_ : digest()) {
487 result[i++] = detail::hex_table[byte_ / 16];
488 result[i++] = detail::hex_table[byte_ % 16];
489 }
490 return result;
491 }
492
493 HASHLIB_CXX17_CONSTEXPR auto clear() noexcept -> void {
494 *this = context{};
495 }
496
497 template<typename Range, detail::enable_if_t<
498 detail::is_input_range<Range>::value &&
499 detail::is_byte_like<detail::range_value_t<Range>>::value
500 >* = nullptr>
501 auto operator<< (Range&& rng) -> context& {
502 this->update(std::forward<Range>(rng));
503 return *this;
504 }
505 };
506}
Definition core.hpp:241
Definition core.hpp:62
Definition core.hpp:71
Definition core.hpp:119
Definition core.hpp:143
Definition core.hpp:228
Definition core.hpp:234
Definition core.hpp:80
Definition core.hpp:54