File indexing completed on 2025-12-17 09:37:10
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef ABSL_RANDOM_INTERNAL_PCG_ENGINE_H_
0016 #define ABSL_RANDOM_INTERNAL_PCG_ENGINE_H_
0017
0018 #include <type_traits>
0019
0020 #include "absl/base/config.h"
0021 #include "absl/meta/type_traits.h"
0022 #include "absl/numeric/bits.h"
0023 #include "absl/numeric/int128.h"
0024 #include "absl/random/internal/fastmath.h"
0025 #include "absl/random/internal/iostream_state_saver.h"
0026
0027 namespace absl {
0028 ABSL_NAMESPACE_BEGIN
0029 namespace random_internal {
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040 template <typename Params, typename Mix>
0041 class pcg_engine {
0042 static_assert(std::is_same<typename Params::state_type,
0043 typename Mix::state_type>::value,
0044 "Class-template absl::pcg_engine must be parameterized by "
0045 "Params and Mix with identical state_type");
0046
0047 static_assert(std::is_unsigned<typename Mix::result_type>::value,
0048 "Class-template absl::pcg_engine must be parameterized by "
0049 "an unsigned Mix::result_type");
0050
0051 using params_type = Params;
0052 using mix_type = Mix;
0053 using state_type = typename Mix::state_type;
0054
0055 public:
0056
0057 using result_type = typename Mix::result_type;
0058
0059 static constexpr result_type(min)() {
0060 return (std::numeric_limits<result_type>::min)();
0061 }
0062
0063 static constexpr result_type(max)() {
0064 return (std::numeric_limits<result_type>::max)();
0065 }
0066
0067 explicit pcg_engine(uint64_t seed_value = 0) { seed(seed_value); }
0068
0069 template <class SeedSequence,
0070 typename = typename absl::enable_if_t<
0071 !std::is_same<SeedSequence, pcg_engine>::value>>
0072 explicit pcg_engine(SeedSequence&& seq) {
0073 seed(seq);
0074 }
0075
0076 pcg_engine(const pcg_engine&) = default;
0077 pcg_engine& operator=(const pcg_engine&) = default;
0078 pcg_engine(pcg_engine&&) = default;
0079 pcg_engine& operator=(pcg_engine&&) = default;
0080
0081 result_type operator()() {
0082
0083 state_ = lcg(state_);
0084 return Mix{}(state_);
0085 }
0086
0087 void seed(uint64_t seed_value = 0) {
0088 state_type tmp = seed_value;
0089 state_ = lcg(tmp + Params::increment());
0090 }
0091
0092 template <class SeedSequence>
0093 typename absl::enable_if_t<
0094 !std::is_convertible<SeedSequence, uint64_t>::value, void>
0095 seed(SeedSequence&& seq) {
0096 reseed(seq);
0097 }
0098
0099 void discard(uint64_t count) { state_ = advance(state_, count); }
0100
0101 bool operator==(const pcg_engine& other) const {
0102 return state_ == other.state_;
0103 }
0104
0105 bool operator!=(const pcg_engine& other) const { return !(*this == other); }
0106
0107 template <class CharT, class Traits>
0108 friend typename absl::enable_if_t<(sizeof(state_type) == 16),
0109 std::basic_ostream<CharT, Traits>&>
0110 operator<<(
0111 std::basic_ostream<CharT, Traits>& os,
0112 const pcg_engine& engine) {
0113 auto saver = random_internal::make_ostream_state_saver(os);
0114 random_internal::stream_u128_helper<state_type> helper;
0115 helper.write(pcg_engine::params_type::multiplier(), os);
0116 os << os.fill();
0117 helper.write(pcg_engine::params_type::increment(), os);
0118 os << os.fill();
0119 helper.write(engine.state_, os);
0120 return os;
0121 }
0122
0123 template <class CharT, class Traits>
0124 friend typename absl::enable_if_t<(sizeof(state_type) <= 8),
0125 std::basic_ostream<CharT, Traits>&>
0126 operator<<(
0127 std::basic_ostream<CharT, Traits>& os,
0128 const pcg_engine& engine) {
0129 auto saver = random_internal::make_ostream_state_saver(os);
0130 os << pcg_engine::params_type::multiplier() << os.fill();
0131 os << pcg_engine::params_type::increment() << os.fill();
0132 os << engine.state_;
0133 return os;
0134 }
0135
0136 template <class CharT, class Traits>
0137 friend typename absl::enable_if_t<(sizeof(state_type) == 16),
0138 std::basic_istream<CharT, Traits>&>
0139 operator>>(
0140 std::basic_istream<CharT, Traits>& is,
0141 pcg_engine& engine) {
0142 random_internal::stream_u128_helper<state_type> helper;
0143 auto mult = helper.read(is);
0144 auto inc = helper.read(is);
0145 auto tmp = helper.read(is);
0146 if (mult != pcg_engine::params_type::multiplier() ||
0147 inc != pcg_engine::params_type::increment()) {
0148
0149 is.setstate(is.rdstate() | std::ios_base::failbit);
0150 }
0151 if (!is.fail()) {
0152 engine.state_ = tmp;
0153 }
0154 return is;
0155 }
0156
0157 template <class CharT, class Traits>
0158 friend typename absl::enable_if_t<(sizeof(state_type) <= 8),
0159 std::basic_istream<CharT, Traits>&>
0160 operator>>(
0161 std::basic_istream<CharT, Traits>& is,
0162 pcg_engine& engine) {
0163 state_type mult{}, inc{}, tmp{};
0164 is >> mult >> inc >> tmp;
0165 if (mult != pcg_engine::params_type::multiplier() ||
0166 inc != pcg_engine::params_type::increment()) {
0167
0168 is.setstate(is.rdstate() | std::ios_base::failbit);
0169 }
0170 if (!is.fail()) {
0171 engine.state_ = tmp;
0172 }
0173 return is;
0174 }
0175
0176 private:
0177 state_type state_;
0178
0179
0180 static inline constexpr state_type lcg(state_type s) {
0181 return s * Params::multiplier() + Params::increment();
0182 }
0183
0184
0185 inline state_type advance(state_type s, uint64_t n) const {
0186 state_type mult = Params::multiplier();
0187 state_type inc = Params::increment();
0188 state_type m = 1;
0189 state_type i = 0;
0190 while (n > 0) {
0191 if (n & 1) {
0192 m *= mult;
0193 i = i * mult + inc;
0194 }
0195 inc = (mult + 1) * inc;
0196 mult *= mult;
0197 n >>= 1;
0198 }
0199 return m * s + i;
0200 }
0201
0202 template <class SeedSequence>
0203 void reseed(SeedSequence& seq) {
0204 using sequence_result_type = typename SeedSequence::result_type;
0205 constexpr size_t kBufferSize =
0206 sizeof(state_type) / sizeof(sequence_result_type);
0207 sequence_result_type buffer[kBufferSize];
0208 seq.generate(std::begin(buffer), std::end(buffer));
0209
0210 state_type tmp = buffer[0];
0211 for (size_t i = 1; i < kBufferSize; i++) {
0212 tmp <<= (sizeof(sequence_result_type) * 8);
0213 tmp |= buffer[i];
0214 }
0215 state_ = lcg(tmp + params_type::increment());
0216 }
0217 };
0218
0219
0220
0221 template <uint64_t kMultA, uint64_t kMultB, uint64_t kIncA, uint64_t kIncB>
0222 class pcg128_params {
0223 public:
0224 using state_type = absl::uint128;
0225 static inline constexpr state_type multiplier() {
0226 return absl::MakeUint128(kMultA, kMultB);
0227 }
0228 static inline constexpr state_type increment() {
0229 return absl::MakeUint128(kIncA, kIncB);
0230 }
0231 };
0232
0233
0234
0235 struct pcg_xsl_rr_128_64 {
0236 using state_type = absl::uint128;
0237 using result_type = uint64_t;
0238
0239 inline uint64_t operator()(state_type state) {
0240
0241 uint64_t rotate = static_cast<uint64_t>(state >> 122u);
0242 state ^= state >> 64;
0243 uint64_t s = static_cast<uint64_t>(state);
0244 return rotr(s, static_cast<int>(rotate));
0245 }
0246 };
0247
0248
0249
0250 template <uint64_t kMult, uint64_t kInc>
0251 class pcg64_params {
0252 public:
0253 using state_type = uint64_t;
0254 static inline constexpr state_type multiplier() { return kMult; }
0255 static inline constexpr state_type increment() { return kInc; }
0256 };
0257
0258
0259
0260 struct pcg_xsh_rr_64_32 {
0261 using state_type = uint64_t;
0262 using result_type = uint32_t;
0263 inline uint32_t operator()(uint64_t state) {
0264 return rotr(static_cast<uint32_t>(((state >> 18) ^ state) >> 27),
0265 state >> 59);
0266 }
0267 };
0268
0269
0270
0271
0272 using pcg64_2018_engine = pcg_engine<
0273 random_internal::pcg128_params<0x2360ed051fc65da4ull, 0x4385df649fccf645ull,
0274 0x5851f42d4c957f2d, 0x14057b7ef767814f>,
0275 random_internal::pcg_xsl_rr_128_64>;
0276
0277
0278
0279 using pcg32_2018_engine = pcg_engine<
0280 random_internal::pcg64_params<0x5851f42d4c957f2dull, 0x14057b7ef767814full>,
0281 random_internal::pcg_xsh_rr_64_32>;
0282
0283 }
0284 ABSL_NAMESPACE_END
0285 }
0286
0287 #endif