1 /////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) Electronic Arts Inc. All rights reserved.
3 /////////////////////////////////////////////////////////////////////////////
4 
5 
6 #if defined(_MSC_VER)
7 	//#pragma warning(disable: 4267)  // 'argument' : conversion from 'size_t' to 'uint32_t', possible loss of data.
8 #endif
9 
10 
11 #include "EASTLTest.h"
12 #include <EASTL/numeric_limits.h>
13 #include <EASTL/set.h>
14 #include <EASTL/random.h>
15 
16 
17 struct GeneratorUint8
18 {
19 	uint8_t mValue;
GeneratorUint8GeneratorUint820 	GeneratorUint8() : mValue(0) {}
operator ()GeneratorUint821 	uint8_t operator()(){ return mValue++; } // This is a pretty bad random number generator, but works for our tests.
22 };
23 
24 struct GeneratorUint16
25 {
26 	uint16_t mValue;
GeneratorUint16GeneratorUint1627 	GeneratorUint16() : mValue(0) {}
operator ()GeneratorUint1628 	uint16_t operator()(){ return mValue++; }
29 };
30 
31 struct GeneratorUint32
32 {
33 	uint32_t mValue;
GeneratorUint32GeneratorUint3234 	GeneratorUint32() : mValue(0) {}
operator ()GeneratorUint3235 	uint32_t operator()(){ return mValue++; }
36 };
37 
38 
39 
40 
41 ///////////////////////////////////////////////////////////////////////////////
42 // TestRandom
43 //
TestRandom()44 int TestRandom()
45 {
46 	int nErrorCount = 0;
47 
48 	{
49 		// template<class IntType = int>
50 		// class uniform_int_distribution
51 
52 		// The C++11 Standard defines a number of formal Generators, such as std::mersenne_twister_engine,
53 		// linear_congruential_engine, discard_block_engine, etc.
54 
55 		using namespace eastl;
56 
57 		{
58 			eastl::uniform_int_distribution<uint8_t> uid(1, 6);
59 			GeneratorUint8 g;
60 
61 			for(uint32_t i = 0; i < UINT8_MAX; i += 1)
62 			{
63 				uint8_t value = uid(g);
64 				EATEST_VERIFY((value >= 1) && (value <= 6));
65 				// To do: Validate the randomness of the value.
66 			}
67 
68 			eastl::uniform_int_distribution<uint8_t> uid2(1, 6);
69 			EATEST_VERIFY(uid == uid2);
70 		}
71 
72 		{
73 			eastl::uniform_int_distribution<uint16_t> uid(1, 6);
74 			GeneratorUint16 g;
75 
76 			for(uint32_t i = 0; i < (UINT16_MAX - (UINT16_MAX / 50)); i += (UINT16_MAX / 50))
77 			{
78 				uint16_t value = uid(g);
79 				EATEST_VERIFY((value >= 1) && (value <= 6));
80 				// To do: Validate the randomness of the value.
81 			}
82 
83 			eastl::uniform_int_distribution<uint16_t> uid2(1, 6);
84 			EATEST_VERIFY(uid == uid2);
85 		}
86 
87 		{
88 			eastl::uniform_int_distribution<uint32_t> uid(1, 6);
89 			GeneratorUint32 g;
90 
91 			for(uint32_t i = 0; i < (UINT32_MAX - (UINT32_MAX / 500)); i += (UINT32_MAX / 500))
92 			{
93 				uint32_t value = uid(g);
94 				EATEST_VERIFY((value >= 1) && (value <= 6));
95 				// To do: Validate the randomness of the value.
96 			}
97 
98 			eastl::uniform_int_distribution<uint32_t> uid2(1, 6);
99 			EATEST_VERIFY(uid == uid2);
100 		}
101 	}
102 
103 
104 
105 	/// Example usage:
106 	///     eastl_size_t Rand(eastl_size_t n) { return (eastl_size_t)(rand() % n); } // Note: The C rand function is poor and slow.
107 	///     pointer_to_unary_function<eastl_size_t, eastl_size_t> randInstance(Rand);
108 	///     random_shuffle(pArrayBegin, pArrayEnd, randInstance);
109 	///
110 	/// Example usage:
111 	///     struct Rand{ eastl_size_t operator()(eastl_size_t n) { return (eastl_size_t)(rand() % n); } }; // Note: The C rand function is poor and slow.
112 	///     Rand randInstance;
113 	///     random_shuffle(pArrayBegin, pArrayEnd, randInstance);
114 
115 
116 	{
117 		// void random_shuffle(RandomAccessIterator first, RandomAccessIterator last, RandomNumberGenerator& rng)
118 		using namespace eastl;
119 
120 		EASTLTest_Rand rng(EA::UnitTest::GetRandSeed());
121 		int intArray[] = { 3, 2, 6, 5, 4, 1 };
122 
123 		random_shuffle(intArray, intArray + 0, rng);
124 		EATEST_VERIFY(VerifySequence(intArray, intArray + 6, int(), "random_shuffle", 3, 2, 6, 5, 4, 1, -1));
125 
126 		random_shuffle(intArray, intArray + (sizeof(intArray) / sizeof(intArray[0])), rng);
127 		bool changed = false;
128 		for(int i = 0; (i < 5) && !changed; i++)
129 		{
130 			changed = (intArray[0] != 3) || (intArray[1] != 2) || (intArray[2] != 6) ||
131 					  (intArray[3] != 5) || (intArray[4] != 4) || (intArray[5] != 1);
132 		}
133 		EATEST_VERIFY(changed);
134 
135 		// Test of possible bug report by user John Chin.
136 		// The report is that shuffling an ordered array 0, 1, 2, 3, 4 ... results in duplicates, such as 5, 2, 2, 4 ...
137 		eastl::vector<eastl_size_t> rngArray;
138 
139 		for(eastl_size_t i = 0; i < 200; ++i)
140 			rngArray.push_back(i);
141 
142 		random_shuffle(rngArray.begin(), rngArray.end(), rng);
143 		EATEST_VERIFY(rngArray.validate());
144 
145 		eastl::set<eastl_size_t> intSet;
146 
147 		for(eastl_size_t s = 0, sEnd = rngArray.size(); s < sEnd; ++s)
148 			intSet.insert(rngArray[s]);
149 
150 		// If the shuffled array is unique, then a set of its values should be the same size as the array.
151 		EATEST_VERIFY(intSet.size() == rngArray.size());
152 	}
153 
154 
155 	return nErrorCount;
156 }
157 
158 
159 
160 
161 
162 
163 
164 
165 
166 
167 
168 
169