/////////////////////////////////////////////////////////////////////////////// // Copyright (c) Electronic Arts Inc. All rights reserved. /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // This file defines random number generation like the std C++ header. /////////////////////////////////////////////////////////////////////////////// #ifndef EASTL_RANDOM_H #define EASTL_RANDOM_H #if defined(EA_PRAGMA_ONCE_SUPPORTED) #pragma once #endif #include #include /////////////////////////////////////////////////////////////////////////////// // min/max workaround // // MSVC++ has #defines for min/max which collide with the min/max algorithm // declarations. The following may still not completely resolve some kinds of // problems with MSVC++ #defines, though it deals with most cases in production // game code. // #if EASTL_NOMINMAX #ifdef min #undef min #endif #ifdef max #undef max #endif #endif namespace eastl { // Implements a uniform distribution of values generated by a Generator, // where Generator is typically a random or pseudo-random number generator. // Note that the min/max range for this class is inclusive, so if you want // random integers 0, 1, 2, and 3, then you need to init this class with (0, 3) // and not (0, 4). // See the C++11 Standard, section 26.5.1.6 template class uniform_int_distribution { static_assert(eastl::is_integral::value, "uniform_int_distribution: IntType must be integral."); public: typedef IntType result_type; // For uniform_int_distribution, param_type defines simply the min and max values of // the range returned by operator(). It may mean something else for other distribution types. struct param_type { explicit param_type(IntType a = 0, IntType b = eastl::numeric_limits::max()); result_type a() const; result_type b() const; bool operator==(const param_type& x) { return (x.mA == mA) && (x.mB == mB); } bool operator!=(const param_type& x) { return (x.mA != mA) || (x.mB != mB); } protected: IntType mA; IntType mB; }; uniform_int_distribution(IntType a = 0, IntType b = eastl::numeric_limits::max()); uniform_int_distribution(const param_type& params); void reset(); template result_type operator()(Generator& g); template result_type operator()(Generator& g, const param_type& params); result_type a() const; result_type b() const; param_type param() const; void param(const param_type& params); result_type min() const; result_type max() const; protected: param_type mParam; }; /////////////////////////////////////////////////////////////////////// // uniform_int_distribution /////////////////////////////////////////////////////////////////////// template inline uniform_int_distribution::param_type::param_type(IntType aValue, IntType bValue) : mA(aValue), mB(bValue) { EASTL_ASSERT(aValue <= bValue); } template inline typename uniform_int_distribution::result_type uniform_int_distribution::param_type::a() const { return mA; } template inline typename uniform_int_distribution::result_type uniform_int_distribution::param_type::b() const { return mB; } template inline uniform_int_distribution::uniform_int_distribution(IntType aValue, IntType bValue) : mParam(aValue, bValue) { // Nothing more to do. } template inline uniform_int_distribution::uniform_int_distribution(const param_type& params) : mParam(params) { // Nothing more to do. } template void uniform_int_distribution::reset() { // Nothing to do. } template template inline typename uniform_int_distribution::result_type uniform_int_distribution::operator()(Generator& g) { return operator()(g, mParam); } template template inline typename uniform_int_distribution::result_type uniform_int_distribution::operator()(Generator& g, const param_type& params) { // This is a tricky function to implement in a generic way for all integral types. // The solution will involve handling the case of signed types and 64 bit types, // probably in a way that uses template metaprogramming to deal with signed ranges. // Temporary solution while we research a full solution. It supports only uint8_t, // uint16_t, and uint32_t uniform_int_distribution types. static_assert(eastl::is_unsigned::value && (sizeof(result_type) <= 4), "uniform_int_distribution currently supports only uint8_t, uint16_t, uint32_t."); result_type v = g(); // Generates a value in the range of (numeric_limits::min(), numeric_limits::max()). result_type r = (result_type)((v * (uint64_t)((params.b() - params.a()) + 1)) >> (sizeof(result_type) * 8)); // +1 because ranges are inclusive. return params.a() + r; } template inline typename uniform_int_distribution::result_type uniform_int_distribution::a() const { return mParam.mA; } template inline typename uniform_int_distribution::result_type uniform_int_distribution::b() const { return mParam.mB; } template inline typename uniform_int_distribution::param_type uniform_int_distribution::param() const { return mParam; } template inline void uniform_int_distribution::param(const param_type& params) { mParam = params; } template inline typename uniform_int_distribution::result_type uniform_int_distribution::min() const { return mParam.mA; } template inline typename uniform_int_distribution::result_type uniform_int_distribution::max() const { return mParam.mB; } template inline bool operator==(const uniform_int_distribution& lhs, const uniform_int_distribution& rhs) { return (lhs.param() == rhs.param()); } template inline bool operator!=(const uniform_int_distribution& lhs, const uniform_int_distribution& rhs) { return (lhs.param() != rhs.param()); } // EASTL doesn't currently implement IO stream-related functionality. // It may be useful to forward declare these templates and let the user implement them in the meantime. // // template // eastl::basic_ostream& operator<<(eastl::basic_ostream& os, const uniform_int_distribution& uid); // // template // eastl::basic_istream& operator>>(eastl::basic_istream& is, uniform_int_distribution& uid); } // namespace eastl #endif // Header include guard