mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-19 10:05:48 +00:00
* Rename ASSERT to XRPL_ASSERT * Upgrade to Anthithesis SDK 0.4.4, and use new 0.4.4 features * automatic cast to bool, like assert * Add instrumentation workflow to verify build with instrumentation enabled
211 lines
6.3 KiB
C++
211 lines
6.3 KiB
C++
//------------------------------------------------------------------------------
|
|
/*
|
|
This file is part of rippled: https://github.com/ripple/rippled
|
|
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
|
|
|
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 RIPPLE_BASICS_RANDOM_H_INCLUDED
|
|
#define RIPPLE_BASICS_RANDOM_H_INCLUDED
|
|
|
|
#include <xrpl/beast/utility/instrumentation.h>
|
|
#include <xrpl/beast/xor_shift_engine.h>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
#include <limits>
|
|
#include <mutex>
|
|
#include <random>
|
|
#include <type_traits>
|
|
|
|
namespace ripple {
|
|
|
|
#ifndef __INTELLISENSE__
|
|
static_assert(
|
|
std::is_integral<beast::xor_shift_engine::result_type>::value &&
|
|
std::is_unsigned<beast::xor_shift_engine::result_type>::value,
|
|
"The Ripple default PRNG engine must return an unsigned integral type.");
|
|
|
|
static_assert(
|
|
std::numeric_limits<beast::xor_shift_engine::result_type>::max() >=
|
|
std::numeric_limits<std::uint64_t>::max(),
|
|
"The Ripple default PRNG engine return must be at least 64 bits wide.");
|
|
#endif
|
|
|
|
namespace detail {
|
|
|
|
// Determines if a type can be called like an Engine
|
|
template <class Engine, class Result = typename Engine::result_type>
|
|
using is_engine = std::is_invocable_r<Result, Engine>;
|
|
} // namespace detail
|
|
|
|
/** Return the default random engine.
|
|
|
|
This engine is guaranteed to be deterministic, but by
|
|
default will be randomly seeded. It is NOT cryptographically
|
|
secure and MUST NOT be used to generate randomness that
|
|
will be used for keys, secure cookies, IVs, padding, etc.
|
|
|
|
Each thread gets its own instance of the engine which
|
|
will be randomly seeded.
|
|
*/
|
|
inline beast::xor_shift_engine&
|
|
default_prng()
|
|
{
|
|
// This is used to seed the thread-specific PRNGs on demand
|
|
static beast::xor_shift_engine seeder = [] {
|
|
std::random_device rng;
|
|
std::uniform_int_distribution<std::uint64_t> distribution{1};
|
|
return beast::xor_shift_engine(distribution(rng));
|
|
}();
|
|
|
|
// This protects the seeder
|
|
static std::mutex m;
|
|
|
|
// The thread-specific PRNGs:
|
|
thread_local beast::xor_shift_engine engine = [] {
|
|
std::uint64_t seed;
|
|
{
|
|
std::lock_guard lk(m);
|
|
std::uniform_int_distribution<std::uint64_t> distribution{1};
|
|
seed = distribution(seeder);
|
|
}
|
|
return beast::xor_shift_engine{seed};
|
|
}();
|
|
|
|
return engine;
|
|
}
|
|
|
|
/** Return a uniformly distributed random integer.
|
|
|
|
@param min The smallest value to return. If not specified
|
|
the value defaults to 0.
|
|
@param max The largest value to return. If not specified
|
|
the value defaults to the largest value that
|
|
can be represented.
|
|
|
|
The randomness is generated by the specified engine (or
|
|
the default engine if one is not specified). The result
|
|
is cryptographically secure only when the engine passed
|
|
into the function is cryptographically secure.
|
|
|
|
@note The range is always a closed interval, so calling
|
|
rand_int(-5, 15) can return any integer in the
|
|
closed interval [-5, 15]; similarly, calling
|
|
rand_int(7) can return any integer in the closed
|
|
interval [0, 7].
|
|
*/
|
|
/** @{ */
|
|
template <class Engine, class Integral>
|
|
std::enable_if_t<
|
|
std::is_integral<Integral>::value && detail::is_engine<Engine>::value,
|
|
Integral>
|
|
rand_int(Engine& engine, Integral min, Integral max)
|
|
{
|
|
XRPL_ASSERT(max > min, "ripple::rand_int : max over min inputs");
|
|
|
|
// This should have no state and constructing it should
|
|
// be very cheap. If that turns out not to be the case
|
|
// it could be hand-optimized.
|
|
return std::uniform_int_distribution<Integral>(min, max)(engine);
|
|
}
|
|
|
|
template <class Integral>
|
|
std::enable_if_t<std::is_integral<Integral>::value, Integral>
|
|
rand_int(Integral min, Integral max)
|
|
{
|
|
return rand_int(default_prng(), min, max);
|
|
}
|
|
|
|
template <class Engine, class Integral>
|
|
std::enable_if_t<
|
|
std::is_integral<Integral>::value && detail::is_engine<Engine>::value,
|
|
Integral>
|
|
rand_int(Engine& engine, Integral max)
|
|
{
|
|
return rand_int(engine, Integral(0), max);
|
|
}
|
|
|
|
template <class Integral>
|
|
std::enable_if_t<std::is_integral<Integral>::value, Integral>
|
|
rand_int(Integral max)
|
|
{
|
|
return rand_int(default_prng(), max);
|
|
}
|
|
|
|
template <class Integral, class Engine>
|
|
std::enable_if_t<
|
|
std::is_integral<Integral>::value && detail::is_engine<Engine>::value,
|
|
Integral>
|
|
rand_int(Engine& engine)
|
|
{
|
|
return rand_int(engine, std::numeric_limits<Integral>::max());
|
|
}
|
|
|
|
template <class Integral = int>
|
|
std::enable_if_t<std::is_integral<Integral>::value, Integral>
|
|
rand_int()
|
|
{
|
|
return rand_int(default_prng(), std::numeric_limits<Integral>::max());
|
|
}
|
|
/** @} */
|
|
|
|
/** Return a random byte */
|
|
/** @{ */
|
|
template <class Byte, class Engine>
|
|
std::enable_if_t<
|
|
(std::is_same<Byte, unsigned char>::value ||
|
|
std::is_same<Byte, std::uint8_t>::value) &&
|
|
detail::is_engine<Engine>::value,
|
|
Byte>
|
|
rand_byte(Engine& engine)
|
|
{
|
|
return static_cast<Byte>(rand_int<Engine, std::uint32_t>(
|
|
engine,
|
|
std::numeric_limits<Byte>::min(),
|
|
std::numeric_limits<Byte>::max()));
|
|
}
|
|
|
|
template <class Byte = std::uint8_t>
|
|
std::enable_if_t<
|
|
(std::is_same<Byte, unsigned char>::value ||
|
|
std::is_same<Byte, std::uint8_t>::value),
|
|
Byte>
|
|
rand_byte()
|
|
{
|
|
return rand_byte<Byte>(default_prng());
|
|
}
|
|
/** @} */
|
|
|
|
/** Return a random boolean value */
|
|
/** @{ */
|
|
template <class Engine>
|
|
inline bool
|
|
rand_bool(Engine& engine)
|
|
{
|
|
return rand_int(engine, 1) == 1;
|
|
}
|
|
|
|
inline bool
|
|
rand_bool()
|
|
{
|
|
return rand_bool(default_prng());
|
|
}
|
|
/** @} */
|
|
|
|
} // namespace ripple
|
|
|
|
#endif // RIPPLE_BASICS_RANDOM_H_INCLUDED
|