Random.h 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. /*
  2. * Copyright 2011-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #pragma once
  17. #define FOLLY_RANDOM_H_
  18. #include <array>
  19. #include <cstdint>
  20. #include <random>
  21. #include <type_traits>
  22. #include <folly/Portability.h>
  23. #include <folly/Traits.h>
  24. #include <folly/functional/Invoke.h>
  25. #if FOLLY_HAVE_EXTRANDOM_SFMT19937
  26. #include <ext/random>
  27. #endif
  28. namespace folly {
  29. /**
  30. * A PRNG with one instance per thread. This PRNG uses a mersenne twister random
  31. * number generator and is seeded from /dev/urandom. It should not be used for
  32. * anything which requires security, only for statistical randomness.
  33. *
  34. * An instance of this class represents the current threads PRNG. This means
  35. * copying an instance of this class across threads will result in corruption
  36. *
  37. * Most users will use the Random class which implicitly creates this class.
  38. * However, if you are worried about performance, you can memoize the TLS
  39. * lookups that get the per thread state by manually using this class:
  40. *
  41. * ThreadLocalPRNG rng;
  42. * for (...) {
  43. * Random::rand32(rng);
  44. * }
  45. */
  46. class ThreadLocalPRNG {
  47. public:
  48. using result_type = uint32_t;
  49. result_type operator()();
  50. static constexpr result_type min() {
  51. return std::numeric_limits<result_type>::min();
  52. }
  53. static constexpr result_type max() {
  54. return std::numeric_limits<result_type>::max();
  55. }
  56. };
  57. class Random {
  58. private:
  59. template <class RNG>
  60. using ValidRNG = typename std::
  61. enable_if<std::is_unsigned<invoke_result_t<RNG&>>::value, RNG>::type;
  62. template <class T>
  63. class SecureRNG {
  64. public:
  65. using result_type = typename std::enable_if<
  66. std::is_integral<T>::value && !std::is_same<T, bool>::value,
  67. T>::type;
  68. result_type operator()() {
  69. return Random::secureRandom<result_type>();
  70. }
  71. static constexpr result_type min() {
  72. return std::numeric_limits<result_type>::min();
  73. }
  74. static constexpr result_type max() {
  75. return std::numeric_limits<result_type>::max();
  76. }
  77. };
  78. public:
  79. // Default generator type.
  80. #if FOLLY_HAVE_EXTRANDOM_SFMT19937
  81. typedef __gnu_cxx::sfmt19937 DefaultGenerator;
  82. #else
  83. typedef std::mt19937 DefaultGenerator;
  84. #endif
  85. /**
  86. * Get secure random bytes. (On Linux and OSX, this means /dev/urandom).
  87. */
  88. static void secureRandom(void* data, size_t len);
  89. /**
  90. * Shortcut to get a secure random value of integral type.
  91. */
  92. template <class T>
  93. static typename std::enable_if<
  94. std::is_integral<T>::value && !std::is_same<T, bool>::value,
  95. T>::type
  96. secureRandom() {
  97. T val;
  98. secureRandom(&val, sizeof(val));
  99. return val;
  100. }
  101. /**
  102. * Returns a secure random uint32_t
  103. */
  104. static uint32_t secureRand32() {
  105. return secureRandom<uint32_t>();
  106. }
  107. /**
  108. * Returns a secure random uint32_t in [0, max). If max == 0, returns 0.
  109. */
  110. static uint32_t secureRand32(uint32_t max) {
  111. SecureRNG<uint32_t> srng;
  112. return rand32(max, srng);
  113. }
  114. /**
  115. * Returns a secure random uint32_t in [min, max). If min == max, returns 0.
  116. */
  117. static uint32_t secureRand32(uint32_t min, uint32_t max) {
  118. SecureRNG<uint32_t> srng;
  119. return rand32(min, max, srng);
  120. }
  121. /**
  122. * Returns a secure random uint64_t
  123. */
  124. static uint64_t secureRand64() {
  125. return secureRandom<uint64_t>();
  126. }
  127. /**
  128. * Returns a secure random uint64_t in [0, max). If max == 0, returns 0.
  129. */
  130. static uint64_t secureRand64(uint64_t max) {
  131. SecureRNG<uint64_t> srng;
  132. return rand64(max, srng);
  133. }
  134. /**
  135. * Returns a secure random uint64_t in [min, max). If min == max, returns 0.
  136. */
  137. static uint64_t secureRand64(uint64_t min, uint64_t max) {
  138. SecureRNG<uint64_t> srng;
  139. return rand64(min, max, srng);
  140. }
  141. /**
  142. * Returns true 1/n of the time. If n == 0, always returns false
  143. */
  144. static bool secureOneIn(uint32_t n) {
  145. SecureRNG<uint32_t> srng;
  146. return rand32(0, n, srng) == 0;
  147. }
  148. /**
  149. * Returns a secure double in [0, 1)
  150. */
  151. static double secureRandDouble01() {
  152. SecureRNG<uint64_t> srng;
  153. return randDouble01(srng);
  154. }
  155. /**
  156. * Returns a secure double in [min, max), if min == max, returns 0.
  157. */
  158. static double secureRandDouble(double min, double max) {
  159. SecureRNG<uint64_t> srng;
  160. return randDouble(min, max, srng);
  161. }
  162. /**
  163. * (Re-)Seed an existing RNG with a good seed.
  164. *
  165. * Note that you should usually use ThreadLocalPRNG unless you need
  166. * reproducibility (such as during a test), in which case you'd want
  167. * to create a RNG with a good seed in production, and seed it yourself
  168. * in test.
  169. */
  170. template <class RNG = DefaultGenerator, class /* EnableIf */ = ValidRNG<RNG>>
  171. static void seed(RNG& rng);
  172. /**
  173. * Create a new RNG, seeded with a good seed.
  174. *
  175. * Note that you should usually use ThreadLocalPRNG unless you need
  176. * reproducibility (such as during a test), in which case you'd want
  177. * to create a RNG with a good seed in production, and seed it yourself
  178. * in test.
  179. */
  180. template <class RNG = DefaultGenerator, class /* EnableIf */ = ValidRNG<RNG>>
  181. static RNG create();
  182. /**
  183. * Returns a random uint32_t
  184. */
  185. static uint32_t rand32() {
  186. return rand32(ThreadLocalPRNG());
  187. }
  188. /**
  189. * Returns a random uint32_t given a specific RNG
  190. */
  191. template <class RNG, class /* EnableIf */ = ValidRNG<RNG>>
  192. static uint32_t rand32(RNG&& rng) {
  193. return rng();
  194. }
  195. /**
  196. * Returns a random uint32_t in [0, max). If max == 0, returns 0.
  197. */
  198. static uint32_t rand32(uint32_t max) {
  199. return rand32(0, max, ThreadLocalPRNG());
  200. }
  201. /**
  202. * Returns a random uint32_t in [0, max) given a specific RNG.
  203. * If max == 0, returns 0.
  204. */
  205. template <class RNG = ThreadLocalPRNG, class /* EnableIf */ = ValidRNG<RNG>>
  206. static uint32_t rand32(uint32_t max, RNG&& rng) {
  207. return rand32(0, max, rng);
  208. }
  209. /**
  210. * Returns a random uint32_t in [min, max). If min == max, returns 0.
  211. */
  212. static uint32_t rand32(uint32_t min, uint32_t max) {
  213. return rand32(min, max, ThreadLocalPRNG());
  214. }
  215. /**
  216. * Returns a random uint32_t in [min, max) given a specific RNG.
  217. * If min == max, returns 0.
  218. */
  219. template <class RNG = ThreadLocalPRNG, class /* EnableIf */ = ValidRNG<RNG>>
  220. static uint32_t rand32(uint32_t min, uint32_t max, RNG&& rng) {
  221. if (min == max) {
  222. return 0;
  223. }
  224. return std::uniform_int_distribution<uint32_t>(min, max - 1)(rng);
  225. }
  226. /**
  227. * Returns a random uint64_t
  228. */
  229. static uint64_t rand64() {
  230. return rand64(ThreadLocalPRNG());
  231. }
  232. /**
  233. * Returns a random uint64_t
  234. */
  235. template <class RNG = ThreadLocalPRNG, class /* EnableIf */ = ValidRNG<RNG>>
  236. static uint64_t rand64(RNG&& rng) {
  237. return ((uint64_t)rng() << 32) | rng();
  238. }
  239. /**
  240. * Returns a random uint64_t in [0, max). If max == 0, returns 0.
  241. */
  242. static uint64_t rand64(uint64_t max) {
  243. return rand64(0, max, ThreadLocalPRNG());
  244. }
  245. /**
  246. * Returns a random uint64_t in [0, max). If max == 0, returns 0.
  247. */
  248. template <class RNG = ThreadLocalPRNG, class /* EnableIf */ = ValidRNG<RNG>>
  249. static uint64_t rand64(uint64_t max, RNG&& rng) {
  250. return rand64(0, max, rng);
  251. }
  252. /**
  253. * Returns a random uint64_t in [min, max). If min == max, returns 0.
  254. */
  255. static uint64_t rand64(uint64_t min, uint64_t max) {
  256. return rand64(min, max, ThreadLocalPRNG());
  257. }
  258. /**
  259. * Returns a random uint64_t in [min, max). If min == max, returns 0.
  260. */
  261. template <class RNG = ThreadLocalPRNG, class /* EnableIf */ = ValidRNG<RNG>>
  262. static uint64_t rand64(uint64_t min, uint64_t max, RNG&& rng) {
  263. if (min == max) {
  264. return 0;
  265. }
  266. return std::uniform_int_distribution<uint64_t>(min, max - 1)(rng);
  267. }
  268. /**
  269. * Returns true 1/n of the time. If n == 0, always returns false
  270. */
  271. static bool oneIn(uint32_t n) {
  272. return oneIn(n, ThreadLocalPRNG());
  273. }
  274. /**
  275. * Returns true 1/n of the time. If n == 0, always returns false
  276. */
  277. template <class RNG = ThreadLocalPRNG, class /* EnableIf */ = ValidRNG<RNG>>
  278. static bool oneIn(uint32_t n, RNG&& rng) {
  279. if (n == 0) {
  280. return false;
  281. }
  282. return rand32(0, n, rng) == 0;
  283. }
  284. /**
  285. * Returns a double in [0, 1)
  286. */
  287. static double randDouble01() {
  288. return randDouble01(ThreadLocalPRNG());
  289. }
  290. /**
  291. * Returns a double in [0, 1)
  292. */
  293. template <class RNG = ThreadLocalPRNG, class /* EnableIf */ = ValidRNG<RNG>>
  294. static double randDouble01(RNG&& rng) {
  295. return std::generate_canonical<double, std::numeric_limits<double>::digits>(
  296. rng);
  297. }
  298. /**
  299. * Returns a double in [min, max), if min == max, returns 0.
  300. */
  301. static double randDouble(double min, double max) {
  302. return randDouble(min, max, ThreadLocalPRNG());
  303. }
  304. /**
  305. * Returns a double in [min, max), if min == max, returns 0.
  306. */
  307. template <class RNG = ThreadLocalPRNG, class /* EnableIf */ = ValidRNG<RNG>>
  308. static double randDouble(double min, double max, RNG&& rng) {
  309. if (std::fabs(max - min) < std::numeric_limits<double>::epsilon()) {
  310. return 0;
  311. }
  312. return std::uniform_real_distribution<double>(min, max)(rng);
  313. }
  314. };
  315. /*
  316. * Return a good seed for a random number generator.
  317. * Note that this is a legacy function, as it returns a 32-bit value, which
  318. * is too small to be useful as a "real" RNG seed. Use the functions in class
  319. * Random instead.
  320. */
  321. inline uint32_t randomNumberSeed() {
  322. return Random::rand32();
  323. }
  324. } // namespace folly
  325. #include <folly/Random-inl.h>