1 /////////////////////////////////////////////////////////////////////////////// 2 // Copyright (c) Electronic Arts Inc. All rights reserved. 3 /////////////////////////////////////////////////////////////////////////////// 4 5 /////////////////////////////////////////////////////////////////////////////// 6 // This file defines random number generation like the std C++ <random> header. 7 /////////////////////////////////////////////////////////////////////////////// 8 9 10 #ifndef EASTL_RANDOM_H 11 #define EASTL_RANDOM_H 12 13 #if defined(EA_PRAGMA_ONCE_SUPPORTED) 14 #pragma once 15 #endif 16 17 18 #include <EASTL/internal/config.h> 19 #include <EASTL/numeric_limits.h> 20 21 22 23 /////////////////////////////////////////////////////////////////////////////// 24 // min/max workaround 25 // 26 // MSVC++ has #defines for min/max which collide with the min/max algorithm 27 // declarations. The following may still not completely resolve some kinds of 28 // problems with MSVC++ #defines, though it deals with most cases in production 29 // game code. 30 // 31 #if EASTL_NOMINMAX 32 #ifdef min 33 #undef min 34 #endif 35 #ifdef max 36 #undef max 37 #endif 38 #endif 39 40 41 namespace eastl 42 { 43 44 // Implements a uniform distribution of values generated by a Generator, 45 // where Generator is typically a random or pseudo-random number generator. 46 // Note that the min/max range for this class is inclusive, so if you want 47 // random integers 0, 1, 2, and 3, then you need to init this class with (0, 3) 48 // and not (0, 4). 49 // See the C++11 Standard, section 26.5.1.6 50 template<class IntType = int> 51 class uniform_int_distribution 52 { 53 static_assert(eastl::is_integral<IntType>::value, "uniform_int_distribution: IntType must be integral."); 54 55 public: 56 typedef IntType result_type; 57 58 // For uniform_int_distribution, param_type defines simply the min and max values of 59 // the range returned by operator(). It may mean something else for other distribution types. 60 struct param_type 61 { 62 explicit param_type(IntType a = 0, IntType b = eastl::numeric_limits<IntType>::max()); 63 64 result_type a() const; 65 result_type b() const; 66 67 bool operator==(const param_type& x) { return (x.mA == mA) && (x.mB == mB); } 68 bool operator!=(const param_type& x) { return (x.mA != mA) || (x.mB != mB); } 69 70 protected: 71 IntType mA; 72 IntType mB; 73 }; 74 75 uniform_int_distribution(IntType a = 0, IntType b = eastl::numeric_limits<IntType>::max()); 76 uniform_int_distribution(const param_type& params); 77 78 void reset(); 79 80 template<class Generator> 81 result_type operator()(Generator& g); 82 83 template<class Generator> 84 result_type operator()(Generator& g, const param_type& params); 85 86 result_type a() const; 87 result_type b() const; 88 89 param_type param() const; 90 void param(const param_type& params); 91 92 result_type min() const; 93 result_type max() const; 94 95 protected: 96 param_type mParam; 97 }; 98 99 100 101 /////////////////////////////////////////////////////////////////////// 102 // uniform_int_distribution 103 /////////////////////////////////////////////////////////////////////// 104 105 template<class IntType> param_type(IntType aValue,IntType bValue)106 inline uniform_int_distribution<IntType>::param_type::param_type(IntType aValue, IntType bValue) 107 : mA(aValue), mB(bValue) 108 { 109 EASTL_ASSERT(aValue <= bValue); 110 } 111 112 template<class IntType> 113 inline typename uniform_int_distribution<IntType>::result_type a()114 uniform_int_distribution<IntType>::param_type::a() const 115 { 116 return mA; 117 } 118 119 template<class IntType> 120 inline typename uniform_int_distribution<IntType>::result_type b()121 uniform_int_distribution<IntType>::param_type::b() const 122 { 123 return mB; 124 } 125 126 127 128 template<class IntType> uniform_int_distribution(IntType aValue,IntType bValue)129 inline uniform_int_distribution<IntType>::uniform_int_distribution(IntType aValue, IntType bValue) 130 : mParam(aValue, bValue) 131 { 132 // Nothing more to do. 133 } 134 135 template<class IntType> uniform_int_distribution(const param_type & params)136 inline uniform_int_distribution<IntType>::uniform_int_distribution(const param_type& params) 137 : mParam(params) 138 { 139 // Nothing more to do. 140 } 141 142 template<class IntType> reset()143 void uniform_int_distribution<IntType>::reset() 144 { 145 // Nothing to do. 146 } 147 148 template<class IntType> 149 template<class Generator> 150 inline typename uniform_int_distribution<IntType>::result_type operator()151 uniform_int_distribution<IntType>::operator()(Generator& g) 152 { 153 return operator()(g, mParam); 154 } 155 156 template<class IntType> 157 template<class Generator> 158 inline typename uniform_int_distribution<IntType>::result_type operator()159 uniform_int_distribution<IntType>::operator()(Generator& g, const param_type& params) 160 { 161 // This is a tricky function to implement in a generic way for all integral types. 162 // The solution will involve handling the case of signed types and 64 bit types, 163 // probably in a way that uses template metaprogramming to deal with signed ranges. 164 165 // Temporary solution while we research a full solution. It supports only uint8_t, 166 // uint16_t, and uint32_t uniform_int_distribution types. 167 static_assert(eastl::is_unsigned<result_type>::value && (sizeof(result_type) <= 4), "uniform_int_distribution currently supports only uint8_t, uint16_t, uint32_t."); 168 169 result_type v = g(); // Generates a value in the range of (numeric_limits<result_type>::min(), numeric_limits<result_type>::max()). 170 result_type r = (result_type)((v * (uint64_t)((params.b() - params.a()) + 1)) >> (sizeof(result_type) * 8)); // +1 because ranges are inclusive. 171 return params.a() + r; 172 } 173 174 template<class IntType> 175 inline typename uniform_int_distribution<IntType>::result_type a()176 uniform_int_distribution<IntType>::a() const 177 { 178 return mParam.mA; 179 } 180 181 template<class IntType> 182 inline typename uniform_int_distribution<IntType>::result_type b()183 uniform_int_distribution<IntType>::b() const 184 { 185 return mParam.mB; 186 } 187 188 189 template<class IntType> 190 inline typename uniform_int_distribution<IntType>::param_type param()191 uniform_int_distribution<IntType>::param() const 192 { 193 return mParam; 194 } 195 196 template<class IntType> 197 inline void param(const param_type & params)198 uniform_int_distribution<IntType>::param(const param_type& params) 199 { 200 mParam = params; 201 } 202 203 template<class IntType> 204 inline typename uniform_int_distribution<IntType>::result_type min()205 uniform_int_distribution<IntType>::min() const 206 { 207 return mParam.mA; 208 } 209 210 template<class IntType> 211 inline typename uniform_int_distribution<IntType>::result_type max()212 uniform_int_distribution<IntType>::max() const 213 { 214 return mParam.mB; 215 } 216 217 218 219 template<class ResultType> 220 inline bool operator==(const uniform_int_distribution<ResultType>& lhs, 221 const uniform_int_distribution<ResultType>& rhs) 222 { 223 return (lhs.param() == rhs.param()); 224 } 225 226 template<class ResultType> 227 inline bool operator!=(const uniform_int_distribution<ResultType>& lhs, 228 const uniform_int_distribution<ResultType>& rhs) 229 { 230 return (lhs.param() != rhs.param()); 231 } 232 233 234 // EASTL doesn't currently implement IO stream-related functionality. 235 // It may be useful to forward declare these templates and let the user implement them in the meantime. 236 // 237 // template<class CharT, class Traits, class ResultType> 238 // eastl::basic_ostream<CharT, Traits>& operator<<(eastl::basic_ostream<CharT, Traits>& os, const uniform_int_distribution& uid); 239 // 240 // template<class CharT, class Traits, class ResultType> 241 // eastl::basic_istream<CharT, Traits>& operator>>(eastl::basic_istream<CharT, Traits>& is, uniform_int_distribution& uid); 242 243 244 } // namespace eastl 245 246 247 #endif // Header include guard 248 249 250 251 252 253 254 255