blob: 730fa2ea12d208947fa212b91dc56f72a180e89e [file] [log] [blame]
Austin Schuh36244a12019-09-21 17:52:38 -07001// Copyright 2017 The Abseil Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#ifndef ABSL_RANDOM_INTERNAL_NONSECURE_BASE_H_
16#define ABSL_RANDOM_INTERNAL_NONSECURE_BASE_H_
17
18#include <algorithm>
19#include <cstdint>
20#include <iostream>
21#include <iterator>
22#include <random>
23#include <string>
24#include <type_traits>
25#include <vector>
26
27#include "absl/base/macros.h"
28#include "absl/meta/type_traits.h"
29#include "absl/random/internal/pool_urbg.h"
30#include "absl/random/internal/salted_seed_seq.h"
31#include "absl/random/internal/seed_material.h"
32#include "absl/types/optional.h"
33#include "absl/types/span.h"
34
35namespace absl {
Austin Schuhb4691e92020-12-31 12:37:18 -080036ABSL_NAMESPACE_BEGIN
Austin Schuh36244a12019-09-21 17:52:38 -070037namespace random_internal {
38
39// Each instance of NonsecureURBGBase<URBG> will be seeded by variates produced
40// by a thread-unique URBG-instance.
41template <typename URBG>
42class NonsecureURBGBase {
43 public:
44 using result_type = typename URBG::result_type;
45
46 // Default constructor
47 NonsecureURBGBase() : urbg_(ConstructURBG()) {}
48
49 // Copy disallowed, move allowed.
50 NonsecureURBGBase(const NonsecureURBGBase&) = delete;
51 NonsecureURBGBase& operator=(const NonsecureURBGBase&) = delete;
52 NonsecureURBGBase(NonsecureURBGBase&&) = default;
53 NonsecureURBGBase& operator=(NonsecureURBGBase&&) = default;
54
55 // Constructor using a seed
56 template <class SSeq, typename = typename absl::enable_if_t<
57 !std::is_same<SSeq, NonsecureURBGBase>::value>>
58 explicit NonsecureURBGBase(SSeq&& seq)
59 : urbg_(ConstructURBG(std::forward<SSeq>(seq))) {}
60
61 // Note: on MSVC, min() or max() can be interpreted as MIN() or MAX(), so we
62 // enclose min() or max() in parens as (min)() and (max)().
63 // Additionally, clang-format requires no space before this construction.
64
65 // NonsecureURBGBase::min()
66 static constexpr result_type(min)() { return (URBG::min)(); }
67
68 // NonsecureURBGBase::max()
69 static constexpr result_type(max)() { return (URBG::max)(); }
70
71 // NonsecureURBGBase::operator()()
72 result_type operator()() { return urbg_(); }
73
74 // NonsecureURBGBase::discard()
75 void discard(unsigned long long values) { // NOLINT(runtime/int)
76 urbg_.discard(values);
77 }
78
79 bool operator==(const NonsecureURBGBase& other) const {
80 return urbg_ == other.urbg_;
81 }
82
83 bool operator!=(const NonsecureURBGBase& other) const {
84 return !(urbg_ == other.urbg_);
85 }
86
87 private:
88 // Seeder is a custom seed sequence type where generate() fills the provided
89 // buffer via the RandenPool entropy source.
90 struct Seeder {
91 using result_type = uint32_t;
92
93 size_t size() { return 0; }
94
95 template <typename OutIterator>
96 void param(OutIterator) const {}
97
98 template <typename RandomAccessIterator>
99 void generate(RandomAccessIterator begin, RandomAccessIterator end) {
100 if (begin != end) {
101 // begin, end must be random access iterators assignable from uint32_t.
102 generate_impl(
103 std::integral_constant<bool, sizeof(*begin) == sizeof(uint32_t)>{},
104 begin, end);
105 }
106 }
107
108 // Commonly, generate is invoked with a pointer to a buffer which
109 // can be cast to a uint32_t.
110 template <typename RandomAccessIterator>
111 void generate_impl(std::integral_constant<bool, true>,
112 RandomAccessIterator begin, RandomAccessIterator end) {
113 auto buffer = absl::MakeSpan(begin, end);
114 auto target = absl::MakeSpan(reinterpret_cast<uint32_t*>(buffer.data()),
115 buffer.size());
116 RandenPool<uint32_t>::Fill(target);
117 }
118
119 // The non-uint32_t case should be uncommon, and involves an extra copy,
120 // filling the uint32_t buffer and then mixing into the output.
121 template <typename RandomAccessIterator>
122 void generate_impl(std::integral_constant<bool, false>,
123 RandomAccessIterator begin, RandomAccessIterator end) {
124 const size_t n = std::distance(begin, end);
125 absl::InlinedVector<uint32_t, 8> data(n, 0);
126 RandenPool<uint32_t>::Fill(absl::MakeSpan(data.begin(), data.end()));
127 std::copy(std::begin(data), std::end(data), begin);
128 }
129 };
130
131 static URBG ConstructURBG() {
132 Seeder seeder;
133 return URBG(seeder);
134 }
135
136 template <typename SSeq>
137 static URBG ConstructURBG(SSeq&& seq) { // NOLINT(runtime/references)
138 auto salted_seq =
139 random_internal::MakeSaltedSeedSeq(std::forward<SSeq>(seq));
140 return URBG(salted_seq);
141 }
142
143 URBG urbg_;
144};
145
146} // namespace random_internal
Austin Schuhb4691e92020-12-31 12:37:18 -0800147ABSL_NAMESPACE_END
Austin Schuh36244a12019-09-21 17:52:38 -0700148} // namespace absl
149
150#endif // ABSL_RANDOM_INTERNAL_NONSECURE_BASE_H_