/*
- * Copyright 2015 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* limitations under the License.
*/
-#ifndef FOLLY_RANDOM_H_
+#pragma once
#define FOLLY_RANDOM_H_
-#include <type_traits>
+#include <array>
+#include <cstdint>
#include <random>
-#include <stdint.h>
-#include <folly/ThreadLocal.h>
+#include <type_traits>
-#if __GNUC_PREREQ(4, 8) && !defined(ANDROID)
+#include <folly/Portability.h>
+#include <folly/Traits.h>
+
+#if FOLLY_HAVE_EXTRANDOM_SFMT19937
#include <ext/random>
-#define FOLLY_USE_SIMD_PRNG 1
#endif
namespace folly {
* However, if you are worried about performance, you can memoize the TLS
* lookups that get the per thread state by manually using this class:
*
- * ThreadLocalPRNG rng = Random::threadLocalPRNG()
+ * ThreadLocalPRNG rng;
* for (...) {
* Random::rand32(rng);
* }
ThreadLocalPRNG();
- private:
class LocalInstancePRNG;
+ private:
static result_type getImpl(LocalInstancePRNG* local);
LocalInstancePRNG* local_;
};
class Random {
private:
- template<class RNG>
+ template <class RNG>
using ValidRNG = typename std::enable_if<
- std::is_unsigned<typename std::result_of<RNG&()>::type>::value,
- RNG>::type;
+ std::is_unsigned<typename std::result_of<RNG&()>::type>::value,
+ RNG>::type;
public:
// Default generator type.
-#if FOLLY_USE_SIMD_PRNG
+#if FOLLY_HAVE_EXTRANDOM_SFMT19937
typedef __gnu_cxx::sfmt19937 DefaultGenerator;
#else
typedef std::mt19937 DefaultGenerator;
* to create a RNG with a good seed in production, and seed it yourself
* in test.
*/
- template <class RNG = DefaultGenerator>
- static void seed(ValidRNG<RNG>& rng);
+ template <class RNG = DefaultGenerator, class /* EnableIf */ = ValidRNG<RNG>>
+ static void seed(RNG& rng);
/**
* Create a new RNG, seeded with a good seed.
* to create a RNG with a good seed in production, and seed it yourself
* in test.
*/
- template <class RNG = DefaultGenerator>
- static ValidRNG<RNG> create();
+ template <class RNG = DefaultGenerator, class /* EnableIf */ = ValidRNG<RNG>>
+ static RNG create();
/**
* Returns a random uint32_t
*/
- template<class RNG = ThreadLocalPRNG>
- static uint32_t rand32(ValidRNG<RNG> rng = RNG()) {
- uint32_t r = rng.operator()();
- return r;
+ static uint32_t rand32() {
+ return rand32(ThreadLocalPRNG());
+ }
+
+ /**
+ * Returns a random uint32_t given a specific RNG
+ */
+ template <class RNG, class /* EnableIf */ = ValidRNG<RNG>>
+ static uint32_t rand32(RNG&& rng) {
+ return rng();
}
/**
* Returns a random uint32_t in [0, max). If max == 0, returns 0.
*/
- template<class RNG = ThreadLocalPRNG>
- static uint32_t rand32(uint32_t max, ValidRNG<RNG> rng = RNG()) {
- if (max == 0) {
- return 0;
- }
+ static uint32_t rand32(uint32_t max) {
+ return rand32(0, max, ThreadLocalPRNG());
+ }
- return std::uniform_int_distribution<uint32_t>(0, max - 1)(rng);
+ /**
+ * Returns a random uint32_t in [0, max) given a specific RNG.
+ * If max == 0, returns 0.
+ */
+ template <class RNG = ThreadLocalPRNG, class /* EnableIf */ = ValidRNG<RNG>>
+ static uint32_t rand32(uint32_t max, RNG&& rng) {
+ return rand32(0, max, rng);
}
/**
* Returns a random uint32_t in [min, max). If min == max, returns 0.
*/
- template<class RNG = ThreadLocalPRNG>
- static uint32_t rand32(uint32_t min,
- uint32_t max,
- ValidRNG<RNG> rng = RNG()) {
+ static uint32_t rand32(uint32_t min, uint32_t max) {
+ return rand32(min, max, ThreadLocalPRNG());
+ }
+
+ /**
+ * Returns a random uint32_t in [min, max) given a specific RNG.
+ * If min == max, returns 0.
+ */
+ template <class RNG = ThreadLocalPRNG, class /* EnableIf */ = ValidRNG<RNG>>
+ static uint32_t rand32(uint32_t min, uint32_t max, RNG&& rng) {
if (min == max) {
return 0;
}
-
return std::uniform_int_distribution<uint32_t>(min, max - 1)(rng);
}
/**
* Returns a random uint64_t
*/
- template<class RNG = ThreadLocalPRNG>
- static uint64_t rand64(ValidRNG<RNG> rng = RNG()) {
- return ((uint64_t) rng() << 32) | rng();
+ static uint64_t rand64() {
+ return rand64(ThreadLocalPRNG());
+ }
+
+ /**
+ * Returns a random uint64_t
+ */
+ template <class RNG = ThreadLocalPRNG, class /* EnableIf */ = ValidRNG<RNG>>
+ static uint64_t rand64(RNG&& rng) {
+ return ((uint64_t)rng() << 32) | rng();
}
/**
* Returns a random uint64_t in [0, max). If max == 0, returns 0.
*/
- template<class RNG = ThreadLocalPRNG>
- static uint64_t rand64(uint64_t max, ValidRNG<RNG> rng = RNG()) {
- if (max == 0) {
- return 0;
- }
+ static uint64_t rand64(uint64_t max) {
+ return rand64(0, max, ThreadLocalPRNG());
+ }
- return std::uniform_int_distribution<uint64_t>(0, max - 1)(rng);
+ /**
+ * Returns a random uint64_t in [0, max). If max == 0, returns 0.
+ */
+ template <class RNG = ThreadLocalPRNG, class /* EnableIf */ = ValidRNG<RNG>>
+ static uint64_t rand64(uint64_t max, RNG&& rng) {
+ return rand64(0, max, rng);
}
/**
* Returns a random uint64_t in [min, max). If min == max, returns 0.
*/
- template<class RNG = ThreadLocalPRNG>
- static uint64_t rand64(uint64_t min,
- uint64_t max,
- ValidRNG<RNG> rng = RNG()) {
+ static uint64_t rand64(uint64_t min, uint64_t max) {
+ return rand64(min, max, ThreadLocalPRNG());
+ }
+
+ /**
+ * Returns a random uint64_t in [min, max). If min == max, returns 0.
+ */
+ template <class RNG = ThreadLocalPRNG, class /* EnableIf */ = ValidRNG<RNG>>
+ static uint64_t rand64(uint64_t min, uint64_t max, RNG&& rng) {
if (min == max) {
return 0;
}
-
return std::uniform_int_distribution<uint64_t>(min, max - 1)(rng);
}
/**
* Returns true 1/n of the time. If n == 0, always returns false
*/
- template<class RNG = ThreadLocalPRNG>
- static bool oneIn(uint32_t n, ValidRNG<RNG> rng = RNG()) {
+ static bool oneIn(uint32_t n) {
+ return oneIn(n, ThreadLocalPRNG());
+ }
+
+ /**
+ * Returns true 1/n of the time. If n == 0, always returns false
+ */
+ template <class RNG = ThreadLocalPRNG, class /* EnableIf */ = ValidRNG<RNG>>
+ static bool oneIn(uint32_t n, RNG&& rng) {
if (n == 0) {
return false;
}
+ return rand32(0, n, rng) == 0;
+ }
- return rand32(n, rng) == 0;
+ /**
+ * Returns a double in [0, 1)
+ */
+ static double randDouble01() {
+ return randDouble01(ThreadLocalPRNG());
}
/**
* Returns a double in [0, 1)
*/
- template<class RNG = ThreadLocalPRNG>
- static double randDouble01(ValidRNG<RNG> rng = RNG()) {
- return std::generate_canonical<double, std::numeric_limits<double>::digits>
- (rng);
+ template <class RNG = ThreadLocalPRNG, class /* EnableIf */ = ValidRNG<RNG>>
+ static double randDouble01(RNG&& rng) {
+ return std::generate_canonical<double, std::numeric_limits<double>::digits>(
+ rng);
}
/**
* Returns a double in [min, max), if min == max, returns 0.
*/
- template<class RNG = ThreadLocalPRNG>
- static double randDouble(double min, double max, ValidRNG<RNG> rng = RNG()) {
+ static double randDouble(double min, double max) {
+ return randDouble(min, max, ThreadLocalPRNG());
+ }
+
+ /**
+ * Returns a double in [min, max), if min == max, returns 0.
+ */
+ template <class RNG = ThreadLocalPRNG, class /* EnableIf */ = ValidRNG<RNG>>
+ static double randDouble(double min, double max, RNG&& rng) {
if (std::fabs(max - min) < std::numeric_limits<double>::epsilon()) {
return 0;
}
}
#include <folly/Random-inl.h>
-
-#endif