f2f3b4ba9397b462fa6267f71ddb66e1a0db6b23
[folly.git] / folly / Random-inl.h
1 /*
2  * Copyright 2017 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
17 #ifndef FOLLY_RANDOM_H_
18 #error This file may only be included from folly/Random.h
19 #endif
20
21 namespace folly {
22
23 namespace detail {
24
25 // Return the state size needed by RNG, expressed as a number of uint32_t
26 // integers. Specialized for all templates specified in the C++11 standard.
27 // For some (mersenne_twister_engine), this is exported as a state_size static
28 // data member; for others, the standard shows formulas.
29
30 template <class RNG, typename = void>
31 struct StateSize {
32   // A sane default.
33   using type = std::integral_constant<size_t, 512>;
34 };
35
36 template <class RNG>
37 struct StateSize<RNG, void_t<decltype(RNG::state_size)>> {
38   using type = std::integral_constant<size_t, RNG::state_size>;
39 };
40
41 template <class UIntType, UIntType a, UIntType c, UIntType m>
42 struct StateSize<std::linear_congruential_engine<UIntType, a, c, m>> {
43   // From the standard [rand.eng.lcong], this is ceil(log2(m) / 32) + 3,
44   // which is the same as ceil(ceil(log2(m) / 32) + 3, and
45   // ceil(log2(m)) <= std::numeric_limits<UIntType>::digits
46   using type = std::integral_constant<
47       size_t,
48       (std::numeric_limits<UIntType>::digits + 31) / 32 + 3>;
49 };
50
51 template <class UIntType, size_t w, size_t s, size_t r>
52 struct StateSize<std::subtract_with_carry_engine<UIntType, w, s, r>> {
53   // [rand.eng.sub]: r * ceil(w / 32)
54   using type = std::integral_constant<size_t, r*((w + 31) / 32)>;
55 };
56
57 template <typename RNG>
58 using StateSizeT = _t<StateSize<RNG>>;
59
60 template <class RNG>
61 struct SeedData {
62   SeedData() {
63     Random::secureRandom(seedData.data(), seedData.size() * sizeof(uint32_t));
64   }
65
66   static constexpr size_t stateSize = StateSizeT<RNG>::value;
67   std::array<uint32_t, stateSize> seedData;
68 };
69
70 }  // namespace detail
71
72 template <class RNG, class /* EnableIf */>
73 void Random::seed(RNG& rng) {
74   detail::SeedData<RNG> sd;
75   std::seed_seq s(std::begin(sd.seedData), std::end(sd.seedData));
76   rng.seed(s);
77 }
78
79 template <class RNG, class /* EnableIf */>
80 auto Random::create() -> RNG {
81   detail::SeedData<RNG> sd;
82   std::seed_seq s(std::begin(sd.seedData), std::end(sd.seedData));
83   return RNG(s);
84 }
85
86 }  // namespaces