Adding support for signed integers
[folly.git] / folly / Random.cpp
index 24486452214d880b5470b41992cded1440ecb87b..e69a4452564e0fb32744cbf3e05d28b5dd37b089 100644 (file)
 #include <atomic>
 #include <unistd.h>
 #include <sys/time.h>
+#include <random>
+#include <array>
+
+#if __GNUC_PREREQ(4, 8)
+#include <ext/random>
+#define USE_SIMD_PRNG
+#endif
 
 namespace folly {
 
@@ -28,7 +35,7 @@ std::atomic<uint32_t> seedInput(0);
 
 uint32_t randomNumberSeed() {
   struct timeval tv;
-  gettimeofday(&tv, NULL);
+  gettimeofday(&tv, nullptr);
   const uint32_t kPrime0 = 51551;
   const uint32_t kPrime1 = 61631;
   const uint32_t kPrime2 = 64997;
@@ -39,4 +46,39 @@ uint32_t randomNumberSeed() {
        + kPrime3 * static_cast<uint32_t>(tv.tv_usec);
 }
 
+
+folly::ThreadLocalPtr<ThreadLocalPRNG::LocalInstancePRNG>
+ThreadLocalPRNG::localInstance;
+
+class ThreadLocalPRNG::LocalInstancePRNG {
+#ifdef USE_SIMD_PRNG
+  typedef  __gnu_cxx::sfmt19937 RNG;
+#else
+  typedef std::mt19937 RNG;
+#endif
+
+  static RNG makeRng() {
+    std::array<int, RNG::state_size> seed_data;
+    std::random_device r;
+    std::generate_n(seed_data.data(), seed_data.size(), std::ref(r));
+    std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
+    return RNG(seq);
+  }
+
+ public:
+  LocalInstancePRNG() : rng(std::move(makeRng())) {}
+
+  RNG rng;
+};
+
+ThreadLocalPRNG::LocalInstancePRNG* ThreadLocalPRNG::initLocal() {
+  auto ret = new LocalInstancePRNG;
+  localInstance.reset(ret);
+  return ret;
+}
+
+uint32_t ThreadLocalPRNG::getImpl(LocalInstancePRNG* local) {
+  return local->rng();
+}
+
 }