1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-05-08 19:57:46 +00:00
sapphire/src/world/Manager/RNGMgr.h

123 lines
3.7 KiB
C
Raw Normal View History

#pragma once
#include "Forwards.h"
#include <array>
#include <algorithm>
#include <chrono>
#include <random>
#include <memory>
#include <type_traits>
#include <vector>
namespace Sapphire::World::Manager
{
/*!
* @brief Generator object that is used on multiple state situations
*/
template< typename T, typename = typename std::enable_if< std::is_arithmetic< T >::value, T >::type >
class RandGenerator
{
public:
RandGenerator( std::shared_ptr< std::mt19937 > pEngine, T minRange = std::numeric_limits< T >::min(), T maxRange = std::numeric_limits< T >::max() )
: m_engine( pEngine ), m_fpuDist( minRange, maxRange ), m_intDist( minRange, maxRange )
{
}
// returns a single value for T type on set ranges, deducing real or integer distribution from given numeric type
T next()
{
if constexpr( std::is_integral< T >::value )
return m_intDist( *m_engine );
2023-01-18 21:44:09 +01:00
return static_cast< T >( m_fpuDist( *m_engine ) );
}
// returns an array of size nSize with values type T on set ranges, deducing real or integer distribution from given numeric type
template< std::size_t nSize >
const std::array< T, nSize > nextCount()
{
std::array< T, nSize > _valPush;
for( auto i = 0; i < nSize; ++i )
{
if constexpr( std::is_integral< T >::value )
_valPush[ i ] = ( m_intDist( *m_engine ) );
else
_valPush[ i ] = ( m_fpuDist( *m_engine ) );
}
return _valPush;
}
protected:
std::uniform_real_distribution<> m_fpuDist;
std::uniform_int_distribution<> m_intDist;
std::shared_ptr< std::mt19937 > m_engine;
};
2020-03-01 01:00:57 +11:00
class RNGMgr
{
public:
// Constructs a manager to supply states for random integer and float distribution using a Mersenne Twister engine
RNGMgr()
{
m_engine = std::make_shared< std::mt19937 >( *engineSeed< std::mt19937::state_size >() );
}
virtual ~RNGMgr() = default;
RNGMgr( const RNGMgr& pRNGMgr ) = delete;
RNGMgr& operator=( const RNGMgr& pRNGMgr ) = delete;
/*!
* @brief Creates a state with specified parameters for multiple uses
* @tparam Numeric type to be used for the generator
* @param Minimum value possible for the random value
* @param Maximum value possible for the random value
* @return Random number generator object
*/
template< typename T, typename = typename std::enable_if< std::is_arithmetic< T >::value, T >::type >
RandGenerator< T > getRandGenerator( T minRange, T maxRange )
{
return RandGenerator< T >( m_engine, minRange, maxRange );
}
/*!
* @brief Creates a state with only typed data arithmetic range
* @tparam Numeric type to be used for the generator and range (::min(), ::max() of numeric type)
* @return Random number generator object
*/
template< typename T, typename = typename std::enable_if< std::is_arithmetic< T >::value, T >::type >
RandGenerator< T > getRandGenerator()
{
return RandGenerator< T >( m_engine );
}
private:
template< std::size_t STATE_SIZE >
std::unique_ptr< std::seed_seq > engineSeed()
{
// initialize mt engine with manually seeded random_device
std::array< uint32_t, STATE_SIZE > seedArray;
std::random_device rd;
// check if kernel can supply sufficiently non-deterministic output
if( rd.entropy() == 0.f )
Logger::error( "Kernel random device entropy reported zero - Random number generator may be poor quality" );
std::generate_n( seedArray.data(), seedArray.size(), std::ref( rd ) );
auto pSeq = std::make_unique< std::seed_seq >( std::begin( seedArray ), std::end( seedArray ) );
return pSeq;
}
std::shared_ptr< std::mt19937 > m_engine;
};
}