2#ifndef HASHLIB_ALL_IN_ONE
24 using bool_constant = std::integral_constant<bool, C>;
26 template<
bool C,
typename T =
void>
27 using enable_if_t =
typename std::enable_if<C, T>::type;
29 template<
bool C,
typename T,
typename U>
30 using conditional_t =
typename std::conditional<C, T, U>::type;
36 using remove_const_t =
typename std::remove_const<T>::type;
39 using remove_reference_t =
typename std::remove_reference<T>::type;
42 using remove_pointer_t =
typename std::remove_pointer<T>::type;
45 using remove_cv_t =
typename std::remove_cv<T>::type;
48 using remove_cvref_t = remove_cv_t<remove_reference_t<T>>;
51 using add_pointer_t =
typename std::add_pointer<T>::type;
59 using type_identity_t =
typename type_identity<T>::type;
67 template<
typename B1,
typename... Bn>
68 struct conjunction<B1, Bn...> : conditional_t<bool(B1::value), conjunction<Bn...>, B1> {};
76 template<
typename B1,
typename... Bn>
77 struct disjunction<B1, Bn...> : conditional_t<bool(B1::value), B1, disjunction<Bn...>> {};
80 struct negation : bool_constant<!bool(B::value)> {};
82 template<
typename T,
typename U>
86 using iter_reference_t =
decltype(*std::declval<T&>());
89 using iter_value_t = remove_cvref_t<iter_reference_t<T>>;
91#ifndef __cpp_lib_nonmember_container_access
93 HASHLIB_CXX17_CONSTEXPR
auto data(C& c) ->
decltype(c.data()) {
98 HASHLIB_CXX17_CONSTEXPR
auto data(
const C& c) ->
decltype(c.data()) {
102 template<
typename T, std::
size_t N>
103 HASHLIB_CXX17_CONSTEXPR
auto data(T(&array)[N])
noexcept -> T* {
108 HASHLIB_CXX17_CONSTEXPR
auto data(std::initializer_list<E> il)
noexcept ->
const E* {
116 using iter_cat_t =
typename std::iterator_traits<T>::iterator_category;
118 template<
typename,
typename,
typename =
void>
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> {};
124 template<
typename,
typename,
typename =
void>
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 {};
131 using range_iter_t =
decltype(std::begin(std::declval<T&>()));
134 using range_sent_t =
decltype(std::end(std::declval<T&>()));
137 using range_reference_t = iter_reference_t<range_iter_t<T>>;
140 using range_value_t = iter_value_t<range_iter_t<T>>;
142 template<
typename,
typename,
typename =
void>
145 template<
typename T,
typename Tag>
149 >> : std::true_type {};
151 template<
typename,
typename =
void>
158 decltype(data(std::declval<T&>())),
159 add_pointer_t<iter_reference_t<range_iter_t<T>>>
161 >> : std::true_type {};
178 template<
typename T,
typename It>
196#ifdef __cpp_lib_endian
200#if defined(_MSC_VER) && !defined(__clang__)
205 little = __ORDER_LITTLE_ENDIAN__,
206 big = __ORDER_BIG_ENDIAN__,
207 native = __BYTE_ORDER__
212 static_assert(endian::native == endian::big || endian::native == endian::little,
"unsupported mixed-endian.");
214 constexpr auto is_little_endian() noexcept ->
bool {
215 return endian::native == endian::little;
219 HASHLIB_MOD_EXPORT
using byte =
unsigned char;
221 HASHLIB_MOD_EXPORT HASHLIB_CXX17_INLINE
constexpr std::size_t dynamic_extent =
static_cast<std::size_t
>(-1);
223 template<
typename T, std::
size_t N = dynamic_extent>
230 template<
typename T, std::
size_t N>
236 template<
typename T,
size_t N>
240 HASHLIB_MOD_EXPORT
template<
typename T, std::
size_t N>
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;
248 using const_pointer =
const T*;
249 using reference = T&;
250 using const_reference =
const 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>;
259 HASHLIB_CXX17_CONSTEXPR span(pointer data, size_type size) noexcept : data_(data), size_(size) {
260 assert(data_ || size_ == 0);
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) {}
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) {}
269 template<size_type M, detail::enable_if_t<
270 std::is_const<T>::value &&
271 (N == dynamic_extent || M == N)
273 HASHLIB_CXX17_CONSTEXPR span(
const std::array<value_type, M>& array) noexcept : span(array.data(), N) {}
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>
279 HASHLIB_CXX17_CONSTEXPR span(span<U> other) : span(other.data(), other.size()) {}
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
288 HASHLIB_CXX17_CONSTEXPR span(Range& rng): span(detail::data(rng), std::distance(std::begin(rng), std::end(rng))) {}
290 HASHLIB_CXX17_CONSTEXPR span(
const span& other)
noexcept =
default;
292 span& operator= (
const span& other)
noexcept =
default;
296 HASHLIB_CXX17_CONSTEXPR
auto first(size_type count)
const noexcept -> span {
297 assert(count <= size_);
298 return span(data_, count);
301 HASHLIB_CXX17_CONSTEXPR
auto last(size_type count)
const noexcept -> span {
302 assert(count <= size_);
303 return span(data_ + (size_ - count), count);
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);
311 count == dynamic_extent ? size_ - pos : count
315 HASHLIB_CXX17_CONSTEXPR
auto size()
const noexcept -> size_type {
319 HASHLIB_CXX17_CONSTEXPR
auto size_bytes()
const noexcept -> size_type {
320 return size() *
sizeof(T);
323 HASHLIB_CXX17_CONSTEXPR
auto empty()
const noexcept ->
bool {
327 HASHLIB_CXX17_CONSTEXPR
auto operator[](size_type index)
const noexcept -> T& {
328 assert(index < size_);
332 HASHLIB_CXX17_CONSTEXPR
auto front()
const noexcept -> T& {
337 HASHLIB_CXX17_CONSTEXPR
auto back()
const noexcept -> T& {
339 return *(data() + size() - 1);
342 HASHLIB_CXX17_CONSTEXPR
auto data()
const noexcept -> T* {
343 return static_cast<T*
>(data_);
346 HASHLIB_CXX17_CONSTEXPR
auto begin()
const noexcept -> iterator {
347 return static_cast<T*
>(data_);
350 HASHLIB_CXX17_CONSTEXPR
auto end()
const noexcept -> iterator {
351 return begin() + size_;
354 HASHLIB_CXX17_CONSTEXPR
auto cbegin()
const noexcept -> const_iterator {
358 HASHLIB_CXX17_CONSTEXPR
auto cend()
const noexcept -> const_iterator {
362 HASHLIB_CXX17_CONSTEXPR
auto rbegin()
const noexcept -> reverse_iterator {
363 return reverse_iterator(end());
366 HASHLIB_CXX17_CONSTEXPR
auto rend()
const noexcept -> reverse_iterator {
367 return reverse_iterator(begin());
370 HASHLIB_CXX17_CONSTEXPR
auto crbegin()
const noexcept -> const_reverse_iterator {
371 return const_reverse_iterator(cend());
374 HASHLIB_CXX17_CONSTEXPR
auto crend()
const noexcept -> const_reverse_iterator {
375 return const_reverse_iterator(cbegin());
383 HASHLIB_MOD_EXPORT
template<
typename T>
385 return {
reinterpret_cast<const byte*
>(s.data()), s.size_bytes()};
388 HASHLIB_MOD_EXPORT template<typename T, detail::enable_if_t<!std::is_const<T>::value>* =
nullptr>
390 return {
reinterpret_cast<byte*
>(s.data()), s.size_bytes()};
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");
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"
404 HASHLIB_CXX20_CONSTEXPR
explicit auto_restorer(T& target)
noexcept(std::is_nothrow_copy_constructible<T>::value) : ref_(target), old_(target) {}
406 auto_restorer(
const auto_restorer&) =
delete;
408 HASHLIB_CXX20_CONSTEXPR ~auto_restorer() {
409 ref_ = std::move(old_);
412 auto operator= (
const auto_restorer&) -> auto_restorer& =
delete;
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>
425 ,std::is_same<remove_const_t<T>, std::byte>
429 HASHLIB_CXX17_INLINE
constexpr char hex_table[] =
"0123456789abcdef";
433 HASHLIB_MOD_EXPORT
template<
typename Base>
434 class context :
private Base {
436 using Base::digest_size;
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
450 explicit context(InputIt first, Sentinel last) : context() {
451 this->update(std::move(first), std::move(last));
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
458 explicit context(Range&& rng) : context(std::begin(rng), std::end(rng)) {}
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
464 auto update(Range&& rng) ->
void {
465 this->update(std::begin(rng), std::end(rng));
468 HASHLIB_NODISCARD
auto digest()
noexcept -> std::array<byte, digest_size> {
469 std::array<byte, digest_size> result;
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)) {
478 assert(i == digest_size);
482 HASHLIB_NODISCARD
auto hexdigest() -> std::string {
484 result.resize(2 * digest_size);
486 for (
auto byte_ : digest()) {
487 result[i++] = detail::hex_table[byte_ / 16];
488 result[i++] = detail::hex_table[byte_ % 16];
493 HASHLIB_CXX17_CONSTEXPR
auto clear()
noexcept ->
void {
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
501 auto operator<< (Range&& rng) -> context& {
502 this->update(std::forward<Range>(rng));