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