mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
The codebase is filled with includes that are unused, and which thus can be removed. At the same time, the files often do not include all headers that contain the definitions used in those files. This change uses clang-format and clang-tidy to clean up the includes, with minor manual intervention to ensure the code compiles on all platforms.
507 lines
14 KiB
C++
507 lines
14 KiB
C++
//------------------------------------------------------------------------------
|
|
/*
|
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
|
Copyright 2014, Howard Hinnant <howard.hinnant@gmail.com>,
|
|
Vinnie Falco <vinnie.falco@gmail.com
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
purpose with or without fee is hereby granted, provided that the above
|
|
copyright notice and this permission notice appear in all copies.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
//==============================================================================
|
|
|
|
#ifndef BEAST_HASH_HASH_APPEND_H_INCLUDED
|
|
#define BEAST_HASH_HASH_APPEND_H_INCLUDED
|
|
|
|
#include <boost/container/flat_set.hpp>
|
|
#include <boost/endian/conversion.hpp>
|
|
|
|
#include <array>
|
|
#include <chrono>
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
#include <functional>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <set>
|
|
#include <string>
|
|
#include <system_error>
|
|
#include <tuple>
|
|
#include <type_traits>
|
|
#include <unordered_map>
|
|
#include <unordered_set>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
namespace beast {
|
|
|
|
namespace detail {
|
|
|
|
template <class T>
|
|
/*constexpr*/
|
|
inline void
|
|
reverse_bytes(T& t)
|
|
{
|
|
unsigned char* bytes = static_cast<unsigned char*>(
|
|
std::memmove(std::addressof(t), std::addressof(t), sizeof(T)));
|
|
for (unsigned i = 0; i < sizeof(T) / 2; ++i)
|
|
std::swap(bytes[i], bytes[sizeof(T) - 1 - i]);
|
|
}
|
|
|
|
template <class T>
|
|
/*constexpr*/
|
|
inline void
|
|
maybe_reverse_bytes(T& t, std::false_type)
|
|
{
|
|
}
|
|
|
|
template <class T>
|
|
/*constexpr*/
|
|
inline void
|
|
maybe_reverse_bytes(T& t, std::true_type)
|
|
{
|
|
reverse_bytes(t);
|
|
}
|
|
|
|
template <class T, class Hasher>
|
|
/*constexpr*/
|
|
inline void
|
|
maybe_reverse_bytes(T& t, Hasher&)
|
|
{
|
|
maybe_reverse_bytes(
|
|
t,
|
|
std::integral_constant<
|
|
bool,
|
|
Hasher::endian != boost::endian::order::native>{});
|
|
}
|
|
|
|
} // namespace detail
|
|
|
|
// is_uniquely_represented<T>
|
|
|
|
// A type T is contiguously hashable if for all combinations of two values of
|
|
// a type, say x and y, if x == y, then it must also be true that
|
|
// memcmp(addressof(x), addressof(y), sizeof(T)) == 0. I.e. if x == y,
|
|
// then x and y have the same bit pattern representation.
|
|
|
|
template <class T>
|
|
struct is_uniquely_represented
|
|
: public std::integral_constant<
|
|
bool,
|
|
std::is_integral<T>::value || std::is_enum<T>::value ||
|
|
std::is_pointer<T>::value>
|
|
{
|
|
explicit is_uniquely_represented() = default;
|
|
};
|
|
|
|
template <class T>
|
|
struct is_uniquely_represented<T const> : public is_uniquely_represented<T>
|
|
{
|
|
explicit is_uniquely_represented() = default;
|
|
};
|
|
|
|
template <class T>
|
|
struct is_uniquely_represented<T volatile> : public is_uniquely_represented<T>
|
|
{
|
|
explicit is_uniquely_represented() = default;
|
|
};
|
|
|
|
template <class T>
|
|
struct is_uniquely_represented<T const volatile>
|
|
: public is_uniquely_represented<T>
|
|
{
|
|
explicit is_uniquely_represented() = default;
|
|
};
|
|
|
|
// is_uniquely_represented<std::pair<T, U>>
|
|
|
|
template <class T, class U>
|
|
struct is_uniquely_represented<std::pair<T, U>>
|
|
: public std::integral_constant<
|
|
bool,
|
|
is_uniquely_represented<T>::value &&
|
|
is_uniquely_represented<U>::value &&
|
|
sizeof(T) + sizeof(U) == sizeof(std::pair<T, U>)>
|
|
{
|
|
explicit is_uniquely_represented() = default;
|
|
};
|
|
|
|
// is_uniquely_represented<std::tuple<T...>>
|
|
|
|
template <class... T>
|
|
struct is_uniquely_represented<std::tuple<T...>>
|
|
: public std::integral_constant<
|
|
bool,
|
|
std::conjunction_v<is_uniquely_represented<T>...> &&
|
|
sizeof(std::tuple<T...>) == (sizeof(T) + ...)>
|
|
{
|
|
explicit is_uniquely_represented() = default;
|
|
};
|
|
|
|
// is_uniquely_represented<T[N]>
|
|
|
|
template <class T, std::size_t N>
|
|
struct is_uniquely_represented<T[N]> : public is_uniquely_represented<T>
|
|
{
|
|
explicit is_uniquely_represented() = default;
|
|
};
|
|
|
|
// is_uniquely_represented<std::array<T, N>>
|
|
|
|
template <class T, std::size_t N>
|
|
struct is_uniquely_represented<std::array<T, N>>
|
|
: public std::integral_constant<
|
|
bool,
|
|
is_uniquely_represented<T>::value &&
|
|
sizeof(T) * N == sizeof(std::array<T, N>)>
|
|
{
|
|
explicit is_uniquely_represented() = default;
|
|
};
|
|
|
|
/** Metafunction returning `true` if the type can be hashed in one call.
|
|
|
|
For `is_contiguously_hashable<T>::value` to be true, then for every
|
|
combination of possible values of `T` held in `x` and `y`,
|
|
if `x == y`, then it must be true that `memcmp(&x, &y, sizeof(T))`
|
|
return 0; i.e. that `x` and `y` are represented by the same bit pattern.
|
|
|
|
For example: A two's complement `int` should be contiguously hashable.
|
|
Every bit pattern produces a unique value that does not compare equal to
|
|
any other bit pattern's value. A IEEE floating point should not be
|
|
contiguously hashable because -0. and 0. have different bit patterns,
|
|
though they compare equal.
|
|
*/
|
|
/** @{ */
|
|
template <class T, class HashAlgorithm>
|
|
struct is_contiguously_hashable
|
|
: public std::integral_constant<
|
|
bool,
|
|
is_uniquely_represented<T>::value &&
|
|
(sizeof(T) == 1 ||
|
|
HashAlgorithm::endian == boost::endian::order::native)>
|
|
{
|
|
explicit is_contiguously_hashable() = default;
|
|
};
|
|
|
|
template <class T, std::size_t N, class HashAlgorithm>
|
|
struct is_contiguously_hashable<T[N], HashAlgorithm>
|
|
: public std::integral_constant<
|
|
bool,
|
|
is_uniquely_represented<T[N]>::value &&
|
|
(sizeof(T) == 1 ||
|
|
HashAlgorithm::endian == boost::endian::order::native)>
|
|
{
|
|
explicit is_contiguously_hashable() = default;
|
|
};
|
|
/** @} */
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
/** Logically concatenate input data to a `Hasher`.
|
|
|
|
Hasher requirements:
|
|
|
|
`X` is the type `Hasher`
|
|
`h` is a value of type `x`
|
|
`p` is a value convertible to `void const*`
|
|
`n` is a value of type `std::size_t`, greater than zero
|
|
|
|
Expression:
|
|
`h.append (p, n);`
|
|
Throws:
|
|
Never
|
|
Effect:
|
|
Adds the input data to the hasher state.
|
|
|
|
Expression:
|
|
`static_cast<std::size_t>(j)`
|
|
Throws:
|
|
Never
|
|
Effect:
|
|
Returns the reslting hash of all the input data.
|
|
*/
|
|
/** @{ */
|
|
|
|
// scalars
|
|
|
|
template <class Hasher, class T>
|
|
inline std::enable_if_t<is_contiguously_hashable<T, Hasher>::value>
|
|
hash_append(Hasher& h, T const& t) noexcept
|
|
{
|
|
h(std::addressof(t), sizeof(t));
|
|
}
|
|
|
|
template <class Hasher, class T>
|
|
inline std::enable_if_t<
|
|
!is_contiguously_hashable<T, Hasher>::value &&
|
|
(std::is_integral<T>::value || std::is_pointer<T>::value ||
|
|
std::is_enum<T>::value)>
|
|
hash_append(Hasher& h, T t) noexcept
|
|
{
|
|
detail::reverse_bytes(t);
|
|
h(std::addressof(t), sizeof(t));
|
|
}
|
|
|
|
template <class Hasher, class T>
|
|
inline std::enable_if_t<std::is_floating_point<T>::value>
|
|
hash_append(Hasher& h, T t) noexcept
|
|
{
|
|
if (t == 0)
|
|
t = 0;
|
|
detail::maybe_reverse_bytes(t, h);
|
|
h(&t, sizeof(t));
|
|
}
|
|
|
|
template <class Hasher>
|
|
inline void
|
|
hash_append(Hasher& h, std::nullptr_t) noexcept
|
|
{
|
|
void const* p = nullptr;
|
|
detail::maybe_reverse_bytes(p, h);
|
|
h(&p, sizeof(p));
|
|
}
|
|
|
|
// Forward declarations for ADL purposes
|
|
|
|
template <class Hasher, class T, std::size_t N>
|
|
std::enable_if_t<!is_contiguously_hashable<T, Hasher>::value>
|
|
hash_append(Hasher& h, T (&a)[N]) noexcept;
|
|
|
|
template <class Hasher, class CharT, class Traits, class Alloc>
|
|
std::enable_if_t<!is_contiguously_hashable<CharT, Hasher>::value>
|
|
hash_append(
|
|
Hasher& h,
|
|
std::basic_string<CharT, Traits, Alloc> const& s) noexcept;
|
|
|
|
template <class Hasher, class CharT, class Traits, class Alloc>
|
|
std::enable_if_t<is_contiguously_hashable<CharT, Hasher>::value>
|
|
hash_append(
|
|
Hasher& h,
|
|
std::basic_string<CharT, Traits, Alloc> const& s) noexcept;
|
|
|
|
template <class Hasher, class T, class U>
|
|
std::enable_if_t<!is_contiguously_hashable<std::pair<T, U>, Hasher>::value>
|
|
hash_append(Hasher& h, std::pair<T, U> const& p) noexcept;
|
|
|
|
template <class Hasher, class T, class Alloc>
|
|
std::enable_if_t<!is_contiguously_hashable<T, Hasher>::value>
|
|
hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
|
|
|
|
template <class Hasher, class T, class Alloc>
|
|
std::enable_if_t<is_contiguously_hashable<T, Hasher>::value>
|
|
hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
|
|
|
|
template <class Hasher, class T, std::size_t N>
|
|
std::enable_if_t<!is_contiguously_hashable<std::array<T, N>, Hasher>::value>
|
|
hash_append(Hasher& h, std::array<T, N> const& a) noexcept;
|
|
|
|
template <class Hasher, class... T>
|
|
std::enable_if_t<!is_contiguously_hashable<std::tuple<T...>, Hasher>::value>
|
|
hash_append(Hasher& h, std::tuple<T...> const& t) noexcept;
|
|
|
|
template <class Hasher, class Key, class T, class Hash, class Pred, class Alloc>
|
|
void
|
|
hash_append(Hasher& h, std::unordered_map<Key, T, Hash, Pred, Alloc> const& m);
|
|
|
|
template <class Hasher, class Key, class Hash, class Pred, class Alloc>
|
|
void
|
|
hash_append(Hasher& h, std::unordered_set<Key, Hash, Pred, Alloc> const& s);
|
|
|
|
template <class Hasher, class Key, class Compare, class Alloc>
|
|
std::enable_if_t<!is_contiguously_hashable<Key, Hasher>::value>
|
|
hash_append(
|
|
Hasher& h,
|
|
boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
|
|
template <class Hasher, class Key, class Compare, class Alloc>
|
|
std::enable_if_t<is_contiguously_hashable<Key, Hasher>::value>
|
|
hash_append(
|
|
Hasher& h,
|
|
boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
|
|
template <class Hasher, class T0, class T1, class... T>
|
|
void
|
|
hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept;
|
|
|
|
// c-array
|
|
|
|
template <class Hasher, class T, std::size_t N>
|
|
std::enable_if_t<!is_contiguously_hashable<T, Hasher>::value>
|
|
hash_append(Hasher& h, T (&a)[N]) noexcept
|
|
{
|
|
for (auto const& t : a)
|
|
hash_append(h, t);
|
|
}
|
|
|
|
// basic_string
|
|
|
|
template <class Hasher, class CharT, class Traits, class Alloc>
|
|
inline std::enable_if_t<!is_contiguously_hashable<CharT, Hasher>::value>
|
|
hash_append(
|
|
Hasher& h,
|
|
std::basic_string<CharT, Traits, Alloc> const& s) noexcept
|
|
{
|
|
for (auto c : s)
|
|
hash_append(h, c);
|
|
hash_append(h, s.size());
|
|
}
|
|
|
|
template <class Hasher, class CharT, class Traits, class Alloc>
|
|
inline std::enable_if_t<is_contiguously_hashable<CharT, Hasher>::value>
|
|
hash_append(
|
|
Hasher& h,
|
|
std::basic_string<CharT, Traits, Alloc> const& s) noexcept
|
|
{
|
|
h(s.data(), s.size() * sizeof(CharT));
|
|
hash_append(h, s.size());
|
|
}
|
|
|
|
// pair
|
|
|
|
template <class Hasher, class T, class U>
|
|
inline std::enable_if_t<
|
|
!is_contiguously_hashable<std::pair<T, U>, Hasher>::value>
|
|
hash_append(Hasher& h, std::pair<T, U> const& p) noexcept
|
|
{
|
|
hash_append(h, p.first, p.second);
|
|
}
|
|
|
|
// vector
|
|
|
|
template <class Hasher, class T, class Alloc>
|
|
inline std::enable_if_t<!is_contiguously_hashable<T, Hasher>::value>
|
|
hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
|
|
{
|
|
for (auto const& t : v)
|
|
hash_append(h, t);
|
|
hash_append(h, v.size());
|
|
}
|
|
|
|
template <class Hasher, class T, class Alloc>
|
|
inline std::enable_if_t<is_contiguously_hashable<T, Hasher>::value>
|
|
hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
|
|
{
|
|
h(v.data(), v.size() * sizeof(T));
|
|
hash_append(h, v.size());
|
|
}
|
|
|
|
// array
|
|
|
|
template <class Hasher, class T, std::size_t N>
|
|
std::enable_if_t<!is_contiguously_hashable<std::array<T, N>, Hasher>::value>
|
|
hash_append(Hasher& h, std::array<T, N> const& a) noexcept
|
|
{
|
|
for (auto const& t : a)
|
|
hash_append(h, t);
|
|
}
|
|
|
|
template <class Hasher, class Key, class Compare, class Alloc>
|
|
std::enable_if_t<!is_contiguously_hashable<Key, Hasher>::value>
|
|
hash_append(
|
|
Hasher& h,
|
|
boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
|
|
{
|
|
for (auto const& t : v)
|
|
hash_append(h, t);
|
|
}
|
|
template <class Hasher, class Key, class Compare, class Alloc>
|
|
std::enable_if_t<is_contiguously_hashable<Key, Hasher>::value>
|
|
hash_append(
|
|
Hasher& h,
|
|
boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
|
|
{
|
|
h(&(v.begin()), v.size() * sizeof(Key));
|
|
}
|
|
// tuple
|
|
|
|
namespace detail {
|
|
|
|
inline void
|
|
for_each_item(...) noexcept
|
|
{
|
|
}
|
|
|
|
template <class Hasher, class T>
|
|
inline int
|
|
hash_one(Hasher& h, T const& t) noexcept
|
|
{
|
|
hash_append(h, t);
|
|
return 0;
|
|
}
|
|
|
|
template <class Hasher, class... T, std::size_t... I>
|
|
inline void
|
|
tuple_hash(
|
|
Hasher& h,
|
|
std::tuple<T...> const& t,
|
|
std::index_sequence<I...>) noexcept
|
|
{
|
|
for_each_item(hash_one(h, std::get<I>(t))...);
|
|
}
|
|
|
|
} // namespace detail
|
|
|
|
template <class Hasher, class... T>
|
|
inline std::enable_if_t<
|
|
!is_contiguously_hashable<std::tuple<T...>, Hasher>::value>
|
|
hash_append(Hasher& h, std::tuple<T...> const& t) noexcept
|
|
{
|
|
detail::tuple_hash(h, t, std::index_sequence_for<T...>{});
|
|
}
|
|
|
|
// shared_ptr
|
|
|
|
template <class Hasher, class T>
|
|
inline void
|
|
hash_append(Hasher& h, std::shared_ptr<T> const& p) noexcept
|
|
{
|
|
hash_append(h, p.get());
|
|
}
|
|
|
|
// chrono
|
|
|
|
template <class Hasher, class Rep, class Period>
|
|
inline void
|
|
hash_append(Hasher& h, std::chrono::duration<Rep, Period> const& d) noexcept
|
|
{
|
|
hash_append(h, d.count());
|
|
}
|
|
|
|
template <class Hasher, class Clock, class Duration>
|
|
inline void
|
|
hash_append(
|
|
Hasher& h,
|
|
std::chrono::time_point<Clock, Duration> const& tp) noexcept
|
|
{
|
|
hash_append(h, tp.time_since_epoch());
|
|
}
|
|
|
|
// variadic
|
|
|
|
template <class Hasher, class T0, class T1, class... T>
|
|
inline void
|
|
hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept
|
|
{
|
|
hash_append(h, t0);
|
|
hash_append(h, t1, t...);
|
|
}
|
|
|
|
// error_code
|
|
|
|
template <class HashAlgorithm>
|
|
inline void
|
|
hash_append(HashAlgorithm& h, std::error_code const& ec)
|
|
{
|
|
hash_append(h, ec.value(), &ec.category());
|
|
}
|
|
|
|
} // namespace beast
|
|
|
|
#endif
|