diff options
author | anastasy888 <anastasy888@yandex-team.ru> | 2022-02-10 16:45:55 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:55 +0300 |
commit | 3a7a498715ef1b66f5054455421b845e45e3a653 (patch) | |
tree | 1a2c5ffcf89eb53ecd79dbc9bc0a195c27404d0c /contrib/restricted/abseil-cpp/absl/random | |
parent | 49f765d71da452ea93138a25559dfa68dd76c7f3 (diff) | |
download | ydb-3a7a498715ef1b66f5054455421b845e45e3a653.tar.gz |
Restoring authorship annotation for <anastasy888@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/restricted/abseil-cpp/absl/random')
61 files changed, 8833 insertions, 8833 deletions
diff --git a/contrib/restricted/abseil-cpp/absl/random/absl_random_distributions/ya.make b/contrib/restricted/abseil-cpp/absl/random/absl_random_distributions/ya.make index 37bdf88c98..73d9caa424 100644 --- a/contrib/restricted/abseil-cpp/absl/random/absl_random_distributions/ya.make +++ b/contrib/restricted/abseil-cpp/absl/random/absl_random_distributions/ya.make @@ -1,41 +1,41 @@ -# Generated by devtools/yamaker. - -LIBRARY() - +# Generated by devtools/yamaker. + +LIBRARY() + WITHOUT_LICENSE_TEXTS() -OWNER(g:cpp-contrib) - -LICENSE(Apache-2.0) - -PEERDIR( - contrib/restricted/abseil-cpp/absl/base - contrib/restricted/abseil-cpp/absl/base/internal/raw_logging - contrib/restricted/abseil-cpp/absl/base/internal/spinlock_wait - contrib/restricted/abseil-cpp/absl/base/internal/throw_delegate - contrib/restricted/abseil-cpp/absl/base/log_severity - contrib/restricted/abseil-cpp/absl/numeric +OWNER(g:cpp-contrib) + +LICENSE(Apache-2.0) + +PEERDIR( + contrib/restricted/abseil-cpp/absl/base + contrib/restricted/abseil-cpp/absl/base/internal/raw_logging + contrib/restricted/abseil-cpp/absl/base/internal/spinlock_wait + contrib/restricted/abseil-cpp/absl/base/internal/throw_delegate + contrib/restricted/abseil-cpp/absl/base/log_severity + contrib/restricted/abseil-cpp/absl/numeric contrib/restricted/abseil-cpp/absl/strings contrib/restricted/abseil-cpp/absl/strings/internal/absl_strings_internal -) - -ADDINCL( - GLOBAL contrib/restricted/abseil-cpp -) - -NO_COMPILER_WARNINGS() - -NO_UTIL() - +) + +ADDINCL( + GLOBAL contrib/restricted/abseil-cpp +) + +NO_COMPILER_WARNINGS() + +NO_UTIL() + CFLAGS( -DNOMINMAX ) SRCDIR(contrib/restricted/abseil-cpp/absl/random) -SRCS( +SRCS( discrete_distribution.cc gaussian_distribution.cc -) - -END() +) + +END() diff --git a/contrib/restricted/abseil-cpp/absl/random/bernoulli_distribution.h b/contrib/restricted/abseil-cpp/absl/random/bernoulli_distribution.h index 6c4d28dbb9..25bd0d5ca4 100644 --- a/contrib/restricted/abseil-cpp/absl/random/bernoulli_distribution.h +++ b/contrib/restricted/abseil-cpp/absl/random/bernoulli_distribution.h @@ -1,200 +1,200 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_BERNOULLI_DISTRIBUTION_H_ -#define ABSL_RANDOM_BERNOULLI_DISTRIBUTION_H_ - -#include <cstdint> -#include <istream> -#include <limits> - -#include "absl/base/optimization.h" -#include "absl/random/internal/fast_uniform_bits.h" -#include "absl/random/internal/iostream_state_saver.h" - -namespace absl { +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_BERNOULLI_DISTRIBUTION_H_ +#define ABSL_RANDOM_BERNOULLI_DISTRIBUTION_H_ + +#include <cstdint> +#include <istream> +#include <limits> + +#include "absl/base/optimization.h" +#include "absl/random/internal/fast_uniform_bits.h" +#include "absl/random/internal/iostream_state_saver.h" + +namespace absl { ABSL_NAMESPACE_BEGIN - -// absl::bernoulli_distribution is a drop in replacement for -// std::bernoulli_distribution. It guarantees that (given a perfect -// UniformRandomBitGenerator) the acceptance probability is *exactly* equal to -// the given double. -// -// The implementation assumes that double is IEEE754 -class bernoulli_distribution { - public: - using result_type = bool; - - class param_type { - public: - using distribution_type = bernoulli_distribution; - - explicit param_type(double p = 0.5) : prob_(p) { - assert(p >= 0.0 && p <= 1.0); - } - - double p() const { return prob_; } - - friend bool operator==(const param_type& p1, const param_type& p2) { - return p1.p() == p2.p(); - } - friend bool operator!=(const param_type& p1, const param_type& p2) { - return p1.p() != p2.p(); - } - - private: - double prob_; - }; - - bernoulli_distribution() : bernoulli_distribution(0.5) {} - - explicit bernoulli_distribution(double p) : param_(p) {} - - explicit bernoulli_distribution(param_type p) : param_(p) {} - - // no-op - void reset() {} - - template <typename URBG> - bool operator()(URBG& g) { // NOLINT(runtime/references) - return Generate(param_.p(), g); - } - - template <typename URBG> - bool operator()(URBG& g, // NOLINT(runtime/references) - const param_type& param) { - return Generate(param.p(), g); - } - - param_type param() const { return param_; } - void param(const param_type& param) { param_ = param; } - - double p() const { return param_.p(); } - - result_type(min)() const { return false; } - result_type(max)() const { return true; } - - friend bool operator==(const bernoulli_distribution& d1, - const bernoulli_distribution& d2) { - return d1.param_ == d2.param_; - } - - friend bool operator!=(const bernoulli_distribution& d1, - const bernoulli_distribution& d2) { - return d1.param_ != d2.param_; - } - - private: - static constexpr uint64_t kP32 = static_cast<uint64_t>(1) << 32; - - template <typename URBG> - static bool Generate(double p, URBG& g); // NOLINT(runtime/references) - - param_type param_; -}; - -template <typename CharT, typename Traits> -std::basic_ostream<CharT, Traits>& operator<<( - std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) - const bernoulli_distribution& x) { - auto saver = random_internal::make_ostream_state_saver(os); - os.precision(random_internal::stream_precision_helper<double>::kPrecision); - os << x.p(); - return os; -} - -template <typename CharT, typename Traits> -std::basic_istream<CharT, Traits>& operator>>( - std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) - bernoulli_distribution& x) { // NOLINT(runtime/references) - auto saver = random_internal::make_istream_state_saver(is); - auto p = random_internal::read_floating_point<double>(is); - if (!is.fail()) { - x.param(bernoulli_distribution::param_type(p)); - } - return is; -} - -template <typename URBG> -bool bernoulli_distribution::Generate(double p, - URBG& g) { // NOLINT(runtime/references) - random_internal::FastUniformBits<uint32_t> fast_u32; - - while (true) { - // There are two aspects of the definition of `c` below that are worth - // commenting on. First, because `p` is in the range [0, 1], `c` is in the - // range [0, 2^32] which does not fit in a uint32_t and therefore requires - // 64 bits. - // - // Second, `c` is constructed by first casting explicitly to a signed - // integer and then converting implicitly to an unsigned integer of the same - // size. This is done because the hardware conversion instructions produce - // signed integers from double; if taken as a uint64_t the conversion would - // be wrong for doubles greater than 2^63 (not relevant in this use-case). - // If converted directly to an unsigned integer, the compiler would end up - // emitting code to handle such large values that are not relevant due to - // the known bounds on `c`. To avoid these extra instructions this - // implementation converts first to the signed type and then use the - // implicit conversion to unsigned (which is a no-op). - const uint64_t c = static_cast<int64_t>(p * kP32); - const uint32_t v = fast_u32(g); - // FAST PATH: this path fails with probability 1/2^32. Note that simply - // returning v <= c would approximate P very well (up to an absolute error - // of 1/2^32); the slow path (taken in that range of possible error, in the - // case of equality) eliminates the remaining error. - if (ABSL_PREDICT_TRUE(v != c)) return v < c; - - // It is guaranteed that `q` is strictly less than 1, because if `q` were - // greater than or equal to 1, the same would be true for `p`. Certainly `p` - // cannot be greater than 1, and if `p == 1`, then the fast path would - // necessary have been taken already. - const double q = static_cast<double>(c) / kP32; - - // The probability of acceptance on the fast path is `q` and so the - // probability of acceptance here should be `p - q`. - // - // Note that `q` is obtained from `p` via some shifts and conversions, the - // upshot of which is that `q` is simply `p` with some of the - // least-significant bits of its mantissa set to zero. This means that the - // difference `p - q` will not have any rounding errors. To see why, pretend - // that double has 10 bits of resolution and q is obtained from `p` in such - // a way that the 4 least-significant bits of its mantissa are set to zero. - // For example: - // p = 1.1100111011 * 2^-1 - // q = 1.1100110000 * 2^-1 - // p - q = 1.011 * 2^-8 - // The difference `p - q` has exactly the nonzero mantissa bits that were - // "lost" in `q` producing a number which is certainly representable in a - // double. - const double left = p - q; - - // By construction, the probability of being on this slow path is 1/2^32, so - // P(accept in slow path) = P(accept| in slow path) * P(slow path), - // which means the probability of acceptance here is `1 / (left * kP32)`: - const double here = left * kP32; - - // The simplest way to compute the result of this trial is to repeat the - // whole algorithm with the new probability. This terminates because even - // given arbitrarily unfriendly "random" bits, each iteration either - // multiplies a tiny probability by 2^32 (if c == 0) or strips off some - // number of nonzero mantissa bits. That process is bounded. - if (here == 0) return false; - p = here; - } -} - + +// absl::bernoulli_distribution is a drop in replacement for +// std::bernoulli_distribution. It guarantees that (given a perfect +// UniformRandomBitGenerator) the acceptance probability is *exactly* equal to +// the given double. +// +// The implementation assumes that double is IEEE754 +class bernoulli_distribution { + public: + using result_type = bool; + + class param_type { + public: + using distribution_type = bernoulli_distribution; + + explicit param_type(double p = 0.5) : prob_(p) { + assert(p >= 0.0 && p <= 1.0); + } + + double p() const { return prob_; } + + friend bool operator==(const param_type& p1, const param_type& p2) { + return p1.p() == p2.p(); + } + friend bool operator!=(const param_type& p1, const param_type& p2) { + return p1.p() != p2.p(); + } + + private: + double prob_; + }; + + bernoulli_distribution() : bernoulli_distribution(0.5) {} + + explicit bernoulli_distribution(double p) : param_(p) {} + + explicit bernoulli_distribution(param_type p) : param_(p) {} + + // no-op + void reset() {} + + template <typename URBG> + bool operator()(URBG& g) { // NOLINT(runtime/references) + return Generate(param_.p(), g); + } + + template <typename URBG> + bool operator()(URBG& g, // NOLINT(runtime/references) + const param_type& param) { + return Generate(param.p(), g); + } + + param_type param() const { return param_; } + void param(const param_type& param) { param_ = param; } + + double p() const { return param_.p(); } + + result_type(min)() const { return false; } + result_type(max)() const { return true; } + + friend bool operator==(const bernoulli_distribution& d1, + const bernoulli_distribution& d2) { + return d1.param_ == d2.param_; + } + + friend bool operator!=(const bernoulli_distribution& d1, + const bernoulli_distribution& d2) { + return d1.param_ != d2.param_; + } + + private: + static constexpr uint64_t kP32 = static_cast<uint64_t>(1) << 32; + + template <typename URBG> + static bool Generate(double p, URBG& g); // NOLINT(runtime/references) + + param_type param_; +}; + +template <typename CharT, typename Traits> +std::basic_ostream<CharT, Traits>& operator<<( + std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) + const bernoulli_distribution& x) { + auto saver = random_internal::make_ostream_state_saver(os); + os.precision(random_internal::stream_precision_helper<double>::kPrecision); + os << x.p(); + return os; +} + +template <typename CharT, typename Traits> +std::basic_istream<CharT, Traits>& operator>>( + std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) + bernoulli_distribution& x) { // NOLINT(runtime/references) + auto saver = random_internal::make_istream_state_saver(is); + auto p = random_internal::read_floating_point<double>(is); + if (!is.fail()) { + x.param(bernoulli_distribution::param_type(p)); + } + return is; +} + +template <typename URBG> +bool bernoulli_distribution::Generate(double p, + URBG& g) { // NOLINT(runtime/references) + random_internal::FastUniformBits<uint32_t> fast_u32; + + while (true) { + // There are two aspects of the definition of `c` below that are worth + // commenting on. First, because `p` is in the range [0, 1], `c` is in the + // range [0, 2^32] which does not fit in a uint32_t and therefore requires + // 64 bits. + // + // Second, `c` is constructed by first casting explicitly to a signed + // integer and then converting implicitly to an unsigned integer of the same + // size. This is done because the hardware conversion instructions produce + // signed integers from double; if taken as a uint64_t the conversion would + // be wrong for doubles greater than 2^63 (not relevant in this use-case). + // If converted directly to an unsigned integer, the compiler would end up + // emitting code to handle such large values that are not relevant due to + // the known bounds on `c`. To avoid these extra instructions this + // implementation converts first to the signed type and then use the + // implicit conversion to unsigned (which is a no-op). + const uint64_t c = static_cast<int64_t>(p * kP32); + const uint32_t v = fast_u32(g); + // FAST PATH: this path fails with probability 1/2^32. Note that simply + // returning v <= c would approximate P very well (up to an absolute error + // of 1/2^32); the slow path (taken in that range of possible error, in the + // case of equality) eliminates the remaining error. + if (ABSL_PREDICT_TRUE(v != c)) return v < c; + + // It is guaranteed that `q` is strictly less than 1, because if `q` were + // greater than or equal to 1, the same would be true for `p`. Certainly `p` + // cannot be greater than 1, and if `p == 1`, then the fast path would + // necessary have been taken already. + const double q = static_cast<double>(c) / kP32; + + // The probability of acceptance on the fast path is `q` and so the + // probability of acceptance here should be `p - q`. + // + // Note that `q` is obtained from `p` via some shifts and conversions, the + // upshot of which is that `q` is simply `p` with some of the + // least-significant bits of its mantissa set to zero. This means that the + // difference `p - q` will not have any rounding errors. To see why, pretend + // that double has 10 bits of resolution and q is obtained from `p` in such + // a way that the 4 least-significant bits of its mantissa are set to zero. + // For example: + // p = 1.1100111011 * 2^-1 + // q = 1.1100110000 * 2^-1 + // p - q = 1.011 * 2^-8 + // The difference `p - q` has exactly the nonzero mantissa bits that were + // "lost" in `q` producing a number which is certainly representable in a + // double. + const double left = p - q; + + // By construction, the probability of being on this slow path is 1/2^32, so + // P(accept in slow path) = P(accept| in slow path) * P(slow path), + // which means the probability of acceptance here is `1 / (left * kP32)`: + const double here = left * kP32; + + // The simplest way to compute the result of this trial is to repeat the + // whole algorithm with the new probability. This terminates because even + // given arbitrarily unfriendly "random" bits, each iteration either + // multiplies a tiny probability by 2^32 (if c == 0) or strips off some + // number of nonzero mantissa bits. That process is bounded. + if (here == 0) return false; + p = here; + } +} + ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_BERNOULLI_DISTRIBUTION_H_ +} // namespace absl + +#endif // ABSL_RANDOM_BERNOULLI_DISTRIBUTION_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/beta_distribution.h b/contrib/restricted/abseil-cpp/absl/random/beta_distribution.h index 1d302f8b98..c154066fb8 100644 --- a/contrib/restricted/abseil-cpp/absl/random/beta_distribution.h +++ b/contrib/restricted/abseil-cpp/absl/random/beta_distribution.h @@ -1,427 +1,427 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_BETA_DISTRIBUTION_H_ -#define ABSL_RANDOM_BETA_DISTRIBUTION_H_ - -#include <cassert> -#include <cmath> -#include <istream> -#include <limits> -#include <ostream> -#include <type_traits> - -#include "absl/meta/type_traits.h" -#include "absl/random/internal/fast_uniform_bits.h" -#include "absl/random/internal/fastmath.h" -#include "absl/random/internal/generate_real.h" -#include "absl/random/internal/iostream_state_saver.h" - -namespace absl { +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_BETA_DISTRIBUTION_H_ +#define ABSL_RANDOM_BETA_DISTRIBUTION_H_ + +#include <cassert> +#include <cmath> +#include <istream> +#include <limits> +#include <ostream> +#include <type_traits> + +#include "absl/meta/type_traits.h" +#include "absl/random/internal/fast_uniform_bits.h" +#include "absl/random/internal/fastmath.h" +#include "absl/random/internal/generate_real.h" +#include "absl/random/internal/iostream_state_saver.h" + +namespace absl { ABSL_NAMESPACE_BEGIN - -// absl::beta_distribution: -// Generate a floating-point variate conforming to a Beta distribution: -// pdf(x) \propto x^(alpha-1) * (1-x)^(beta-1), -// where the params alpha and beta are both strictly positive real values. -// -// The support is the open interval (0, 1), but the return value might be equal -// to 0 or 1, due to numerical errors when alpha and beta are very different. -// -// Usage note: One usage is that alpha and beta are counts of number of -// successes and failures. When the total number of trials are large, consider -// approximating a beta distribution with a Gaussian distribution with the same -// mean and variance. One could use the skewness, which depends only on the -// smaller of alpha and beta when the number of trials are sufficiently large, -// to quantify how far a beta distribution is from the normal distribution. -template <typename RealType = double> -class beta_distribution { - public: - using result_type = RealType; - - class param_type { - public: - using distribution_type = beta_distribution; - - explicit param_type(result_type alpha, result_type beta) - : alpha_(alpha), beta_(beta) { - assert(alpha >= 0); - assert(beta >= 0); - assert(alpha <= (std::numeric_limits<result_type>::max)()); - assert(beta <= (std::numeric_limits<result_type>::max)()); - if (alpha == 0 || beta == 0) { - method_ = DEGENERATE_SMALL; - x_ = (alpha >= beta) ? 1 : 0; - return; - } - // a_ = min(beta, alpha), b_ = max(beta, alpha). - if (beta < alpha) { - inverted_ = true; - a_ = beta; - b_ = alpha; - } else { - inverted_ = false; - a_ = alpha; - b_ = beta; - } - if (a_ <= 1 && b_ >= ThresholdForLargeA()) { - method_ = DEGENERATE_SMALL; - x_ = inverted_ ? result_type(1) : result_type(0); - return; - } - // For threshold values, see also: - // Evaluation of Beta Generation Algorithms, Ying-Chao Hung, et. al. - // February, 2009. - if ((b_ < 1.0 && a_ + b_ <= 1.2) || a_ <= ThresholdForSmallA()) { - // Choose Joehnk over Cheng when it's faster or when Cheng encounters - // numerical issues. - method_ = JOEHNK; - a_ = result_type(1) / alpha_; - b_ = result_type(1) / beta_; - if (std::isinf(a_) || std::isinf(b_)) { - method_ = DEGENERATE_SMALL; - x_ = inverted_ ? result_type(1) : result_type(0); - } - return; - } - if (a_ >= ThresholdForLargeA()) { - method_ = DEGENERATE_LARGE; - // Note: on PPC for long double, evaluating - // `std::numeric_limits::max() / ThresholdForLargeA` results in NaN. - result_type r = a_ / b_; - x_ = (inverted_ ? result_type(1) : r) / (1 + r); - return; - } - x_ = a_ + b_; - log_x_ = std::log(x_); - if (a_ <= 1) { - method_ = CHENG_BA; - y_ = result_type(1) / a_; - gamma_ = a_ + a_; - return; - } - method_ = CHENG_BB; - result_type r = (a_ - 1) / (b_ - 1); - y_ = std::sqrt((1 + r) / (b_ * r * 2 - r + 1)); - gamma_ = a_ + result_type(1) / y_; - } - - result_type alpha() const { return alpha_; } - result_type beta() const { return beta_; } - - friend bool operator==(const param_type& a, const param_type& b) { - return a.alpha_ == b.alpha_ && a.beta_ == b.beta_; - } - - friend bool operator!=(const param_type& a, const param_type& b) { - return !(a == b); - } - - private: - friend class beta_distribution; - -#ifdef _MSC_VER - // MSVC does not have constexpr implementations for std::log and std::exp - // so they are computed at runtime. -#define ABSL_RANDOM_INTERNAL_LOG_EXP_CONSTEXPR -#else -#define ABSL_RANDOM_INTERNAL_LOG_EXP_CONSTEXPR constexpr -#endif - - // The threshold for whether std::exp(1/a) is finite. - // Note that this value is quite large, and a smaller a_ is NOT abnormal. - static ABSL_RANDOM_INTERNAL_LOG_EXP_CONSTEXPR result_type - ThresholdForSmallA() { - return result_type(1) / - std::log((std::numeric_limits<result_type>::max)()); - } - - // The threshold for whether a * std::log(a) is finite. - static ABSL_RANDOM_INTERNAL_LOG_EXP_CONSTEXPR result_type - ThresholdForLargeA() { - return std::exp( - std::log((std::numeric_limits<result_type>::max)()) - - std::log(std::log((std::numeric_limits<result_type>::max)())) - - ThresholdPadding()); - } - -#undef ABSL_RANDOM_INTERNAL_LOG_EXP_CONSTEXPR - - // Pad the threshold for large A for long double on PPC. This is done via a - // template specialization below. - static constexpr result_type ThresholdPadding() { return 0; } - - enum Method { - JOEHNK, // Uses algorithm Joehnk - CHENG_BA, // Uses algorithm BA in Cheng - CHENG_BB, // Uses algorithm BB in Cheng - - // Note: See also: - // Hung et al. Evaluation of beta generation algorithms. Communications - // in Statistics-Simulation and Computation 38.4 (2009): 750-770. - // especially: - // Zechner, Heinz, and Ernst Stadlober. Generating beta variates via - // patchwork rejection. Computing 50.1 (1993): 1-18. - - DEGENERATE_SMALL, // a_ is abnormally small. - DEGENERATE_LARGE, // a_ is abnormally large. - }; - - result_type alpha_; - result_type beta_; - - result_type a_; // the smaller of {alpha, beta}, or 1.0/alpha_ in JOEHNK - result_type b_; // the larger of {alpha, beta}, or 1.0/beta_ in JOEHNK - result_type x_; // alpha + beta, or the result in degenerate cases - result_type log_x_; // log(x_) - result_type y_; // "beta" in Cheng - result_type gamma_; // "gamma" in Cheng - - Method method_; - - // Placing this last for optimal alignment. - // Whether alpha_ != a_, i.e. true iff alpha_ > beta_. - bool inverted_; - - static_assert(std::is_floating_point<RealType>::value, - "Class-template absl::beta_distribution<> must be " - "parameterized using a floating-point type."); - }; - - beta_distribution() : beta_distribution(1) {} - - explicit beta_distribution(result_type alpha, result_type beta = 1) - : param_(alpha, beta) {} - - explicit beta_distribution(const param_type& p) : param_(p) {} - - void reset() {} - - // Generating functions - template <typename URBG> - result_type operator()(URBG& g) { // NOLINT(runtime/references) - return (*this)(g, param_); - } - - template <typename URBG> - result_type operator()(URBG& g, // NOLINT(runtime/references) - const param_type& p); - - param_type param() const { return param_; } - void param(const param_type& p) { param_ = p; } - - result_type(min)() const { return 0; } - result_type(max)() const { return 1; } - - result_type alpha() const { return param_.alpha(); } - result_type beta() const { return param_.beta(); } - - friend bool operator==(const beta_distribution& a, - const beta_distribution& b) { - return a.param_ == b.param_; - } - friend bool operator!=(const beta_distribution& a, - const beta_distribution& b) { - return a.param_ != b.param_; - } - - private: - template <typename URBG> - result_type AlgorithmJoehnk(URBG& g, // NOLINT(runtime/references) - const param_type& p); - - template <typename URBG> - result_type AlgorithmCheng(URBG& g, // NOLINT(runtime/references) - const param_type& p); - - template <typename URBG> - result_type DegenerateCase(URBG& g, // NOLINT(runtime/references) - const param_type& p) { - if (p.method_ == param_type::DEGENERATE_SMALL && p.alpha_ == p.beta_) { - // Returns 0 or 1 with equal probability. - random_internal::FastUniformBits<uint8_t> fast_u8; - return static_cast<result_type>((fast_u8(g) & 0x10) != - 0); // pick any single bit. - } - return p.x_; - } - - param_type param_; - random_internal::FastUniformBits<uint64_t> fast_u64_; -}; - -#if defined(__powerpc64__) || defined(__PPC64__) || defined(__powerpc__) || \ - defined(__ppc__) || defined(__PPC__) -// PPC needs a more stringent boundary for long double. -template <> -constexpr long double -beta_distribution<long double>::param_type::ThresholdPadding() { - return 10; -} -#endif - -template <typename RealType> -template <typename URBG> -typename beta_distribution<RealType>::result_type -beta_distribution<RealType>::AlgorithmJoehnk( - URBG& g, // NOLINT(runtime/references) - const param_type& p) { - using random_internal::GeneratePositiveTag; - using random_internal::GenerateRealFromBits; - using real_type = - absl::conditional_t<std::is_same<RealType, float>::value, float, double>; - - // Based on Joehnk, M. D. Erzeugung von betaverteilten und gammaverteilten - // Zufallszahlen. Metrika 8.1 (1964): 5-15. - // This method is described in Knuth, Vol 2 (Third Edition), pp 134. - - result_type u, v, x, y, z; - for (;;) { - u = GenerateRealFromBits<real_type, GeneratePositiveTag, false>( - fast_u64_(g)); - v = GenerateRealFromBits<real_type, GeneratePositiveTag, false>( - fast_u64_(g)); - - // Direct method. std::pow is slow for float, so rely on the optimizer to - // remove the std::pow() path for that case. - if (!std::is_same<float, result_type>::value) { - x = std::pow(u, p.a_); - y = std::pow(v, p.b_); - z = x + y; - if (z > 1) { - // Reject if and only if `x + y > 1.0` - continue; - } - if (z > 0) { - // When both alpha and beta are small, x and y are both close to 0, so - // divide by (x+y) directly may result in nan. - return x / z; - } - } - - // Log transform. - // x = log( pow(u, p.a_) ), y = log( pow(v, p.b_) ) - // since u, v <= 1.0, x, y < 0. - x = std::log(u) * p.a_; - y = std::log(v) * p.b_; - if (!std::isfinite(x) || !std::isfinite(y)) { - continue; - } - // z = log( pow(u, a) + pow(v, b) ) - z = x > y ? (x + std::log(1 + std::exp(y - x))) - : (y + std::log(1 + std::exp(x - y))); - // Reject iff log(x+y) > 0. - if (z > 0) { - continue; - } - return std::exp(x - z); - } -} - -template <typename RealType> -template <typename URBG> -typename beta_distribution<RealType>::result_type -beta_distribution<RealType>::AlgorithmCheng( - URBG& g, // NOLINT(runtime/references) - const param_type& p) { - using random_internal::GeneratePositiveTag; - using random_internal::GenerateRealFromBits; - using real_type = - absl::conditional_t<std::is_same<RealType, float>::value, float, double>; - - // Based on Cheng, Russell CH. Generating beta variates with nonintegral - // shape parameters. Communications of the ACM 21.4 (1978): 317-322. - // (https://dl.acm.org/citation.cfm?id=359482). - static constexpr result_type kLogFour = - result_type(1.3862943611198906188344642429163531361); // log(4) - static constexpr result_type kS = - result_type(2.6094379124341003746007593332261876); // 1+log(5) - - const bool use_algorithm_ba = (p.method_ == param_type::CHENG_BA); - result_type u1, u2, v, w, z, r, s, t, bw_inv, lhs; - for (;;) { - u1 = GenerateRealFromBits<real_type, GeneratePositiveTag, false>( - fast_u64_(g)); - u2 = GenerateRealFromBits<real_type, GeneratePositiveTag, false>( - fast_u64_(g)); - v = p.y_ * std::log(u1 / (1 - u1)); - w = p.a_ * std::exp(v); - bw_inv = result_type(1) / (p.b_ + w); - r = p.gamma_ * v - kLogFour; - s = p.a_ + r - w; - z = u1 * u1 * u2; - if (!use_algorithm_ba && s + kS >= 5 * z) { - break; - } - t = std::log(z); - if (!use_algorithm_ba && s >= t) { - break; - } - lhs = p.x_ * (p.log_x_ + std::log(bw_inv)) + r; - if (lhs >= t) { - break; - } - } - return p.inverted_ ? (1 - w * bw_inv) : w * bw_inv; -} - -template <typename RealType> -template <typename URBG> -typename beta_distribution<RealType>::result_type -beta_distribution<RealType>::operator()(URBG& g, // NOLINT(runtime/references) - const param_type& p) { - switch (p.method_) { - case param_type::JOEHNK: - return AlgorithmJoehnk(g, p); - case param_type::CHENG_BA: - ABSL_FALLTHROUGH_INTENDED; - case param_type::CHENG_BB: - return AlgorithmCheng(g, p); - default: - return DegenerateCase(g, p); - } -} - -template <typename CharT, typename Traits, typename RealType> -std::basic_ostream<CharT, Traits>& operator<<( - std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) - const beta_distribution<RealType>& x) { - auto saver = random_internal::make_ostream_state_saver(os); - os.precision(random_internal::stream_precision_helper<RealType>::kPrecision); - os << x.alpha() << os.fill() << x.beta(); - return os; -} - -template <typename CharT, typename Traits, typename RealType> -std::basic_istream<CharT, Traits>& operator>>( - std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) - beta_distribution<RealType>& x) { // NOLINT(runtime/references) - using result_type = typename beta_distribution<RealType>::result_type; - using param_type = typename beta_distribution<RealType>::param_type; - result_type alpha, beta; - - auto saver = random_internal::make_istream_state_saver(is); - alpha = random_internal::read_floating_point<result_type>(is); - if (is.fail()) return is; - beta = random_internal::read_floating_point<result_type>(is); - if (!is.fail()) { - x.param(param_type(alpha, beta)); - } - return is; -} - + +// absl::beta_distribution: +// Generate a floating-point variate conforming to a Beta distribution: +// pdf(x) \propto x^(alpha-1) * (1-x)^(beta-1), +// where the params alpha and beta are both strictly positive real values. +// +// The support is the open interval (0, 1), but the return value might be equal +// to 0 or 1, due to numerical errors when alpha and beta are very different. +// +// Usage note: One usage is that alpha and beta are counts of number of +// successes and failures. When the total number of trials are large, consider +// approximating a beta distribution with a Gaussian distribution with the same +// mean and variance. One could use the skewness, which depends only on the +// smaller of alpha and beta when the number of trials are sufficiently large, +// to quantify how far a beta distribution is from the normal distribution. +template <typename RealType = double> +class beta_distribution { + public: + using result_type = RealType; + + class param_type { + public: + using distribution_type = beta_distribution; + + explicit param_type(result_type alpha, result_type beta) + : alpha_(alpha), beta_(beta) { + assert(alpha >= 0); + assert(beta >= 0); + assert(alpha <= (std::numeric_limits<result_type>::max)()); + assert(beta <= (std::numeric_limits<result_type>::max)()); + if (alpha == 0 || beta == 0) { + method_ = DEGENERATE_SMALL; + x_ = (alpha >= beta) ? 1 : 0; + return; + } + // a_ = min(beta, alpha), b_ = max(beta, alpha). + if (beta < alpha) { + inverted_ = true; + a_ = beta; + b_ = alpha; + } else { + inverted_ = false; + a_ = alpha; + b_ = beta; + } + if (a_ <= 1 && b_ >= ThresholdForLargeA()) { + method_ = DEGENERATE_SMALL; + x_ = inverted_ ? result_type(1) : result_type(0); + return; + } + // For threshold values, see also: + // Evaluation of Beta Generation Algorithms, Ying-Chao Hung, et. al. + // February, 2009. + if ((b_ < 1.0 && a_ + b_ <= 1.2) || a_ <= ThresholdForSmallA()) { + // Choose Joehnk over Cheng when it's faster or when Cheng encounters + // numerical issues. + method_ = JOEHNK; + a_ = result_type(1) / alpha_; + b_ = result_type(1) / beta_; + if (std::isinf(a_) || std::isinf(b_)) { + method_ = DEGENERATE_SMALL; + x_ = inverted_ ? result_type(1) : result_type(0); + } + return; + } + if (a_ >= ThresholdForLargeA()) { + method_ = DEGENERATE_LARGE; + // Note: on PPC for long double, evaluating + // `std::numeric_limits::max() / ThresholdForLargeA` results in NaN. + result_type r = a_ / b_; + x_ = (inverted_ ? result_type(1) : r) / (1 + r); + return; + } + x_ = a_ + b_; + log_x_ = std::log(x_); + if (a_ <= 1) { + method_ = CHENG_BA; + y_ = result_type(1) / a_; + gamma_ = a_ + a_; + return; + } + method_ = CHENG_BB; + result_type r = (a_ - 1) / (b_ - 1); + y_ = std::sqrt((1 + r) / (b_ * r * 2 - r + 1)); + gamma_ = a_ + result_type(1) / y_; + } + + result_type alpha() const { return alpha_; } + result_type beta() const { return beta_; } + + friend bool operator==(const param_type& a, const param_type& b) { + return a.alpha_ == b.alpha_ && a.beta_ == b.beta_; + } + + friend bool operator!=(const param_type& a, const param_type& b) { + return !(a == b); + } + + private: + friend class beta_distribution; + +#ifdef _MSC_VER + // MSVC does not have constexpr implementations for std::log and std::exp + // so they are computed at runtime. +#define ABSL_RANDOM_INTERNAL_LOG_EXP_CONSTEXPR +#else +#define ABSL_RANDOM_INTERNAL_LOG_EXP_CONSTEXPR constexpr +#endif + + // The threshold for whether std::exp(1/a) is finite. + // Note that this value is quite large, and a smaller a_ is NOT abnormal. + static ABSL_RANDOM_INTERNAL_LOG_EXP_CONSTEXPR result_type + ThresholdForSmallA() { + return result_type(1) / + std::log((std::numeric_limits<result_type>::max)()); + } + + // The threshold for whether a * std::log(a) is finite. + static ABSL_RANDOM_INTERNAL_LOG_EXP_CONSTEXPR result_type + ThresholdForLargeA() { + return std::exp( + std::log((std::numeric_limits<result_type>::max)()) - + std::log(std::log((std::numeric_limits<result_type>::max)())) - + ThresholdPadding()); + } + +#undef ABSL_RANDOM_INTERNAL_LOG_EXP_CONSTEXPR + + // Pad the threshold for large A for long double on PPC. This is done via a + // template specialization below. + static constexpr result_type ThresholdPadding() { return 0; } + + enum Method { + JOEHNK, // Uses algorithm Joehnk + CHENG_BA, // Uses algorithm BA in Cheng + CHENG_BB, // Uses algorithm BB in Cheng + + // Note: See also: + // Hung et al. Evaluation of beta generation algorithms. Communications + // in Statistics-Simulation and Computation 38.4 (2009): 750-770. + // especially: + // Zechner, Heinz, and Ernst Stadlober. Generating beta variates via + // patchwork rejection. Computing 50.1 (1993): 1-18. + + DEGENERATE_SMALL, // a_ is abnormally small. + DEGENERATE_LARGE, // a_ is abnormally large. + }; + + result_type alpha_; + result_type beta_; + + result_type a_; // the smaller of {alpha, beta}, or 1.0/alpha_ in JOEHNK + result_type b_; // the larger of {alpha, beta}, or 1.0/beta_ in JOEHNK + result_type x_; // alpha + beta, or the result in degenerate cases + result_type log_x_; // log(x_) + result_type y_; // "beta" in Cheng + result_type gamma_; // "gamma" in Cheng + + Method method_; + + // Placing this last for optimal alignment. + // Whether alpha_ != a_, i.e. true iff alpha_ > beta_. + bool inverted_; + + static_assert(std::is_floating_point<RealType>::value, + "Class-template absl::beta_distribution<> must be " + "parameterized using a floating-point type."); + }; + + beta_distribution() : beta_distribution(1) {} + + explicit beta_distribution(result_type alpha, result_type beta = 1) + : param_(alpha, beta) {} + + explicit beta_distribution(const param_type& p) : param_(p) {} + + void reset() {} + + // Generating functions + template <typename URBG> + result_type operator()(URBG& g) { // NOLINT(runtime/references) + return (*this)(g, param_); + } + + template <typename URBG> + result_type operator()(URBG& g, // NOLINT(runtime/references) + const param_type& p); + + param_type param() const { return param_; } + void param(const param_type& p) { param_ = p; } + + result_type(min)() const { return 0; } + result_type(max)() const { return 1; } + + result_type alpha() const { return param_.alpha(); } + result_type beta() const { return param_.beta(); } + + friend bool operator==(const beta_distribution& a, + const beta_distribution& b) { + return a.param_ == b.param_; + } + friend bool operator!=(const beta_distribution& a, + const beta_distribution& b) { + return a.param_ != b.param_; + } + + private: + template <typename URBG> + result_type AlgorithmJoehnk(URBG& g, // NOLINT(runtime/references) + const param_type& p); + + template <typename URBG> + result_type AlgorithmCheng(URBG& g, // NOLINT(runtime/references) + const param_type& p); + + template <typename URBG> + result_type DegenerateCase(URBG& g, // NOLINT(runtime/references) + const param_type& p) { + if (p.method_ == param_type::DEGENERATE_SMALL && p.alpha_ == p.beta_) { + // Returns 0 or 1 with equal probability. + random_internal::FastUniformBits<uint8_t> fast_u8; + return static_cast<result_type>((fast_u8(g) & 0x10) != + 0); // pick any single bit. + } + return p.x_; + } + + param_type param_; + random_internal::FastUniformBits<uint64_t> fast_u64_; +}; + +#if defined(__powerpc64__) || defined(__PPC64__) || defined(__powerpc__) || \ + defined(__ppc__) || defined(__PPC__) +// PPC needs a more stringent boundary for long double. +template <> +constexpr long double +beta_distribution<long double>::param_type::ThresholdPadding() { + return 10; +} +#endif + +template <typename RealType> +template <typename URBG> +typename beta_distribution<RealType>::result_type +beta_distribution<RealType>::AlgorithmJoehnk( + URBG& g, // NOLINT(runtime/references) + const param_type& p) { + using random_internal::GeneratePositiveTag; + using random_internal::GenerateRealFromBits; + using real_type = + absl::conditional_t<std::is_same<RealType, float>::value, float, double>; + + // Based on Joehnk, M. D. Erzeugung von betaverteilten und gammaverteilten + // Zufallszahlen. Metrika 8.1 (1964): 5-15. + // This method is described in Knuth, Vol 2 (Third Edition), pp 134. + + result_type u, v, x, y, z; + for (;;) { + u = GenerateRealFromBits<real_type, GeneratePositiveTag, false>( + fast_u64_(g)); + v = GenerateRealFromBits<real_type, GeneratePositiveTag, false>( + fast_u64_(g)); + + // Direct method. std::pow is slow for float, so rely on the optimizer to + // remove the std::pow() path for that case. + if (!std::is_same<float, result_type>::value) { + x = std::pow(u, p.a_); + y = std::pow(v, p.b_); + z = x + y; + if (z > 1) { + // Reject if and only if `x + y > 1.0` + continue; + } + if (z > 0) { + // When both alpha and beta are small, x and y are both close to 0, so + // divide by (x+y) directly may result in nan. + return x / z; + } + } + + // Log transform. + // x = log( pow(u, p.a_) ), y = log( pow(v, p.b_) ) + // since u, v <= 1.0, x, y < 0. + x = std::log(u) * p.a_; + y = std::log(v) * p.b_; + if (!std::isfinite(x) || !std::isfinite(y)) { + continue; + } + // z = log( pow(u, a) + pow(v, b) ) + z = x > y ? (x + std::log(1 + std::exp(y - x))) + : (y + std::log(1 + std::exp(x - y))); + // Reject iff log(x+y) > 0. + if (z > 0) { + continue; + } + return std::exp(x - z); + } +} + +template <typename RealType> +template <typename URBG> +typename beta_distribution<RealType>::result_type +beta_distribution<RealType>::AlgorithmCheng( + URBG& g, // NOLINT(runtime/references) + const param_type& p) { + using random_internal::GeneratePositiveTag; + using random_internal::GenerateRealFromBits; + using real_type = + absl::conditional_t<std::is_same<RealType, float>::value, float, double>; + + // Based on Cheng, Russell CH. Generating beta variates with nonintegral + // shape parameters. Communications of the ACM 21.4 (1978): 317-322. + // (https://dl.acm.org/citation.cfm?id=359482). + static constexpr result_type kLogFour = + result_type(1.3862943611198906188344642429163531361); // log(4) + static constexpr result_type kS = + result_type(2.6094379124341003746007593332261876); // 1+log(5) + + const bool use_algorithm_ba = (p.method_ == param_type::CHENG_BA); + result_type u1, u2, v, w, z, r, s, t, bw_inv, lhs; + for (;;) { + u1 = GenerateRealFromBits<real_type, GeneratePositiveTag, false>( + fast_u64_(g)); + u2 = GenerateRealFromBits<real_type, GeneratePositiveTag, false>( + fast_u64_(g)); + v = p.y_ * std::log(u1 / (1 - u1)); + w = p.a_ * std::exp(v); + bw_inv = result_type(1) / (p.b_ + w); + r = p.gamma_ * v - kLogFour; + s = p.a_ + r - w; + z = u1 * u1 * u2; + if (!use_algorithm_ba && s + kS >= 5 * z) { + break; + } + t = std::log(z); + if (!use_algorithm_ba && s >= t) { + break; + } + lhs = p.x_ * (p.log_x_ + std::log(bw_inv)) + r; + if (lhs >= t) { + break; + } + } + return p.inverted_ ? (1 - w * bw_inv) : w * bw_inv; +} + +template <typename RealType> +template <typename URBG> +typename beta_distribution<RealType>::result_type +beta_distribution<RealType>::operator()(URBG& g, // NOLINT(runtime/references) + const param_type& p) { + switch (p.method_) { + case param_type::JOEHNK: + return AlgorithmJoehnk(g, p); + case param_type::CHENG_BA: + ABSL_FALLTHROUGH_INTENDED; + case param_type::CHENG_BB: + return AlgorithmCheng(g, p); + default: + return DegenerateCase(g, p); + } +} + +template <typename CharT, typename Traits, typename RealType> +std::basic_ostream<CharT, Traits>& operator<<( + std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) + const beta_distribution<RealType>& x) { + auto saver = random_internal::make_ostream_state_saver(os); + os.precision(random_internal::stream_precision_helper<RealType>::kPrecision); + os << x.alpha() << os.fill() << x.beta(); + return os; +} + +template <typename CharT, typename Traits, typename RealType> +std::basic_istream<CharT, Traits>& operator>>( + std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) + beta_distribution<RealType>& x) { // NOLINT(runtime/references) + using result_type = typename beta_distribution<RealType>::result_type; + using param_type = typename beta_distribution<RealType>::param_type; + result_type alpha, beta; + + auto saver = random_internal::make_istream_state_saver(is); + alpha = random_internal::read_floating_point<result_type>(is); + if (is.fail()) return is; + beta = random_internal::read_floating_point<result_type>(is); + if (!is.fail()) { + x.param(param_type(alpha, beta)); + } + return is; +} + ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_BETA_DISTRIBUTION_H_ +} // namespace absl + +#endif // ABSL_RANDOM_BETA_DISTRIBUTION_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/discrete_distribution.cc b/contrib/restricted/abseil-cpp/absl/random/discrete_distribution.cc index 03ca2a2b0b..081accee52 100644 --- a/contrib/restricted/abseil-cpp/absl/random/discrete_distribution.cc +++ b/contrib/restricted/abseil-cpp/absl/random/discrete_distribution.cc @@ -1,98 +1,98 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "absl/random/discrete_distribution.h" - -namespace absl { +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/random/discrete_distribution.h" + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - -// Initializes the distribution table for Walker's Aliasing algorithm, described -// in Knuth, Vol 2. as well as in https://en.wikipedia.org/wiki/Alias_method -std::vector<std::pair<double, size_t>> InitDiscreteDistribution( - std::vector<double>* probabilities) { - // The empty-case should already be handled by the constructor. - assert(probabilities); - assert(!probabilities->empty()); - - // Step 1. Normalize the input probabilities to 1.0. - double sum = std::accumulate(std::begin(*probabilities), - std::end(*probabilities), 0.0); - if (std::fabs(sum - 1.0) > 1e-6) { - // Scale `probabilities` only when the sum is too far from 1.0. Scaling - // unconditionally will alter the probabilities slightly. - for (double& item : *probabilities) { - item = item / sum; - } - } - - // Step 2. At this point `probabilities` is set to the conditional - // probabilities of each element which sum to 1.0, to within reasonable error. - // These values are used to construct the proportional probability tables for - // the selection phases of Walker's Aliasing algorithm. - // - // To construct the table, pick an element which is under-full (i.e., an - // element for which `(*probabilities)[i] < 1.0/n`), and pair it with an - // element which is over-full (i.e., an element for which - // `(*probabilities)[i] > 1.0/n`). The smaller value can always be retired. - // The larger may still be greater than 1.0/n, or may now be less than 1.0/n, - // and put back onto the appropriate collection. - const size_t n = probabilities->size(); - std::vector<std::pair<double, size_t>> q; - q.reserve(n); - - std::vector<size_t> over; - std::vector<size_t> under; - size_t idx = 0; - for (const double item : *probabilities) { - assert(item >= 0); - const double v = item * n; - q.emplace_back(v, 0); - if (v < 1.0) { - under.push_back(idx++); - } else { - over.push_back(idx++); - } - } - while (!over.empty() && !under.empty()) { - auto lo = under.back(); - under.pop_back(); - auto hi = over.back(); - over.pop_back(); - - q[lo].second = hi; - const double r = q[hi].first - (1.0 - q[lo].first); - q[hi].first = r; - if (r < 1.0) { - under.push_back(hi); - } else { - over.push_back(hi); - } - } - - // Due to rounding errors, there may be un-paired elements in either - // collection; these should all be values near 1.0. For these values, set `q` - // to 1.0 and set the alternate to the identity. - for (auto i : over) { - q[i] = {1.0, i}; - } - for (auto i : under) { - q[i] = {1.0, i}; - } - return q; -} - -} // namespace random_internal +namespace random_internal { + +// Initializes the distribution table for Walker's Aliasing algorithm, described +// in Knuth, Vol 2. as well as in https://en.wikipedia.org/wiki/Alias_method +std::vector<std::pair<double, size_t>> InitDiscreteDistribution( + std::vector<double>* probabilities) { + // The empty-case should already be handled by the constructor. + assert(probabilities); + assert(!probabilities->empty()); + + // Step 1. Normalize the input probabilities to 1.0. + double sum = std::accumulate(std::begin(*probabilities), + std::end(*probabilities), 0.0); + if (std::fabs(sum - 1.0) > 1e-6) { + // Scale `probabilities` only when the sum is too far from 1.0. Scaling + // unconditionally will alter the probabilities slightly. + for (double& item : *probabilities) { + item = item / sum; + } + } + + // Step 2. At this point `probabilities` is set to the conditional + // probabilities of each element which sum to 1.0, to within reasonable error. + // These values are used to construct the proportional probability tables for + // the selection phases of Walker's Aliasing algorithm. + // + // To construct the table, pick an element which is under-full (i.e., an + // element for which `(*probabilities)[i] < 1.0/n`), and pair it with an + // element which is over-full (i.e., an element for which + // `(*probabilities)[i] > 1.0/n`). The smaller value can always be retired. + // The larger may still be greater than 1.0/n, or may now be less than 1.0/n, + // and put back onto the appropriate collection. + const size_t n = probabilities->size(); + std::vector<std::pair<double, size_t>> q; + q.reserve(n); + + std::vector<size_t> over; + std::vector<size_t> under; + size_t idx = 0; + for (const double item : *probabilities) { + assert(item >= 0); + const double v = item * n; + q.emplace_back(v, 0); + if (v < 1.0) { + under.push_back(idx++); + } else { + over.push_back(idx++); + } + } + while (!over.empty() && !under.empty()) { + auto lo = under.back(); + under.pop_back(); + auto hi = over.back(); + over.pop_back(); + + q[lo].second = hi; + const double r = q[hi].first - (1.0 - q[lo].first); + q[hi].first = r; + if (r < 1.0) { + under.push_back(hi); + } else { + over.push_back(hi); + } + } + + // Due to rounding errors, there may be un-paired elements in either + // collection; these should all be values near 1.0. For these values, set `q` + // to 1.0 and set the alternate to the identity. + for (auto i : over) { + q[i] = {1.0, i}; + } + for (auto i : under) { + q[i] = {1.0, i}; + } + return q; +} + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl +} // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/random/discrete_distribution.h b/contrib/restricted/abseil-cpp/absl/random/discrete_distribution.h index 8a390fde21..171aa11a1e 100644 --- a/contrib/restricted/abseil-cpp/absl/random/discrete_distribution.h +++ b/contrib/restricted/abseil-cpp/absl/random/discrete_distribution.h @@ -1,247 +1,247 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_DISCRETE_DISTRIBUTION_H_ -#define ABSL_RANDOM_DISCRETE_DISTRIBUTION_H_ - -#include <cassert> -#include <cmath> -#include <istream> -#include <limits> -#include <numeric> -#include <type_traits> -#include <utility> -#include <vector> - -#include "absl/random/bernoulli_distribution.h" -#include "absl/random/internal/iostream_state_saver.h" -#include "absl/random/uniform_int_distribution.h" - -namespace absl { +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_DISCRETE_DISTRIBUTION_H_ +#define ABSL_RANDOM_DISCRETE_DISTRIBUTION_H_ + +#include <cassert> +#include <cmath> +#include <istream> +#include <limits> +#include <numeric> +#include <type_traits> +#include <utility> +#include <vector> + +#include "absl/random/bernoulli_distribution.h" +#include "absl/random/internal/iostream_state_saver.h" +#include "absl/random/uniform_int_distribution.h" + +namespace absl { ABSL_NAMESPACE_BEGIN - -// absl::discrete_distribution -// -// A discrete distribution produces random integers i, where 0 <= i < n -// distributed according to the discrete probability function: -// -// P(i|p0,...,pn−1)=pi -// -// This class is an implementation of discrete_distribution (see -// [rand.dist.samp.discrete]). -// -// The algorithm used is Walker's Aliasing algorithm, described in Knuth, Vol 2. -// absl::discrete_distribution takes O(N) time to precompute the probabilities -// (where N is the number of possible outcomes in the distribution) at -// construction, and then takes O(1) time for each variate generation. Many -// other implementations also take O(N) time to construct an ordered sequence of -// partial sums, plus O(log N) time per variate to binary search. -// -template <typename IntType = int> -class discrete_distribution { - public: - using result_type = IntType; - - class param_type { - public: - using distribution_type = discrete_distribution; - - param_type() { init(); } - - template <typename InputIterator> - explicit param_type(InputIterator begin, InputIterator end) - : p_(begin, end) { - init(); - } - - explicit param_type(std::initializer_list<double> weights) : p_(weights) { - init(); - } - - template <class UnaryOperation> - explicit param_type(size_t nw, double xmin, double xmax, - UnaryOperation fw) { - if (nw > 0) { - p_.reserve(nw); - double delta = (xmax - xmin) / static_cast<double>(nw); - assert(delta > 0); - double t = delta * 0.5; - for (size_t i = 0; i < nw; ++i) { - p_.push_back(fw(xmin + i * delta + t)); - } - } - init(); - } - - const std::vector<double>& probabilities() const { return p_; } - size_t n() const { return p_.size() - 1; } - - friend bool operator==(const param_type& a, const param_type& b) { - return a.probabilities() == b.probabilities(); - } - - friend bool operator!=(const param_type& a, const param_type& b) { - return !(a == b); - } - - private: - friend class discrete_distribution; - - void init(); - - std::vector<double> p_; // normalized probabilities - std::vector<std::pair<double, size_t>> q_; // (acceptance, alternate) pairs - - static_assert(std::is_integral<result_type>::value, - "Class-template absl::discrete_distribution<> must be " - "parameterized using an integral type."); - }; - - discrete_distribution() : param_() {} - - explicit discrete_distribution(const param_type& p) : param_(p) {} - - template <typename InputIterator> - explicit discrete_distribution(InputIterator begin, InputIterator end) - : param_(begin, end) {} - - explicit discrete_distribution(std::initializer_list<double> weights) - : param_(weights) {} - - template <class UnaryOperation> - explicit discrete_distribution(size_t nw, double xmin, double xmax, - UnaryOperation fw) - : param_(nw, xmin, xmax, std::move(fw)) {} - - void reset() {} - - // generating functions - template <typename URBG> - result_type operator()(URBG& g) { // NOLINT(runtime/references) - return (*this)(g, param_); - } - - template <typename URBG> - result_type operator()(URBG& g, // NOLINT(runtime/references) - const param_type& p); - - const param_type& param() const { return param_; } - void param(const param_type& p) { param_ = p; } - - result_type(min)() const { return 0; } - result_type(max)() const { - return static_cast<result_type>(param_.n()); - } // inclusive - - // NOTE [rand.dist.sample.discrete] returns a std::vector<double> not a - // const std::vector<double>&. - const std::vector<double>& probabilities() const { - return param_.probabilities(); - } - - friend bool operator==(const discrete_distribution& a, - const discrete_distribution& b) { - return a.param_ == b.param_; - } - friend bool operator!=(const discrete_distribution& a, - const discrete_distribution& b) { - return a.param_ != b.param_; - } - - private: - param_type param_; -}; - -// -------------------------------------------------------------------------- -// Implementation details only below -// -------------------------------------------------------------------------- - -namespace random_internal { - -// Using the vector `*probabilities`, whose values are the weights or -// probabilities of an element being selected, constructs the proportional -// probabilities used by the discrete distribution. `*probabilities` will be -// scaled, if necessary, so that its entries sum to a value sufficiently close -// to 1.0. -std::vector<std::pair<double, size_t>> InitDiscreteDistribution( - std::vector<double>* probabilities); - -} // namespace random_internal - -template <typename IntType> -void discrete_distribution<IntType>::param_type::init() { - if (p_.empty()) { - p_.push_back(1.0); - q_.emplace_back(1.0, 0); - } else { - assert(n() <= (std::numeric_limits<IntType>::max)()); - q_ = random_internal::InitDiscreteDistribution(&p_); - } -} - -template <typename IntType> -template <typename URBG> -typename discrete_distribution<IntType>::result_type -discrete_distribution<IntType>::operator()( - URBG& g, // NOLINT(runtime/references) - const param_type& p) { - const auto idx = absl::uniform_int_distribution<result_type>(0, p.n())(g); - const auto& q = p.q_[idx]; - const bool selected = absl::bernoulli_distribution(q.first)(g); - return selected ? idx : static_cast<result_type>(q.second); -} - -template <typename CharT, typename Traits, typename IntType> -std::basic_ostream<CharT, Traits>& operator<<( - std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) - const discrete_distribution<IntType>& x) { - auto saver = random_internal::make_ostream_state_saver(os); - const auto& probabilities = x.param().probabilities(); - os << probabilities.size(); - - os.precision(random_internal::stream_precision_helper<double>::kPrecision); - for (const auto& p : probabilities) { - os << os.fill() << p; - } - return os; -} - -template <typename CharT, typename Traits, typename IntType> -std::basic_istream<CharT, Traits>& operator>>( - std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) - discrete_distribution<IntType>& x) { // NOLINT(runtime/references) - using param_type = typename discrete_distribution<IntType>::param_type; - auto saver = random_internal::make_istream_state_saver(is); - - size_t n; - std::vector<double> p; - - is >> n; - if (is.fail()) return is; - if (n > 0) { - p.reserve(n); - for (IntType i = 0; i < n && !is.fail(); ++i) { - auto tmp = random_internal::read_floating_point<double>(is); - if (is.fail()) return is; - p.push_back(tmp); - } - } - x.param(param_type(p.begin(), p.end())); - return is; -} - + +// absl::discrete_distribution +// +// A discrete distribution produces random integers i, where 0 <= i < n +// distributed according to the discrete probability function: +// +// P(i|p0,...,pn−1)=pi +// +// This class is an implementation of discrete_distribution (see +// [rand.dist.samp.discrete]). +// +// The algorithm used is Walker's Aliasing algorithm, described in Knuth, Vol 2. +// absl::discrete_distribution takes O(N) time to precompute the probabilities +// (where N is the number of possible outcomes in the distribution) at +// construction, and then takes O(1) time for each variate generation. Many +// other implementations also take O(N) time to construct an ordered sequence of +// partial sums, plus O(log N) time per variate to binary search. +// +template <typename IntType = int> +class discrete_distribution { + public: + using result_type = IntType; + + class param_type { + public: + using distribution_type = discrete_distribution; + + param_type() { init(); } + + template <typename InputIterator> + explicit param_type(InputIterator begin, InputIterator end) + : p_(begin, end) { + init(); + } + + explicit param_type(std::initializer_list<double> weights) : p_(weights) { + init(); + } + + template <class UnaryOperation> + explicit param_type(size_t nw, double xmin, double xmax, + UnaryOperation fw) { + if (nw > 0) { + p_.reserve(nw); + double delta = (xmax - xmin) / static_cast<double>(nw); + assert(delta > 0); + double t = delta * 0.5; + for (size_t i = 0; i < nw; ++i) { + p_.push_back(fw(xmin + i * delta + t)); + } + } + init(); + } + + const std::vector<double>& probabilities() const { return p_; } + size_t n() const { return p_.size() - 1; } + + friend bool operator==(const param_type& a, const param_type& b) { + return a.probabilities() == b.probabilities(); + } + + friend bool operator!=(const param_type& a, const param_type& b) { + return !(a == b); + } + + private: + friend class discrete_distribution; + + void init(); + + std::vector<double> p_; // normalized probabilities + std::vector<std::pair<double, size_t>> q_; // (acceptance, alternate) pairs + + static_assert(std::is_integral<result_type>::value, + "Class-template absl::discrete_distribution<> must be " + "parameterized using an integral type."); + }; + + discrete_distribution() : param_() {} + + explicit discrete_distribution(const param_type& p) : param_(p) {} + + template <typename InputIterator> + explicit discrete_distribution(InputIterator begin, InputIterator end) + : param_(begin, end) {} + + explicit discrete_distribution(std::initializer_list<double> weights) + : param_(weights) {} + + template <class UnaryOperation> + explicit discrete_distribution(size_t nw, double xmin, double xmax, + UnaryOperation fw) + : param_(nw, xmin, xmax, std::move(fw)) {} + + void reset() {} + + // generating functions + template <typename URBG> + result_type operator()(URBG& g) { // NOLINT(runtime/references) + return (*this)(g, param_); + } + + template <typename URBG> + result_type operator()(URBG& g, // NOLINT(runtime/references) + const param_type& p); + + const param_type& param() const { return param_; } + void param(const param_type& p) { param_ = p; } + + result_type(min)() const { return 0; } + result_type(max)() const { + return static_cast<result_type>(param_.n()); + } // inclusive + + // NOTE [rand.dist.sample.discrete] returns a std::vector<double> not a + // const std::vector<double>&. + const std::vector<double>& probabilities() const { + return param_.probabilities(); + } + + friend bool operator==(const discrete_distribution& a, + const discrete_distribution& b) { + return a.param_ == b.param_; + } + friend bool operator!=(const discrete_distribution& a, + const discrete_distribution& b) { + return a.param_ != b.param_; + } + + private: + param_type param_; +}; + +// -------------------------------------------------------------------------- +// Implementation details only below +// -------------------------------------------------------------------------- + +namespace random_internal { + +// Using the vector `*probabilities`, whose values are the weights or +// probabilities of an element being selected, constructs the proportional +// probabilities used by the discrete distribution. `*probabilities` will be +// scaled, if necessary, so that its entries sum to a value sufficiently close +// to 1.0. +std::vector<std::pair<double, size_t>> InitDiscreteDistribution( + std::vector<double>* probabilities); + +} // namespace random_internal + +template <typename IntType> +void discrete_distribution<IntType>::param_type::init() { + if (p_.empty()) { + p_.push_back(1.0); + q_.emplace_back(1.0, 0); + } else { + assert(n() <= (std::numeric_limits<IntType>::max)()); + q_ = random_internal::InitDiscreteDistribution(&p_); + } +} + +template <typename IntType> +template <typename URBG> +typename discrete_distribution<IntType>::result_type +discrete_distribution<IntType>::operator()( + URBG& g, // NOLINT(runtime/references) + const param_type& p) { + const auto idx = absl::uniform_int_distribution<result_type>(0, p.n())(g); + const auto& q = p.q_[idx]; + const bool selected = absl::bernoulli_distribution(q.first)(g); + return selected ? idx : static_cast<result_type>(q.second); +} + +template <typename CharT, typename Traits, typename IntType> +std::basic_ostream<CharT, Traits>& operator<<( + std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) + const discrete_distribution<IntType>& x) { + auto saver = random_internal::make_ostream_state_saver(os); + const auto& probabilities = x.param().probabilities(); + os << probabilities.size(); + + os.precision(random_internal::stream_precision_helper<double>::kPrecision); + for (const auto& p : probabilities) { + os << os.fill() << p; + } + return os; +} + +template <typename CharT, typename Traits, typename IntType> +std::basic_istream<CharT, Traits>& operator>>( + std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) + discrete_distribution<IntType>& x) { // NOLINT(runtime/references) + using param_type = typename discrete_distribution<IntType>::param_type; + auto saver = random_internal::make_istream_state_saver(is); + + size_t n; + std::vector<double> p; + + is >> n; + if (is.fail()) return is; + if (n > 0) { + p.reserve(n); + for (IntType i = 0; i < n && !is.fail(); ++i) { + auto tmp = random_internal::read_floating_point<double>(is); + if (is.fail()) return is; + p.push_back(tmp); + } + } + x.param(param_type(p.begin(), p.end())); + return is; +} + ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_DISCRETE_DISTRIBUTION_H_ +} // namespace absl + +#endif // ABSL_RANDOM_DISCRETE_DISTRIBUTION_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/distributions.h b/contrib/restricted/abseil-cpp/absl/random/distributions.h index ee33d64416..31c79694e5 100644 --- a/contrib/restricted/abseil-cpp/absl/random/distributions.h +++ b/contrib/restricted/abseil-cpp/absl/random/distributions.h @@ -1,452 +1,452 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// ----------------------------------------------------------------------------- -// File: distributions.h -// ----------------------------------------------------------------------------- -// -// This header defines functions representing distributions, which you use in -// combination with an Abseil random bit generator to produce random values -// according to the rules of that distribution. -// -// The Abseil random library defines the following distributions within this -// file: -// -// * `absl::Uniform` for uniform (constant) distributions having constant -// probability -// * `absl::Bernoulli` for discrete distributions having exactly two outcomes -// * `absl::Beta` for continuous distributions parameterized through two -// free parameters -// * `absl::Exponential` for discrete distributions of events occurring -// continuously and independently at a constant average rate -// * `absl::Gaussian` (also known as "normal distributions") for continuous -// distributions using an associated quadratic function -// * `absl::LogUniform` for continuous uniform distributions where the log -// to the given base of all values is uniform -// * `absl::Poisson` for discrete probability distributions that express the -// probability of a given number of events occurring within a fixed interval -// * `absl::Zipf` for discrete probability distributions commonly used for -// modelling of rare events -// -// Prefer use of these distribution function classes over manual construction of -// your own distribution classes, as it allows library maintainers greater -// flexibility to change the underlying implementation in the future. - -#ifndef ABSL_RANDOM_DISTRIBUTIONS_H_ -#define ABSL_RANDOM_DISTRIBUTIONS_H_ - -#include <algorithm> -#include <cmath> -#include <limits> -#include <random> -#include <type_traits> - -#include "absl/base/internal/inline_variable.h" -#include "absl/random/bernoulli_distribution.h" -#include "absl/random/beta_distribution.h" -#include "absl/random/exponential_distribution.h" -#include "absl/random/gaussian_distribution.h" +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: distributions.h +// ----------------------------------------------------------------------------- +// +// This header defines functions representing distributions, which you use in +// combination with an Abseil random bit generator to produce random values +// according to the rules of that distribution. +// +// The Abseil random library defines the following distributions within this +// file: +// +// * `absl::Uniform` for uniform (constant) distributions having constant +// probability +// * `absl::Bernoulli` for discrete distributions having exactly two outcomes +// * `absl::Beta` for continuous distributions parameterized through two +// free parameters +// * `absl::Exponential` for discrete distributions of events occurring +// continuously and independently at a constant average rate +// * `absl::Gaussian` (also known as "normal distributions") for continuous +// distributions using an associated quadratic function +// * `absl::LogUniform` for continuous uniform distributions where the log +// to the given base of all values is uniform +// * `absl::Poisson` for discrete probability distributions that express the +// probability of a given number of events occurring within a fixed interval +// * `absl::Zipf` for discrete probability distributions commonly used for +// modelling of rare events +// +// Prefer use of these distribution function classes over manual construction of +// your own distribution classes, as it allows library maintainers greater +// flexibility to change the underlying implementation in the future. + +#ifndef ABSL_RANDOM_DISTRIBUTIONS_H_ +#define ABSL_RANDOM_DISTRIBUTIONS_H_ + +#include <algorithm> +#include <cmath> +#include <limits> +#include <random> +#include <type_traits> + +#include "absl/base/internal/inline_variable.h" +#include "absl/random/bernoulli_distribution.h" +#include "absl/random/beta_distribution.h" +#include "absl/random/exponential_distribution.h" +#include "absl/random/gaussian_distribution.h" #include "absl/random/internal/distribution_caller.h" // IWYU pragma: export -#include "absl/random/internal/uniform_helper.h" // IWYU pragma: export -#include "absl/random/log_uniform_int_distribution.h" -#include "absl/random/poisson_distribution.h" -#include "absl/random/uniform_int_distribution.h" -#include "absl/random/uniform_real_distribution.h" -#include "absl/random/zipf_distribution.h" - -namespace absl { +#include "absl/random/internal/uniform_helper.h" // IWYU pragma: export +#include "absl/random/log_uniform_int_distribution.h" +#include "absl/random/poisson_distribution.h" +#include "absl/random/uniform_int_distribution.h" +#include "absl/random/uniform_real_distribution.h" +#include "absl/random/zipf_distribution.h" + +namespace absl { ABSL_NAMESPACE_BEGIN - -ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalClosedClosedTag, IntervalClosedClosed, - {}); -ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalClosedClosedTag, IntervalClosed, {}); -ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalClosedOpenTag, IntervalClosedOpen, {}); -ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalOpenOpenTag, IntervalOpenOpen, {}); -ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalOpenOpenTag, IntervalOpen, {}); -ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalOpenClosedTag, IntervalOpenClosed, {}); - -// ----------------------------------------------------------------------------- -// absl::Uniform<T>(tag, bitgen, lo, hi) -// ----------------------------------------------------------------------------- -// -// `absl::Uniform()` produces random values of type `T` uniformly distributed in -// a defined interval {lo, hi}. The interval `tag` defines the type of interval -// which should be one of the following possible values: -// -// * `absl::IntervalOpenOpen` -// * `absl::IntervalOpenClosed` -// * `absl::IntervalClosedOpen` -// * `absl::IntervalClosedClosed` -// -// where "open" refers to an exclusive value (excluded) from the output, while -// "closed" refers to an inclusive value (included) from the output. -// -// In the absence of an explicit return type `T`, `absl::Uniform()` will deduce -// the return type based on the provided endpoint arguments {A lo, B hi}. -// Given these endpoints, one of {A, B} will be chosen as the return type, if -// a type can be implicitly converted into the other in a lossless way. The -// lack of any such implicit conversion between {A, B} will produce a -// compile-time error -// -// See https://en.wikipedia.org/wiki/Uniform_distribution_(continuous) -// -// Example: -// -// absl::BitGen bitgen; -// -// // Produce a random float value between 0.0 and 1.0, inclusive -// auto x = absl::Uniform(absl::IntervalClosedClosed, bitgen, 0.0f, 1.0f); -// -// // The most common interval of `absl::IntervalClosedOpen` is available by -// // default: -// -// auto x = absl::Uniform(bitgen, 0.0f, 1.0f); -// -// // Return-types are typically inferred from the arguments, however callers -// // can optionally provide an explicit return-type to the template. -// -// auto x = absl::Uniform<float>(bitgen, 0, 1); -// -template <typename R = void, typename TagType, typename URBG> -typename absl::enable_if_t<!std::is_same<R, void>::value, R> // -Uniform(TagType tag, - URBG&& urbg, // NOLINT(runtime/references) - R lo, R hi) { - using gen_t = absl::decay_t<URBG>; - using distribution_t = random_internal::UniformDistributionWrapper<R>; - - auto a = random_internal::uniform_lower_bound(tag, lo, hi); - auto b = random_internal::uniform_upper_bound(tag, lo, hi); + +ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalClosedClosedTag, IntervalClosedClosed, + {}); +ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalClosedClosedTag, IntervalClosed, {}); +ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalClosedOpenTag, IntervalClosedOpen, {}); +ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalOpenOpenTag, IntervalOpenOpen, {}); +ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalOpenOpenTag, IntervalOpen, {}); +ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalOpenClosedTag, IntervalOpenClosed, {}); + +// ----------------------------------------------------------------------------- +// absl::Uniform<T>(tag, bitgen, lo, hi) +// ----------------------------------------------------------------------------- +// +// `absl::Uniform()` produces random values of type `T` uniformly distributed in +// a defined interval {lo, hi}. The interval `tag` defines the type of interval +// which should be one of the following possible values: +// +// * `absl::IntervalOpenOpen` +// * `absl::IntervalOpenClosed` +// * `absl::IntervalClosedOpen` +// * `absl::IntervalClosedClosed` +// +// where "open" refers to an exclusive value (excluded) from the output, while +// "closed" refers to an inclusive value (included) from the output. +// +// In the absence of an explicit return type `T`, `absl::Uniform()` will deduce +// the return type based on the provided endpoint arguments {A lo, B hi}. +// Given these endpoints, one of {A, B} will be chosen as the return type, if +// a type can be implicitly converted into the other in a lossless way. The +// lack of any such implicit conversion between {A, B} will produce a +// compile-time error +// +// See https://en.wikipedia.org/wiki/Uniform_distribution_(continuous) +// +// Example: +// +// absl::BitGen bitgen; +// +// // Produce a random float value between 0.0 and 1.0, inclusive +// auto x = absl::Uniform(absl::IntervalClosedClosed, bitgen, 0.0f, 1.0f); +// +// // The most common interval of `absl::IntervalClosedOpen` is available by +// // default: +// +// auto x = absl::Uniform(bitgen, 0.0f, 1.0f); +// +// // Return-types are typically inferred from the arguments, however callers +// // can optionally provide an explicit return-type to the template. +// +// auto x = absl::Uniform<float>(bitgen, 0, 1); +// +template <typename R = void, typename TagType, typename URBG> +typename absl::enable_if_t<!std::is_same<R, void>::value, R> // +Uniform(TagType tag, + URBG&& urbg, // NOLINT(runtime/references) + R lo, R hi) { + using gen_t = absl::decay_t<URBG>; + using distribution_t = random_internal::UniformDistributionWrapper<R>; + + auto a = random_internal::uniform_lower_bound(tag, lo, hi); + auto b = random_internal::uniform_upper_bound(tag, lo, hi); if (!random_internal::is_uniform_range_valid(a, b)) return lo; - - return random_internal::DistributionCaller<gen_t>::template Call< + + return random_internal::DistributionCaller<gen_t>::template Call< distribution_t>(&urbg, tag, lo, hi); -} - -// absl::Uniform<T>(bitgen, lo, hi) -// -// Overload of `Uniform()` using the default closed-open interval of [lo, hi), -// and returning values of type `T` -template <typename R = void, typename URBG> -typename absl::enable_if_t<!std::is_same<R, void>::value, R> // -Uniform(URBG&& urbg, // NOLINT(runtime/references) - R lo, R hi) { - using gen_t = absl::decay_t<URBG>; - using distribution_t = random_internal::UniformDistributionWrapper<R>; +} + +// absl::Uniform<T>(bitgen, lo, hi) +// +// Overload of `Uniform()` using the default closed-open interval of [lo, hi), +// and returning values of type `T` +template <typename R = void, typename URBG> +typename absl::enable_if_t<!std::is_same<R, void>::value, R> // +Uniform(URBG&& urbg, // NOLINT(runtime/references) + R lo, R hi) { + using gen_t = absl::decay_t<URBG>; + using distribution_t = random_internal::UniformDistributionWrapper<R>; constexpr auto tag = absl::IntervalClosedOpen; - - auto a = random_internal::uniform_lower_bound(tag, lo, hi); - auto b = random_internal::uniform_upper_bound(tag, lo, hi); + + auto a = random_internal::uniform_lower_bound(tag, lo, hi); + auto b = random_internal::uniform_upper_bound(tag, lo, hi); if (!random_internal::is_uniform_range_valid(a, b)) return lo; - - return random_internal::DistributionCaller<gen_t>::template Call< + + return random_internal::DistributionCaller<gen_t>::template Call< distribution_t>(&urbg, lo, hi); -} - -// absl::Uniform(tag, bitgen, lo, hi) -// -// Overload of `Uniform()` using different (but compatible) lo, hi types. Note -// that a compile-error will result if the return type cannot be deduced -// correctly from the passed types. -template <typename R = void, typename TagType, typename URBG, typename A, - typename B> -typename absl::enable_if_t<std::is_same<R, void>::value, - random_internal::uniform_inferred_return_t<A, B>> -Uniform(TagType tag, - URBG&& urbg, // NOLINT(runtime/references) - A lo, B hi) { - using gen_t = absl::decay_t<URBG>; - using return_t = typename random_internal::uniform_inferred_return_t<A, B>; - using distribution_t = random_internal::UniformDistributionWrapper<return_t>; - - auto a = random_internal::uniform_lower_bound<return_t>(tag, lo, hi); - auto b = random_internal::uniform_upper_bound<return_t>(tag, lo, hi); +} + +// absl::Uniform(tag, bitgen, lo, hi) +// +// Overload of `Uniform()` using different (but compatible) lo, hi types. Note +// that a compile-error will result if the return type cannot be deduced +// correctly from the passed types. +template <typename R = void, typename TagType, typename URBG, typename A, + typename B> +typename absl::enable_if_t<std::is_same<R, void>::value, + random_internal::uniform_inferred_return_t<A, B>> +Uniform(TagType tag, + URBG&& urbg, // NOLINT(runtime/references) + A lo, B hi) { + using gen_t = absl::decay_t<URBG>; + using return_t = typename random_internal::uniform_inferred_return_t<A, B>; + using distribution_t = random_internal::UniformDistributionWrapper<return_t>; + + auto a = random_internal::uniform_lower_bound<return_t>(tag, lo, hi); + auto b = random_internal::uniform_upper_bound<return_t>(tag, lo, hi); if (!random_internal::is_uniform_range_valid(a, b)) return lo; - - return random_internal::DistributionCaller<gen_t>::template Call< + + return random_internal::DistributionCaller<gen_t>::template Call< distribution_t>(&urbg, tag, static_cast<return_t>(lo), - static_cast<return_t>(hi)); -} - -// absl::Uniform(bitgen, lo, hi) -// -// Overload of `Uniform()` using different (but compatible) lo, hi types and the -// default closed-open interval of [lo, hi). Note that a compile-error will -// result if the return type cannot be deduced correctly from the passed types. -template <typename R = void, typename URBG, typename A, typename B> -typename absl::enable_if_t<std::is_same<R, void>::value, - random_internal::uniform_inferred_return_t<A, B>> -Uniform(URBG&& urbg, // NOLINT(runtime/references) - A lo, B hi) { - using gen_t = absl::decay_t<URBG>; - using return_t = typename random_internal::uniform_inferred_return_t<A, B>; - using distribution_t = random_internal::UniformDistributionWrapper<return_t>; - - constexpr auto tag = absl::IntervalClosedOpen; - auto a = random_internal::uniform_lower_bound<return_t>(tag, lo, hi); - auto b = random_internal::uniform_upper_bound<return_t>(tag, lo, hi); + static_cast<return_t>(hi)); +} + +// absl::Uniform(bitgen, lo, hi) +// +// Overload of `Uniform()` using different (but compatible) lo, hi types and the +// default closed-open interval of [lo, hi). Note that a compile-error will +// result if the return type cannot be deduced correctly from the passed types. +template <typename R = void, typename URBG, typename A, typename B> +typename absl::enable_if_t<std::is_same<R, void>::value, + random_internal::uniform_inferred_return_t<A, B>> +Uniform(URBG&& urbg, // NOLINT(runtime/references) + A lo, B hi) { + using gen_t = absl::decay_t<URBG>; + using return_t = typename random_internal::uniform_inferred_return_t<A, B>; + using distribution_t = random_internal::UniformDistributionWrapper<return_t>; + + constexpr auto tag = absl::IntervalClosedOpen; + auto a = random_internal::uniform_lower_bound<return_t>(tag, lo, hi); + auto b = random_internal::uniform_upper_bound<return_t>(tag, lo, hi); if (!random_internal::is_uniform_range_valid(a, b)) return lo; - - return random_internal::DistributionCaller<gen_t>::template Call< + + return random_internal::DistributionCaller<gen_t>::template Call< distribution_t>(&urbg, static_cast<return_t>(lo), - static_cast<return_t>(hi)); -} - -// absl::Uniform<unsigned T>(bitgen) -// -// Overload of Uniform() using the minimum and maximum values of a given type -// `T` (which must be unsigned), returning a value of type `unsigned T` -template <typename R, typename URBG> -typename absl::enable_if_t<!std::is_signed<R>::value, R> // -Uniform(URBG&& urbg) { // NOLINT(runtime/references) - using gen_t = absl::decay_t<URBG>; - using distribution_t = random_internal::UniformDistributionWrapper<R>; - - return random_internal::DistributionCaller<gen_t>::template Call< + static_cast<return_t>(hi)); +} + +// absl::Uniform<unsigned T>(bitgen) +// +// Overload of Uniform() using the minimum and maximum values of a given type +// `T` (which must be unsigned), returning a value of type `unsigned T` +template <typename R, typename URBG> +typename absl::enable_if_t<!std::is_signed<R>::value, R> // +Uniform(URBG&& urbg) { // NOLINT(runtime/references) + using gen_t = absl::decay_t<URBG>; + using distribution_t = random_internal::UniformDistributionWrapper<R>; + + return random_internal::DistributionCaller<gen_t>::template Call< distribution_t>(&urbg); -} - -// ----------------------------------------------------------------------------- -// absl::Bernoulli(bitgen, p) -// ----------------------------------------------------------------------------- -// -// `absl::Bernoulli` produces a random boolean value, with probability `p` -// (where 0.0 <= p <= 1.0) equaling `true`. -// -// Prefer `absl::Bernoulli` to produce boolean values over other alternatives -// such as comparing an `absl::Uniform()` value to a specific output. -// -// See https://en.wikipedia.org/wiki/Bernoulli_distribution -// -// Example: -// -// absl::BitGen bitgen; -// ... -// if (absl::Bernoulli(bitgen, 1.0/3721.0)) { -// std::cout << "Asteroid field navigation successful."; -// } -// -template <typename URBG> -bool Bernoulli(URBG&& urbg, // NOLINT(runtime/references) - double p) { - using gen_t = absl::decay_t<URBG>; - using distribution_t = absl::bernoulli_distribution; - - return random_internal::DistributionCaller<gen_t>::template Call< +} + +// ----------------------------------------------------------------------------- +// absl::Bernoulli(bitgen, p) +// ----------------------------------------------------------------------------- +// +// `absl::Bernoulli` produces a random boolean value, with probability `p` +// (where 0.0 <= p <= 1.0) equaling `true`. +// +// Prefer `absl::Bernoulli` to produce boolean values over other alternatives +// such as comparing an `absl::Uniform()` value to a specific output. +// +// See https://en.wikipedia.org/wiki/Bernoulli_distribution +// +// Example: +// +// absl::BitGen bitgen; +// ... +// if (absl::Bernoulli(bitgen, 1.0/3721.0)) { +// std::cout << "Asteroid field navigation successful."; +// } +// +template <typename URBG> +bool Bernoulli(URBG&& urbg, // NOLINT(runtime/references) + double p) { + using gen_t = absl::decay_t<URBG>; + using distribution_t = absl::bernoulli_distribution; + + return random_internal::DistributionCaller<gen_t>::template Call< distribution_t>(&urbg, p); -} - -// ----------------------------------------------------------------------------- -// absl::Beta<T>(bitgen, alpha, beta) -// ----------------------------------------------------------------------------- -// -// `absl::Beta` produces a floating point number distributed in the closed -// interval [0,1] and parameterized by two values `alpha` and `beta` as per a -// Beta distribution. `T` must be a floating point type, but may be inferred -// from the types of `alpha` and `beta`. -// -// See https://en.wikipedia.org/wiki/Beta_distribution. -// -// Example: -// -// absl::BitGen bitgen; -// ... -// double sample = absl::Beta(bitgen, 3.0, 2.0); -// -template <typename RealType, typename URBG> -RealType Beta(URBG&& urbg, // NOLINT(runtime/references) - RealType alpha, RealType beta) { - static_assert( - std::is_floating_point<RealType>::value, - "Template-argument 'RealType' must be a floating-point type, in " - "absl::Beta<RealType, URBG>(...)"); - - using gen_t = absl::decay_t<URBG>; - using distribution_t = typename absl::beta_distribution<RealType>; - - return random_internal::DistributionCaller<gen_t>::template Call< +} + +// ----------------------------------------------------------------------------- +// absl::Beta<T>(bitgen, alpha, beta) +// ----------------------------------------------------------------------------- +// +// `absl::Beta` produces a floating point number distributed in the closed +// interval [0,1] and parameterized by two values `alpha` and `beta` as per a +// Beta distribution. `T` must be a floating point type, but may be inferred +// from the types of `alpha` and `beta`. +// +// See https://en.wikipedia.org/wiki/Beta_distribution. +// +// Example: +// +// absl::BitGen bitgen; +// ... +// double sample = absl::Beta(bitgen, 3.0, 2.0); +// +template <typename RealType, typename URBG> +RealType Beta(URBG&& urbg, // NOLINT(runtime/references) + RealType alpha, RealType beta) { + static_assert( + std::is_floating_point<RealType>::value, + "Template-argument 'RealType' must be a floating-point type, in " + "absl::Beta<RealType, URBG>(...)"); + + using gen_t = absl::decay_t<URBG>; + using distribution_t = typename absl::beta_distribution<RealType>; + + return random_internal::DistributionCaller<gen_t>::template Call< distribution_t>(&urbg, alpha, beta); -} - -// ----------------------------------------------------------------------------- -// absl::Exponential<T>(bitgen, lambda = 1) -// ----------------------------------------------------------------------------- -// +} + +// ----------------------------------------------------------------------------- +// absl::Exponential<T>(bitgen, lambda = 1) +// ----------------------------------------------------------------------------- +// // `absl::Exponential` produces a floating point number representing the // distance (time) between two consecutive events in a point process of events // occurring continuously and independently at a constant average rate. `T` must // be a floating point type, but may be inferred from the type of `lambda`. -// -// See https://en.wikipedia.org/wiki/Exponential_distribution. -// -// Example: -// -// absl::BitGen bitgen; -// ... -// double call_length = absl::Exponential(bitgen, 7.0); -// -template <typename RealType, typename URBG> -RealType Exponential(URBG&& urbg, // NOLINT(runtime/references) - RealType lambda = 1) { - static_assert( - std::is_floating_point<RealType>::value, - "Template-argument 'RealType' must be a floating-point type, in " - "absl::Exponential<RealType, URBG>(...)"); - - using gen_t = absl::decay_t<URBG>; - using distribution_t = typename absl::exponential_distribution<RealType>; - - return random_internal::DistributionCaller<gen_t>::template Call< +// +// See https://en.wikipedia.org/wiki/Exponential_distribution. +// +// Example: +// +// absl::BitGen bitgen; +// ... +// double call_length = absl::Exponential(bitgen, 7.0); +// +template <typename RealType, typename URBG> +RealType Exponential(URBG&& urbg, // NOLINT(runtime/references) + RealType lambda = 1) { + static_assert( + std::is_floating_point<RealType>::value, + "Template-argument 'RealType' must be a floating-point type, in " + "absl::Exponential<RealType, URBG>(...)"); + + using gen_t = absl::decay_t<URBG>; + using distribution_t = typename absl::exponential_distribution<RealType>; + + return random_internal::DistributionCaller<gen_t>::template Call< distribution_t>(&urbg, lambda); -} - -// ----------------------------------------------------------------------------- -// absl::Gaussian<T>(bitgen, mean = 0, stddev = 1) -// ----------------------------------------------------------------------------- -// -// `absl::Gaussian` produces a floating point number selected from the Gaussian -// (ie. "Normal") distribution. `T` must be a floating point type, but may be -// inferred from the types of `mean` and `stddev`. -// -// See https://en.wikipedia.org/wiki/Normal_distribution -// -// Example: -// -// absl::BitGen bitgen; -// ... -// double giraffe_height = absl::Gaussian(bitgen, 16.3, 3.3); -// -template <typename RealType, typename URBG> -RealType Gaussian(URBG&& urbg, // NOLINT(runtime/references) - RealType mean = 0, RealType stddev = 1) { - static_assert( - std::is_floating_point<RealType>::value, - "Template-argument 'RealType' must be a floating-point type, in " - "absl::Gaussian<RealType, URBG>(...)"); - - using gen_t = absl::decay_t<URBG>; - using distribution_t = typename absl::gaussian_distribution<RealType>; - - return random_internal::DistributionCaller<gen_t>::template Call< +} + +// ----------------------------------------------------------------------------- +// absl::Gaussian<T>(bitgen, mean = 0, stddev = 1) +// ----------------------------------------------------------------------------- +// +// `absl::Gaussian` produces a floating point number selected from the Gaussian +// (ie. "Normal") distribution. `T` must be a floating point type, but may be +// inferred from the types of `mean` and `stddev`. +// +// See https://en.wikipedia.org/wiki/Normal_distribution +// +// Example: +// +// absl::BitGen bitgen; +// ... +// double giraffe_height = absl::Gaussian(bitgen, 16.3, 3.3); +// +template <typename RealType, typename URBG> +RealType Gaussian(URBG&& urbg, // NOLINT(runtime/references) + RealType mean = 0, RealType stddev = 1) { + static_assert( + std::is_floating_point<RealType>::value, + "Template-argument 'RealType' must be a floating-point type, in " + "absl::Gaussian<RealType, URBG>(...)"); + + using gen_t = absl::decay_t<URBG>; + using distribution_t = typename absl::gaussian_distribution<RealType>; + + return random_internal::DistributionCaller<gen_t>::template Call< distribution_t>(&urbg, mean, stddev); -} - -// ----------------------------------------------------------------------------- -// absl::LogUniform<T>(bitgen, lo, hi, base = 2) -// ----------------------------------------------------------------------------- -// -// `absl::LogUniform` produces random values distributed where the log to a -// given base of all values is uniform in a closed interval [lo, hi]. `T` must -// be an integral type, but may be inferred from the types of `lo` and `hi`. -// -// I.e., `LogUniform(0, n, b)` is uniformly distributed across buckets -// [0], [1, b-1], [b, b^2-1] .. [b^(k-1), (b^k)-1] .. [b^floor(log(n, b)), n] -// and is uniformly distributed within each bucket. -// -// The resulting probability density is inversely related to bucket size, though -// values in the final bucket may be more likely than previous values. (In the -// extreme case where n = b^i the final value will be tied with zero as the most -// probable result. -// -// If `lo` is nonzero then this distribution is shifted to the desired interval, -// so LogUniform(lo, hi, b) is equivalent to LogUniform(0, hi-lo, b)+lo. -// -// See http://ecolego.facilia.se/ecolego/show/Log-Uniform%20Distribution -// -// Example: -// -// absl::BitGen bitgen; -// ... -// int v = absl::LogUniform(bitgen, 0, 1000); -// -template <typename IntType, typename URBG> -IntType LogUniform(URBG&& urbg, // NOLINT(runtime/references) - IntType lo, IntType hi, IntType base = 2) { - static_assert(std::is_integral<IntType>::value, - "Template-argument 'IntType' must be an integral type, in " - "absl::LogUniform<IntType, URBG>(...)"); - - using gen_t = absl::decay_t<URBG>; - using distribution_t = typename absl::log_uniform_int_distribution<IntType>; - - return random_internal::DistributionCaller<gen_t>::template Call< +} + +// ----------------------------------------------------------------------------- +// absl::LogUniform<T>(bitgen, lo, hi, base = 2) +// ----------------------------------------------------------------------------- +// +// `absl::LogUniform` produces random values distributed where the log to a +// given base of all values is uniform in a closed interval [lo, hi]. `T` must +// be an integral type, but may be inferred from the types of `lo` and `hi`. +// +// I.e., `LogUniform(0, n, b)` is uniformly distributed across buckets +// [0], [1, b-1], [b, b^2-1] .. [b^(k-1), (b^k)-1] .. [b^floor(log(n, b)), n] +// and is uniformly distributed within each bucket. +// +// The resulting probability density is inversely related to bucket size, though +// values in the final bucket may be more likely than previous values. (In the +// extreme case where n = b^i the final value will be tied with zero as the most +// probable result. +// +// If `lo` is nonzero then this distribution is shifted to the desired interval, +// so LogUniform(lo, hi, b) is equivalent to LogUniform(0, hi-lo, b)+lo. +// +// See http://ecolego.facilia.se/ecolego/show/Log-Uniform%20Distribution +// +// Example: +// +// absl::BitGen bitgen; +// ... +// int v = absl::LogUniform(bitgen, 0, 1000); +// +template <typename IntType, typename URBG> +IntType LogUniform(URBG&& urbg, // NOLINT(runtime/references) + IntType lo, IntType hi, IntType base = 2) { + static_assert(std::is_integral<IntType>::value, + "Template-argument 'IntType' must be an integral type, in " + "absl::LogUniform<IntType, URBG>(...)"); + + using gen_t = absl::decay_t<URBG>; + using distribution_t = typename absl::log_uniform_int_distribution<IntType>; + + return random_internal::DistributionCaller<gen_t>::template Call< distribution_t>(&urbg, lo, hi, base); -} - -// ----------------------------------------------------------------------------- -// absl::Poisson<T>(bitgen, mean = 1) -// ----------------------------------------------------------------------------- -// -// `absl::Poisson` produces discrete probabilities for a given number of events -// occurring within a fixed interval within the closed interval [0, max]. `T` -// must be an integral type. -// -// See https://en.wikipedia.org/wiki/Poisson_distribution -// -// Example: -// -// absl::BitGen bitgen; -// ... -// int requests_per_minute = absl::Poisson<int>(bitgen, 3.2); -// -template <typename IntType, typename URBG> -IntType Poisson(URBG&& urbg, // NOLINT(runtime/references) - double mean = 1.0) { - static_assert(std::is_integral<IntType>::value, - "Template-argument 'IntType' must be an integral type, in " - "absl::Poisson<IntType, URBG>(...)"); - - using gen_t = absl::decay_t<URBG>; - using distribution_t = typename absl::poisson_distribution<IntType>; - - return random_internal::DistributionCaller<gen_t>::template Call< +} + +// ----------------------------------------------------------------------------- +// absl::Poisson<T>(bitgen, mean = 1) +// ----------------------------------------------------------------------------- +// +// `absl::Poisson` produces discrete probabilities for a given number of events +// occurring within a fixed interval within the closed interval [0, max]. `T` +// must be an integral type. +// +// See https://en.wikipedia.org/wiki/Poisson_distribution +// +// Example: +// +// absl::BitGen bitgen; +// ... +// int requests_per_minute = absl::Poisson<int>(bitgen, 3.2); +// +template <typename IntType, typename URBG> +IntType Poisson(URBG&& urbg, // NOLINT(runtime/references) + double mean = 1.0) { + static_assert(std::is_integral<IntType>::value, + "Template-argument 'IntType' must be an integral type, in " + "absl::Poisson<IntType, URBG>(...)"); + + using gen_t = absl::decay_t<URBG>; + using distribution_t = typename absl::poisson_distribution<IntType>; + + return random_internal::DistributionCaller<gen_t>::template Call< distribution_t>(&urbg, mean); -} - -// ----------------------------------------------------------------------------- -// absl::Zipf<T>(bitgen, hi = max, q = 2, v = 1) -// ----------------------------------------------------------------------------- -// -// `absl::Zipf` produces discrete probabilities commonly used for modelling of -// rare events over the closed interval [0, hi]. The parameters `v` and `q` -// determine the skew of the distribution. `T` must be an integral type, but -// may be inferred from the type of `hi`. -// -// See http://mathworld.wolfram.com/ZipfDistribution.html -// -// Example: -// -// absl::BitGen bitgen; -// ... -// int term_rank = absl::Zipf<int>(bitgen); -// -template <typename IntType, typename URBG> -IntType Zipf(URBG&& urbg, // NOLINT(runtime/references) - IntType hi = (std::numeric_limits<IntType>::max)(), double q = 2.0, - double v = 1.0) { - static_assert(std::is_integral<IntType>::value, - "Template-argument 'IntType' must be an integral type, in " - "absl::Zipf<IntType, URBG>(...)"); - - using gen_t = absl::decay_t<URBG>; - using distribution_t = typename absl::zipf_distribution<IntType>; - - return random_internal::DistributionCaller<gen_t>::template Call< +} + +// ----------------------------------------------------------------------------- +// absl::Zipf<T>(bitgen, hi = max, q = 2, v = 1) +// ----------------------------------------------------------------------------- +// +// `absl::Zipf` produces discrete probabilities commonly used for modelling of +// rare events over the closed interval [0, hi]. The parameters `v` and `q` +// determine the skew of the distribution. `T` must be an integral type, but +// may be inferred from the type of `hi`. +// +// See http://mathworld.wolfram.com/ZipfDistribution.html +// +// Example: +// +// absl::BitGen bitgen; +// ... +// int term_rank = absl::Zipf<int>(bitgen); +// +template <typename IntType, typename URBG> +IntType Zipf(URBG&& urbg, // NOLINT(runtime/references) + IntType hi = (std::numeric_limits<IntType>::max)(), double q = 2.0, + double v = 1.0) { + static_assert(std::is_integral<IntType>::value, + "Template-argument 'IntType' must be an integral type, in " + "absl::Zipf<IntType, URBG>(...)"); + + using gen_t = absl::decay_t<URBG>; + using distribution_t = typename absl::zipf_distribution<IntType>; + + return random_internal::DistributionCaller<gen_t>::template Call< distribution_t>(&urbg, hi, q, v); -} - +} + ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_DISTRIBUTIONS_H_ +} // namespace absl + +#endif // ABSL_RANDOM_DISTRIBUTIONS_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/exponential_distribution.h b/contrib/restricted/abseil-cpp/absl/random/exponential_distribution.h index aff1c481f0..b5caf8a1e1 100644 --- a/contrib/restricted/abseil-cpp/absl/random/exponential_distribution.h +++ b/contrib/restricted/abseil-cpp/absl/random/exponential_distribution.h @@ -1,165 +1,165 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_EXPONENTIAL_DISTRIBUTION_H_ -#define ABSL_RANDOM_EXPONENTIAL_DISTRIBUTION_H_ - -#include <cassert> -#include <cmath> -#include <istream> -#include <limits> -#include <type_traits> - -#include "absl/meta/type_traits.h" -#include "absl/random/internal/fast_uniform_bits.h" -#include "absl/random/internal/generate_real.h" -#include "absl/random/internal/iostream_state_saver.h" - -namespace absl { +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_EXPONENTIAL_DISTRIBUTION_H_ +#define ABSL_RANDOM_EXPONENTIAL_DISTRIBUTION_H_ + +#include <cassert> +#include <cmath> +#include <istream> +#include <limits> +#include <type_traits> + +#include "absl/meta/type_traits.h" +#include "absl/random/internal/fast_uniform_bits.h" +#include "absl/random/internal/generate_real.h" +#include "absl/random/internal/iostream_state_saver.h" + +namespace absl { ABSL_NAMESPACE_BEGIN - -// absl::exponential_distribution: -// Generates a number conforming to an exponential distribution and is -// equivalent to the standard [rand.dist.pois.exp] distribution. -template <typename RealType = double> -class exponential_distribution { - public: - using result_type = RealType; - - class param_type { - public: - using distribution_type = exponential_distribution; - - explicit param_type(result_type lambda = 1) : lambda_(lambda) { - assert(lambda > 0); - neg_inv_lambda_ = -result_type(1) / lambda_; - } - - result_type lambda() const { return lambda_; } - - friend bool operator==(const param_type& a, const param_type& b) { - return a.lambda_ == b.lambda_; - } - - friend bool operator!=(const param_type& a, const param_type& b) { - return !(a == b); - } - - private: - friend class exponential_distribution; - - result_type lambda_; - result_type neg_inv_lambda_; - - static_assert( - std::is_floating_point<RealType>::value, - "Class-template absl::exponential_distribution<> must be parameterized " - "using a floating-point type."); - }; - - exponential_distribution() : exponential_distribution(1) {} - - explicit exponential_distribution(result_type lambda) : param_(lambda) {} - - explicit exponential_distribution(const param_type& p) : param_(p) {} - - void reset() {} - - // Generating functions - template <typename URBG> - result_type operator()(URBG& g) { // NOLINT(runtime/references) - return (*this)(g, param_); - } - - template <typename URBG> - result_type operator()(URBG& g, // NOLINT(runtime/references) - const param_type& p); - - param_type param() const { return param_; } - void param(const param_type& p) { param_ = p; } - - result_type(min)() const { return 0; } - result_type(max)() const { - return std::numeric_limits<result_type>::infinity(); - } - - result_type lambda() const { return param_.lambda(); } - - friend bool operator==(const exponential_distribution& a, - const exponential_distribution& b) { - return a.param_ == b.param_; - } - friend bool operator!=(const exponential_distribution& a, - const exponential_distribution& b) { - return a.param_ != b.param_; - } - - private: - param_type param_; - random_internal::FastUniformBits<uint64_t> fast_u64_; -}; - -// -------------------------------------------------------------------------- -// Implementation details follow -// -------------------------------------------------------------------------- - -template <typename RealType> -template <typename URBG> -typename exponential_distribution<RealType>::result_type -exponential_distribution<RealType>::operator()( - URBG& g, // NOLINT(runtime/references) - const param_type& p) { - using random_internal::GenerateNegativeTag; - using random_internal::GenerateRealFromBits; - using real_type = - absl::conditional_t<std::is_same<RealType, float>::value, float, double>; - - const result_type u = GenerateRealFromBits<real_type, GenerateNegativeTag, - false>(fast_u64_(g)); // U(-1, 0) - - // log1p(-x) is mathematically equivalent to log(1 - x) but has more - // accuracy for x near zero. - return p.neg_inv_lambda_ * std::log1p(u); -} - -template <typename CharT, typename Traits, typename RealType> -std::basic_ostream<CharT, Traits>& operator<<( - std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) - const exponential_distribution<RealType>& x) { - auto saver = random_internal::make_ostream_state_saver(os); - os.precision(random_internal::stream_precision_helper<RealType>::kPrecision); - os << x.lambda(); - return os; -} - -template <typename CharT, typename Traits, typename RealType> -std::basic_istream<CharT, Traits>& operator>>( - std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) - exponential_distribution<RealType>& x) { // NOLINT(runtime/references) - using result_type = typename exponential_distribution<RealType>::result_type; - using param_type = typename exponential_distribution<RealType>::param_type; - result_type lambda; - - auto saver = random_internal::make_istream_state_saver(is); - lambda = random_internal::read_floating_point<result_type>(is); - if (!is.fail()) { - x.param(param_type(lambda)); - } - return is; -} - + +// absl::exponential_distribution: +// Generates a number conforming to an exponential distribution and is +// equivalent to the standard [rand.dist.pois.exp] distribution. +template <typename RealType = double> +class exponential_distribution { + public: + using result_type = RealType; + + class param_type { + public: + using distribution_type = exponential_distribution; + + explicit param_type(result_type lambda = 1) : lambda_(lambda) { + assert(lambda > 0); + neg_inv_lambda_ = -result_type(1) / lambda_; + } + + result_type lambda() const { return lambda_; } + + friend bool operator==(const param_type& a, const param_type& b) { + return a.lambda_ == b.lambda_; + } + + friend bool operator!=(const param_type& a, const param_type& b) { + return !(a == b); + } + + private: + friend class exponential_distribution; + + result_type lambda_; + result_type neg_inv_lambda_; + + static_assert( + std::is_floating_point<RealType>::value, + "Class-template absl::exponential_distribution<> must be parameterized " + "using a floating-point type."); + }; + + exponential_distribution() : exponential_distribution(1) {} + + explicit exponential_distribution(result_type lambda) : param_(lambda) {} + + explicit exponential_distribution(const param_type& p) : param_(p) {} + + void reset() {} + + // Generating functions + template <typename URBG> + result_type operator()(URBG& g) { // NOLINT(runtime/references) + return (*this)(g, param_); + } + + template <typename URBG> + result_type operator()(URBG& g, // NOLINT(runtime/references) + const param_type& p); + + param_type param() const { return param_; } + void param(const param_type& p) { param_ = p; } + + result_type(min)() const { return 0; } + result_type(max)() const { + return std::numeric_limits<result_type>::infinity(); + } + + result_type lambda() const { return param_.lambda(); } + + friend bool operator==(const exponential_distribution& a, + const exponential_distribution& b) { + return a.param_ == b.param_; + } + friend bool operator!=(const exponential_distribution& a, + const exponential_distribution& b) { + return a.param_ != b.param_; + } + + private: + param_type param_; + random_internal::FastUniformBits<uint64_t> fast_u64_; +}; + +// -------------------------------------------------------------------------- +// Implementation details follow +// -------------------------------------------------------------------------- + +template <typename RealType> +template <typename URBG> +typename exponential_distribution<RealType>::result_type +exponential_distribution<RealType>::operator()( + URBG& g, // NOLINT(runtime/references) + const param_type& p) { + using random_internal::GenerateNegativeTag; + using random_internal::GenerateRealFromBits; + using real_type = + absl::conditional_t<std::is_same<RealType, float>::value, float, double>; + + const result_type u = GenerateRealFromBits<real_type, GenerateNegativeTag, + false>(fast_u64_(g)); // U(-1, 0) + + // log1p(-x) is mathematically equivalent to log(1 - x) but has more + // accuracy for x near zero. + return p.neg_inv_lambda_ * std::log1p(u); +} + +template <typename CharT, typename Traits, typename RealType> +std::basic_ostream<CharT, Traits>& operator<<( + std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) + const exponential_distribution<RealType>& x) { + auto saver = random_internal::make_ostream_state_saver(os); + os.precision(random_internal::stream_precision_helper<RealType>::kPrecision); + os << x.lambda(); + return os; +} + +template <typename CharT, typename Traits, typename RealType> +std::basic_istream<CharT, Traits>& operator>>( + std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) + exponential_distribution<RealType>& x) { // NOLINT(runtime/references) + using result_type = typename exponential_distribution<RealType>::result_type; + using param_type = typename exponential_distribution<RealType>::param_type; + result_type lambda; + + auto saver = random_internal::make_istream_state_saver(is); + lambda = random_internal::read_floating_point<result_type>(is); + if (!is.fail()) { + x.param(param_type(lambda)); + } + return is; +} + ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_EXPONENTIAL_DISTRIBUTION_H_ +} // namespace absl + +#endif // ABSL_RANDOM_EXPONENTIAL_DISTRIBUTION_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/gaussian_distribution.cc b/contrib/restricted/abseil-cpp/absl/random/gaussian_distribution.cc index 4d1ba4d893..c7a72cb2f6 100644 --- a/contrib/restricted/abseil-cpp/absl/random/gaussian_distribution.cc +++ b/contrib/restricted/abseil-cpp/absl/random/gaussian_distribution.cc @@ -1,104 +1,104 @@ -// BEGIN GENERATED CODE; DO NOT EDIT -// clang-format off - -#include "absl/random/gaussian_distribution.h" - -namespace absl { +// BEGIN GENERATED CODE; DO NOT EDIT +// clang-format off + +#include "absl/random/gaussian_distribution.h" + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - -const gaussian_distribution_base::Tables - gaussian_distribution_base::zg_ = { - {3.7130862467425505, 3.442619855899000214, 3.223084984581141565, - 3.083228858216868318, 2.978696252647779819, 2.894344007021528942, - 2.82312535054891045, 2.761169372387176857, 2.706113573121819549, - 2.656406411261359679, 2.610972248431847387, 2.56903362592493778, - 2.530009672388827457, 2.493454522095372106, 2.459018177411830486, - 2.426420645533749809, 2.395434278011062457, 2.365871370117638595, - 2.337575241339236776, 2.310413683698762988, 2.284274059677471769, - 2.25905957386919809, 2.234686395590979036, 2.21108140887870297, - 2.188180432076048731, 2.165926793748921497, 2.144270182360394905, - 2.123165708673976138, 2.102573135189237608, 2.082456237992015957, - 2.062782274508307978, 2.043521536655067194, 2.02464697337738464, - 2.006133869963471206, 1.987959574127619033, 1.970103260854325633, - 1.952545729553555764, 1.935269228296621957, 1.918257300864508963, - 1.901494653105150423, 1.884967035707758143, 1.868661140994487768, - 1.852564511728090002, 1.836665460258444904, 1.820952996596124418, - 1.805416764219227366, 1.790046982599857506, 1.77483439558606837, - 1.759770224899592339, 1.744846128113799244, 1.730054160563729182, - 1.71538674071366648, 1.700836618569915748, 1.686396846779167014, - 1.6720607540975998, 1.657821920954023254, 1.643674156862867441, - 1.629611479470633562, 1.615628095043159629, 1.601718380221376581, - 1.587876864890574558, 1.574098216022999264, 1.560377222366167382, - 1.546708779859908844, 1.533087877674041755, 1.519509584765938559, - 1.505969036863201937, 1.492461423781352714, 1.478981976989922842, - 1.465525957342709296, 1.452088642889222792, 1.438665316684561546, - 1.425251254514058319, 1.411841712447055919, 1.398431914131003539, - 1.385017037732650058, 1.371592202427340812, 1.358152454330141534, - 1.34469275175354519, 1.331207949665625279, 1.317692783209412299, - 1.304141850128615054, 1.290549591926194894, 1.27691027356015363, - 1.263217961454619287, 1.249466499573066436, 1.23564948326336066, - 1.221760230539994385, 1.207791750415947662, 1.193736707833126465, - 1.17958738466398616, 1.165335636164750222, 1.150972842148865416, - 1.136489852013158774, 1.121876922582540237, 1.107123647534034028, - 1.092218876907275371, 1.077150624892893482, 1.061905963694822042, - 1.046470900764042922, 1.030830236068192907, 1.014967395251327842, - 0.9988642334929808131, 0.9825008035154263464, 0.9658550794011470098, - 0.9489026255113034436, 0.9316161966151479401, 0.9139652510230292792, - 0.8959153525809346874, 0.8774274291129204872, 0.8584568431938099931, - 0.8389522142975741614, 0.8188539067003538507, 0.7980920606440534693, - 0.7765839878947563557, 0.7542306644540520688, 0.7309119106424850631, - 0.7064796113354325779, 0.6807479186691505202, 0.6534786387399710295, - 0.6243585973360461505, 0.5929629424714434327, 0.5586921784081798625, - 0.5206560387620546848, 0.4774378372966830431, 0.4265479863554152429, - 0.3628714310970211909, 0.2723208648139477384, 0}, - {0.001014352564120377413, 0.002669629083880922793, 0.005548995220771345792, - 0.008624484412859888607, 0.01183947865788486861, 0.01516729801054656976, - 0.01859210273701129151, 0.02210330461592709475, 0.02569329193593428151, - 0.02935631744000685023, 0.03308788614622575758, 0.03688438878665621645, - 0.04074286807444417458, 0.04466086220049143157, 0.04863629585986780496, - 0.05266740190305100461, 0.05675266348104984759, 0.06089077034804041277, - 0.06508058521306804567, 0.06932111739357792179, 0.07361150188411341722, - 0.07795098251397346301, 0.08233889824223575293, 0.08677467189478028919, - 0.09125780082683036809, 0.095787849121731522, 0.1003644410286559929, - 0.1049872554094214289, 0.1096560210148404546, 0.1143705124488661323, - 0.1191305467076509556, 0.1239359802028679736, 0.1287867061959434012, - 0.1336826525834396151, 0.1386237799845948804, 0.1436100800906280339, - 0.1486415742423425057, 0.1537183122081819397, 0.1588403711394795748, - 0.1640078546834206341, 0.1692208922373653057, 0.1744796383307898324, - 0.1797842721232958407, 0.1851349970089926078, 0.1905320403191375633, - 0.1959756531162781534, 0.2014661100743140865, 0.2070037094399269362, - 0.2125887730717307134, 0.2182216465543058426, 0.2239026993850088965, - 0.229632325232116602, 0.2354109422634795556, 0.2412389935454402889, - 0.2471169475123218551, 0.2530452985073261551, 0.2590245673962052742, - 0.2650553022555897087, 0.271138079138385224, 0.2772735029191887857, - 0.2834622082232336471, 0.2897048604429605656, 0.2960021568469337061, - 0.3023548277864842593, 0.3087636380061818397, 0.3152293880650116065, - 0.3217529158759855901, 0.3283350983728509642, 0.3349768533135899506, - 0.3416791412315512977, 0.3484429675463274756, 0.355269384847918035, - 0.3621594953693184626, 0.3691144536644731522, 0.376135469510563536, - 0.3832238110559021416, 0.3903808082373155797, 0.3976078564938743676, - 0.404906420807223999, 0.4122780401026620578, 0.4197243320495753771, - 0.4272469983049970721, 0.4348478302499918513, 0.4425287152754694975, - 0.4502916436820402768, 0.458138716267873114, 0.4660721526894572309, - 0.4740943006930180559, 0.4822076463294863724, 0.4904148252838453348, - 0.4987186354709807201, 0.5071220510755701794, 0.5156282382440030565, - 0.5242405726729852944, 0.5329626593838373561, 0.5417983550254266145, - 0.5507517931146057588, 0.5598274127040882009, 0.5690299910679523787, - 0.5783646811197646898, 0.5878370544347081283, 0.5974531509445183408, - 0.6072195366251219584, 0.6171433708188825973, 0.6272324852499290282, - 0.6374954773350440806, 0.6479418211102242475, 0.6585820000500898219, - 0.6694276673488921414, 0.6804918409973358395, 0.6917891434366769676, - 0.7033360990161600101, 0.7151515074105005976, 0.7272569183441868201, - 0.7396772436726493094, 0.7524415591746134169, 0.7655841738977066102, - 0.7791460859296898134, 0.7931770117713072832, 0.8077382946829627652, - 0.8229072113814113187, 0.8387836052959920519, 0.8555006078694531446, - 0.873243048910072206, 0.8922816507840289901, 0.9130436479717434217, - 0.9362826816850632339, 0.9635996931270905952, 1}}; - -} // namespace random_internal +namespace random_internal { + +const gaussian_distribution_base::Tables + gaussian_distribution_base::zg_ = { + {3.7130862467425505, 3.442619855899000214, 3.223084984581141565, + 3.083228858216868318, 2.978696252647779819, 2.894344007021528942, + 2.82312535054891045, 2.761169372387176857, 2.706113573121819549, + 2.656406411261359679, 2.610972248431847387, 2.56903362592493778, + 2.530009672388827457, 2.493454522095372106, 2.459018177411830486, + 2.426420645533749809, 2.395434278011062457, 2.365871370117638595, + 2.337575241339236776, 2.310413683698762988, 2.284274059677471769, + 2.25905957386919809, 2.234686395590979036, 2.21108140887870297, + 2.188180432076048731, 2.165926793748921497, 2.144270182360394905, + 2.123165708673976138, 2.102573135189237608, 2.082456237992015957, + 2.062782274508307978, 2.043521536655067194, 2.02464697337738464, + 2.006133869963471206, 1.987959574127619033, 1.970103260854325633, + 1.952545729553555764, 1.935269228296621957, 1.918257300864508963, + 1.901494653105150423, 1.884967035707758143, 1.868661140994487768, + 1.852564511728090002, 1.836665460258444904, 1.820952996596124418, + 1.805416764219227366, 1.790046982599857506, 1.77483439558606837, + 1.759770224899592339, 1.744846128113799244, 1.730054160563729182, + 1.71538674071366648, 1.700836618569915748, 1.686396846779167014, + 1.6720607540975998, 1.657821920954023254, 1.643674156862867441, + 1.629611479470633562, 1.615628095043159629, 1.601718380221376581, + 1.587876864890574558, 1.574098216022999264, 1.560377222366167382, + 1.546708779859908844, 1.533087877674041755, 1.519509584765938559, + 1.505969036863201937, 1.492461423781352714, 1.478981976989922842, + 1.465525957342709296, 1.452088642889222792, 1.438665316684561546, + 1.425251254514058319, 1.411841712447055919, 1.398431914131003539, + 1.385017037732650058, 1.371592202427340812, 1.358152454330141534, + 1.34469275175354519, 1.331207949665625279, 1.317692783209412299, + 1.304141850128615054, 1.290549591926194894, 1.27691027356015363, + 1.263217961454619287, 1.249466499573066436, 1.23564948326336066, + 1.221760230539994385, 1.207791750415947662, 1.193736707833126465, + 1.17958738466398616, 1.165335636164750222, 1.150972842148865416, + 1.136489852013158774, 1.121876922582540237, 1.107123647534034028, + 1.092218876907275371, 1.077150624892893482, 1.061905963694822042, + 1.046470900764042922, 1.030830236068192907, 1.014967395251327842, + 0.9988642334929808131, 0.9825008035154263464, 0.9658550794011470098, + 0.9489026255113034436, 0.9316161966151479401, 0.9139652510230292792, + 0.8959153525809346874, 0.8774274291129204872, 0.8584568431938099931, + 0.8389522142975741614, 0.8188539067003538507, 0.7980920606440534693, + 0.7765839878947563557, 0.7542306644540520688, 0.7309119106424850631, + 0.7064796113354325779, 0.6807479186691505202, 0.6534786387399710295, + 0.6243585973360461505, 0.5929629424714434327, 0.5586921784081798625, + 0.5206560387620546848, 0.4774378372966830431, 0.4265479863554152429, + 0.3628714310970211909, 0.2723208648139477384, 0}, + {0.001014352564120377413, 0.002669629083880922793, 0.005548995220771345792, + 0.008624484412859888607, 0.01183947865788486861, 0.01516729801054656976, + 0.01859210273701129151, 0.02210330461592709475, 0.02569329193593428151, + 0.02935631744000685023, 0.03308788614622575758, 0.03688438878665621645, + 0.04074286807444417458, 0.04466086220049143157, 0.04863629585986780496, + 0.05266740190305100461, 0.05675266348104984759, 0.06089077034804041277, + 0.06508058521306804567, 0.06932111739357792179, 0.07361150188411341722, + 0.07795098251397346301, 0.08233889824223575293, 0.08677467189478028919, + 0.09125780082683036809, 0.095787849121731522, 0.1003644410286559929, + 0.1049872554094214289, 0.1096560210148404546, 0.1143705124488661323, + 0.1191305467076509556, 0.1239359802028679736, 0.1287867061959434012, + 0.1336826525834396151, 0.1386237799845948804, 0.1436100800906280339, + 0.1486415742423425057, 0.1537183122081819397, 0.1588403711394795748, + 0.1640078546834206341, 0.1692208922373653057, 0.1744796383307898324, + 0.1797842721232958407, 0.1851349970089926078, 0.1905320403191375633, + 0.1959756531162781534, 0.2014661100743140865, 0.2070037094399269362, + 0.2125887730717307134, 0.2182216465543058426, 0.2239026993850088965, + 0.229632325232116602, 0.2354109422634795556, 0.2412389935454402889, + 0.2471169475123218551, 0.2530452985073261551, 0.2590245673962052742, + 0.2650553022555897087, 0.271138079138385224, 0.2772735029191887857, + 0.2834622082232336471, 0.2897048604429605656, 0.2960021568469337061, + 0.3023548277864842593, 0.3087636380061818397, 0.3152293880650116065, + 0.3217529158759855901, 0.3283350983728509642, 0.3349768533135899506, + 0.3416791412315512977, 0.3484429675463274756, 0.355269384847918035, + 0.3621594953693184626, 0.3691144536644731522, 0.376135469510563536, + 0.3832238110559021416, 0.3903808082373155797, 0.3976078564938743676, + 0.404906420807223999, 0.4122780401026620578, 0.4197243320495753771, + 0.4272469983049970721, 0.4348478302499918513, 0.4425287152754694975, + 0.4502916436820402768, 0.458138716267873114, 0.4660721526894572309, + 0.4740943006930180559, 0.4822076463294863724, 0.4904148252838453348, + 0.4987186354709807201, 0.5071220510755701794, 0.5156282382440030565, + 0.5242405726729852944, 0.5329626593838373561, 0.5417983550254266145, + 0.5507517931146057588, 0.5598274127040882009, 0.5690299910679523787, + 0.5783646811197646898, 0.5878370544347081283, 0.5974531509445183408, + 0.6072195366251219584, 0.6171433708188825973, 0.6272324852499290282, + 0.6374954773350440806, 0.6479418211102242475, 0.6585820000500898219, + 0.6694276673488921414, 0.6804918409973358395, 0.6917891434366769676, + 0.7033360990161600101, 0.7151515074105005976, 0.7272569183441868201, + 0.7396772436726493094, 0.7524415591746134169, 0.7655841738977066102, + 0.7791460859296898134, 0.7931770117713072832, 0.8077382946829627652, + 0.8229072113814113187, 0.8387836052959920519, 0.8555006078694531446, + 0.873243048910072206, 0.8922816507840289901, 0.9130436479717434217, + 0.9362826816850632339, 0.9635996931270905952, 1}}; + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -// clang-format on -// END GENERATED CODE +} // namespace absl + +// clang-format on +// END GENERATED CODE diff --git a/contrib/restricted/abseil-cpp/absl/random/gaussian_distribution.h b/contrib/restricted/abseil-cpp/absl/random/gaussian_distribution.h index ed0d99bd9d..4b07a5c0af 100644 --- a/contrib/restricted/abseil-cpp/absl/random/gaussian_distribution.h +++ b/contrib/restricted/abseil-cpp/absl/random/gaussian_distribution.h @@ -1,275 +1,275 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_GAUSSIAN_DISTRIBUTION_H_ -#define ABSL_RANDOM_GAUSSIAN_DISTRIBUTION_H_ - -// absl::gaussian_distribution implements the Ziggurat algorithm -// for generating random gaussian numbers. -// -// Implementation based on "The Ziggurat Method for Generating Random Variables" -// by George Marsaglia and Wai Wan Tsang: http://www.jstatsoft.org/v05/i08/ -// - -#include <cmath> -#include <cstdint> -#include <istream> -#include <limits> -#include <type_traits> - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_GAUSSIAN_DISTRIBUTION_H_ +#define ABSL_RANDOM_GAUSSIAN_DISTRIBUTION_H_ + +// absl::gaussian_distribution implements the Ziggurat algorithm +// for generating random gaussian numbers. +// +// Implementation based on "The Ziggurat Method for Generating Random Variables" +// by George Marsaglia and Wai Wan Tsang: http://www.jstatsoft.org/v05/i08/ +// + +#include <cmath> +#include <cstdint> +#include <istream> +#include <limits> +#include <type_traits> + #include "absl/base/config.h" -#include "absl/random/internal/fast_uniform_bits.h" -#include "absl/random/internal/generate_real.h" -#include "absl/random/internal/iostream_state_saver.h" - -namespace absl { +#include "absl/random/internal/fast_uniform_bits.h" +#include "absl/random/internal/generate_real.h" +#include "absl/random/internal/iostream_state_saver.h" + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - -// absl::gaussian_distribution_base implements the underlying ziggurat algorithm -// using the ziggurat tables generated by the gaussian_distribution_gentables -// binary. -// -// The specific algorithm has some of the improvements suggested by the -// 2005 paper, "An Improved Ziggurat Method to Generate Normal Random Samples", -// Jurgen A Doornik. (https://www.doornik.com/research/ziggurat.pdf) +namespace random_internal { + +// absl::gaussian_distribution_base implements the underlying ziggurat algorithm +// using the ziggurat tables generated by the gaussian_distribution_gentables +// binary. +// +// The specific algorithm has some of the improvements suggested by the +// 2005 paper, "An Improved Ziggurat Method to Generate Normal Random Samples", +// Jurgen A Doornik. (https://www.doornik.com/research/ziggurat.pdf) class ABSL_DLL gaussian_distribution_base { - public: - template <typename URBG> - inline double zignor(URBG& g); // NOLINT(runtime/references) - - private: - friend class TableGenerator; - - template <typename URBG> - inline double zignor_fallback(URBG& g, // NOLINT(runtime/references) - bool neg); - - // Constants used for the gaussian distribution. - static constexpr double kR = 3.442619855899; // Start of the tail. - static constexpr double kRInv = 0.29047645161474317; // ~= (1.0 / kR) . - static constexpr double kV = 9.91256303526217e-3; - static constexpr uint64_t kMask = 0x07f; - - // The ziggurat tables store the pdf(f) and inverse-pdf(x) for equal-area - // points on one-half of the normal distribution, where the pdf function, - // pdf = e ^ (-1/2 *x^2), assumes that the mean = 0 & stddev = 1. - // - // These tables are just over 2kb in size; larger tables might improve the - // distributions, but also lead to more cache pollution. - // - // x = {3.71308, 3.44261, 3.22308, ..., 0} - // f = {0.00101, 0.00266, 0.00554, ..., 1} - struct Tables { - double x[kMask + 2]; - double f[kMask + 2]; - }; - static const Tables zg_; - random_internal::FastUniformBits<uint64_t> fast_u64_; -}; - -} // namespace random_internal - -// absl::gaussian_distribution: -// Generates a number conforming to a Gaussian distribution. -template <typename RealType = double> -class gaussian_distribution : random_internal::gaussian_distribution_base { - public: - using result_type = RealType; - - class param_type { - public: - using distribution_type = gaussian_distribution; - - explicit param_type(result_type mean = 0, result_type stddev = 1) - : mean_(mean), stddev_(stddev) {} - - // Returns the mean distribution parameter. The mean specifies the location - // of the peak. The default value is 0.0. - result_type mean() const { return mean_; } - - // Returns the deviation distribution parameter. The default value is 1.0. - result_type stddev() const { return stddev_; } - - friend bool operator==(const param_type& a, const param_type& b) { - return a.mean_ == b.mean_ && a.stddev_ == b.stddev_; - } - - friend bool operator!=(const param_type& a, const param_type& b) { - return !(a == b); - } - - private: - result_type mean_; - result_type stddev_; - - static_assert( - std::is_floating_point<RealType>::value, - "Class-template absl::gaussian_distribution<> must be parameterized " - "using a floating-point type."); - }; - - gaussian_distribution() : gaussian_distribution(0) {} - - explicit gaussian_distribution(result_type mean, result_type stddev = 1) - : param_(mean, stddev) {} - - explicit gaussian_distribution(const param_type& p) : param_(p) {} - - void reset() {} - - // Generating functions - template <typename URBG> - result_type operator()(URBG& g) { // NOLINT(runtime/references) - return (*this)(g, param_); - } - - template <typename URBG> - result_type operator()(URBG& g, // NOLINT(runtime/references) - const param_type& p); - - param_type param() const { return param_; } - void param(const param_type& p) { param_ = p; } - - result_type(min)() const { - return -std::numeric_limits<result_type>::infinity(); - } - result_type(max)() const { - return std::numeric_limits<result_type>::infinity(); - } - - result_type mean() const { return param_.mean(); } - result_type stddev() const { return param_.stddev(); } - - friend bool operator==(const gaussian_distribution& a, - const gaussian_distribution& b) { - return a.param_ == b.param_; - } - friend bool operator!=(const gaussian_distribution& a, - const gaussian_distribution& b) { - return a.param_ != b.param_; - } - - private: - param_type param_; -}; - -// -------------------------------------------------------------------------- -// Implementation details only below -// -------------------------------------------------------------------------- - -template <typename RealType> -template <typename URBG> -typename gaussian_distribution<RealType>::result_type -gaussian_distribution<RealType>::operator()( - URBG& g, // NOLINT(runtime/references) - const param_type& p) { - return p.mean() + p.stddev() * static_cast<result_type>(zignor(g)); -} - -template <typename CharT, typename Traits, typename RealType> -std::basic_ostream<CharT, Traits>& operator<<( - std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) - const gaussian_distribution<RealType>& x) { - auto saver = random_internal::make_ostream_state_saver(os); - os.precision(random_internal::stream_precision_helper<RealType>::kPrecision); - os << x.mean() << os.fill() << x.stddev(); - return os; -} - -template <typename CharT, typename Traits, typename RealType> -std::basic_istream<CharT, Traits>& operator>>( - std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) - gaussian_distribution<RealType>& x) { // NOLINT(runtime/references) - using result_type = typename gaussian_distribution<RealType>::result_type; - using param_type = typename gaussian_distribution<RealType>::param_type; - - auto saver = random_internal::make_istream_state_saver(is); - auto mean = random_internal::read_floating_point<result_type>(is); - if (is.fail()) return is; - auto stddev = random_internal::read_floating_point<result_type>(is); - if (!is.fail()) { - x.param(param_type(mean, stddev)); - } - return is; -} - -namespace random_internal { - -template <typename URBG> -inline double gaussian_distribution_base::zignor_fallback(URBG& g, bool neg) { - using random_internal::GeneratePositiveTag; - using random_internal::GenerateRealFromBits; - - // This fallback path happens approximately 0.05% of the time. - double x, y; - do { - // kRInv = 1/r, U(0, 1) - x = kRInv * - std::log(GenerateRealFromBits<double, GeneratePositiveTag, false>( - fast_u64_(g))); - y = -std::log( - GenerateRealFromBits<double, GeneratePositiveTag, false>(fast_u64_(g))); - } while ((y + y) < (x * x)); - return neg ? (x - kR) : (kR - x); -} - -template <typename URBG> -inline double gaussian_distribution_base::zignor( - URBG& g) { // NOLINT(runtime/references) - using random_internal::GeneratePositiveTag; - using random_internal::GenerateRealFromBits; - using random_internal::GenerateSignedTag; - - while (true) { - // We use a single uint64_t to generate both a double and a strip. - // These bits are unused when the generated double is > 1/2^5. - // This may introduce some bias from the duplicated low bits of small - // values (those smaller than 1/2^5, which all end up on the left tail). - uint64_t bits = fast_u64_(g); - int i = static_cast<int>(bits & kMask); // pick a random strip - double j = GenerateRealFromBits<double, GenerateSignedTag, false>( - bits); // U(-1, 1) - const double x = j * zg_.x[i]; - - // Retangular box. Handles >97% of all cases. - // For any given box, this handles between 75% and 99% of values. - // Equivalent to U(01) < (x[i+1] / x[i]), and when i == 0, ~93.5% - if (std::abs(x) < zg_.x[i + 1]) { - return x; - } - - // i == 0: Base box. Sample using a ratio of uniforms. - if (i == 0) { - // This path happens about 0.05% of the time. - return zignor_fallback(g, j < 0); - } - - // i > 0: Wedge samples using precomputed values. - double v = GenerateRealFromBits<double, GeneratePositiveTag, false>( - fast_u64_(g)); // U(0, 1) - if ((zg_.f[i + 1] + v * (zg_.f[i] - zg_.f[i + 1])) < - std::exp(-0.5 * x * x)) { - return x; - } - - // The wedge was missed; reject the value and try again. - } -} - -} // namespace random_internal + public: + template <typename URBG> + inline double zignor(URBG& g); // NOLINT(runtime/references) + + private: + friend class TableGenerator; + + template <typename URBG> + inline double zignor_fallback(URBG& g, // NOLINT(runtime/references) + bool neg); + + // Constants used for the gaussian distribution. + static constexpr double kR = 3.442619855899; // Start of the tail. + static constexpr double kRInv = 0.29047645161474317; // ~= (1.0 / kR) . + static constexpr double kV = 9.91256303526217e-3; + static constexpr uint64_t kMask = 0x07f; + + // The ziggurat tables store the pdf(f) and inverse-pdf(x) for equal-area + // points on one-half of the normal distribution, where the pdf function, + // pdf = e ^ (-1/2 *x^2), assumes that the mean = 0 & stddev = 1. + // + // These tables are just over 2kb in size; larger tables might improve the + // distributions, but also lead to more cache pollution. + // + // x = {3.71308, 3.44261, 3.22308, ..., 0} + // f = {0.00101, 0.00266, 0.00554, ..., 1} + struct Tables { + double x[kMask + 2]; + double f[kMask + 2]; + }; + static const Tables zg_; + random_internal::FastUniformBits<uint64_t> fast_u64_; +}; + +} // namespace random_internal + +// absl::gaussian_distribution: +// Generates a number conforming to a Gaussian distribution. +template <typename RealType = double> +class gaussian_distribution : random_internal::gaussian_distribution_base { + public: + using result_type = RealType; + + class param_type { + public: + using distribution_type = gaussian_distribution; + + explicit param_type(result_type mean = 0, result_type stddev = 1) + : mean_(mean), stddev_(stddev) {} + + // Returns the mean distribution parameter. The mean specifies the location + // of the peak. The default value is 0.0. + result_type mean() const { return mean_; } + + // Returns the deviation distribution parameter. The default value is 1.0. + result_type stddev() const { return stddev_; } + + friend bool operator==(const param_type& a, const param_type& b) { + return a.mean_ == b.mean_ && a.stddev_ == b.stddev_; + } + + friend bool operator!=(const param_type& a, const param_type& b) { + return !(a == b); + } + + private: + result_type mean_; + result_type stddev_; + + static_assert( + std::is_floating_point<RealType>::value, + "Class-template absl::gaussian_distribution<> must be parameterized " + "using a floating-point type."); + }; + + gaussian_distribution() : gaussian_distribution(0) {} + + explicit gaussian_distribution(result_type mean, result_type stddev = 1) + : param_(mean, stddev) {} + + explicit gaussian_distribution(const param_type& p) : param_(p) {} + + void reset() {} + + // Generating functions + template <typename URBG> + result_type operator()(URBG& g) { // NOLINT(runtime/references) + return (*this)(g, param_); + } + + template <typename URBG> + result_type operator()(URBG& g, // NOLINT(runtime/references) + const param_type& p); + + param_type param() const { return param_; } + void param(const param_type& p) { param_ = p; } + + result_type(min)() const { + return -std::numeric_limits<result_type>::infinity(); + } + result_type(max)() const { + return std::numeric_limits<result_type>::infinity(); + } + + result_type mean() const { return param_.mean(); } + result_type stddev() const { return param_.stddev(); } + + friend bool operator==(const gaussian_distribution& a, + const gaussian_distribution& b) { + return a.param_ == b.param_; + } + friend bool operator!=(const gaussian_distribution& a, + const gaussian_distribution& b) { + return a.param_ != b.param_; + } + + private: + param_type param_; +}; + +// -------------------------------------------------------------------------- +// Implementation details only below +// -------------------------------------------------------------------------- + +template <typename RealType> +template <typename URBG> +typename gaussian_distribution<RealType>::result_type +gaussian_distribution<RealType>::operator()( + URBG& g, // NOLINT(runtime/references) + const param_type& p) { + return p.mean() + p.stddev() * static_cast<result_type>(zignor(g)); +} + +template <typename CharT, typename Traits, typename RealType> +std::basic_ostream<CharT, Traits>& operator<<( + std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) + const gaussian_distribution<RealType>& x) { + auto saver = random_internal::make_ostream_state_saver(os); + os.precision(random_internal::stream_precision_helper<RealType>::kPrecision); + os << x.mean() << os.fill() << x.stddev(); + return os; +} + +template <typename CharT, typename Traits, typename RealType> +std::basic_istream<CharT, Traits>& operator>>( + std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) + gaussian_distribution<RealType>& x) { // NOLINT(runtime/references) + using result_type = typename gaussian_distribution<RealType>::result_type; + using param_type = typename gaussian_distribution<RealType>::param_type; + + auto saver = random_internal::make_istream_state_saver(is); + auto mean = random_internal::read_floating_point<result_type>(is); + if (is.fail()) return is; + auto stddev = random_internal::read_floating_point<result_type>(is); + if (!is.fail()) { + x.param(param_type(mean, stddev)); + } + return is; +} + +namespace random_internal { + +template <typename URBG> +inline double gaussian_distribution_base::zignor_fallback(URBG& g, bool neg) { + using random_internal::GeneratePositiveTag; + using random_internal::GenerateRealFromBits; + + // This fallback path happens approximately 0.05% of the time. + double x, y; + do { + // kRInv = 1/r, U(0, 1) + x = kRInv * + std::log(GenerateRealFromBits<double, GeneratePositiveTag, false>( + fast_u64_(g))); + y = -std::log( + GenerateRealFromBits<double, GeneratePositiveTag, false>(fast_u64_(g))); + } while ((y + y) < (x * x)); + return neg ? (x - kR) : (kR - x); +} + +template <typename URBG> +inline double gaussian_distribution_base::zignor( + URBG& g) { // NOLINT(runtime/references) + using random_internal::GeneratePositiveTag; + using random_internal::GenerateRealFromBits; + using random_internal::GenerateSignedTag; + + while (true) { + // We use a single uint64_t to generate both a double and a strip. + // These bits are unused when the generated double is > 1/2^5. + // This may introduce some bias from the duplicated low bits of small + // values (those smaller than 1/2^5, which all end up on the left tail). + uint64_t bits = fast_u64_(g); + int i = static_cast<int>(bits & kMask); // pick a random strip + double j = GenerateRealFromBits<double, GenerateSignedTag, false>( + bits); // U(-1, 1) + const double x = j * zg_.x[i]; + + // Retangular box. Handles >97% of all cases. + // For any given box, this handles between 75% and 99% of values. + // Equivalent to U(01) < (x[i+1] / x[i]), and when i == 0, ~93.5% + if (std::abs(x) < zg_.x[i + 1]) { + return x; + } + + // i == 0: Base box. Sample using a ratio of uniforms. + if (i == 0) { + // This path happens about 0.05% of the time. + return zignor_fallback(g, j < 0); + } + + // i > 0: Wedge samples using precomputed values. + double v = GenerateRealFromBits<double, GeneratePositiveTag, false>( + fast_u64_(g)); // U(0, 1) + if ((zg_.f[i + 1] + v * (zg_.f[i] - zg_.f[i + 1])) < + std::exp(-0.5 * x * x)) { + return x; + } + + // The wedge was missed; reject the value and try again. + } +} + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_GAUSSIAN_DISTRIBUTION_H_ +} // namespace absl + +#endif // ABSL_RANDOM_GAUSSIAN_DISTRIBUTION_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/absl_random_internal_distribution_test_util/ya.make b/contrib/restricted/abseil-cpp/absl/random/internal/absl_random_internal_distribution_test_util/ya.make index c19fb5333a..340d08c827 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/absl_random_internal_distribution_test_util/ya.make +++ b/contrib/restricted/abseil-cpp/absl/random/internal/absl_random_internal_distribution_test_util/ya.make @@ -1,42 +1,42 @@ -# Generated by devtools/yamaker. - -LIBRARY() - +# Generated by devtools/yamaker. + +LIBRARY() + WITHOUT_LICENSE_TEXTS() -OWNER(g:cpp-contrib) - -LICENSE(Apache-2.0) - -PEERDIR( - contrib/restricted/abseil-cpp/absl/base - contrib/restricted/abseil-cpp/absl/base/internal/raw_logging - contrib/restricted/abseil-cpp/absl/base/internal/spinlock_wait - contrib/restricted/abseil-cpp/absl/base/internal/throw_delegate - contrib/restricted/abseil-cpp/absl/base/log_severity - contrib/restricted/abseil-cpp/absl/numeric - contrib/restricted/abseil-cpp/absl/strings +OWNER(g:cpp-contrib) + +LICENSE(Apache-2.0) + +PEERDIR( + contrib/restricted/abseil-cpp/absl/base + contrib/restricted/abseil-cpp/absl/base/internal/raw_logging + contrib/restricted/abseil-cpp/absl/base/internal/spinlock_wait + contrib/restricted/abseil-cpp/absl/base/internal/throw_delegate + contrib/restricted/abseil-cpp/absl/base/log_severity + contrib/restricted/abseil-cpp/absl/numeric + contrib/restricted/abseil-cpp/absl/strings contrib/restricted/abseil-cpp/absl/strings/internal/absl_strings_internal - contrib/restricted/abseil-cpp/absl/strings/internal/str_format -) - -ADDINCL( - GLOBAL contrib/restricted/abseil-cpp -) - -NO_COMPILER_WARNINGS() - -NO_UTIL() - + contrib/restricted/abseil-cpp/absl/strings/internal/str_format +) + +ADDINCL( + GLOBAL contrib/restricted/abseil-cpp +) + +NO_COMPILER_WARNINGS() + +NO_UTIL() + CFLAGS( -DNOMINMAX ) -SRCDIR(contrib/restricted/abseil-cpp/absl/random/internal) - -SRCS( - chi_square.cc - distribution_test_util.cc -) - -END() +SRCDIR(contrib/restricted/abseil-cpp/absl/random/internal) + +SRCS( + chi_square.cc + distribution_test_util.cc +) + +END() diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/chi_square.cc b/contrib/restricted/abseil-cpp/absl/random/internal/chi_square.cc index 6796cb8db4..640d48cea6 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/chi_square.cc +++ b/contrib/restricted/abseil-cpp/absl/random/internal/chi_square.cc @@ -1,232 +1,232 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "absl/random/internal/chi_square.h" - -#include <cmath> - -#include "absl/random/internal/distribution_test_util.h" - -namespace absl { +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/random/internal/chi_square.h" + +#include <cmath> + +#include "absl/random/internal/distribution_test_util.h" + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { -namespace { - -#if defined(__EMSCRIPTEN__) -// Workaround __EMSCRIPTEN__ error: llvm_fma_f64 not found. -inline double fma(double x, double y, double z) { - return (x * y) + z; -} -#endif - -// Use Horner's method to evaluate a polynomial. -template <typename T, unsigned N> -inline T EvaluatePolynomial(T x, const T (&poly)[N]) { -#if !defined(__EMSCRIPTEN__) - using std::fma; -#endif - T p = poly[N - 1]; - for (unsigned i = 2; i <= N; i++) { - p = fma(p, x, poly[N - i]); - } - return p; -} - -static constexpr int kLargeDOF = 150; - -// Returns the probability of a normal z-value. -// -// Adapted from the POZ function in: -// Ibbetson D, Algorithm 209 -// Collected Algorithms of the CACM 1963 p. 616 -// -double POZ(double z) { - static constexpr double kP1[] = { - 0.797884560593, -0.531923007300, 0.319152932694, - -0.151968751364, 0.059054035642, -0.019198292004, - 0.005198775019, -0.001075204047, 0.000124818987, - }; - static constexpr double kP2[] = { - 0.999936657524, 0.000535310849, -0.002141268741, 0.005353579108, - -0.009279453341, 0.011630447319, -0.010557625006, 0.006549791214, - -0.002034254874, -0.000794620820, 0.001390604284, -0.000676904986, - -0.000019538132, 0.000152529290, -0.000045255659, - }; - - const double kZMax = 6.0; // Maximum meaningful z-value. - if (z == 0.0) { - return 0.5; - } - double x; - double y = 0.5 * std::fabs(z); - if (y >= (kZMax * 0.5)) { - x = 1.0; - } else if (y < 1.0) { - double w = y * y; - x = EvaluatePolynomial(w, kP1) * y * 2.0; - } else { - y -= 2.0; - x = EvaluatePolynomial(y, kP2); - } - return z > 0.0 ? ((x + 1.0) * 0.5) : ((1.0 - x) * 0.5); -} - -// Approximates the survival function of the normal distribution. -// -// Algorithm 26.2.18, from: -// [Abramowitz and Stegun, Handbook of Mathematical Functions,p.932] -// http://people.math.sfu.ca/~cbm/aands/abramowitz_and_stegun.pdf -// -double normal_survival(double z) { - // Maybe replace with the alternate formulation. - // 0.5 * erfc((x - mean)/(sqrt(2) * sigma)) - static constexpr double kR[] = { - 1.0, 0.196854, 0.115194, 0.000344, 0.019527, - }; - double r = EvaluatePolynomial(z, kR); - r *= r; - return 0.5 / (r * r); -} - -} // namespace - -// Calculates the critical chi-square value given degrees-of-freedom and a -// p-value, usually using bisection. Also known by the name CRITCHI. -double ChiSquareValue(int dof, double p) { - static constexpr double kChiEpsilon = - 0.000001; // Accuracy of the approximation. - static constexpr double kChiMax = - 99999.0; // Maximum chi-squared value. - - const double p_value = 1.0 - p; - if (dof < 1 || p_value > 1.0) { - return 0.0; - } - - if (dof > kLargeDOF) { - // For large degrees of freedom, use the normal approximation by - // Wilson, E. B. and Hilferty, M. M. (1931) - // chi^2 - mean - // Z = -------------- - // stddev - const double z = InverseNormalSurvival(p_value); - const double mean = 1 - 2.0 / (9 * dof); - const double variance = 2.0 / (9 * dof); - // Cannot use this method if the variance is 0. - if (variance != 0) { - return std::pow(z * std::sqrt(variance) + mean, 3.0) * dof; - } - } - - if (p_value <= 0.0) return kChiMax; - - // Otherwise search for the p value by bisection - double min_chisq = 0.0; - double max_chisq = kChiMax; - double current = dof / std::sqrt(p_value); - while ((max_chisq - min_chisq) > kChiEpsilon) { - if (ChiSquarePValue(current, dof) < p_value) { - max_chisq = current; - } else { - min_chisq = current; - } - current = (max_chisq + min_chisq) * 0.5; - } - return current; -} - -// Calculates the p-value (probability) of a given chi-square value -// and degrees of freedom. -// -// Adapted from the POCHISQ function from: -// Hill, I. D. and Pike, M. C. Algorithm 299 -// Collected Algorithms of the CACM 1963 p. 243 -// -double ChiSquarePValue(double chi_square, int dof) { - static constexpr double kLogSqrtPi = - 0.5723649429247000870717135; // Log[Sqrt[Pi]] - static constexpr double kInverseSqrtPi = - 0.5641895835477562869480795; // 1/(Sqrt[Pi]) - - // For large degrees of freedom, use the normal approximation by - // Wilson, E. B. and Hilferty, M. M. (1931) - // Via Wikipedia: - // By the Central Limit Theorem, because the chi-square distribution is the - // sum of k independent random variables with finite mean and variance, it - // converges to a normal distribution for large k. - if (dof > kLargeDOF) { - // Re-scale everything. - const double chi_square_scaled = std::pow(chi_square / dof, 1.0 / 3); - const double mean = 1 - 2.0 / (9 * dof); - const double variance = 2.0 / (9 * dof); - // If variance is 0, this method cannot be used. - if (variance != 0) { - const double z = (chi_square_scaled - mean) / std::sqrt(variance); - if (z > 0) { - return normal_survival(z); - } else if (z < 0) { - return 1.0 - normal_survival(-z); - } else { - return 0.5; - } - } - } - - // The chi square function is >= 0 for any degrees of freedom. - // In other words, probability that the chi square function >= 0 is 1. - if (chi_square <= 0.0) return 1.0; - - // If the degrees of freedom is zero, the chi square function is always 0 by - // definition. In other words, the probability that the chi square function - // is > 0 is zero (chi square values <= 0 have been filtered above). - if (dof < 1) return 0; - - auto capped_exp = [](double x) { return x < -20 ? 0.0 : std::exp(x); }; - static constexpr double kBigX = 20; - - double a = 0.5 * chi_square; - const bool even = !(dof & 1); // True if dof is an even number. - const double y = capped_exp(-a); - double s = even ? y : (2.0 * POZ(-std::sqrt(chi_square))); - - if (dof <= 2) { - return s; - } - - chi_square = 0.5 * (dof - 1.0); - double z = (even ? 1.0 : 0.5); - if (a > kBigX) { - double e = (even ? 0.0 : kLogSqrtPi); - double c = std::log(a); - while (z <= chi_square) { - e = std::log(z) + e; - s += capped_exp(c * z - a - e); - z += 1.0; - } - return s; - } - - double e = (even ? 1.0 : (kInverseSqrtPi / std::sqrt(a))); - double c = 0.0; - while (z <= chi_square) { - e = e * (a / z); - c = c + e; - z += 1.0; - } - return c * y + s; -} - -} // namespace random_internal +namespace random_internal { +namespace { + +#if defined(__EMSCRIPTEN__) +// Workaround __EMSCRIPTEN__ error: llvm_fma_f64 not found. +inline double fma(double x, double y, double z) { + return (x * y) + z; +} +#endif + +// Use Horner's method to evaluate a polynomial. +template <typename T, unsigned N> +inline T EvaluatePolynomial(T x, const T (&poly)[N]) { +#if !defined(__EMSCRIPTEN__) + using std::fma; +#endif + T p = poly[N - 1]; + for (unsigned i = 2; i <= N; i++) { + p = fma(p, x, poly[N - i]); + } + return p; +} + +static constexpr int kLargeDOF = 150; + +// Returns the probability of a normal z-value. +// +// Adapted from the POZ function in: +// Ibbetson D, Algorithm 209 +// Collected Algorithms of the CACM 1963 p. 616 +// +double POZ(double z) { + static constexpr double kP1[] = { + 0.797884560593, -0.531923007300, 0.319152932694, + -0.151968751364, 0.059054035642, -0.019198292004, + 0.005198775019, -0.001075204047, 0.000124818987, + }; + static constexpr double kP2[] = { + 0.999936657524, 0.000535310849, -0.002141268741, 0.005353579108, + -0.009279453341, 0.011630447319, -0.010557625006, 0.006549791214, + -0.002034254874, -0.000794620820, 0.001390604284, -0.000676904986, + -0.000019538132, 0.000152529290, -0.000045255659, + }; + + const double kZMax = 6.0; // Maximum meaningful z-value. + if (z == 0.0) { + return 0.5; + } + double x; + double y = 0.5 * std::fabs(z); + if (y >= (kZMax * 0.5)) { + x = 1.0; + } else if (y < 1.0) { + double w = y * y; + x = EvaluatePolynomial(w, kP1) * y * 2.0; + } else { + y -= 2.0; + x = EvaluatePolynomial(y, kP2); + } + return z > 0.0 ? ((x + 1.0) * 0.5) : ((1.0 - x) * 0.5); +} + +// Approximates the survival function of the normal distribution. +// +// Algorithm 26.2.18, from: +// [Abramowitz and Stegun, Handbook of Mathematical Functions,p.932] +// http://people.math.sfu.ca/~cbm/aands/abramowitz_and_stegun.pdf +// +double normal_survival(double z) { + // Maybe replace with the alternate formulation. + // 0.5 * erfc((x - mean)/(sqrt(2) * sigma)) + static constexpr double kR[] = { + 1.0, 0.196854, 0.115194, 0.000344, 0.019527, + }; + double r = EvaluatePolynomial(z, kR); + r *= r; + return 0.5 / (r * r); +} + +} // namespace + +// Calculates the critical chi-square value given degrees-of-freedom and a +// p-value, usually using bisection. Also known by the name CRITCHI. +double ChiSquareValue(int dof, double p) { + static constexpr double kChiEpsilon = + 0.000001; // Accuracy of the approximation. + static constexpr double kChiMax = + 99999.0; // Maximum chi-squared value. + + const double p_value = 1.0 - p; + if (dof < 1 || p_value > 1.0) { + return 0.0; + } + + if (dof > kLargeDOF) { + // For large degrees of freedom, use the normal approximation by + // Wilson, E. B. and Hilferty, M. M. (1931) + // chi^2 - mean + // Z = -------------- + // stddev + const double z = InverseNormalSurvival(p_value); + const double mean = 1 - 2.0 / (9 * dof); + const double variance = 2.0 / (9 * dof); + // Cannot use this method if the variance is 0. + if (variance != 0) { + return std::pow(z * std::sqrt(variance) + mean, 3.0) * dof; + } + } + + if (p_value <= 0.0) return kChiMax; + + // Otherwise search for the p value by bisection + double min_chisq = 0.0; + double max_chisq = kChiMax; + double current = dof / std::sqrt(p_value); + while ((max_chisq - min_chisq) > kChiEpsilon) { + if (ChiSquarePValue(current, dof) < p_value) { + max_chisq = current; + } else { + min_chisq = current; + } + current = (max_chisq + min_chisq) * 0.5; + } + return current; +} + +// Calculates the p-value (probability) of a given chi-square value +// and degrees of freedom. +// +// Adapted from the POCHISQ function from: +// Hill, I. D. and Pike, M. C. Algorithm 299 +// Collected Algorithms of the CACM 1963 p. 243 +// +double ChiSquarePValue(double chi_square, int dof) { + static constexpr double kLogSqrtPi = + 0.5723649429247000870717135; // Log[Sqrt[Pi]] + static constexpr double kInverseSqrtPi = + 0.5641895835477562869480795; // 1/(Sqrt[Pi]) + + // For large degrees of freedom, use the normal approximation by + // Wilson, E. B. and Hilferty, M. M. (1931) + // Via Wikipedia: + // By the Central Limit Theorem, because the chi-square distribution is the + // sum of k independent random variables with finite mean and variance, it + // converges to a normal distribution for large k. + if (dof > kLargeDOF) { + // Re-scale everything. + const double chi_square_scaled = std::pow(chi_square / dof, 1.0 / 3); + const double mean = 1 - 2.0 / (9 * dof); + const double variance = 2.0 / (9 * dof); + // If variance is 0, this method cannot be used. + if (variance != 0) { + const double z = (chi_square_scaled - mean) / std::sqrt(variance); + if (z > 0) { + return normal_survival(z); + } else if (z < 0) { + return 1.0 - normal_survival(-z); + } else { + return 0.5; + } + } + } + + // The chi square function is >= 0 for any degrees of freedom. + // In other words, probability that the chi square function >= 0 is 1. + if (chi_square <= 0.0) return 1.0; + + // If the degrees of freedom is zero, the chi square function is always 0 by + // definition. In other words, the probability that the chi square function + // is > 0 is zero (chi square values <= 0 have been filtered above). + if (dof < 1) return 0; + + auto capped_exp = [](double x) { return x < -20 ? 0.0 : std::exp(x); }; + static constexpr double kBigX = 20; + + double a = 0.5 * chi_square; + const bool even = !(dof & 1); // True if dof is an even number. + const double y = capped_exp(-a); + double s = even ? y : (2.0 * POZ(-std::sqrt(chi_square))); + + if (dof <= 2) { + return s; + } + + chi_square = 0.5 * (dof - 1.0); + double z = (even ? 1.0 : 0.5); + if (a > kBigX) { + double e = (even ? 0.0 : kLogSqrtPi); + double c = std::log(a); + while (z <= chi_square) { + e = std::log(z) + e; + s += capped_exp(c * z - a - e); + z += 1.0; + } + return s; + } + + double e = (even ? 1.0 : (kInverseSqrtPi / std::sqrt(a))); + double c = 0.0; + while (z <= chi_square) { + e = e * (a / z); + c = c + e; + z += 1.0; + } + return c * y + s; +} + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl +} // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/chi_square.h b/contrib/restricted/abseil-cpp/absl/random/internal/chi_square.h index aedeec4f11..07f4fbe522 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/chi_square.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/chi_square.h @@ -1,89 +1,89 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_INTERNAL_CHI_SQUARE_H_ -#define ABSL_RANDOM_INTERNAL_CHI_SQUARE_H_ - -// The chi-square statistic. -// -// Useful for evaluating if `D` independent random variables are behaving as -// expected, or if two distributions are similar. (`D` is the degrees of -// freedom). -// -// Each bucket should have an expected count of 10 or more for the chi square to -// be meaningful. - -#include <cassert> - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_INTERNAL_CHI_SQUARE_H_ +#define ABSL_RANDOM_INTERNAL_CHI_SQUARE_H_ + +// The chi-square statistic. +// +// Useful for evaluating if `D` independent random variables are behaving as +// expected, or if two distributions are similar. (`D` is the degrees of +// freedom). +// +// Each bucket should have an expected count of 10 or more for the chi square to +// be meaningful. + +#include <cassert> + #include "absl/base/config.h" -namespace absl { +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - -constexpr const char kChiSquared[] = "chi-squared"; - -// Returns the measured chi square value, using a single expected value. This -// assumes that the values in [begin, end) are uniformly distributed. -template <typename Iterator> -double ChiSquareWithExpected(Iterator begin, Iterator end, double expected) { - // Compute the sum and the number of buckets. - assert(expected >= 10); // require at least 10 samples per bucket. - double chi_square = 0; - for (auto it = begin; it != end; it++) { - double d = static_cast<double>(*it) - expected; - chi_square += d * d; - } - chi_square = chi_square / expected; - return chi_square; -} - -// Returns the measured chi square value, taking the actual value of each bucket -// from the first set of iterators, and the expected value of each bucket from -// the second set of iterators. -template <typename Iterator, typename Expected> -double ChiSquare(Iterator it, Iterator end, Expected eit, Expected eend) { - double chi_square = 0; - for (; it != end && eit != eend; ++it, ++eit) { - if (*it > 0) { - assert(*eit > 0); - } - double e = static_cast<double>(*eit); - double d = static_cast<double>(*it - *eit); - if (d != 0) { - assert(e > 0); - chi_square += (d * d) / e; - } - } - assert(it == end && eit == eend); - return chi_square; -} - -// ====================================================================== -// The following methods can be used for an arbitrary significance level. -// - -// Calculates critical chi-square values to produce the given p-value using a -// bisection search for a value within epsilon, relying on the monotonicity of -// ChiSquarePValue(). -double ChiSquareValue(int dof, double p); - -// Calculates the p-value (probability) of a given chi-square value. -double ChiSquarePValue(double chi_square, int dof); - -} // namespace random_internal +namespace random_internal { + +constexpr const char kChiSquared[] = "chi-squared"; + +// Returns the measured chi square value, using a single expected value. This +// assumes that the values in [begin, end) are uniformly distributed. +template <typename Iterator> +double ChiSquareWithExpected(Iterator begin, Iterator end, double expected) { + // Compute the sum and the number of buckets. + assert(expected >= 10); // require at least 10 samples per bucket. + double chi_square = 0; + for (auto it = begin; it != end; it++) { + double d = static_cast<double>(*it) - expected; + chi_square += d * d; + } + chi_square = chi_square / expected; + return chi_square; +} + +// Returns the measured chi square value, taking the actual value of each bucket +// from the first set of iterators, and the expected value of each bucket from +// the second set of iterators. +template <typename Iterator, typename Expected> +double ChiSquare(Iterator it, Iterator end, Expected eit, Expected eend) { + double chi_square = 0; + for (; it != end && eit != eend; ++it, ++eit) { + if (*it > 0) { + assert(*eit > 0); + } + double e = static_cast<double>(*eit); + double d = static_cast<double>(*it - *eit); + if (d != 0) { + assert(e > 0); + chi_square += (d * d) / e; + } + } + assert(it == end && eit == eend); + return chi_square; +} + +// ====================================================================== +// The following methods can be used for an arbitrary significance level. +// + +// Calculates critical chi-square values to produce the given p-value using a +// bisection search for a value within epsilon, relying on the monotonicity of +// ChiSquarePValue(). +double ChiSquareValue(int dof, double p); + +// Calculates the p-value (probability) of a given chi-square value. +double ChiSquarePValue(double chi_square, int dof); + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_CHI_SQUARE_H_ +} // namespace absl + +#endif // ABSL_RANDOM_INTERNAL_CHI_SQUARE_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/distribution_caller.h b/contrib/restricted/abseil-cpp/absl/random/internal/distribution_caller.h index 3e2dfed99d..fc81b787eb 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/distribution_caller.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/distribution_caller.h @@ -1,40 +1,40 @@ -// -// Copyright 2018 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#ifndef ABSL_RANDOM_INTERNAL_DISTRIBUTION_CALLER_H_ -#define ABSL_RANDOM_INTERNAL_DISTRIBUTION_CALLER_H_ - -#include <utility> - +// +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef ABSL_RANDOM_INTERNAL_DISTRIBUTION_CALLER_H_ +#define ABSL_RANDOM_INTERNAL_DISTRIBUTION_CALLER_H_ + +#include <utility> + #include "absl/base/config.h" #include "absl/base/internal/fast_type_id.h" #include "absl/utility/utility.h" -namespace absl { +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - -// DistributionCaller provides an opportunity to overload the general -// mechanism for calling a distribution, allowing for mock-RNG classes -// to intercept such calls. -template <typename URBG> -struct DistributionCaller { +namespace random_internal { + +// DistributionCaller provides an opportunity to overload the general +// mechanism for calling a distribution, allowing for mock-RNG classes +// to intercept such calls. +template <typename URBG> +struct DistributionCaller { // SFINAE to detect whether the URBG type includes a member matching // bool InvokeMock(base_internal::FastTypeIdType, void*, void*). - // + // // These live inside BitGenRef so that they have friend access // to MockingBitGen. (see similar methods in DistributionCaller). template <template <class...> class Trait, class AlwaysVoid, class... Args> @@ -54,9 +54,9 @@ struct DistributionCaller { template <typename DistrT, typename... Args> static typename DistrT::result_type Impl(std::false_type, URBG* urbg, Args&&... args) { - DistrT dist(std::forward<Args>(args)...); - return dist(*urbg); - } + DistrT dist(std::forward<Args>(args)...); + return dist(*urbg); + } // Mock implementation of distribution caller. // The underlying KeyT must match the KeyT constructed by MockOverloadSet. @@ -83,10 +83,10 @@ struct DistributionCaller { return Impl<DistrT, Args...>(HasInvokeMock{}, urbg, std::forward<Args>(args)...); } -}; - -} // namespace random_internal +}; + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_DISTRIBUTION_CALLER_H_ +} // namespace absl + +#endif // ABSL_RANDOM_INTERNAL_DISTRIBUTION_CALLER_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/distribution_test_util.cc b/contrib/restricted/abseil-cpp/absl/random/internal/distribution_test_util.cc index 6796322a1b..e9005658c0 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/distribution_test_util.cc +++ b/contrib/restricted/abseil-cpp/absl/random/internal/distribution_test_util.cc @@ -1,418 +1,418 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "absl/random/internal/distribution_test_util.h" - -#include <cassert> -#include <cmath> -#include <string> -#include <vector> - -#include "absl/base/internal/raw_logging.h" -#include "absl/base/macros.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/str_format.h" - -namespace absl { +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/random/internal/distribution_test_util.h" + +#include <cassert> +#include <cmath> +#include <string> +#include <vector> + +#include "absl/base/internal/raw_logging.h" +#include "absl/base/macros.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { -namespace { - -#if defined(__EMSCRIPTEN__) -// Workaround __EMSCRIPTEN__ error: llvm_fma_f64 not found. -inline double fma(double x, double y, double z) { return (x * y) + z; } -#endif - -} // namespace - -DistributionMoments ComputeDistributionMoments( - absl::Span<const double> data_points) { - DistributionMoments result; - - // Compute m1 - for (double x : data_points) { - result.n++; - result.mean += x; - } - result.mean /= static_cast<double>(result.n); - - // Compute m2, m3, m4 - for (double x : data_points) { - double v = x - result.mean; - result.variance += v * v; - result.skewness += v * v * v; - result.kurtosis += v * v * v * v; - } - result.variance /= static_cast<double>(result.n - 1); - - result.skewness /= static_cast<double>(result.n); - result.skewness /= std::pow(result.variance, 1.5); - - result.kurtosis /= static_cast<double>(result.n); - result.kurtosis /= std::pow(result.variance, 2.0); - return result; - - // When validating the min/max count, the following confidence intervals may - // be of use: - // 3.291 * stddev = 99.9% CI - // 2.576 * stddev = 99% CI - // 1.96 * stddev = 95% CI - // 1.65 * stddev = 90% CI -} - -std::ostream& operator<<(std::ostream& os, const DistributionMoments& moments) { - return os << absl::StrFormat("mean=%f, stddev=%f, skewness=%f, kurtosis=%f", - moments.mean, std::sqrt(moments.variance), - moments.skewness, moments.kurtosis); -} - -double InverseNormalSurvival(double x) { - // inv_sf(u) = -sqrt(2) * erfinv(2u-1) - static constexpr double kSqrt2 = 1.4142135623730950488; - return -kSqrt2 * absl::random_internal::erfinv(2 * x - 1.0); -} - -bool Near(absl::string_view msg, double actual, double expected, double bound) { - assert(bound > 0.0); - double delta = fabs(expected - actual); - if (delta < bound) { - return true; - } - - std::string formatted = absl::StrCat( - msg, " actual=", actual, " expected=", expected, " err=", delta / bound); - ABSL_RAW_LOG(INFO, "%s", formatted.c_str()); - return false; -} - -// TODO(absl-team): Replace with an "ABSL_HAVE_SPECIAL_MATH" and try -// to use std::beta(). As of this writing P0226R1 is not implemented -// in libc++: http://libcxx.llvm.org/cxx1z_status.html -double beta(double p, double q) { - // Beta(x, y) = Gamma(x) * Gamma(y) / Gamma(x+y) - double lbeta = std::lgamma(p) + std::lgamma(q) - std::lgamma(p + q); - return std::exp(lbeta); -} - -// Approximation to inverse of the Error Function in double precision. -// (http://people.maths.ox.ac.uk/gilesm/files/gems_erfinv.pdf) -double erfinv(double x) { -#if !defined(__EMSCRIPTEN__) - using std::fma; -#endif - - double w = 0.0; - double p = 0.0; - w = -std::log((1.0 - x) * (1.0 + x)); - if (w < 6.250000) { - w = w - 3.125000; - p = -3.6444120640178196996e-21; - p = fma(p, w, -1.685059138182016589e-19); - p = fma(p, w, 1.2858480715256400167e-18); - p = fma(p, w, 1.115787767802518096e-17); - p = fma(p, w, -1.333171662854620906e-16); - p = fma(p, w, 2.0972767875968561637e-17); - p = fma(p, w, 6.6376381343583238325e-15); - p = fma(p, w, -4.0545662729752068639e-14); - p = fma(p, w, -8.1519341976054721522e-14); - p = fma(p, w, 2.6335093153082322977e-12); - p = fma(p, w, -1.2975133253453532498e-11); - p = fma(p, w, -5.4154120542946279317e-11); - p = fma(p, w, 1.051212273321532285e-09); - p = fma(p, w, -4.1126339803469836976e-09); - p = fma(p, w, -2.9070369957882005086e-08); - p = fma(p, w, 4.2347877827932403518e-07); - p = fma(p, w, -1.3654692000834678645e-06); - p = fma(p, w, -1.3882523362786468719e-05); - p = fma(p, w, 0.0001867342080340571352); - p = fma(p, w, -0.00074070253416626697512); - p = fma(p, w, -0.0060336708714301490533); - p = fma(p, w, 0.24015818242558961693); - p = fma(p, w, 1.6536545626831027356); - } else if (w < 16.000000) { - w = std::sqrt(w) - 3.250000; - p = 2.2137376921775787049e-09; - p = fma(p, w, 9.0756561938885390979e-08); - p = fma(p, w, -2.7517406297064545428e-07); - p = fma(p, w, 1.8239629214389227755e-08); - p = fma(p, w, 1.5027403968909827627e-06); - p = fma(p, w, -4.013867526981545969e-06); - p = fma(p, w, 2.9234449089955446044e-06); - p = fma(p, w, 1.2475304481671778723e-05); - p = fma(p, w, -4.7318229009055733981e-05); - p = fma(p, w, 6.8284851459573175448e-05); - p = fma(p, w, 2.4031110387097893999e-05); - p = fma(p, w, -0.0003550375203628474796); - p = fma(p, w, 0.00095328937973738049703); - p = fma(p, w, -0.0016882755560235047313); - p = fma(p, w, 0.0024914420961078508066); - p = fma(p, w, -0.0037512085075692412107); - p = fma(p, w, 0.005370914553590063617); - p = fma(p, w, 1.0052589676941592334); - p = fma(p, w, 3.0838856104922207635); - } else { - w = std::sqrt(w) - 5.000000; - p = -2.7109920616438573243e-11; - p = fma(p, w, -2.5556418169965252055e-10); - p = fma(p, w, 1.5076572693500548083e-09); - p = fma(p, w, -3.7894654401267369937e-09); - p = fma(p, w, 7.6157012080783393804e-09); - p = fma(p, w, -1.4960026627149240478e-08); - p = fma(p, w, 2.9147953450901080826e-08); - p = fma(p, w, -6.7711997758452339498e-08); - p = fma(p, w, 2.2900482228026654717e-07); - p = fma(p, w, -9.9298272942317002539e-07); - p = fma(p, w, 4.5260625972231537039e-06); - p = fma(p, w, -1.9681778105531670567e-05); - p = fma(p, w, 7.5995277030017761139e-05); - p = fma(p, w, -0.00021503011930044477347); - p = fma(p, w, -0.00013871931833623122026); - p = fma(p, w, 1.0103004648645343977); - p = fma(p, w, 4.8499064014085844221); - } - return p * x; -} - -namespace { - -// Direct implementation of AS63, BETAIN() -// https://www.jstor.org/stable/2346797?seq=3#page_scan_tab_contents. -// -// BETAIN(x, p, q, beta) -// x: the value of the upper limit x. -// p: the value of the parameter p. -// q: the value of the parameter q. -// beta: the value of ln B(p, q) -// -double BetaIncompleteImpl(const double x, const double p, const double q, - const double beta) { - if (p < (p + q) * x) { - // Incomplete beta function is symmetrical, so return the complement. - return 1. - BetaIncompleteImpl(1.0 - x, q, p, beta); - } - - double psq = p + q; - const double kErr = 1e-14; - const double xc = 1. - x; - const double pre = - std::exp(p * std::log(x) + (q - 1.) * std::log(xc) - beta) / p; - - double term = 1.; - double ai = 1.; - double result = 1.; - int ns = static_cast<int>(q + xc * psq); - - // Use the soper reduction forumla. - double rx = (ns == 0) ? x : x / xc; - double temp = q - ai; - for (;;) { - term = term * temp * rx / (p + ai); - result = result + term; - temp = std::fabs(term); - if (temp < kErr && temp < kErr * result) { - return result * pre; - } - ai = ai + 1.; - --ns; - if (ns >= 0) { - temp = q - ai; - if (ns == 0) { - rx = x; - } - } else { - temp = psq; - psq = psq + 1.; - } - } - - // NOTE: See also TOMS Alogrithm 708. - // http://www.netlib.org/toms/index.html - // - // NOTE: The NWSC library also includes BRATIO / ISUBX (p87) - // https://archive.org/details/DTIC_ADA261511/page/n75 -} - -// Direct implementation of AS109, XINBTA(p, q, beta, alpha) -// https://www.jstor.org/stable/2346798?read-now=1&seq=4#page_scan_tab_contents -// https://www.jstor.org/stable/2346887?seq=1#page_scan_tab_contents -// -// XINBTA(p, q, beta, alhpa) -// p: the value of the parameter p. -// q: the value of the parameter q. -// beta: the value of ln B(p, q) -// alpha: the value of the lower tail area. -// -double BetaIncompleteInvImpl(const double p, const double q, const double beta, - const double alpha) { - if (alpha < 0.5) { - // Inverse Incomplete beta function is symmetrical, return the complement. - return 1. - BetaIncompleteInvImpl(q, p, beta, 1. - alpha); - } - const double kErr = 1e-14; - double value = kErr; - - // Compute the initial estimate. - { - double r = std::sqrt(-std::log(alpha * alpha)); - double y = - r - fma(r, 0.27061, 2.30753) / fma(r, fma(r, 0.04481, 0.99229), 1.0); - if (p > 1. && q > 1.) { - r = (y * y - 3.) / 6.; - double s = 1. / (p + p - 1.); - double t = 1. / (q + q - 1.); - double h = 2. / s + t; - double w = - y * std::sqrt(h + r) / h - (t - s) * (r + 5. / 6. - t / (3. * h)); - value = p / (p + q * std::exp(w + w)); - } else { - r = q + q; - double t = 1.0 / (9. * q); - double u = 1.0 - t + y * std::sqrt(t); - t = r * (u * u * u); - if (t <= 0) { - value = 1.0 - std::exp((std::log((1.0 - alpha) * q) + beta) / q); - } else { - t = (4.0 * p + r - 2.0) / t; - if (t <= 1) { - value = std::exp((std::log(alpha * p) + beta) / p); - } else { - value = 1.0 - 2.0 / (t + 1.0); - } - } - } - } - - // Solve for x using a modified newton-raphson method using the function - // BetaIncomplete. - { - value = std::max(value, kErr); - value = std::min(value, 1.0 - kErr); - - const double r = 1.0 - p; - const double t = 1.0 - q; - double y; - double yprev = 0; - double sq = 1; - double prev = 1; - for (;;) { - if (value < 0 || value > 1.0) { - // Error case; value went infinite. - return std::numeric_limits<double>::infinity(); - } else if (value == 0 || value == 1) { - y = value; - } else { - y = BetaIncompleteImpl(value, p, q, beta); - if (!std::isfinite(y)) { - return y; - } - } - y = (y - alpha) * - std::exp(beta + r * std::log(value) + t * std::log(1.0 - value)); - if (y * yprev <= 0) { - prev = std::max(sq, std::numeric_limits<double>::min()); - } - double g = 1.0; - for (;;) { - const double adj = g * y; - const double adj_sq = adj * adj; - if (adj_sq >= prev) { - g = g / 3.0; - continue; - } - const double tx = value - adj; - if (tx < 0 || tx > 1) { - g = g / 3.0; - continue; - } - if (prev < kErr) { - return value; - } - if (y * y < kErr) { - return value; - } - if (tx == value) { - return value; - } - if (tx == 0 || tx == 1) { - g = g / 3.0; - continue; - } - value = tx; - yprev = y; - break; - } - } - } - - // NOTES: See also: Asymptotic inversion of the incomplete beta function. - // https://core.ac.uk/download/pdf/82140723.pdf - // - // NOTE: See the Boost library documentation as well: - // https://www.boost.org/doc/libs/1_52_0/libs/math/doc/sf_and_dist/html/math_toolkit/special/sf_beta/ibeta_function.html -} - -} // namespace - -double BetaIncomplete(const double x, const double p, const double q) { - // Error cases. - if (p < 0 || q < 0 || x < 0 || x > 1.0) { - return std::numeric_limits<double>::infinity(); - } - if (x == 0 || x == 1) { - return x; - } - // ln(Beta(p, q)) - double beta = std::lgamma(p) + std::lgamma(q) - std::lgamma(p + q); - return BetaIncompleteImpl(x, p, q, beta); -} - -double BetaIncompleteInv(const double p, const double q, const double alpha) { - // Error cases. - if (p < 0 || q < 0 || alpha < 0 || alpha > 1.0) { - return std::numeric_limits<double>::infinity(); - } - if (alpha == 0 || alpha == 1) { - return alpha; - } - // ln(Beta(p, q)) - double beta = std::lgamma(p) + std::lgamma(q) - std::lgamma(p + q); - return BetaIncompleteInvImpl(p, q, beta, alpha); -} - -// Given `num_trials` trials each with probability `p` of success, the -// probability of no failures is `p^k`. To ensure the probability of a failure -// is no more than `p_fail`, it must be that `p^k == 1 - p_fail`. This function -// computes `p` from that equation. -double RequiredSuccessProbability(const double p_fail, const int num_trials) { - double p = std::exp(std::log(1.0 - p_fail) / static_cast<double>(num_trials)); - ABSL_ASSERT(p > 0); - return p; -} - -double ZScore(double expected_mean, const DistributionMoments& moments) { - return (moments.mean - expected_mean) / - (std::sqrt(moments.variance) / - std::sqrt(static_cast<double>(moments.n))); -} - -double MaxErrorTolerance(double acceptance_probability) { - double one_sided_pvalue = 0.5 * (1.0 - acceptance_probability); - const double max_err = InverseNormalSurvival(one_sided_pvalue); - ABSL_ASSERT(max_err > 0); - return max_err; -} - -} // namespace random_internal +namespace random_internal { +namespace { + +#if defined(__EMSCRIPTEN__) +// Workaround __EMSCRIPTEN__ error: llvm_fma_f64 not found. +inline double fma(double x, double y, double z) { return (x * y) + z; } +#endif + +} // namespace + +DistributionMoments ComputeDistributionMoments( + absl::Span<const double> data_points) { + DistributionMoments result; + + // Compute m1 + for (double x : data_points) { + result.n++; + result.mean += x; + } + result.mean /= static_cast<double>(result.n); + + // Compute m2, m3, m4 + for (double x : data_points) { + double v = x - result.mean; + result.variance += v * v; + result.skewness += v * v * v; + result.kurtosis += v * v * v * v; + } + result.variance /= static_cast<double>(result.n - 1); + + result.skewness /= static_cast<double>(result.n); + result.skewness /= std::pow(result.variance, 1.5); + + result.kurtosis /= static_cast<double>(result.n); + result.kurtosis /= std::pow(result.variance, 2.0); + return result; + + // When validating the min/max count, the following confidence intervals may + // be of use: + // 3.291 * stddev = 99.9% CI + // 2.576 * stddev = 99% CI + // 1.96 * stddev = 95% CI + // 1.65 * stddev = 90% CI +} + +std::ostream& operator<<(std::ostream& os, const DistributionMoments& moments) { + return os << absl::StrFormat("mean=%f, stddev=%f, skewness=%f, kurtosis=%f", + moments.mean, std::sqrt(moments.variance), + moments.skewness, moments.kurtosis); +} + +double InverseNormalSurvival(double x) { + // inv_sf(u) = -sqrt(2) * erfinv(2u-1) + static constexpr double kSqrt2 = 1.4142135623730950488; + return -kSqrt2 * absl::random_internal::erfinv(2 * x - 1.0); +} + +bool Near(absl::string_view msg, double actual, double expected, double bound) { + assert(bound > 0.0); + double delta = fabs(expected - actual); + if (delta < bound) { + return true; + } + + std::string formatted = absl::StrCat( + msg, " actual=", actual, " expected=", expected, " err=", delta / bound); + ABSL_RAW_LOG(INFO, "%s", formatted.c_str()); + return false; +} + +// TODO(absl-team): Replace with an "ABSL_HAVE_SPECIAL_MATH" and try +// to use std::beta(). As of this writing P0226R1 is not implemented +// in libc++: http://libcxx.llvm.org/cxx1z_status.html +double beta(double p, double q) { + // Beta(x, y) = Gamma(x) * Gamma(y) / Gamma(x+y) + double lbeta = std::lgamma(p) + std::lgamma(q) - std::lgamma(p + q); + return std::exp(lbeta); +} + +// Approximation to inverse of the Error Function in double precision. +// (http://people.maths.ox.ac.uk/gilesm/files/gems_erfinv.pdf) +double erfinv(double x) { +#if !defined(__EMSCRIPTEN__) + using std::fma; +#endif + + double w = 0.0; + double p = 0.0; + w = -std::log((1.0 - x) * (1.0 + x)); + if (w < 6.250000) { + w = w - 3.125000; + p = -3.6444120640178196996e-21; + p = fma(p, w, -1.685059138182016589e-19); + p = fma(p, w, 1.2858480715256400167e-18); + p = fma(p, w, 1.115787767802518096e-17); + p = fma(p, w, -1.333171662854620906e-16); + p = fma(p, w, 2.0972767875968561637e-17); + p = fma(p, w, 6.6376381343583238325e-15); + p = fma(p, w, -4.0545662729752068639e-14); + p = fma(p, w, -8.1519341976054721522e-14); + p = fma(p, w, 2.6335093153082322977e-12); + p = fma(p, w, -1.2975133253453532498e-11); + p = fma(p, w, -5.4154120542946279317e-11); + p = fma(p, w, 1.051212273321532285e-09); + p = fma(p, w, -4.1126339803469836976e-09); + p = fma(p, w, -2.9070369957882005086e-08); + p = fma(p, w, 4.2347877827932403518e-07); + p = fma(p, w, -1.3654692000834678645e-06); + p = fma(p, w, -1.3882523362786468719e-05); + p = fma(p, w, 0.0001867342080340571352); + p = fma(p, w, -0.00074070253416626697512); + p = fma(p, w, -0.0060336708714301490533); + p = fma(p, w, 0.24015818242558961693); + p = fma(p, w, 1.6536545626831027356); + } else if (w < 16.000000) { + w = std::sqrt(w) - 3.250000; + p = 2.2137376921775787049e-09; + p = fma(p, w, 9.0756561938885390979e-08); + p = fma(p, w, -2.7517406297064545428e-07); + p = fma(p, w, 1.8239629214389227755e-08); + p = fma(p, w, 1.5027403968909827627e-06); + p = fma(p, w, -4.013867526981545969e-06); + p = fma(p, w, 2.9234449089955446044e-06); + p = fma(p, w, 1.2475304481671778723e-05); + p = fma(p, w, -4.7318229009055733981e-05); + p = fma(p, w, 6.8284851459573175448e-05); + p = fma(p, w, 2.4031110387097893999e-05); + p = fma(p, w, -0.0003550375203628474796); + p = fma(p, w, 0.00095328937973738049703); + p = fma(p, w, -0.0016882755560235047313); + p = fma(p, w, 0.0024914420961078508066); + p = fma(p, w, -0.0037512085075692412107); + p = fma(p, w, 0.005370914553590063617); + p = fma(p, w, 1.0052589676941592334); + p = fma(p, w, 3.0838856104922207635); + } else { + w = std::sqrt(w) - 5.000000; + p = -2.7109920616438573243e-11; + p = fma(p, w, -2.5556418169965252055e-10); + p = fma(p, w, 1.5076572693500548083e-09); + p = fma(p, w, -3.7894654401267369937e-09); + p = fma(p, w, 7.6157012080783393804e-09); + p = fma(p, w, -1.4960026627149240478e-08); + p = fma(p, w, 2.9147953450901080826e-08); + p = fma(p, w, -6.7711997758452339498e-08); + p = fma(p, w, 2.2900482228026654717e-07); + p = fma(p, w, -9.9298272942317002539e-07); + p = fma(p, w, 4.5260625972231537039e-06); + p = fma(p, w, -1.9681778105531670567e-05); + p = fma(p, w, 7.5995277030017761139e-05); + p = fma(p, w, -0.00021503011930044477347); + p = fma(p, w, -0.00013871931833623122026); + p = fma(p, w, 1.0103004648645343977); + p = fma(p, w, 4.8499064014085844221); + } + return p * x; +} + +namespace { + +// Direct implementation of AS63, BETAIN() +// https://www.jstor.org/stable/2346797?seq=3#page_scan_tab_contents. +// +// BETAIN(x, p, q, beta) +// x: the value of the upper limit x. +// p: the value of the parameter p. +// q: the value of the parameter q. +// beta: the value of ln B(p, q) +// +double BetaIncompleteImpl(const double x, const double p, const double q, + const double beta) { + if (p < (p + q) * x) { + // Incomplete beta function is symmetrical, so return the complement. + return 1. - BetaIncompleteImpl(1.0 - x, q, p, beta); + } + + double psq = p + q; + const double kErr = 1e-14; + const double xc = 1. - x; + const double pre = + std::exp(p * std::log(x) + (q - 1.) * std::log(xc) - beta) / p; + + double term = 1.; + double ai = 1.; + double result = 1.; + int ns = static_cast<int>(q + xc * psq); + + // Use the soper reduction forumla. + double rx = (ns == 0) ? x : x / xc; + double temp = q - ai; + for (;;) { + term = term * temp * rx / (p + ai); + result = result + term; + temp = std::fabs(term); + if (temp < kErr && temp < kErr * result) { + return result * pre; + } + ai = ai + 1.; + --ns; + if (ns >= 0) { + temp = q - ai; + if (ns == 0) { + rx = x; + } + } else { + temp = psq; + psq = psq + 1.; + } + } + + // NOTE: See also TOMS Alogrithm 708. + // http://www.netlib.org/toms/index.html + // + // NOTE: The NWSC library also includes BRATIO / ISUBX (p87) + // https://archive.org/details/DTIC_ADA261511/page/n75 +} + +// Direct implementation of AS109, XINBTA(p, q, beta, alpha) +// https://www.jstor.org/stable/2346798?read-now=1&seq=4#page_scan_tab_contents +// https://www.jstor.org/stable/2346887?seq=1#page_scan_tab_contents +// +// XINBTA(p, q, beta, alhpa) +// p: the value of the parameter p. +// q: the value of the parameter q. +// beta: the value of ln B(p, q) +// alpha: the value of the lower tail area. +// +double BetaIncompleteInvImpl(const double p, const double q, const double beta, + const double alpha) { + if (alpha < 0.5) { + // Inverse Incomplete beta function is symmetrical, return the complement. + return 1. - BetaIncompleteInvImpl(q, p, beta, 1. - alpha); + } + const double kErr = 1e-14; + double value = kErr; + + // Compute the initial estimate. + { + double r = std::sqrt(-std::log(alpha * alpha)); + double y = + r - fma(r, 0.27061, 2.30753) / fma(r, fma(r, 0.04481, 0.99229), 1.0); + if (p > 1. && q > 1.) { + r = (y * y - 3.) / 6.; + double s = 1. / (p + p - 1.); + double t = 1. / (q + q - 1.); + double h = 2. / s + t; + double w = + y * std::sqrt(h + r) / h - (t - s) * (r + 5. / 6. - t / (3. * h)); + value = p / (p + q * std::exp(w + w)); + } else { + r = q + q; + double t = 1.0 / (9. * q); + double u = 1.0 - t + y * std::sqrt(t); + t = r * (u * u * u); + if (t <= 0) { + value = 1.0 - std::exp((std::log((1.0 - alpha) * q) + beta) / q); + } else { + t = (4.0 * p + r - 2.0) / t; + if (t <= 1) { + value = std::exp((std::log(alpha * p) + beta) / p); + } else { + value = 1.0 - 2.0 / (t + 1.0); + } + } + } + } + + // Solve for x using a modified newton-raphson method using the function + // BetaIncomplete. + { + value = std::max(value, kErr); + value = std::min(value, 1.0 - kErr); + + const double r = 1.0 - p; + const double t = 1.0 - q; + double y; + double yprev = 0; + double sq = 1; + double prev = 1; + for (;;) { + if (value < 0 || value > 1.0) { + // Error case; value went infinite. + return std::numeric_limits<double>::infinity(); + } else if (value == 0 || value == 1) { + y = value; + } else { + y = BetaIncompleteImpl(value, p, q, beta); + if (!std::isfinite(y)) { + return y; + } + } + y = (y - alpha) * + std::exp(beta + r * std::log(value) + t * std::log(1.0 - value)); + if (y * yprev <= 0) { + prev = std::max(sq, std::numeric_limits<double>::min()); + } + double g = 1.0; + for (;;) { + const double adj = g * y; + const double adj_sq = adj * adj; + if (adj_sq >= prev) { + g = g / 3.0; + continue; + } + const double tx = value - adj; + if (tx < 0 || tx > 1) { + g = g / 3.0; + continue; + } + if (prev < kErr) { + return value; + } + if (y * y < kErr) { + return value; + } + if (tx == value) { + return value; + } + if (tx == 0 || tx == 1) { + g = g / 3.0; + continue; + } + value = tx; + yprev = y; + break; + } + } + } + + // NOTES: See also: Asymptotic inversion of the incomplete beta function. + // https://core.ac.uk/download/pdf/82140723.pdf + // + // NOTE: See the Boost library documentation as well: + // https://www.boost.org/doc/libs/1_52_0/libs/math/doc/sf_and_dist/html/math_toolkit/special/sf_beta/ibeta_function.html +} + +} // namespace + +double BetaIncomplete(const double x, const double p, const double q) { + // Error cases. + if (p < 0 || q < 0 || x < 0 || x > 1.0) { + return std::numeric_limits<double>::infinity(); + } + if (x == 0 || x == 1) { + return x; + } + // ln(Beta(p, q)) + double beta = std::lgamma(p) + std::lgamma(q) - std::lgamma(p + q); + return BetaIncompleteImpl(x, p, q, beta); +} + +double BetaIncompleteInv(const double p, const double q, const double alpha) { + // Error cases. + if (p < 0 || q < 0 || alpha < 0 || alpha > 1.0) { + return std::numeric_limits<double>::infinity(); + } + if (alpha == 0 || alpha == 1) { + return alpha; + } + // ln(Beta(p, q)) + double beta = std::lgamma(p) + std::lgamma(q) - std::lgamma(p + q); + return BetaIncompleteInvImpl(p, q, beta, alpha); +} + +// Given `num_trials` trials each with probability `p` of success, the +// probability of no failures is `p^k`. To ensure the probability of a failure +// is no more than `p_fail`, it must be that `p^k == 1 - p_fail`. This function +// computes `p` from that equation. +double RequiredSuccessProbability(const double p_fail, const int num_trials) { + double p = std::exp(std::log(1.0 - p_fail) / static_cast<double>(num_trials)); + ABSL_ASSERT(p > 0); + return p; +} + +double ZScore(double expected_mean, const DistributionMoments& moments) { + return (moments.mean - expected_mean) / + (std::sqrt(moments.variance) / + std::sqrt(static_cast<double>(moments.n))); +} + +double MaxErrorTolerance(double acceptance_probability) { + double one_sided_pvalue = 0.5 * (1.0 - acceptance_probability); + const double max_err = InverseNormalSurvival(one_sided_pvalue); + ABSL_ASSERT(max_err > 0); + return max_err; +} + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl +} // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/distribution_test_util.h b/contrib/restricted/abseil-cpp/absl/random/internal/distribution_test_util.h index ea44666b4b..6d94cf6c97 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/distribution_test_util.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/distribution_test_util.h @@ -1,113 +1,113 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_INTERNAL_DISTRIBUTION_TEST_UTIL_H_ -#define ABSL_RANDOM_INTERNAL_DISTRIBUTION_TEST_UTIL_H_ - -#include <cstddef> -#include <iostream> -#include <vector> - -#include "absl/strings/string_view.h" -#include "absl/types/span.h" - -// NOTE: The functions in this file are test only, and are should not be used in -// non-test code. - -namespace absl { +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_INTERNAL_DISTRIBUTION_TEST_UTIL_H_ +#define ABSL_RANDOM_INTERNAL_DISTRIBUTION_TEST_UTIL_H_ + +#include <cstddef> +#include <iostream> +#include <vector> + +#include "absl/strings/string_view.h" +#include "absl/types/span.h" + +// NOTE: The functions in this file are test only, and are should not be used in +// non-test code. + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - -// http://webspace.ship.edu/pgmarr/Geo441/Lectures/Lec%205%20-%20Normality%20Testing.pdf - -// Compute the 1st to 4th standard moments: -// mean, variance, skewness, and kurtosis. -// http://www.itl.nist.gov/div898/handbook/eda/section3/eda35b.htm -struct DistributionMoments { - size_t n = 0; - double mean = 0.0; - double variance = 0.0; - double skewness = 0.0; - double kurtosis = 0.0; -}; -DistributionMoments ComputeDistributionMoments( - absl::Span<const double> data_points); - -std::ostream& operator<<(std::ostream& os, const DistributionMoments& moments); - -// Computes the Z-score for a set of data with the given distribution moments -// compared against `expected_mean`. -double ZScore(double expected_mean, const DistributionMoments& moments); - -// Returns the probability of success required for a single trial to ensure that -// after `num_trials` trials, the probability of at least one failure is no more -// than `p_fail`. -double RequiredSuccessProbability(double p_fail, int num_trials); - -// Computes the maximum distance from the mean tolerable, for Z-Tests that are -// expected to pass with `acceptance_probability`. Will terminate if the -// resulting tolerance is zero (due to passing in 0.0 for -// `acceptance_probability` or rounding errors). -// -// For example, -// MaxErrorTolerance(0.001) = 0.0 -// MaxErrorTolerance(0.5) = ~0.47 -// MaxErrorTolerance(1.0) = inf -double MaxErrorTolerance(double acceptance_probability); - -// Approximation to inverse of the Error Function in double precision. -// (http://people.maths.ox.ac.uk/gilesm/files/gems_erfinv.pdf) -double erfinv(double x); - -// Beta(p, q) = Gamma(p) * Gamma(q) / Gamma(p+q) -double beta(double p, double q); - -// The inverse of the normal survival function. -double InverseNormalSurvival(double x); - -// Returns whether actual is "near" expected, based on the bound. -bool Near(absl::string_view msg, double actual, double expected, double bound); - -// Implements the incomplete regularized beta function, AS63, BETAIN. -// https://www.jstor.org/stable/2346797 -// -// BetaIncomplete(x, p, q), where -// `x` is the value of the upper limit -// `p` is beta parameter p, `q` is beta parameter q. -// -// NOTE: This is a test-only function which is only accurate to within, at most, -// 1e-13 of the actual value. -// -double BetaIncomplete(double x, double p, double q); - -// Implements the inverse of the incomplete regularized beta function, AS109, -// XINBTA. -// https://www.jstor.org/stable/2346798 -// https://www.jstor.org/stable/2346887 -// -// BetaIncompleteInv(p, q, beta, alhpa) -// `p` is beta parameter p, `q` is beta parameter q. -// `alpha` is the value of the lower tail area. -// -// NOTE: This is a test-only function and, when successful, is only accurate to -// within ~1e-6 of the actual value; there are some cases where it diverges from -// the actual value by much more than that. The function uses Newton's method, -// and thus the runtime is highly variable. -double BetaIncompleteInv(double p, double q, double alpha); - -} // namespace random_internal +namespace random_internal { + +// http://webspace.ship.edu/pgmarr/Geo441/Lectures/Lec%205%20-%20Normality%20Testing.pdf + +// Compute the 1st to 4th standard moments: +// mean, variance, skewness, and kurtosis. +// http://www.itl.nist.gov/div898/handbook/eda/section3/eda35b.htm +struct DistributionMoments { + size_t n = 0; + double mean = 0.0; + double variance = 0.0; + double skewness = 0.0; + double kurtosis = 0.0; +}; +DistributionMoments ComputeDistributionMoments( + absl::Span<const double> data_points); + +std::ostream& operator<<(std::ostream& os, const DistributionMoments& moments); + +// Computes the Z-score for a set of data with the given distribution moments +// compared against `expected_mean`. +double ZScore(double expected_mean, const DistributionMoments& moments); + +// Returns the probability of success required for a single trial to ensure that +// after `num_trials` trials, the probability of at least one failure is no more +// than `p_fail`. +double RequiredSuccessProbability(double p_fail, int num_trials); + +// Computes the maximum distance from the mean tolerable, for Z-Tests that are +// expected to pass with `acceptance_probability`. Will terminate if the +// resulting tolerance is zero (due to passing in 0.0 for +// `acceptance_probability` or rounding errors). +// +// For example, +// MaxErrorTolerance(0.001) = 0.0 +// MaxErrorTolerance(0.5) = ~0.47 +// MaxErrorTolerance(1.0) = inf +double MaxErrorTolerance(double acceptance_probability); + +// Approximation to inverse of the Error Function in double precision. +// (http://people.maths.ox.ac.uk/gilesm/files/gems_erfinv.pdf) +double erfinv(double x); + +// Beta(p, q) = Gamma(p) * Gamma(q) / Gamma(p+q) +double beta(double p, double q); + +// The inverse of the normal survival function. +double InverseNormalSurvival(double x); + +// Returns whether actual is "near" expected, based on the bound. +bool Near(absl::string_view msg, double actual, double expected, double bound); + +// Implements the incomplete regularized beta function, AS63, BETAIN. +// https://www.jstor.org/stable/2346797 +// +// BetaIncomplete(x, p, q), where +// `x` is the value of the upper limit +// `p` is beta parameter p, `q` is beta parameter q. +// +// NOTE: This is a test-only function which is only accurate to within, at most, +// 1e-13 of the actual value. +// +double BetaIncomplete(double x, double p, double q); + +// Implements the inverse of the incomplete regularized beta function, AS109, +// XINBTA. +// https://www.jstor.org/stable/2346798 +// https://www.jstor.org/stable/2346887 +// +// BetaIncompleteInv(p, q, beta, alhpa) +// `p` is beta parameter p, `q` is beta parameter q. +// `alpha` is the value of the lower tail area. +// +// NOTE: This is a test-only function and, when successful, is only accurate to +// within ~1e-6 of the actual value; there are some cases where it diverges from +// the actual value by much more than that. The function uses Newton's method, +// and thus the runtime is highly variable. +double BetaIncompleteInv(double p, double q, double alpha); + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_DISTRIBUTION_TEST_UTIL_H_ +} // namespace absl + +#endif // ABSL_RANDOM_INTERNAL_DISTRIBUTION_TEST_UTIL_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/explicit_seed_seq.h b/contrib/restricted/abseil-cpp/absl/random/internal/explicit_seed_seq.h index 01db58444a..25f791535f 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/explicit_seed_seq.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/explicit_seed_seq.h @@ -1,92 +1,92 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_INTERNAL_EXPLICIT_SEED_SEQ_H_ -#define ABSL_RANDOM_INTERNAL_EXPLICIT_SEED_SEQ_H_ - -#include <algorithm> -#include <cstddef> -#include <cstdint> -#include <initializer_list> -#include <iterator> -#include <vector> - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_INTERNAL_EXPLICIT_SEED_SEQ_H_ +#define ABSL_RANDOM_INTERNAL_EXPLICIT_SEED_SEQ_H_ + +#include <algorithm> +#include <cstddef> +#include <cstdint> +#include <initializer_list> +#include <iterator> +#include <vector> + #include "absl/base/config.h" #include "absl/base/internal/endian.h" -namespace absl { +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - -// This class conforms to the C++ Standard "Seed Sequence" concept -// [rand.req.seedseq]. -// -// An "ExplicitSeedSeq" is meant to provide a conformant interface for -// forwarding pre-computed seed material to the constructor of a class -// conforming to the "Uniform Random Bit Generator" concept. This class makes no -// attempt to mutate the state provided by its constructor, and returns it -// directly via ExplicitSeedSeq::generate(). -// -// If this class is asked to generate more seed material than was provided to -// the constructor, then the remaining bytes will be filled with deterministic, -// nonrandom data. -class ExplicitSeedSeq { - public: - using result_type = uint32_t; - - ExplicitSeedSeq() : state_() {} - - // Copy and move both allowed. - ExplicitSeedSeq(const ExplicitSeedSeq& other) = default; - ExplicitSeedSeq& operator=(const ExplicitSeedSeq& other) = default; - ExplicitSeedSeq(ExplicitSeedSeq&& other) = default; - ExplicitSeedSeq& operator=(ExplicitSeedSeq&& other) = default; - - template <typename Iterator> - ExplicitSeedSeq(Iterator begin, Iterator end) { - for (auto it = begin; it != end; it++) { - state_.push_back(*it & 0xffffffff); - } - } - - template <typename T> - ExplicitSeedSeq(std::initializer_list<T> il) - : ExplicitSeedSeq(il.begin(), il.end()) {} - - size_t size() const { return state_.size(); } - - template <typename OutIterator> - void param(OutIterator out) const { - std::copy(std::begin(state_), std::end(state_), out); - } - - template <typename OutIterator> - void generate(OutIterator begin, OutIterator end) { - for (size_t index = 0; begin != end; begin++) { +namespace random_internal { + +// This class conforms to the C++ Standard "Seed Sequence" concept +// [rand.req.seedseq]. +// +// An "ExplicitSeedSeq" is meant to provide a conformant interface for +// forwarding pre-computed seed material to the constructor of a class +// conforming to the "Uniform Random Bit Generator" concept. This class makes no +// attempt to mutate the state provided by its constructor, and returns it +// directly via ExplicitSeedSeq::generate(). +// +// If this class is asked to generate more seed material than was provided to +// the constructor, then the remaining bytes will be filled with deterministic, +// nonrandom data. +class ExplicitSeedSeq { + public: + using result_type = uint32_t; + + ExplicitSeedSeq() : state_() {} + + // Copy and move both allowed. + ExplicitSeedSeq(const ExplicitSeedSeq& other) = default; + ExplicitSeedSeq& operator=(const ExplicitSeedSeq& other) = default; + ExplicitSeedSeq(ExplicitSeedSeq&& other) = default; + ExplicitSeedSeq& operator=(ExplicitSeedSeq&& other) = default; + + template <typename Iterator> + ExplicitSeedSeq(Iterator begin, Iterator end) { + for (auto it = begin; it != end; it++) { + state_.push_back(*it & 0xffffffff); + } + } + + template <typename T> + ExplicitSeedSeq(std::initializer_list<T> il) + : ExplicitSeedSeq(il.begin(), il.end()) {} + + size_t size() const { return state_.size(); } + + template <typename OutIterator> + void param(OutIterator out) const { + std::copy(std::begin(state_), std::end(state_), out); + } + + template <typename OutIterator> + void generate(OutIterator begin, OutIterator end) { + for (size_t index = 0; begin != end; begin++) { *begin = state_.empty() ? 0 : state_[index++]; - if (index >= state_.size()) { - index = 0; - } - } - } - - protected: - std::vector<uint32_t> state_; -}; - -} // namespace random_internal + if (index >= state_.size()) { + index = 0; + } + } + } + + protected: + std::vector<uint32_t> state_; +}; + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_EXPLICIT_SEED_SEQ_H_ +} // namespace absl + +#endif // ABSL_RANDOM_INTERNAL_EXPLICIT_SEED_SEQ_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/fast_uniform_bits.h b/contrib/restricted/abseil-cpp/absl/random/internal/fast_uniform_bits.h index 3717a3904d..425aaf7d83 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/fast_uniform_bits.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/fast_uniform_bits.h @@ -1,145 +1,145 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_INTERNAL_FAST_UNIFORM_BITS_H_ -#define ABSL_RANDOM_INTERNAL_FAST_UNIFORM_BITS_H_ - -#include <cstddef> -#include <cstdint> -#include <limits> -#include <type_traits> - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_INTERNAL_FAST_UNIFORM_BITS_H_ +#define ABSL_RANDOM_INTERNAL_FAST_UNIFORM_BITS_H_ + +#include <cstddef> +#include <cstdint> +#include <limits> +#include <type_traits> + #include "absl/base/config.h" #include "absl/meta/type_traits.h" -namespace absl { +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { -// Returns true if the input value is zero or a power of two. Useful for -// determining if the range of output values in a URBG -template <typename UIntType> -constexpr bool IsPowerOfTwoOrZero(UIntType n) { - return (n == 0) || ((n & (n - 1)) == 0); -} - -// Computes the length of the range of values producible by the URBG, or returns -// zero if that would encompass the entire range of representable values in -// URBG::result_type. -template <typename URBG> -constexpr typename URBG::result_type RangeSize() { - using result_type = typename URBG::result_type; +namespace random_internal { +// Returns true if the input value is zero or a power of two. Useful for +// determining if the range of output values in a URBG +template <typename UIntType> +constexpr bool IsPowerOfTwoOrZero(UIntType n) { + return (n == 0) || ((n & (n - 1)) == 0); +} + +// Computes the length of the range of values producible by the URBG, or returns +// zero if that would encompass the entire range of representable values in +// URBG::result_type. +template <typename URBG> +constexpr typename URBG::result_type RangeSize() { + using result_type = typename URBG::result_type; static_assert((URBG::max)() != (URBG::min)(), "URBG range cannot be 0."); - return ((URBG::max)() == (std::numeric_limits<result_type>::max)() && - (URBG::min)() == std::numeric_limits<result_type>::lowest()) - ? result_type{0} + return ((URBG::max)() == (std::numeric_limits<result_type>::max)() && + (URBG::min)() == std::numeric_limits<result_type>::lowest()) + ? result_type{0} : ((URBG::max)() - (URBG::min)() + result_type{1}); -} - -// Computes the floor of the log. (i.e., std::floor(std::log2(N)); -template <typename UIntType> -constexpr UIntType IntegerLog2(UIntType n) { +} + +// Computes the floor of the log. (i.e., std::floor(std::log2(N)); +template <typename UIntType> +constexpr UIntType IntegerLog2(UIntType n) { return (n <= 1) ? 0 : 1 + IntegerLog2(n >> 1); -} - -// Returns the number of bits of randomness returned through -// `PowerOfTwoVariate(urbg)`. -template <typename URBG> -constexpr size_t NumBits() { - return RangeSize<URBG>() == 0 - ? std::numeric_limits<typename URBG::result_type>::digits +} + +// Returns the number of bits of randomness returned through +// `PowerOfTwoVariate(urbg)`. +template <typename URBG> +constexpr size_t NumBits() { + return RangeSize<URBG>() == 0 + ? std::numeric_limits<typename URBG::result_type>::digits : IntegerLog2(RangeSize<URBG>()); -} - -// Given a shift value `n`, constructs a mask with exactly the low `n` bits set. -// If `n == 0`, all bits are set. -template <typename UIntType> +} + +// Given a shift value `n`, constructs a mask with exactly the low `n` bits set. +// If `n == 0`, all bits are set. +template <typename UIntType> constexpr UIntType MaskFromShift(size_t n) { - return ((n % std::numeric_limits<UIntType>::digits) == 0) - ? ~UIntType{0} - : (UIntType{1} << n) - UIntType{1}; -} - + return ((n % std::numeric_limits<UIntType>::digits) == 0) + ? ~UIntType{0} + : (UIntType{1} << n) - UIntType{1}; +} + // Tags used to dispatch FastUniformBits::generate to the simple or more complex // entropy extraction algorithm. struct SimplifiedLoopTag {}; struct RejectionLoopTag {}; -// FastUniformBits implements a fast path to acquire uniform independent bits -// from a type which conforms to the [rand.req.urbg] concept. -// Parameterized by: -// `UIntType`: the result (output) type -// -// The std::independent_bits_engine [rand.adapt.ibits] adaptor can be -// instantiated from an existing generator through a copy or a move. It does -// not, however, facilitate the production of pseudorandom bits from an un-owned -// generator that will outlive the std::independent_bits_engine instance. -template <typename UIntType = uint64_t> -class FastUniformBits { - public: - using result_type = UIntType; - - static constexpr result_type(min)() { return 0; } - static constexpr result_type(max)() { - return (std::numeric_limits<result_type>::max)(); - } - - template <typename URBG> - result_type operator()(URBG& g); // NOLINT(runtime/references) - - private: - static_assert(std::is_unsigned<UIntType>::value, - "Class-template FastUniformBits<> must be parameterized using " - "an unsigned type."); - - // Generate() generates a random value, dispatched on whether +// FastUniformBits implements a fast path to acquire uniform independent bits +// from a type which conforms to the [rand.req.urbg] concept. +// Parameterized by: +// `UIntType`: the result (output) type +// +// The std::independent_bits_engine [rand.adapt.ibits] adaptor can be +// instantiated from an existing generator through a copy or a move. It does +// not, however, facilitate the production of pseudorandom bits from an un-owned +// generator that will outlive the std::independent_bits_engine instance. +template <typename UIntType = uint64_t> +class FastUniformBits { + public: + using result_type = UIntType; + + static constexpr result_type(min)() { return 0; } + static constexpr result_type(max)() { + return (std::numeric_limits<result_type>::max)(); + } + + template <typename URBG> + result_type operator()(URBG& g); // NOLINT(runtime/references) + + private: + static_assert(std::is_unsigned<UIntType>::value, + "Class-template FastUniformBits<> must be parameterized using " + "an unsigned type."); + + // Generate() generates a random value, dispatched on whether // the underlying URBG must use rejection sampling to generate a value, // or whether a simplified loop will suffice. - template <typename URBG> - result_type Generate(URBG& g, // NOLINT(runtime/references) + template <typename URBG> + result_type Generate(URBG& g, // NOLINT(runtime/references) SimplifiedLoopTag); - - template <typename URBG> - result_type Generate(URBG& g, // NOLINT(runtime/references) + + template <typename URBG> + result_type Generate(URBG& g, // NOLINT(runtime/references) RejectionLoopTag); -}; - -template <typename UIntType> -template <typename URBG> -typename FastUniformBits<UIntType>::result_type -FastUniformBits<UIntType>::operator()(URBG& g) { // NOLINT(runtime/references) - // kRangeMask is the mask used when sampling variates from the URBG when the - // width of the URBG range is not a power of 2. - // Y = (2 ^ kRange) - 1 - static_assert((URBG::max)() > (URBG::min)(), - "URBG::max and URBG::min may not be equal."); +}; + +template <typename UIntType> +template <typename URBG> +typename FastUniformBits<UIntType>::result_type +FastUniformBits<UIntType>::operator()(URBG& g) { // NOLINT(runtime/references) + // kRangeMask is the mask used when sampling variates from the URBG when the + // width of the URBG range is not a power of 2. + // Y = (2 ^ kRange) - 1 + static_assert((URBG::max)() > (URBG::min)(), + "URBG::max and URBG::min may not be equal."); using tag = absl::conditional_t<IsPowerOfTwoOrZero(RangeSize<URBG>()), SimplifiedLoopTag, RejectionLoopTag>; return Generate(g, tag{}); -} - -template <typename UIntType> -template <typename URBG> -typename FastUniformBits<UIntType>::result_type -FastUniformBits<UIntType>::Generate(URBG& g, // NOLINT(runtime/references) +} + +template <typename UIntType> +template <typename URBG> +typename FastUniformBits<UIntType>::result_type +FastUniformBits<UIntType>::Generate(URBG& g, // NOLINT(runtime/references) SimplifiedLoopTag) { // The simplified version of FastUniformBits works only on URBGs that have // a range that is a power of 2. In this case we simply loop and shift without // attempting to balance the bits across calls. static_assert(IsPowerOfTwoOrZero(RangeSize<URBG>()), "incorrect Generate tag for URBG instance"); - + static constexpr size_t kResultBits = std::numeric_limits<result_type>::digits; static constexpr size_t kUrbgBits = NumBits<URBG>(); @@ -153,34 +153,34 @@ FastUniformBits<UIntType>::Generate(URBG& g, // NOLINT(runtime/references) r = (r << kShift) + static_cast<result_type>(g() - kMin); } return r; -} - -template <typename UIntType> -template <typename URBG> -typename FastUniformBits<UIntType>::result_type -FastUniformBits<UIntType>::Generate(URBG& g, // NOLINT(runtime/references) +} + +template <typename UIntType> +template <typename URBG> +typename FastUniformBits<UIntType>::result_type +FastUniformBits<UIntType>::Generate(URBG& g, // NOLINT(runtime/references) RejectionLoopTag) { static_assert(!IsPowerOfTwoOrZero(RangeSize<URBG>()), "incorrect Generate tag for URBG instance"); using urbg_result_type = typename URBG::result_type; - // See [rand.adapt.ibits] for more details on the constants calculated below. - // - // It is preferable to use roughly the same number of bits from each generator - // call, however this is only possible when the number of bits provided by the - // URBG is a divisor of the number of bits in `result_type`. In all other - // cases, the number of bits used cannot always be the same, but it can be - // guaranteed to be off by at most 1. Thus we run two loops, one with a - // smaller bit-width size (`kSmallWidth`) and one with a larger width size - // (satisfying `kLargeWidth == kSmallWidth + 1`). The loops are run - // `kSmallIters` and `kLargeIters` times respectively such - // that - // + // See [rand.adapt.ibits] for more details on the constants calculated below. + // + // It is preferable to use roughly the same number of bits from each generator + // call, however this is only possible when the number of bits provided by the + // URBG is a divisor of the number of bits in `result_type`. In all other + // cases, the number of bits used cannot always be the same, but it can be + // guaranteed to be off by at most 1. Thus we run two loops, one with a + // smaller bit-width size (`kSmallWidth`) and one with a larger width size + // (satisfying `kLargeWidth == kSmallWidth + 1`). The loops are run + // `kSmallIters` and `kLargeIters` times respectively such + // that + // // `kResultBits == kSmallIters * kSmallBits // + kLargeIters * kLargeBits` - // + // // where `kResultBits` is the total number of bits in `result_type`. - // + // static constexpr size_t kResultBits = std::numeric_limits<result_type>::digits; // w static constexpr urbg_result_type kUrbgRange = RangeSize<URBG>(); // R @@ -210,24 +210,24 @@ FastUniformBits<UIntType>::Generate(URBG& g, // NOLINT(runtime/references) static constexpr urbg_result_type kLargeRejection = ((kUrbgRange >> kLargeBits) << kLargeBits); // y1 - // + // // Because `kLargeBits == kSmallBits + 1`, it follows that - // + // // `kResultBits == kSmallIters * kSmallBits + kLargeIters` - // - // and therefore - // - // `kLargeIters == kTotalWidth % kSmallWidth` - // - // Intuitively, each iteration with the large width accounts for one unit - // of the remainder when `kTotalWidth` is divided by `kSmallWidth`. As - // mentioned above, if the URBG width is a divisor of `kTotalWidth`, then - // there would be no need for any large iterations (i.e., one loop would - // suffice), and indeed, in this case, `kLargeIters` would be zero. + // + // and therefore + // + // `kLargeIters == kTotalWidth % kSmallWidth` + // + // Intuitively, each iteration with the large width accounts for one unit + // of the remainder when `kTotalWidth` is divided by `kSmallWidth`. As + // mentioned above, if the URBG width is a divisor of `kTotalWidth`, then + // there would be no need for any large iterations (i.e., one loop would + // suffice), and indeed, in this case, `kLargeIters` would be zero. static_assert(kResultBits == kSmallIters * kSmallBits + (kTotalIters - kSmallIters) * kLargeBits, "Error in looping constant calculations."); - + // The small shift is essentially small bits, but due to the potential // of generating a smaller result_type from a larger urbg type, the actual // shift might be 0. @@ -237,32 +237,32 @@ FastUniformBits<UIntType>::Generate(URBG& g, // NOLINT(runtime/references) static constexpr size_t kLargeShift = kLargeBits % kResultBits; static constexpr auto kLargeMask = MaskFromShift<urbg_result_type>(kLargeShift); - + static constexpr auto kMin = (URBG::min)(); - result_type s = 0; - for (size_t n = 0; n < kSmallIters; ++n) { + result_type s = 0; + for (size_t n = 0; n < kSmallIters; ++n) { urbg_result_type v; do { v = g() - kMin; } while (v >= kSmallRejection); - + s = (s << kSmallShift) + static_cast<result_type>(v & kSmallMask); - } - + } + for (size_t n = kSmallIters; n < kTotalIters; ++n) { urbg_result_type v; do { v = g() - kMin; } while (v >= kLargeRejection); - + s = (s << kLargeShift) + static_cast<result_type>(v & kLargeMask); } - return s; -} - -} // namespace random_internal + return s; +} + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_FAST_UNIFORM_BITS_H_ +} // namespace absl + +#endif // ABSL_RANDOM_INTERNAL_FAST_UNIFORM_BITS_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/fastmath.h b/contrib/restricted/abseil-cpp/absl/random/internal/fastmath.h index 83115715dd..963b7690f1 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/fastmath.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/fastmath.h @@ -1,57 +1,57 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_INTERNAL_FASTMATH_H_ -#define ABSL_RANDOM_INTERNAL_FASTMATH_H_ - -// This file contains fast math functions (bitwise ops as well as some others) -// which are implementation details of various absl random number distributions. - -#include <cassert> -#include <cmath> -#include <cstdint> - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_INTERNAL_FASTMATH_H_ +#define ABSL_RANDOM_INTERNAL_FASTMATH_H_ + +// This file contains fast math functions (bitwise ops as well as some others) +// which are implementation details of various absl random number distributions. + +#include <cassert> +#include <cmath> +#include <cstdint> + #include "absl/numeric/bits.h" - -namespace absl { + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - -// Compute log2(n) using integer operations. -// While std::log2 is more accurate than std::log(n) / std::log(2), for -// very large numbers--those close to std::numeric_limits<uint64_t>::max() - 2, -// for instance--std::log2 rounds up rather than down, which introduces -// definite skew in the results. -inline int IntLog2Floor(uint64_t n) { +namespace random_internal { + +// Compute log2(n) using integer operations. +// While std::log2 is more accurate than std::log(n) / std::log(2), for +// very large numbers--those close to std::numeric_limits<uint64_t>::max() - 2, +// for instance--std::log2 rounds up rather than down, which introduces +// definite skew in the results. +inline int IntLog2Floor(uint64_t n) { return (n <= 1) ? 0 : (63 - countl_zero(n)); -} -inline int IntLog2Ceil(uint64_t n) { +} +inline int IntLog2Ceil(uint64_t n) { return (n <= 1) ? 0 : (64 - countl_zero(n - 1)); -} - -inline double StirlingLogFactorial(double n) { - assert(n >= 1); - // Using Stirling's approximation. - constexpr double kLog2PI = 1.83787706640934548356; - const double logn = std::log(n); - const double ninv = 1.0 / static_cast<double>(n); - return n * logn - n + 0.5 * (kLog2PI + logn) + (1.0 / 12.0) * ninv - - (1.0 / 360.0) * ninv * ninv * ninv; -} - -} // namespace random_internal +} + +inline double StirlingLogFactorial(double n) { + assert(n >= 1); + // Using Stirling's approximation. + constexpr double kLog2PI = 1.83787706640934548356; + const double logn = std::log(n); + const double ninv = 1.0 / static_cast<double>(n); + return n * logn - n + 0.5 * (kLog2PI + logn) + (1.0 / 12.0) * ninv - + (1.0 / 360.0) * ninv * ninv * ninv; +} + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_FASTMATH_H_ +} // namespace absl + +#endif // ABSL_RANDOM_INTERNAL_FASTMATH_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/generate_real.h b/contrib/restricted/abseil-cpp/absl/random/internal/generate_real.h index 46ff913090..d5fbb44c24 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/generate_real.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/generate_real.h @@ -1,144 +1,144 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_INTERNAL_GENERATE_REAL_H_ -#define ABSL_RANDOM_INTERNAL_GENERATE_REAL_H_ - -// This file contains some implementation details which are used by one or more -// of the absl random number distributions. - -#include <cstdint> -#include <cstring> -#include <limits> -#include <type_traits> - -#include "absl/meta/type_traits.h" +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_INTERNAL_GENERATE_REAL_H_ +#define ABSL_RANDOM_INTERNAL_GENERATE_REAL_H_ + +// This file contains some implementation details which are used by one or more +// of the absl random number distributions. + +#include <cstdint> +#include <cstring> +#include <limits> +#include <type_traits> + +#include "absl/meta/type_traits.h" #include "absl/numeric/bits.h" -#include "absl/random/internal/fastmath.h" -#include "absl/random/internal/traits.h" - -namespace absl { +#include "absl/random/internal/fastmath.h" +#include "absl/random/internal/traits.h" + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - -// Tristate tag types controlling the output of GenerateRealFromBits. -struct GeneratePositiveTag {}; -struct GenerateNegativeTag {}; -struct GenerateSignedTag {}; - -// GenerateRealFromBits generates a single real value from a single 64-bit -// `bits` with template fields controlling the output. -// -// The `SignedTag` parameter controls whether positive, negative, -// or either signed/unsigned may be returned. -// When SignedTag == GeneratePositiveTag, range is U(0, 1) -// When SignedTag == GenerateNegativeTag, range is U(-1, 0) -// When SignedTag == GenerateSignedTag, range is U(-1, 1) -// -// When the `IncludeZero` parameter is true, the function may return 0 for some -// inputs, otherwise it never returns 0. -// -// When a value in U(0,1) is required, use: -// Uniform64ToReal<double, PositiveValueT, true>; -// -// When a value in U(-1,1) is required, use: -// Uniform64ToReal<double, SignedValueT, false>; -// -// This generates more distinct values than the mathematical equivalent -// `U(0, 1) * 2.0 - 1.0`. -// -// Scaling the result by powers of 2 (and avoiding a multiply) is also possible: -// GenerateRealFromBits<double>(..., -1); => U(0, 0.5) -// GenerateRealFromBits<double>(..., 1); => U(0, 2) -// -template <typename RealType, // Real type, either float or double. - typename SignedTag = GeneratePositiveTag, // Whether a positive, - // negative, or signed - // value is generated. - bool IncludeZero = true> -inline RealType GenerateRealFromBits(uint64_t bits, int exp_bias = 0) { - using real_type = RealType; - using uint_type = absl::conditional_t<std::is_same<real_type, float>::value, - uint32_t, uint64_t>; - - static_assert( - (std::is_same<double, real_type>::value || - std::is_same<float, real_type>::value), - "GenerateRealFromBits must be parameterized by either float or double."); - - static_assert(sizeof(uint_type) == sizeof(real_type), - "Mismatched unsinged and real types."); - - static_assert((std::numeric_limits<real_type>::is_iec559 && - std::numeric_limits<real_type>::radix == 2), - "RealType representation is not IEEE 754 binary."); - - static_assert((std::is_same<SignedTag, GeneratePositiveTag>::value || - std::is_same<SignedTag, GenerateNegativeTag>::value || - std::is_same<SignedTag, GenerateSignedTag>::value), - ""); - - static constexpr int kExp = std::numeric_limits<real_type>::digits - 1; - static constexpr uint_type kMask = (static_cast<uint_type>(1) << kExp) - 1u; - static constexpr int kUintBits = sizeof(uint_type) * 8; - - int exp = exp_bias + int{std::numeric_limits<real_type>::max_exponent - 2}; - - // Determine the sign bit. - // Depending on the SignedTag, this may use the left-most bit - // or it may be a constant value. - uint_type sign = std::is_same<SignedTag, GenerateNegativeTag>::value - ? (static_cast<uint_type>(1) << (kUintBits - 1)) - : 0; - if (std::is_same<SignedTag, GenerateSignedTag>::value) { - if (std::is_same<uint_type, uint64_t>::value) { - sign = bits & uint64_t{0x8000000000000000}; - } - if (std::is_same<uint_type, uint32_t>::value) { - const uint64_t tmp = bits & uint64_t{0x8000000000000000}; - sign = static_cast<uint32_t>(tmp >> 32); - } - // adjust the bits and the exponent to account for removing - // the leading bit. - bits = bits & uint64_t{0x7FFFFFFFFFFFFFFF}; - exp++; - } - if (IncludeZero) { - if (bits == 0u) return 0; - } - - // Number of leading zeros is mapped to the exponent: 2^-clz - // bits is 0..01xxxxxx. After shifting, we're left with 1xxx...0..0 +namespace random_internal { + +// Tristate tag types controlling the output of GenerateRealFromBits. +struct GeneratePositiveTag {}; +struct GenerateNegativeTag {}; +struct GenerateSignedTag {}; + +// GenerateRealFromBits generates a single real value from a single 64-bit +// `bits` with template fields controlling the output. +// +// The `SignedTag` parameter controls whether positive, negative, +// or either signed/unsigned may be returned. +// When SignedTag == GeneratePositiveTag, range is U(0, 1) +// When SignedTag == GenerateNegativeTag, range is U(-1, 0) +// When SignedTag == GenerateSignedTag, range is U(-1, 1) +// +// When the `IncludeZero` parameter is true, the function may return 0 for some +// inputs, otherwise it never returns 0. +// +// When a value in U(0,1) is required, use: +// Uniform64ToReal<double, PositiveValueT, true>; +// +// When a value in U(-1,1) is required, use: +// Uniform64ToReal<double, SignedValueT, false>; +// +// This generates more distinct values than the mathematical equivalent +// `U(0, 1) * 2.0 - 1.0`. +// +// Scaling the result by powers of 2 (and avoiding a multiply) is also possible: +// GenerateRealFromBits<double>(..., -1); => U(0, 0.5) +// GenerateRealFromBits<double>(..., 1); => U(0, 2) +// +template <typename RealType, // Real type, either float or double. + typename SignedTag = GeneratePositiveTag, // Whether a positive, + // negative, or signed + // value is generated. + bool IncludeZero = true> +inline RealType GenerateRealFromBits(uint64_t bits, int exp_bias = 0) { + using real_type = RealType; + using uint_type = absl::conditional_t<std::is_same<real_type, float>::value, + uint32_t, uint64_t>; + + static_assert( + (std::is_same<double, real_type>::value || + std::is_same<float, real_type>::value), + "GenerateRealFromBits must be parameterized by either float or double."); + + static_assert(sizeof(uint_type) == sizeof(real_type), + "Mismatched unsinged and real types."); + + static_assert((std::numeric_limits<real_type>::is_iec559 && + std::numeric_limits<real_type>::radix == 2), + "RealType representation is not IEEE 754 binary."); + + static_assert((std::is_same<SignedTag, GeneratePositiveTag>::value || + std::is_same<SignedTag, GenerateNegativeTag>::value || + std::is_same<SignedTag, GenerateSignedTag>::value), + ""); + + static constexpr int kExp = std::numeric_limits<real_type>::digits - 1; + static constexpr uint_type kMask = (static_cast<uint_type>(1) << kExp) - 1u; + static constexpr int kUintBits = sizeof(uint_type) * 8; + + int exp = exp_bias + int{std::numeric_limits<real_type>::max_exponent - 2}; + + // Determine the sign bit. + // Depending on the SignedTag, this may use the left-most bit + // or it may be a constant value. + uint_type sign = std::is_same<SignedTag, GenerateNegativeTag>::value + ? (static_cast<uint_type>(1) << (kUintBits - 1)) + : 0; + if (std::is_same<SignedTag, GenerateSignedTag>::value) { + if (std::is_same<uint_type, uint64_t>::value) { + sign = bits & uint64_t{0x8000000000000000}; + } + if (std::is_same<uint_type, uint32_t>::value) { + const uint64_t tmp = bits & uint64_t{0x8000000000000000}; + sign = static_cast<uint32_t>(tmp >> 32); + } + // adjust the bits and the exponent to account for removing + // the leading bit. + bits = bits & uint64_t{0x7FFFFFFFFFFFFFFF}; + exp++; + } + if (IncludeZero) { + if (bits == 0u) return 0; + } + + // Number of leading zeros is mapped to the exponent: 2^-clz + // bits is 0..01xxxxxx. After shifting, we're left with 1xxx...0..0 int clz = countl_zero(bits); - bits <<= (IncludeZero ? clz : (clz & 63)); // remove 0-bits. - exp -= clz; // set the exponent. - bits >>= (63 - kExp); - - // Construct the 32-bit or 64-bit IEEE 754 floating-point value from - // the individual fields: sign, exp, mantissa(bits). + bits <<= (IncludeZero ? clz : (clz & 63)); // remove 0-bits. + exp -= clz; // set the exponent. + bits >>= (63 - kExp); + + // Construct the 32-bit or 64-bit IEEE 754 floating-point value from + // the individual fields: sign, exp, mantissa(bits). uint_type val = sign | (static_cast<uint_type>(exp) << kExp) | (static_cast<uint_type>(bits) & kMask); - - // bit_cast to the output-type - real_type result; - memcpy(static_cast<void*>(&result), static_cast<const void*>(&val), - sizeof(result)); - return result; -} - -} // namespace random_internal + + // bit_cast to the output-type + real_type result; + memcpy(static_cast<void*>(&result), static_cast<const void*>(&val), + sizeof(result)); + return result; +} + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_GENERATE_REAL_H_ +} // namespace absl + +#endif // ABSL_RANDOM_INTERNAL_GENERATE_REAL_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/iostream_state_saver.h b/contrib/restricted/abseil-cpp/absl/random/internal/iostream_state_saver.h index aaef9f476c..e6e242ee1e 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/iostream_state_saver.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/iostream_state_saver.h @@ -1,245 +1,245 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_INTERNAL_IOSTREAM_STATE_SAVER_H_ -#define ABSL_RANDOM_INTERNAL_IOSTREAM_STATE_SAVER_H_ - -#include <cmath> -#include <iostream> -#include <limits> -#include <type_traits> - -#include "absl/meta/type_traits.h" -#include "absl/numeric/int128.h" - -namespace absl { +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_INTERNAL_IOSTREAM_STATE_SAVER_H_ +#define ABSL_RANDOM_INTERNAL_IOSTREAM_STATE_SAVER_H_ + +#include <cmath> +#include <iostream> +#include <limits> +#include <type_traits> + +#include "absl/meta/type_traits.h" +#include "absl/numeric/int128.h" + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - -// The null_state_saver does nothing. -template <typename T> -class null_state_saver { - public: - using stream_type = T; - using flags_type = std::ios_base::fmtflags; - - null_state_saver(T&, flags_type) {} - ~null_state_saver() {} -}; - -// ostream_state_saver is a RAII object to save and restore the common -// basic_ostream flags used when implementing `operator <<()` on any of -// the absl random distributions. -template <typename OStream> -class ostream_state_saver { - public: - using ostream_type = OStream; - using flags_type = std::ios_base::fmtflags; - using fill_type = typename ostream_type::char_type; - using precision_type = std::streamsize; - - ostream_state_saver(ostream_type& os, // NOLINT(runtime/references) - flags_type flags, fill_type fill) - : os_(os), - flags_(os.flags(flags)), - fill_(os.fill(fill)), - precision_(os.precision()) { - // Save state in initialized variables. - } - - ~ostream_state_saver() { - // Restore saved state. - os_.precision(precision_); - os_.fill(fill_); - os_.flags(flags_); - } - - private: - ostream_type& os_; - const flags_type flags_; - const fill_type fill_; - const precision_type precision_; -}; - -#if defined(__NDK_MAJOR__) && __NDK_MAJOR__ < 16 -#define ABSL_RANDOM_INTERNAL_IOSTREAM_HEXFLOAT 1 -#else -#define ABSL_RANDOM_INTERNAL_IOSTREAM_HEXFLOAT 0 -#endif - -template <typename CharT, typename Traits> -ostream_state_saver<std::basic_ostream<CharT, Traits>> make_ostream_state_saver( - std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) - std::ios_base::fmtflags flags = std::ios_base::dec | std::ios_base::left | -#if ABSL_RANDOM_INTERNAL_IOSTREAM_HEXFLOAT - std::ios_base::fixed | -#endif - std::ios_base::scientific) { - using result_type = ostream_state_saver<std::basic_ostream<CharT, Traits>>; - return result_type(os, flags, os.widen(' ')); -} - -template <typename T> -typename absl::enable_if_t<!std::is_base_of<std::ios_base, T>::value, - null_state_saver<T>> -make_ostream_state_saver(T& is, // NOLINT(runtime/references) - std::ios_base::fmtflags flags = std::ios_base::dec) { - std::cerr << "null_state_saver"; - using result_type = null_state_saver<T>; - return result_type(is, flags); -} - -// stream_precision_helper<type>::kPrecision returns the base 10 precision -// required to stream and reconstruct a real type exact binary value through -// a binary->decimal->binary transition. -template <typename T> -struct stream_precision_helper { - // max_digits10 may be 0 on MSVC; if so, use digits10 + 3. - static constexpr int kPrecision = - (std::numeric_limits<T>::max_digits10 > std::numeric_limits<T>::digits10) - ? std::numeric_limits<T>::max_digits10 - : (std::numeric_limits<T>::digits10 + 3); -}; - -template <> -struct stream_precision_helper<float> { - static constexpr int kPrecision = 9; -}; -template <> -struct stream_precision_helper<double> { - static constexpr int kPrecision = 17; -}; -template <> -struct stream_precision_helper<long double> { - static constexpr int kPrecision = 36; // assuming fp128 -}; - -// istream_state_saver is a RAII object to save and restore the common -// std::basic_istream<> flags used when implementing `operator >>()` on any of -// the absl random distributions. -template <typename IStream> -class istream_state_saver { - public: - using istream_type = IStream; - using flags_type = std::ios_base::fmtflags; - - istream_state_saver(istream_type& is, // NOLINT(runtime/references) - flags_type flags) - : is_(is), flags_(is.flags(flags)) {} - - ~istream_state_saver() { is_.flags(flags_); } - - private: - istream_type& is_; - flags_type flags_; -}; - -template <typename CharT, typename Traits> -istream_state_saver<std::basic_istream<CharT, Traits>> make_istream_state_saver( - std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) - std::ios_base::fmtflags flags = std::ios_base::dec | - std::ios_base::scientific | - std::ios_base::skipws) { - using result_type = istream_state_saver<std::basic_istream<CharT, Traits>>; - return result_type(is, flags); -} - -template <typename T> -typename absl::enable_if_t<!std::is_base_of<std::ios_base, T>::value, - null_state_saver<T>> -make_istream_state_saver(T& is, // NOLINT(runtime/references) - std::ios_base::fmtflags flags = std::ios_base::dec) { - using result_type = null_state_saver<T>; - return result_type(is, flags); -} - -// stream_format_type<T> is a helper struct to convert types which -// basic_iostream cannot output as decimal numbers into types which -// basic_iostream can output as decimal numbers. Specifically: -// * signed/unsigned char-width types are converted to int. -// * TODO(lar): __int128 => uint128, except there is no operator << yet. -// -template <typename T> -struct stream_format_type - : public std::conditional<(sizeof(T) == sizeof(char)), int, T> {}; - -// stream_u128_helper allows us to write out either absl::uint128 or -// __uint128_t types in the same way, which enables their use as internal -// state of PRNG engines. -template <typename T> -struct stream_u128_helper; - -template <> -struct stream_u128_helper<absl::uint128> { - template <typename IStream> - inline absl::uint128 read(IStream& in) { - uint64_t h = 0; - uint64_t l = 0; - in >> h >> l; - return absl::MakeUint128(h, l); - } - - template <typename OStream> - inline void write(absl::uint128 val, OStream& out) { +namespace random_internal { + +// The null_state_saver does nothing. +template <typename T> +class null_state_saver { + public: + using stream_type = T; + using flags_type = std::ios_base::fmtflags; + + null_state_saver(T&, flags_type) {} + ~null_state_saver() {} +}; + +// ostream_state_saver is a RAII object to save and restore the common +// basic_ostream flags used when implementing `operator <<()` on any of +// the absl random distributions. +template <typename OStream> +class ostream_state_saver { + public: + using ostream_type = OStream; + using flags_type = std::ios_base::fmtflags; + using fill_type = typename ostream_type::char_type; + using precision_type = std::streamsize; + + ostream_state_saver(ostream_type& os, // NOLINT(runtime/references) + flags_type flags, fill_type fill) + : os_(os), + flags_(os.flags(flags)), + fill_(os.fill(fill)), + precision_(os.precision()) { + // Save state in initialized variables. + } + + ~ostream_state_saver() { + // Restore saved state. + os_.precision(precision_); + os_.fill(fill_); + os_.flags(flags_); + } + + private: + ostream_type& os_; + const flags_type flags_; + const fill_type fill_; + const precision_type precision_; +}; + +#if defined(__NDK_MAJOR__) && __NDK_MAJOR__ < 16 +#define ABSL_RANDOM_INTERNAL_IOSTREAM_HEXFLOAT 1 +#else +#define ABSL_RANDOM_INTERNAL_IOSTREAM_HEXFLOAT 0 +#endif + +template <typename CharT, typename Traits> +ostream_state_saver<std::basic_ostream<CharT, Traits>> make_ostream_state_saver( + std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) + std::ios_base::fmtflags flags = std::ios_base::dec | std::ios_base::left | +#if ABSL_RANDOM_INTERNAL_IOSTREAM_HEXFLOAT + std::ios_base::fixed | +#endif + std::ios_base::scientific) { + using result_type = ostream_state_saver<std::basic_ostream<CharT, Traits>>; + return result_type(os, flags, os.widen(' ')); +} + +template <typename T> +typename absl::enable_if_t<!std::is_base_of<std::ios_base, T>::value, + null_state_saver<T>> +make_ostream_state_saver(T& is, // NOLINT(runtime/references) + std::ios_base::fmtflags flags = std::ios_base::dec) { + std::cerr << "null_state_saver"; + using result_type = null_state_saver<T>; + return result_type(is, flags); +} + +// stream_precision_helper<type>::kPrecision returns the base 10 precision +// required to stream and reconstruct a real type exact binary value through +// a binary->decimal->binary transition. +template <typename T> +struct stream_precision_helper { + // max_digits10 may be 0 on MSVC; if so, use digits10 + 3. + static constexpr int kPrecision = + (std::numeric_limits<T>::max_digits10 > std::numeric_limits<T>::digits10) + ? std::numeric_limits<T>::max_digits10 + : (std::numeric_limits<T>::digits10 + 3); +}; + +template <> +struct stream_precision_helper<float> { + static constexpr int kPrecision = 9; +}; +template <> +struct stream_precision_helper<double> { + static constexpr int kPrecision = 17; +}; +template <> +struct stream_precision_helper<long double> { + static constexpr int kPrecision = 36; // assuming fp128 +}; + +// istream_state_saver is a RAII object to save and restore the common +// std::basic_istream<> flags used when implementing `operator >>()` on any of +// the absl random distributions. +template <typename IStream> +class istream_state_saver { + public: + using istream_type = IStream; + using flags_type = std::ios_base::fmtflags; + + istream_state_saver(istream_type& is, // NOLINT(runtime/references) + flags_type flags) + : is_(is), flags_(is.flags(flags)) {} + + ~istream_state_saver() { is_.flags(flags_); } + + private: + istream_type& is_; + flags_type flags_; +}; + +template <typename CharT, typename Traits> +istream_state_saver<std::basic_istream<CharT, Traits>> make_istream_state_saver( + std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) + std::ios_base::fmtflags flags = std::ios_base::dec | + std::ios_base::scientific | + std::ios_base::skipws) { + using result_type = istream_state_saver<std::basic_istream<CharT, Traits>>; + return result_type(is, flags); +} + +template <typename T> +typename absl::enable_if_t<!std::is_base_of<std::ios_base, T>::value, + null_state_saver<T>> +make_istream_state_saver(T& is, // NOLINT(runtime/references) + std::ios_base::fmtflags flags = std::ios_base::dec) { + using result_type = null_state_saver<T>; + return result_type(is, flags); +} + +// stream_format_type<T> is a helper struct to convert types which +// basic_iostream cannot output as decimal numbers into types which +// basic_iostream can output as decimal numbers. Specifically: +// * signed/unsigned char-width types are converted to int. +// * TODO(lar): __int128 => uint128, except there is no operator << yet. +// +template <typename T> +struct stream_format_type + : public std::conditional<(sizeof(T) == sizeof(char)), int, T> {}; + +// stream_u128_helper allows us to write out either absl::uint128 or +// __uint128_t types in the same way, which enables their use as internal +// state of PRNG engines. +template <typename T> +struct stream_u128_helper; + +template <> +struct stream_u128_helper<absl::uint128> { + template <typename IStream> + inline absl::uint128 read(IStream& in) { + uint64_t h = 0; + uint64_t l = 0; + in >> h >> l; + return absl::MakeUint128(h, l); + } + + template <typename OStream> + inline void write(absl::uint128 val, OStream& out) { uint64_t h = absl::Uint128High64(val); uint64_t l = absl::Uint128Low64(val); - out << h << out.fill() << l; - } -}; - -#ifdef ABSL_HAVE_INTRINSIC_INT128 -template <> -struct stream_u128_helper<__uint128_t> { - template <typename IStream> - inline __uint128_t read(IStream& in) { - uint64_t h = 0; - uint64_t l = 0; - in >> h >> l; - return (static_cast<__uint128_t>(h) << 64) | l; - } - - template <typename OStream> - inline void write(__uint128_t val, OStream& out) { - uint64_t h = static_cast<uint64_t>(val >> 64u); - uint64_t l = static_cast<uint64_t>(val); - out << h << out.fill() << l; - } -}; -#endif - -template <typename FloatType, typename IStream> -inline FloatType read_floating_point(IStream& is) { - static_assert(std::is_floating_point<FloatType>::value, ""); - FloatType dest; - is >> dest; - // Parsing a double value may report a subnormal value as an error - // despite being able to represent it. - // See https://stackoverflow.com/q/52410931/3286653 - // It may also report an underflow when parsing DOUBLE_MIN as an - // ERANGE error, as the parsed value may be smaller than DOUBLE_MIN - // and rounded up. - // See: https://stackoverflow.com/q/42005462 - if (is.fail() && - (std::fabs(dest) == (std::numeric_limits<FloatType>::min)() || - std::fpclassify(dest) == FP_SUBNORMAL)) { - is.clear(is.rdstate() & (~std::ios_base::failbit)); - } - return dest; -} - -} // namespace random_internal + out << h << out.fill() << l; + } +}; + +#ifdef ABSL_HAVE_INTRINSIC_INT128 +template <> +struct stream_u128_helper<__uint128_t> { + template <typename IStream> + inline __uint128_t read(IStream& in) { + uint64_t h = 0; + uint64_t l = 0; + in >> h >> l; + return (static_cast<__uint128_t>(h) << 64) | l; + } + + template <typename OStream> + inline void write(__uint128_t val, OStream& out) { + uint64_t h = static_cast<uint64_t>(val >> 64u); + uint64_t l = static_cast<uint64_t>(val); + out << h << out.fill() << l; + } +}; +#endif + +template <typename FloatType, typename IStream> +inline FloatType read_floating_point(IStream& is) { + static_assert(std::is_floating_point<FloatType>::value, ""); + FloatType dest; + is >> dest; + // Parsing a double value may report a subnormal value as an error + // despite being able to represent it. + // See https://stackoverflow.com/q/52410931/3286653 + // It may also report an underflow when parsing DOUBLE_MIN as an + // ERANGE error, as the parsed value may be smaller than DOUBLE_MIN + // and rounded up. + // See: https://stackoverflow.com/q/42005462 + if (is.fail() && + (std::fabs(dest) == (std::numeric_limits<FloatType>::min)() || + std::fpclassify(dest) == FP_SUBNORMAL)) { + is.clear(is.rdstate() & (~std::ios_base::failbit)); + } + return dest; +} + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_IOSTREAM_STATE_SAVER_H_ +} // namespace absl + +#endif // ABSL_RANDOM_INTERNAL_IOSTREAM_STATE_SAVER_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/nanobenchmark.h b/contrib/restricted/abseil-cpp/absl/random/internal/nanobenchmark.h index 103c05f156..a5097ba27b 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/nanobenchmark.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/nanobenchmark.h @@ -1,172 +1,172 @@ -// Copyright 2017 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_INTERNAL_NANOBENCHMARK_H_ -#define ABSL_RANDOM_INTERNAL_NANOBENCHMARK_H_ - -// Benchmarks functions of a single integer argument with realistic branch -// prediction hit rates. Uses a robust estimator to summarize the measurements. -// The precision is about 0.2%. -// -// Examples: see nanobenchmark_test.cc. -// -// Background: Microbenchmarks such as http://github.com/google/benchmark -// can measure elapsed times on the order of a microsecond. Shorter functions -// are typically measured by repeating them thousands of times and dividing -// the total elapsed time by this count. Unfortunately, repetition (especially -// with the same input parameter!) influences the runtime. In time-critical -// code, it is reasonable to expect warm instruction/data caches and TLBs, -// but a perfect record of which branches will be taken is unrealistic. -// Unless the application also repeatedly invokes the measured function with -// the same parameter, the benchmark is measuring something very different - -// a best-case result, almost as if the parameter were made a compile-time -// constant. This may lead to erroneous conclusions about branch-heavy -// algorithms outperforming branch-free alternatives. -// -// Our approach differs in three ways. Adding fences to the timer functions -// reduces variability due to instruction reordering, improving the timer -// resolution to about 40 CPU cycles. However, shorter functions must still -// be invoked repeatedly. For more realistic branch prediction performance, -// we vary the input parameter according to a user-specified distribution. -// Thus, instead of VaryInputs(Measure(Repeat(func))), we change the -// loop nesting to Measure(Repeat(VaryInputs(func))). We also estimate the -// central tendency of the measurement samples with the "half sample mode", -// which is more robust to outliers and skewed data than the mean or median. - -// NOTE: for compatibility with multiple translation units compiled with -// distinct flags, avoid #including headers that define functions. - -#include <stddef.h> -#include <stdint.h> - +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_INTERNAL_NANOBENCHMARK_H_ +#define ABSL_RANDOM_INTERNAL_NANOBENCHMARK_H_ + +// Benchmarks functions of a single integer argument with realistic branch +// prediction hit rates. Uses a robust estimator to summarize the measurements. +// The precision is about 0.2%. +// +// Examples: see nanobenchmark_test.cc. +// +// Background: Microbenchmarks such as http://github.com/google/benchmark +// can measure elapsed times on the order of a microsecond. Shorter functions +// are typically measured by repeating them thousands of times and dividing +// the total elapsed time by this count. Unfortunately, repetition (especially +// with the same input parameter!) influences the runtime. In time-critical +// code, it is reasonable to expect warm instruction/data caches and TLBs, +// but a perfect record of which branches will be taken is unrealistic. +// Unless the application also repeatedly invokes the measured function with +// the same parameter, the benchmark is measuring something very different - +// a best-case result, almost as if the parameter were made a compile-time +// constant. This may lead to erroneous conclusions about branch-heavy +// algorithms outperforming branch-free alternatives. +// +// Our approach differs in three ways. Adding fences to the timer functions +// reduces variability due to instruction reordering, improving the timer +// resolution to about 40 CPU cycles. However, shorter functions must still +// be invoked repeatedly. For more realistic branch prediction performance, +// we vary the input parameter according to a user-specified distribution. +// Thus, instead of VaryInputs(Measure(Repeat(func))), we change the +// loop nesting to Measure(Repeat(VaryInputs(func))). We also estimate the +// central tendency of the measurement samples with the "half sample mode", +// which is more robust to outliers and skewed data than the mean or median. + +// NOTE: for compatibility with multiple translation units compiled with +// distinct flags, avoid #including headers that define functions. + +#include <stddef.h> +#include <stdint.h> + #include "absl/base/config.h" -namespace absl { +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal_nanobenchmark { - -// Input influencing the function being measured (e.g. number of bytes to copy). -using FuncInput = size_t; - -// "Proof of work" returned by Func to ensure the compiler does not elide it. -using FuncOutput = uint64_t; - -// Function to measure: either 1) a captureless lambda or function with two -// arguments or 2) a lambda with capture, in which case the first argument -// is reserved for use by MeasureClosure. -using Func = FuncOutput (*)(const void*, FuncInput); - -// Internal parameters that determine precision/resolution/measuring time. -struct Params { - // For measuring timer overhead/resolution. Used in a nested loop => - // quadratic time, acceptable because we know timer overhead is "low". - // constexpr because this is used to define array bounds. - static constexpr size_t kTimerSamples = 256; - - // Best-case precision, expressed as a divisor of the timer resolution. - // Larger => more calls to Func and higher precision. - size_t precision_divisor = 1024; - - // Ratio between full and subset input distribution sizes. Cannot be less - // than 2; larger values increase measurement time but more faithfully - // model the given input distribution. - size_t subset_ratio = 2; - - // Together with the estimated Func duration, determines how many times to - // call Func before checking the sample variability. Larger values increase - // measurement time, memory/cache use and precision. - double seconds_per_eval = 4E-3; - - // The minimum number of samples before estimating the central tendency. - size_t min_samples_per_eval = 7; - - // The mode is better than median for estimating the central tendency of - // skewed/fat-tailed distributions, but it requires sufficient samples - // relative to the width of half-ranges. - size_t min_mode_samples = 64; - - // Maximum permissible variability (= median absolute deviation / center). - double target_rel_mad = 0.002; - - // Abort after this many evals without reaching target_rel_mad. This - // prevents infinite loops. - size_t max_evals = 9; - - // Retry the measure loop up to this many times. - size_t max_measure_retries = 2; - - // Whether to print additional statistics to stdout. - bool verbose = true; -}; - -// Measurement result for each unique input. -struct Result { - FuncInput input; - - // Robust estimate (mode or median) of duration. - float ticks; - - // Measure of variability (median absolute deviation relative to "ticks"). - float variability; -}; - -// Ensures the thread is running on the specified cpu, and no others. -// Reduces noise due to desynchronized socket RDTSC and context switches. -// If "cpu" is negative, pin to the currently running core. -void PinThreadToCPU(const int cpu = -1); - -// Returns tick rate, useful for converting measurements to seconds. Invariant -// means the tick counter frequency is independent of CPU throttling or sleep. -// This call may be expensive, callers should cache the result. -double InvariantTicksPerSecond(); - -// Precisely measures the number of ticks elapsed when calling "func" with the -// given inputs, shuffled to ensure realistic branch prediction hit rates. -// -// "func" returns a 'proof of work' to ensure its computations are not elided. -// "arg" is passed to Func, or reserved for internal use by MeasureClosure. -// "inputs" is an array of "num_inputs" (not necessarily unique) arguments to -// "func". The values should be chosen to maximize coverage of "func". This -// represents a distribution, so a value's frequency should reflect its -// probability in the real application. Order does not matter; for example, a -// uniform distribution over [0, 4) could be represented as {3,0,2,1}. -// Returns how many Result were written to "results": one per unique input, or -// zero if the measurement failed (an error message goes to stderr). -size_t Measure(const Func func, const void* arg, const FuncInput* inputs, - const size_t num_inputs, Result* results, - const Params& p = Params()); - -// Calls operator() of the given closure (lambda function). -template <class Closure> -static FuncOutput CallClosure(const void* f, const FuncInput input) { - return (*reinterpret_cast<const Closure*>(f))(input); -} - -// Same as Measure, except "closure" is typically a lambda function of -// FuncInput -> FuncOutput with a capture list. -template <class Closure> -static inline size_t MeasureClosure(const Closure& closure, - const FuncInput* inputs, - const size_t num_inputs, Result* results, - const Params& p = Params()) { - return Measure(reinterpret_cast<Func>(&CallClosure<Closure>), - reinterpret_cast<const void*>(&closure), inputs, num_inputs, - results, p); -} - -} // namespace random_internal_nanobenchmark +namespace random_internal_nanobenchmark { + +// Input influencing the function being measured (e.g. number of bytes to copy). +using FuncInput = size_t; + +// "Proof of work" returned by Func to ensure the compiler does not elide it. +using FuncOutput = uint64_t; + +// Function to measure: either 1) a captureless lambda or function with two +// arguments or 2) a lambda with capture, in which case the first argument +// is reserved for use by MeasureClosure. +using Func = FuncOutput (*)(const void*, FuncInput); + +// Internal parameters that determine precision/resolution/measuring time. +struct Params { + // For measuring timer overhead/resolution. Used in a nested loop => + // quadratic time, acceptable because we know timer overhead is "low". + // constexpr because this is used to define array bounds. + static constexpr size_t kTimerSamples = 256; + + // Best-case precision, expressed as a divisor of the timer resolution. + // Larger => more calls to Func and higher precision. + size_t precision_divisor = 1024; + + // Ratio between full and subset input distribution sizes. Cannot be less + // than 2; larger values increase measurement time but more faithfully + // model the given input distribution. + size_t subset_ratio = 2; + + // Together with the estimated Func duration, determines how many times to + // call Func before checking the sample variability. Larger values increase + // measurement time, memory/cache use and precision. + double seconds_per_eval = 4E-3; + + // The minimum number of samples before estimating the central tendency. + size_t min_samples_per_eval = 7; + + // The mode is better than median for estimating the central tendency of + // skewed/fat-tailed distributions, but it requires sufficient samples + // relative to the width of half-ranges. + size_t min_mode_samples = 64; + + // Maximum permissible variability (= median absolute deviation / center). + double target_rel_mad = 0.002; + + // Abort after this many evals without reaching target_rel_mad. This + // prevents infinite loops. + size_t max_evals = 9; + + // Retry the measure loop up to this many times. + size_t max_measure_retries = 2; + + // Whether to print additional statistics to stdout. + bool verbose = true; +}; + +// Measurement result for each unique input. +struct Result { + FuncInput input; + + // Robust estimate (mode or median) of duration. + float ticks; + + // Measure of variability (median absolute deviation relative to "ticks"). + float variability; +}; + +// Ensures the thread is running on the specified cpu, and no others. +// Reduces noise due to desynchronized socket RDTSC and context switches. +// If "cpu" is negative, pin to the currently running core. +void PinThreadToCPU(const int cpu = -1); + +// Returns tick rate, useful for converting measurements to seconds. Invariant +// means the tick counter frequency is independent of CPU throttling or sleep. +// This call may be expensive, callers should cache the result. +double InvariantTicksPerSecond(); + +// Precisely measures the number of ticks elapsed when calling "func" with the +// given inputs, shuffled to ensure realistic branch prediction hit rates. +// +// "func" returns a 'proof of work' to ensure its computations are not elided. +// "arg" is passed to Func, or reserved for internal use by MeasureClosure. +// "inputs" is an array of "num_inputs" (not necessarily unique) arguments to +// "func". The values should be chosen to maximize coverage of "func". This +// represents a distribution, so a value's frequency should reflect its +// probability in the real application. Order does not matter; for example, a +// uniform distribution over [0, 4) could be represented as {3,0,2,1}. +// Returns how many Result were written to "results": one per unique input, or +// zero if the measurement failed (an error message goes to stderr). +size_t Measure(const Func func, const void* arg, const FuncInput* inputs, + const size_t num_inputs, Result* results, + const Params& p = Params()); + +// Calls operator() of the given closure (lambda function). +template <class Closure> +static FuncOutput CallClosure(const void* f, const FuncInput input) { + return (*reinterpret_cast<const Closure*>(f))(input); +} + +// Same as Measure, except "closure" is typically a lambda function of +// FuncInput -> FuncOutput with a capture list. +template <class Closure> +static inline size_t MeasureClosure(const Closure& closure, + const FuncInput* inputs, + const size_t num_inputs, Result* results, + const Params& p = Params()) { + return Measure(reinterpret_cast<Func>(&CallClosure<Closure>), + reinterpret_cast<const void*>(&closure), inputs, num_inputs, + results, p); +} + +} // namespace random_internal_nanobenchmark ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_NANOBENCHMARK_H_ +} // namespace absl + +#endif // ABSL_RANDOM_INTERNAL_NANOBENCHMARK_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/nonsecure_base.h b/contrib/restricted/abseil-cpp/absl/random/internal/nonsecure_base.h index 2635b75d70..730fa2ea12 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/nonsecure_base.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/nonsecure_base.h @@ -1,150 +1,150 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_INTERNAL_NONSECURE_BASE_H_ -#define ABSL_RANDOM_INTERNAL_NONSECURE_BASE_H_ - -#include <algorithm> -#include <cstdint> -#include <iostream> -#include <iterator> -#include <random> -#include <string> -#include <type_traits> -#include <vector> - -#include "absl/base/macros.h" -#include "absl/meta/type_traits.h" -#include "absl/random/internal/pool_urbg.h" -#include "absl/random/internal/salted_seed_seq.h" -#include "absl/random/internal/seed_material.h" -#include "absl/types/optional.h" -#include "absl/types/span.h" - -namespace absl { +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_INTERNAL_NONSECURE_BASE_H_ +#define ABSL_RANDOM_INTERNAL_NONSECURE_BASE_H_ + +#include <algorithm> +#include <cstdint> +#include <iostream> +#include <iterator> +#include <random> +#include <string> +#include <type_traits> +#include <vector> + +#include "absl/base/macros.h" +#include "absl/meta/type_traits.h" +#include "absl/random/internal/pool_urbg.h" +#include "absl/random/internal/salted_seed_seq.h" +#include "absl/random/internal/seed_material.h" +#include "absl/types/optional.h" +#include "absl/types/span.h" + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - -// Each instance of NonsecureURBGBase<URBG> will be seeded by variates produced -// by a thread-unique URBG-instance. -template <typename URBG> -class NonsecureURBGBase { - public: - using result_type = typename URBG::result_type; - - // Default constructor - NonsecureURBGBase() : urbg_(ConstructURBG()) {} - - // Copy disallowed, move allowed. - NonsecureURBGBase(const NonsecureURBGBase&) = delete; - NonsecureURBGBase& operator=(const NonsecureURBGBase&) = delete; - NonsecureURBGBase(NonsecureURBGBase&&) = default; - NonsecureURBGBase& operator=(NonsecureURBGBase&&) = default; - - // Constructor using a seed - template <class SSeq, typename = typename absl::enable_if_t< - !std::is_same<SSeq, NonsecureURBGBase>::value>> - explicit NonsecureURBGBase(SSeq&& seq) - : urbg_(ConstructURBG(std::forward<SSeq>(seq))) {} - - // Note: on MSVC, min() or max() can be interpreted as MIN() or MAX(), so we - // enclose min() or max() in parens as (min)() and (max)(). - // Additionally, clang-format requires no space before this construction. - - // NonsecureURBGBase::min() - static constexpr result_type(min)() { return (URBG::min)(); } - - // NonsecureURBGBase::max() - static constexpr result_type(max)() { return (URBG::max)(); } - - // NonsecureURBGBase::operator()() - result_type operator()() { return urbg_(); } - - // NonsecureURBGBase::discard() - void discard(unsigned long long values) { // NOLINT(runtime/int) - urbg_.discard(values); - } - - bool operator==(const NonsecureURBGBase& other) const { - return urbg_ == other.urbg_; - } - - bool operator!=(const NonsecureURBGBase& other) const { - return !(urbg_ == other.urbg_); - } - - private: - // Seeder is a custom seed sequence type where generate() fills the provided - // buffer via the RandenPool entropy source. - struct Seeder { - using result_type = uint32_t; - - size_t size() { return 0; } - - template <typename OutIterator> - void param(OutIterator) const {} - - template <typename RandomAccessIterator> - void generate(RandomAccessIterator begin, RandomAccessIterator end) { - if (begin != end) { - // begin, end must be random access iterators assignable from uint32_t. - generate_impl( - std::integral_constant<bool, sizeof(*begin) == sizeof(uint32_t)>{}, - begin, end); - } - } - - // Commonly, generate is invoked with a pointer to a buffer which - // can be cast to a uint32_t. - template <typename RandomAccessIterator> - void generate_impl(std::integral_constant<bool, true>, - RandomAccessIterator begin, RandomAccessIterator end) { - auto buffer = absl::MakeSpan(begin, end); - auto target = absl::MakeSpan(reinterpret_cast<uint32_t*>(buffer.data()), - buffer.size()); - RandenPool<uint32_t>::Fill(target); - } - - // The non-uint32_t case should be uncommon, and involves an extra copy, - // filling the uint32_t buffer and then mixing into the output. - template <typename RandomAccessIterator> - void generate_impl(std::integral_constant<bool, false>, - RandomAccessIterator begin, RandomAccessIterator end) { - const size_t n = std::distance(begin, end); - absl::InlinedVector<uint32_t, 8> data(n, 0); - RandenPool<uint32_t>::Fill(absl::MakeSpan(data.begin(), data.end())); - std::copy(std::begin(data), std::end(data), begin); - } - }; - - static URBG ConstructURBG() { - Seeder seeder; - return URBG(seeder); - } - - template <typename SSeq> - static URBG ConstructURBG(SSeq&& seq) { // NOLINT(runtime/references) - auto salted_seq = - random_internal::MakeSaltedSeedSeq(std::forward<SSeq>(seq)); - return URBG(salted_seq); - } - - URBG urbg_; -}; - -} // namespace random_internal +namespace random_internal { + +// Each instance of NonsecureURBGBase<URBG> will be seeded by variates produced +// by a thread-unique URBG-instance. +template <typename URBG> +class NonsecureURBGBase { + public: + using result_type = typename URBG::result_type; + + // Default constructor + NonsecureURBGBase() : urbg_(ConstructURBG()) {} + + // Copy disallowed, move allowed. + NonsecureURBGBase(const NonsecureURBGBase&) = delete; + NonsecureURBGBase& operator=(const NonsecureURBGBase&) = delete; + NonsecureURBGBase(NonsecureURBGBase&&) = default; + NonsecureURBGBase& operator=(NonsecureURBGBase&&) = default; + + // Constructor using a seed + template <class SSeq, typename = typename absl::enable_if_t< + !std::is_same<SSeq, NonsecureURBGBase>::value>> + explicit NonsecureURBGBase(SSeq&& seq) + : urbg_(ConstructURBG(std::forward<SSeq>(seq))) {} + + // Note: on MSVC, min() or max() can be interpreted as MIN() or MAX(), so we + // enclose min() or max() in parens as (min)() and (max)(). + // Additionally, clang-format requires no space before this construction. + + // NonsecureURBGBase::min() + static constexpr result_type(min)() { return (URBG::min)(); } + + // NonsecureURBGBase::max() + static constexpr result_type(max)() { return (URBG::max)(); } + + // NonsecureURBGBase::operator()() + result_type operator()() { return urbg_(); } + + // NonsecureURBGBase::discard() + void discard(unsigned long long values) { // NOLINT(runtime/int) + urbg_.discard(values); + } + + bool operator==(const NonsecureURBGBase& other) const { + return urbg_ == other.urbg_; + } + + bool operator!=(const NonsecureURBGBase& other) const { + return !(urbg_ == other.urbg_); + } + + private: + // Seeder is a custom seed sequence type where generate() fills the provided + // buffer via the RandenPool entropy source. + struct Seeder { + using result_type = uint32_t; + + size_t size() { return 0; } + + template <typename OutIterator> + void param(OutIterator) const {} + + template <typename RandomAccessIterator> + void generate(RandomAccessIterator begin, RandomAccessIterator end) { + if (begin != end) { + // begin, end must be random access iterators assignable from uint32_t. + generate_impl( + std::integral_constant<bool, sizeof(*begin) == sizeof(uint32_t)>{}, + begin, end); + } + } + + // Commonly, generate is invoked with a pointer to a buffer which + // can be cast to a uint32_t. + template <typename RandomAccessIterator> + void generate_impl(std::integral_constant<bool, true>, + RandomAccessIterator begin, RandomAccessIterator end) { + auto buffer = absl::MakeSpan(begin, end); + auto target = absl::MakeSpan(reinterpret_cast<uint32_t*>(buffer.data()), + buffer.size()); + RandenPool<uint32_t>::Fill(target); + } + + // The non-uint32_t case should be uncommon, and involves an extra copy, + // filling the uint32_t buffer and then mixing into the output. + template <typename RandomAccessIterator> + void generate_impl(std::integral_constant<bool, false>, + RandomAccessIterator begin, RandomAccessIterator end) { + const size_t n = std::distance(begin, end); + absl::InlinedVector<uint32_t, 8> data(n, 0); + RandenPool<uint32_t>::Fill(absl::MakeSpan(data.begin(), data.end())); + std::copy(std::begin(data), std::end(data), begin); + } + }; + + static URBG ConstructURBG() { + Seeder seeder; + return URBG(seeder); + } + + template <typename SSeq> + static URBG ConstructURBG(SSeq&& seq) { // NOLINT(runtime/references) + auto salted_seq = + random_internal::MakeSaltedSeedSeq(std::forward<SSeq>(seq)); + return URBG(salted_seq); + } + + URBG urbg_; +}; + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_NONSECURE_BASE_H_ +} // namespace absl + +#endif // ABSL_RANDOM_INTERNAL_NONSECURE_BASE_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/pcg_engine.h b/contrib/restricted/abseil-cpp/absl/random/internal/pcg_engine.h index 5a8340020e..8efaf2e09a 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/pcg_engine.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/pcg_engine.h @@ -1,308 +1,308 @@ -// Copyright 2018 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_INTERNAL_PCG_ENGINE_H_ -#define ABSL_RANDOM_INTERNAL_PCG_ENGINE_H_ - -#include <type_traits> - -#include "absl/base/config.h" -#include "absl/meta/type_traits.h" +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_INTERNAL_PCG_ENGINE_H_ +#define ABSL_RANDOM_INTERNAL_PCG_ENGINE_H_ + +#include <type_traits> + +#include "absl/base/config.h" +#include "absl/meta/type_traits.h" #include "absl/numeric/bits.h" -#include "absl/numeric/int128.h" -#include "absl/random/internal/fastmath.h" -#include "absl/random/internal/iostream_state_saver.h" - -namespace absl { +#include "absl/numeric/int128.h" +#include "absl/random/internal/fastmath.h" +#include "absl/random/internal/iostream_state_saver.h" + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - -// pcg_engine is a simplified implementation of Melissa O'Neil's PCG engine in -// C++. PCG combines a linear congruential generator (LCG) with output state -// mixing functions to generate each random variate. pcg_engine supports only a -// single sequence (oneseq), and does not support streams. -// -// pcg_engine is parameterized by two types: -// Params, which provides the multiplier and increment values; -// Mix, which mixes the state into the result. -// -template <typename Params, typename Mix> -class pcg_engine { - static_assert(std::is_same<typename Params::state_type, - typename Mix::state_type>::value, - "Class-template absl::pcg_engine must be parameterized by " - "Params and Mix with identical state_type"); - - static_assert(std::is_unsigned<typename Mix::result_type>::value, - "Class-template absl::pcg_engine must be parameterized by " - "an unsigned Mix::result_type"); - - using params_type = Params; - using mix_type = Mix; - using state_type = typename Mix::state_type; - - public: - // C++11 URBG interface: - using result_type = typename Mix::result_type; - - static constexpr result_type(min)() { - return (std::numeric_limits<result_type>::min)(); - } - - static constexpr result_type(max)() { - return (std::numeric_limits<result_type>::max)(); - } - - explicit pcg_engine(uint64_t seed_value = 0) { seed(seed_value); } - - template <class SeedSequence, - typename = typename absl::enable_if_t< - !std::is_same<SeedSequence, pcg_engine>::value>> - explicit pcg_engine(SeedSequence&& seq) { - seed(seq); - } - - pcg_engine(const pcg_engine&) = default; - pcg_engine& operator=(const pcg_engine&) = default; - pcg_engine(pcg_engine&&) = default; - pcg_engine& operator=(pcg_engine&&) = default; - - result_type operator()() { - // Advance the LCG state, always using the new value to generate the output. - state_ = lcg(state_); - return Mix{}(state_); - } - - void seed(uint64_t seed_value = 0) { - state_type tmp = seed_value; - state_ = lcg(tmp + Params::increment()); - } - - template <class SeedSequence> - typename absl::enable_if_t< - !std::is_convertible<SeedSequence, uint64_t>::value, void> - seed(SeedSequence&& seq) { - reseed(seq); - } - - void discard(uint64_t count) { state_ = advance(state_, count); } - - bool operator==(const pcg_engine& other) const { - return state_ == other.state_; - } - - bool operator!=(const pcg_engine& other) const { return !(*this == other); } - - template <class CharT, class Traits> - friend typename absl::enable_if_t<(sizeof(state_type) == 16), - std::basic_ostream<CharT, Traits>&> - operator<<( - std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) - const pcg_engine& engine) { - auto saver = random_internal::make_ostream_state_saver(os); - random_internal::stream_u128_helper<state_type> helper; - helper.write(pcg_engine::params_type::multiplier(), os); - os << os.fill(); - helper.write(pcg_engine::params_type::increment(), os); - os << os.fill(); - helper.write(engine.state_, os); - return os; - } - - template <class CharT, class Traits> - friend typename absl::enable_if_t<(sizeof(state_type) <= 8), - std::basic_ostream<CharT, Traits>&> - operator<<( - std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) - const pcg_engine& engine) { - auto saver = random_internal::make_ostream_state_saver(os); - os << pcg_engine::params_type::multiplier() << os.fill(); - os << pcg_engine::params_type::increment() << os.fill(); - os << engine.state_; - return os; - } - - template <class CharT, class Traits> - friend typename absl::enable_if_t<(sizeof(state_type) == 16), - std::basic_istream<CharT, Traits>&> - operator>>( - std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) - pcg_engine& engine) { // NOLINT(runtime/references) - random_internal::stream_u128_helper<state_type> helper; - auto mult = helper.read(is); - auto inc = helper.read(is); - auto tmp = helper.read(is); - if (mult != pcg_engine::params_type::multiplier() || - inc != pcg_engine::params_type::increment()) { - // signal failure by setting the failbit. - is.setstate(is.rdstate() | std::ios_base::failbit); - } - if (!is.fail()) { - engine.state_ = tmp; - } - return is; - } - - template <class CharT, class Traits> - friend typename absl::enable_if_t<(sizeof(state_type) <= 8), - std::basic_istream<CharT, Traits>&> - operator>>( - std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) - pcg_engine& engine) { // NOLINT(runtime/references) - state_type mult{}, inc{}, tmp{}; - is >> mult >> inc >> tmp; - if (mult != pcg_engine::params_type::multiplier() || - inc != pcg_engine::params_type::increment()) { - // signal failure by setting the failbit. - is.setstate(is.rdstate() | std::ios_base::failbit); - } - if (!is.fail()) { - engine.state_ = tmp; - } - return is; - } - - private: - state_type state_; - - // Returns the linear-congruential generator next state. - static inline constexpr state_type lcg(state_type s) { - return s * Params::multiplier() + Params::increment(); - } - - // Returns the linear-congruential arbitrary seek state. - inline state_type advance(state_type s, uint64_t n) const { - state_type mult = Params::multiplier(); - state_type inc = Params::increment(); - state_type m = 1; - state_type i = 0; - while (n > 0) { - if (n & 1) { - m *= mult; - i = i * mult + inc; - } - inc = (mult + 1) * inc; - mult *= mult; - n >>= 1; - } - return m * s + i; - } - - template <class SeedSequence> - void reseed(SeedSequence& seq) { - using sequence_result_type = typename SeedSequence::result_type; - constexpr size_t kBufferSize = - sizeof(state_type) / sizeof(sequence_result_type); - sequence_result_type buffer[kBufferSize]; - seq.generate(std::begin(buffer), std::end(buffer)); - // Convert the seed output to a single state value. - state_type tmp = buffer[0]; - for (size_t i = 1; i < kBufferSize; i++) { - tmp <<= (sizeof(sequence_result_type) * 8); - tmp |= buffer[i]; - } - state_ = lcg(tmp + params_type::increment()); - } -}; - -// Parameterized implementation of the PCG 128-bit oneseq state. -// This provides state_type, multiplier, and increment for pcg_engine. -template <uint64_t kMultA, uint64_t kMultB, uint64_t kIncA, uint64_t kIncB> -class pcg128_params { - public: -#if ABSL_HAVE_INTRINSIC_INT128 - using state_type = __uint128_t; - static inline constexpr state_type make_u128(uint64_t a, uint64_t b) { - return (static_cast<__uint128_t>(a) << 64) | b; - } -#else - using state_type = absl::uint128; - static inline constexpr state_type make_u128(uint64_t a, uint64_t b) { - return absl::MakeUint128(a, b); - } -#endif - - static inline constexpr state_type multiplier() { - return make_u128(kMultA, kMultB); - } - static inline constexpr state_type increment() { - return make_u128(kIncA, kIncB); - } -}; - -// Implementation of the PCG xsl_rr_128_64 128-bit mixing function, which -// accepts an input of state_type and mixes it into an output of result_type. -struct pcg_xsl_rr_128_64 { -#if ABSL_HAVE_INTRINSIC_INT128 - using state_type = __uint128_t; -#else - using state_type = absl::uint128; -#endif - using result_type = uint64_t; - - inline uint64_t operator()(state_type state) { - // This is equivalent to the xsl_rr_128_64 mixing function. -#if ABSL_HAVE_INTRINSIC_INT128 - uint64_t rotate = static_cast<uint64_t>(state >> 122u); - state ^= state >> 64; - uint64_t s = static_cast<uint64_t>(state); -#else - uint64_t h = Uint128High64(state); - uint64_t rotate = h >> 58u; - uint64_t s = Uint128Low64(state) ^ h; -#endif +namespace random_internal { + +// pcg_engine is a simplified implementation of Melissa O'Neil's PCG engine in +// C++. PCG combines a linear congruential generator (LCG) with output state +// mixing functions to generate each random variate. pcg_engine supports only a +// single sequence (oneseq), and does not support streams. +// +// pcg_engine is parameterized by two types: +// Params, which provides the multiplier and increment values; +// Mix, which mixes the state into the result. +// +template <typename Params, typename Mix> +class pcg_engine { + static_assert(std::is_same<typename Params::state_type, + typename Mix::state_type>::value, + "Class-template absl::pcg_engine must be parameterized by " + "Params and Mix with identical state_type"); + + static_assert(std::is_unsigned<typename Mix::result_type>::value, + "Class-template absl::pcg_engine must be parameterized by " + "an unsigned Mix::result_type"); + + using params_type = Params; + using mix_type = Mix; + using state_type = typename Mix::state_type; + + public: + // C++11 URBG interface: + using result_type = typename Mix::result_type; + + static constexpr result_type(min)() { + return (std::numeric_limits<result_type>::min)(); + } + + static constexpr result_type(max)() { + return (std::numeric_limits<result_type>::max)(); + } + + explicit pcg_engine(uint64_t seed_value = 0) { seed(seed_value); } + + template <class SeedSequence, + typename = typename absl::enable_if_t< + !std::is_same<SeedSequence, pcg_engine>::value>> + explicit pcg_engine(SeedSequence&& seq) { + seed(seq); + } + + pcg_engine(const pcg_engine&) = default; + pcg_engine& operator=(const pcg_engine&) = default; + pcg_engine(pcg_engine&&) = default; + pcg_engine& operator=(pcg_engine&&) = default; + + result_type operator()() { + // Advance the LCG state, always using the new value to generate the output. + state_ = lcg(state_); + return Mix{}(state_); + } + + void seed(uint64_t seed_value = 0) { + state_type tmp = seed_value; + state_ = lcg(tmp + Params::increment()); + } + + template <class SeedSequence> + typename absl::enable_if_t< + !std::is_convertible<SeedSequence, uint64_t>::value, void> + seed(SeedSequence&& seq) { + reseed(seq); + } + + void discard(uint64_t count) { state_ = advance(state_, count); } + + bool operator==(const pcg_engine& other) const { + return state_ == other.state_; + } + + bool operator!=(const pcg_engine& other) const { return !(*this == other); } + + template <class CharT, class Traits> + friend typename absl::enable_if_t<(sizeof(state_type) == 16), + std::basic_ostream<CharT, Traits>&> + operator<<( + std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) + const pcg_engine& engine) { + auto saver = random_internal::make_ostream_state_saver(os); + random_internal::stream_u128_helper<state_type> helper; + helper.write(pcg_engine::params_type::multiplier(), os); + os << os.fill(); + helper.write(pcg_engine::params_type::increment(), os); + os << os.fill(); + helper.write(engine.state_, os); + return os; + } + + template <class CharT, class Traits> + friend typename absl::enable_if_t<(sizeof(state_type) <= 8), + std::basic_ostream<CharT, Traits>&> + operator<<( + std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) + const pcg_engine& engine) { + auto saver = random_internal::make_ostream_state_saver(os); + os << pcg_engine::params_type::multiplier() << os.fill(); + os << pcg_engine::params_type::increment() << os.fill(); + os << engine.state_; + return os; + } + + template <class CharT, class Traits> + friend typename absl::enable_if_t<(sizeof(state_type) == 16), + std::basic_istream<CharT, Traits>&> + operator>>( + std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) + pcg_engine& engine) { // NOLINT(runtime/references) + random_internal::stream_u128_helper<state_type> helper; + auto mult = helper.read(is); + auto inc = helper.read(is); + auto tmp = helper.read(is); + if (mult != pcg_engine::params_type::multiplier() || + inc != pcg_engine::params_type::increment()) { + // signal failure by setting the failbit. + is.setstate(is.rdstate() | std::ios_base::failbit); + } + if (!is.fail()) { + engine.state_ = tmp; + } + return is; + } + + template <class CharT, class Traits> + friend typename absl::enable_if_t<(sizeof(state_type) <= 8), + std::basic_istream<CharT, Traits>&> + operator>>( + std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) + pcg_engine& engine) { // NOLINT(runtime/references) + state_type mult{}, inc{}, tmp{}; + is >> mult >> inc >> tmp; + if (mult != pcg_engine::params_type::multiplier() || + inc != pcg_engine::params_type::increment()) { + // signal failure by setting the failbit. + is.setstate(is.rdstate() | std::ios_base::failbit); + } + if (!is.fail()) { + engine.state_ = tmp; + } + return is; + } + + private: + state_type state_; + + // Returns the linear-congruential generator next state. + static inline constexpr state_type lcg(state_type s) { + return s * Params::multiplier() + Params::increment(); + } + + // Returns the linear-congruential arbitrary seek state. + inline state_type advance(state_type s, uint64_t n) const { + state_type mult = Params::multiplier(); + state_type inc = Params::increment(); + state_type m = 1; + state_type i = 0; + while (n > 0) { + if (n & 1) { + m *= mult; + i = i * mult + inc; + } + inc = (mult + 1) * inc; + mult *= mult; + n >>= 1; + } + return m * s + i; + } + + template <class SeedSequence> + void reseed(SeedSequence& seq) { + using sequence_result_type = typename SeedSequence::result_type; + constexpr size_t kBufferSize = + sizeof(state_type) / sizeof(sequence_result_type); + sequence_result_type buffer[kBufferSize]; + seq.generate(std::begin(buffer), std::end(buffer)); + // Convert the seed output to a single state value. + state_type tmp = buffer[0]; + for (size_t i = 1; i < kBufferSize; i++) { + tmp <<= (sizeof(sequence_result_type) * 8); + tmp |= buffer[i]; + } + state_ = lcg(tmp + params_type::increment()); + } +}; + +// Parameterized implementation of the PCG 128-bit oneseq state. +// This provides state_type, multiplier, and increment for pcg_engine. +template <uint64_t kMultA, uint64_t kMultB, uint64_t kIncA, uint64_t kIncB> +class pcg128_params { + public: +#if ABSL_HAVE_INTRINSIC_INT128 + using state_type = __uint128_t; + static inline constexpr state_type make_u128(uint64_t a, uint64_t b) { + return (static_cast<__uint128_t>(a) << 64) | b; + } +#else + using state_type = absl::uint128; + static inline constexpr state_type make_u128(uint64_t a, uint64_t b) { + return absl::MakeUint128(a, b); + } +#endif + + static inline constexpr state_type multiplier() { + return make_u128(kMultA, kMultB); + } + static inline constexpr state_type increment() { + return make_u128(kIncA, kIncB); + } +}; + +// Implementation of the PCG xsl_rr_128_64 128-bit mixing function, which +// accepts an input of state_type and mixes it into an output of result_type. +struct pcg_xsl_rr_128_64 { +#if ABSL_HAVE_INTRINSIC_INT128 + using state_type = __uint128_t; +#else + using state_type = absl::uint128; +#endif + using result_type = uint64_t; + + inline uint64_t operator()(state_type state) { + // This is equivalent to the xsl_rr_128_64 mixing function. +#if ABSL_HAVE_INTRINSIC_INT128 + uint64_t rotate = static_cast<uint64_t>(state >> 122u); + state ^= state >> 64; + uint64_t s = static_cast<uint64_t>(state); +#else + uint64_t h = Uint128High64(state); + uint64_t rotate = h >> 58u; + uint64_t s = Uint128Low64(state) ^ h; +#endif return rotr(s, rotate); - } -}; - -// Parameterized implementation of the PCG 64-bit oneseq state. -// This provides state_type, multiplier, and increment for pcg_engine. -template <uint64_t kMult, uint64_t kInc> -class pcg64_params { - public: - using state_type = uint64_t; - static inline constexpr state_type multiplier() { return kMult; } - static inline constexpr state_type increment() { return kInc; } -}; - -// Implementation of the PCG xsh_rr_64_32 64-bit mixing function, which accepts -// an input of state_type and mixes it into an output of result_type. -struct pcg_xsh_rr_64_32 { - using state_type = uint64_t; - using result_type = uint32_t; - inline uint32_t operator()(uint64_t state) { + } +}; + +// Parameterized implementation of the PCG 64-bit oneseq state. +// This provides state_type, multiplier, and increment for pcg_engine. +template <uint64_t kMult, uint64_t kInc> +class pcg64_params { + public: + using state_type = uint64_t; + static inline constexpr state_type multiplier() { return kMult; } + static inline constexpr state_type increment() { return kInc; } +}; + +// Implementation of the PCG xsh_rr_64_32 64-bit mixing function, which accepts +// an input of state_type and mixes it into an output of result_type. +struct pcg_xsh_rr_64_32 { + using state_type = uint64_t; + using result_type = uint32_t; + inline uint32_t operator()(uint64_t state) { return rotr(static_cast<uint32_t>(((state >> 18) ^ state) >> 27), state >> 59); - } -}; - -// Stable pcg_engine implementations: -// This is a 64-bit generator using 128-bits of state. -// The output sequence is equivalent to Melissa O'Neil's pcg64_oneseq. -using pcg64_2018_engine = pcg_engine< - random_internal::pcg128_params<0x2360ed051fc65da4ull, 0x4385df649fccf645ull, - 0x5851f42d4c957f2d, 0x14057b7ef767814f>, - random_internal::pcg_xsl_rr_128_64>; - -// This is a 32-bit generator using 64-bits of state. -// This is equivalent to Melissa O'Neil's pcg32_oneseq. -using pcg32_2018_engine = pcg_engine< - random_internal::pcg64_params<0x5851f42d4c957f2dull, 0x14057b7ef767814full>, - random_internal::pcg_xsh_rr_64_32>; - -} // namespace random_internal + } +}; + +// Stable pcg_engine implementations: +// This is a 64-bit generator using 128-bits of state. +// The output sequence is equivalent to Melissa O'Neil's pcg64_oneseq. +using pcg64_2018_engine = pcg_engine< + random_internal::pcg128_params<0x2360ed051fc65da4ull, 0x4385df649fccf645ull, + 0x5851f42d4c957f2d, 0x14057b7ef767814f>, + random_internal::pcg_xsl_rr_128_64>; + +// This is a 32-bit generator using 64-bits of state. +// This is equivalent to Melissa O'Neil's pcg32_oneseq. +using pcg32_2018_engine = pcg_engine< + random_internal::pcg64_params<0x5851f42d4c957f2dull, 0x14057b7ef767814full>, + random_internal::pcg_xsh_rr_64_32>; + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_PCG_ENGINE_H_ +} // namespace absl + +#endif // ABSL_RANDOM_INTERNAL_PCG_ENGINE_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/platform.h b/contrib/restricted/abseil-cpp/absl/random/internal/platform.h index fcd5d461a7..bbdb4e6208 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/platform.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/platform.h @@ -1,171 +1,171 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_INTERNAL_PLATFORM_H_ -#define ABSL_RANDOM_INTERNAL_PLATFORM_H_ - -// HERMETIC NOTE: The randen_hwaes target must not introduce duplicate -// symbols from arbitrary system and other headers, since it may be built -// with different flags from other targets, using different levels of -// optimization, potentially introducing ODR violations. - -// ----------------------------------------------------------------------------- -// Platform Feature Checks -// ----------------------------------------------------------------------------- - -// Currently supported operating systems and associated preprocessor -// symbols: -// -// Linux and Linux-derived __linux__ -// Android __ANDROID__ (implies __linux__) -// Linux (non-Android) __linux__ && !__ANDROID__ -// Darwin (macOS and iOS) __APPLE__ -// Akaros (http://akaros.org) __ros__ -// Windows _WIN32 -// NaCL __native_client__ -// AsmJS __asmjs__ -// WebAssembly __wasm__ -// Fuchsia __Fuchsia__ -// -// Note that since Android defines both __ANDROID__ and __linux__, one -// may probe for either Linux or Android by simply testing for __linux__. -// -// NOTE: For __APPLE__ platforms, we use #include <TargetConditionals.h> -// to distinguish os variants. -// -// http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system - -#if defined(__APPLE__) -#include <TargetConditionals.h> -#endif - -// ----------------------------------------------------------------------------- -// Architecture Checks -// ----------------------------------------------------------------------------- - -// These preprocessor directives are trying to determine CPU architecture, -// including necessary headers to support hardware AES. -// -// ABSL_ARCH_{X86/PPC/ARM} macros determine the platform. -#if defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) || \ - defined(_M_X64) -#define ABSL_ARCH_X86_64 -#elif defined(__i386) || defined(_M_IX86) -#define ABSL_ARCH_X86_32 -#elif defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) -#define ABSL_ARCH_AARCH64 -#elif defined(__arm__) || defined(__ARMEL__) || defined(_M_ARM) -#define ABSL_ARCH_ARM -#elif defined(__powerpc64__) || defined(__PPC64__) || defined(__powerpc__) || \ - defined(__ppc__) || defined(__PPC__) -#define ABSL_ARCH_PPC -#else -// Unsupported architecture. -// * https://sourceforge.net/p/predef/wiki/Architectures/ -// * https://msdn.microsoft.com/en-us/library/b0084kay.aspx -// * for gcc, clang: "echo | gcc -E -dM -" -#endif - -// ----------------------------------------------------------------------------- -// Attribute Checks -// ----------------------------------------------------------------------------- - -// ABSL_RANDOM_INTERNAL_RESTRICT annotates whether pointers may be considered -// to be unaliased. -#if defined(__clang__) || defined(__GNUC__) -#define ABSL_RANDOM_INTERNAL_RESTRICT __restrict__ -#elif defined(_MSC_VER) -#define ABSL_RANDOM_INTERNAL_RESTRICT __restrict -#else -#define ABSL_RANDOM_INTERNAL_RESTRICT -#endif - -// ABSL_HAVE_ACCELERATED_AES indicates whether the currently active compiler -// flags (e.g. -maes) allow using hardware accelerated AES instructions, which -// implies us assuming that the target platform supports them. -#define ABSL_HAVE_ACCELERATED_AES 0 - -#if defined(ABSL_ARCH_X86_64) - -#if defined(__AES__) || defined(__AVX__) -#undef ABSL_HAVE_ACCELERATED_AES -#define ABSL_HAVE_ACCELERATED_AES 1 -#endif - -#elif defined(ABSL_ARCH_PPC) - -// Rely on VSX and CRYPTO extensions for vcipher on PowerPC. -#if (defined(__VEC__) || defined(__ALTIVEC__)) && defined(__VSX__) && \ - defined(__CRYPTO__) -#undef ABSL_HAVE_ACCELERATED_AES -#define ABSL_HAVE_ACCELERATED_AES 1 -#endif - -#elif defined(ABSL_ARCH_ARM) || defined(ABSL_ARCH_AARCH64) - -// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0053c/IHI0053C_acle_2_0.pdf -// Rely on NEON+CRYPTO extensions for ARM. -#if defined(__ARM_NEON) && defined(__ARM_FEATURE_CRYPTO) -#undef ABSL_HAVE_ACCELERATED_AES -#define ABSL_HAVE_ACCELERATED_AES 1 -#endif - -#endif - -// NaCl does not allow AES. -#if defined(__native_client__) -#undef ABSL_HAVE_ACCELERATED_AES -#define ABSL_HAVE_ACCELERATED_AES 0 -#endif - -// ABSL_RANDOM_INTERNAL_AES_DISPATCH indicates whether the currently active -// platform has, or should use run-time dispatch for selecting the -// acclerated Randen implementation. -#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 0 - -#if defined(ABSL_ARCH_X86_64) -// Dispatch is available on x86_64 -#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH -#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 1 -#elif defined(__linux__) && defined(ABSL_ARCH_PPC) -// Or when running linux PPC -#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH -#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 1 -#elif defined(__linux__) && defined(ABSL_ARCH_AARCH64) -// Or when running linux AArch64 -#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH -#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 1 -#elif defined(__linux__) && defined(ABSL_ARCH_ARM) && (__ARM_ARCH >= 8) -// Or when running linux ARM v8 or higher. -// (This captures a lot of Android configurations.) -#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH -#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 1 -#endif - -// NaCl does not allow dispatch. -#if defined(__native_client__) -#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH -#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 0 -#endif - -// iOS does not support dispatch, even on x86, since applications -// should be bundled as fat binaries, with a different build tailored for -// each specific supported platform/architecture. -#if (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || \ - (defined(TARGET_OS_IPHONE_SIMULATOR) && TARGET_OS_IPHONE_SIMULATOR) -#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH -#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 0 -#endif - -#endif // ABSL_RANDOM_INTERNAL_PLATFORM_H_ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_INTERNAL_PLATFORM_H_ +#define ABSL_RANDOM_INTERNAL_PLATFORM_H_ + +// HERMETIC NOTE: The randen_hwaes target must not introduce duplicate +// symbols from arbitrary system and other headers, since it may be built +// with different flags from other targets, using different levels of +// optimization, potentially introducing ODR violations. + +// ----------------------------------------------------------------------------- +// Platform Feature Checks +// ----------------------------------------------------------------------------- + +// Currently supported operating systems and associated preprocessor +// symbols: +// +// Linux and Linux-derived __linux__ +// Android __ANDROID__ (implies __linux__) +// Linux (non-Android) __linux__ && !__ANDROID__ +// Darwin (macOS and iOS) __APPLE__ +// Akaros (http://akaros.org) __ros__ +// Windows _WIN32 +// NaCL __native_client__ +// AsmJS __asmjs__ +// WebAssembly __wasm__ +// Fuchsia __Fuchsia__ +// +// Note that since Android defines both __ANDROID__ and __linux__, one +// may probe for either Linux or Android by simply testing for __linux__. +// +// NOTE: For __APPLE__ platforms, we use #include <TargetConditionals.h> +// to distinguish os variants. +// +// http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system + +#if defined(__APPLE__) +#include <TargetConditionals.h> +#endif + +// ----------------------------------------------------------------------------- +// Architecture Checks +// ----------------------------------------------------------------------------- + +// These preprocessor directives are trying to determine CPU architecture, +// including necessary headers to support hardware AES. +// +// ABSL_ARCH_{X86/PPC/ARM} macros determine the platform. +#if defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) || \ + defined(_M_X64) +#define ABSL_ARCH_X86_64 +#elif defined(__i386) || defined(_M_IX86) +#define ABSL_ARCH_X86_32 +#elif defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) +#define ABSL_ARCH_AARCH64 +#elif defined(__arm__) || defined(__ARMEL__) || defined(_M_ARM) +#define ABSL_ARCH_ARM +#elif defined(__powerpc64__) || defined(__PPC64__) || defined(__powerpc__) || \ + defined(__ppc__) || defined(__PPC__) +#define ABSL_ARCH_PPC +#else +// Unsupported architecture. +// * https://sourceforge.net/p/predef/wiki/Architectures/ +// * https://msdn.microsoft.com/en-us/library/b0084kay.aspx +// * for gcc, clang: "echo | gcc -E -dM -" +#endif + +// ----------------------------------------------------------------------------- +// Attribute Checks +// ----------------------------------------------------------------------------- + +// ABSL_RANDOM_INTERNAL_RESTRICT annotates whether pointers may be considered +// to be unaliased. +#if defined(__clang__) || defined(__GNUC__) +#define ABSL_RANDOM_INTERNAL_RESTRICT __restrict__ +#elif defined(_MSC_VER) +#define ABSL_RANDOM_INTERNAL_RESTRICT __restrict +#else +#define ABSL_RANDOM_INTERNAL_RESTRICT +#endif + +// ABSL_HAVE_ACCELERATED_AES indicates whether the currently active compiler +// flags (e.g. -maes) allow using hardware accelerated AES instructions, which +// implies us assuming that the target platform supports them. +#define ABSL_HAVE_ACCELERATED_AES 0 + +#if defined(ABSL_ARCH_X86_64) + +#if defined(__AES__) || defined(__AVX__) +#undef ABSL_HAVE_ACCELERATED_AES +#define ABSL_HAVE_ACCELERATED_AES 1 +#endif + +#elif defined(ABSL_ARCH_PPC) + +// Rely on VSX and CRYPTO extensions for vcipher on PowerPC. +#if (defined(__VEC__) || defined(__ALTIVEC__)) && defined(__VSX__) && \ + defined(__CRYPTO__) +#undef ABSL_HAVE_ACCELERATED_AES +#define ABSL_HAVE_ACCELERATED_AES 1 +#endif + +#elif defined(ABSL_ARCH_ARM) || defined(ABSL_ARCH_AARCH64) + +// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0053c/IHI0053C_acle_2_0.pdf +// Rely on NEON+CRYPTO extensions for ARM. +#if defined(__ARM_NEON) && defined(__ARM_FEATURE_CRYPTO) +#undef ABSL_HAVE_ACCELERATED_AES +#define ABSL_HAVE_ACCELERATED_AES 1 +#endif + +#endif + +// NaCl does not allow AES. +#if defined(__native_client__) +#undef ABSL_HAVE_ACCELERATED_AES +#define ABSL_HAVE_ACCELERATED_AES 0 +#endif + +// ABSL_RANDOM_INTERNAL_AES_DISPATCH indicates whether the currently active +// platform has, or should use run-time dispatch for selecting the +// acclerated Randen implementation. +#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 0 + +#if defined(ABSL_ARCH_X86_64) +// Dispatch is available on x86_64 +#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH +#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 1 +#elif defined(__linux__) && defined(ABSL_ARCH_PPC) +// Or when running linux PPC +#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH +#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 1 +#elif defined(__linux__) && defined(ABSL_ARCH_AARCH64) +// Or when running linux AArch64 +#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH +#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 1 +#elif defined(__linux__) && defined(ABSL_ARCH_ARM) && (__ARM_ARCH >= 8) +// Or when running linux ARM v8 or higher. +// (This captures a lot of Android configurations.) +#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH +#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 1 +#endif + +// NaCl does not allow dispatch. +#if defined(__native_client__) +#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH +#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 0 +#endif + +// iOS does not support dispatch, even on x86, since applications +// should be bundled as fat binaries, with a different build tailored for +// each specific supported platform/architecture. +#if (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || \ + (defined(TARGET_OS_IPHONE_SIMULATOR) && TARGET_OS_IPHONE_SIMULATOR) +#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH +#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 0 +#endif + +#endif // ABSL_RANDOM_INTERNAL_PLATFORM_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/pool_urbg.cc b/contrib/restricted/abseil-cpp/absl/random/internal/pool_urbg.cc index a715397110..725100a415 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/pool_urbg.cc +++ b/contrib/restricted/abseil-cpp/absl/random/internal/pool_urbg.cc @@ -1,253 +1,253 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "absl/random/internal/pool_urbg.h" - -#include <algorithm> -#include <atomic> -#include <cstdint> -#include <cstring> -#include <iterator> - -#include "absl/base/attributes.h" -#include "absl/base/call_once.h" -#include "absl/base/config.h" -#include "absl/base/internal/endian.h" -#include "absl/base/internal/raw_logging.h" -#include "absl/base/internal/spinlock.h" -#include "absl/base/internal/sysinfo.h" -#include "absl/base/internal/unaligned_access.h" -#include "absl/base/optimization.h" -#include "absl/random/internal/randen.h" -#include "absl/random/internal/seed_material.h" -#include "absl/random/seed_gen_exception.h" - -using absl::base_internal::SpinLock; -using absl::base_internal::SpinLockHolder; - -namespace absl { +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/random/internal/pool_urbg.h" + +#include <algorithm> +#include <atomic> +#include <cstdint> +#include <cstring> +#include <iterator> + +#include "absl/base/attributes.h" +#include "absl/base/call_once.h" +#include "absl/base/config.h" +#include "absl/base/internal/endian.h" +#include "absl/base/internal/raw_logging.h" +#include "absl/base/internal/spinlock.h" +#include "absl/base/internal/sysinfo.h" +#include "absl/base/internal/unaligned_access.h" +#include "absl/base/optimization.h" +#include "absl/random/internal/randen.h" +#include "absl/random/internal/seed_material.h" +#include "absl/random/seed_gen_exception.h" + +using absl::base_internal::SpinLock; +using absl::base_internal::SpinLockHolder; + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { -namespace { - -// RandenPoolEntry is a thread-safe pseudorandom bit generator, implementing a -// single generator within a RandenPool<T>. It is an internal implementation -// detail, and does not aim to conform to [rand.req.urng]. -// -// NOTE: There are alignment issues when used on ARM, for instance. -// See the allocation code in PoolAlignedAlloc(). -class RandenPoolEntry { - public: - static constexpr size_t kState = RandenTraits::kStateBytes / sizeof(uint32_t); - static constexpr size_t kCapacity = - RandenTraits::kCapacityBytes / sizeof(uint32_t); - - void Init(absl::Span<const uint32_t> data) { - SpinLockHolder l(&mu_); // Always uncontested. - std::copy(data.begin(), data.end(), std::begin(state_)); - next_ = kState; - } - - // Copy bytes into out. - void Fill(uint8_t* out, size_t bytes) ABSL_LOCKS_EXCLUDED(mu_); - - // Returns random bits from the buffer in units of T. - template <typename T> - inline T Generate() ABSL_LOCKS_EXCLUDED(mu_); - - inline void MaybeRefill() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_) { - if (next_ >= kState) { - next_ = kCapacity; - impl_.Generate(state_); - } - } - - private: - // Randen URBG state. - uint32_t state_[kState] ABSL_GUARDED_BY(mu_); // First to satisfy alignment. - SpinLock mu_; - const Randen impl_; - size_t next_ ABSL_GUARDED_BY(mu_); -}; - -template <> -inline uint8_t RandenPoolEntry::Generate<uint8_t>() { - SpinLockHolder l(&mu_); - MaybeRefill(); - return static_cast<uint8_t>(state_[next_++]); -} - -template <> -inline uint16_t RandenPoolEntry::Generate<uint16_t>() { - SpinLockHolder l(&mu_); - MaybeRefill(); - return static_cast<uint16_t>(state_[next_++]); -} - -template <> -inline uint32_t RandenPoolEntry::Generate<uint32_t>() { - SpinLockHolder l(&mu_); - MaybeRefill(); - return state_[next_++]; -} - -template <> -inline uint64_t RandenPoolEntry::Generate<uint64_t>() { - SpinLockHolder l(&mu_); - if (next_ >= kState - 1) { - next_ = kCapacity; - impl_.Generate(state_); - } - auto p = state_ + next_; - next_ += 2; - - uint64_t result; - std::memcpy(&result, p, sizeof(result)); - return result; -} - -void RandenPoolEntry::Fill(uint8_t* out, size_t bytes) { - SpinLockHolder l(&mu_); - while (bytes > 0) { - MaybeRefill(); - size_t remaining = (kState - next_) * sizeof(state_[0]); - size_t to_copy = std::min(bytes, remaining); - std::memcpy(out, &state_[next_], to_copy); - out += to_copy; - bytes -= to_copy; - next_ += (to_copy + sizeof(state_[0]) - 1) / sizeof(state_[0]); - } -} - -// Number of pooled urbg entries. -static constexpr int kPoolSize = 8; - -// Shared pool entries. -static absl::once_flag pool_once; -ABSL_CACHELINE_ALIGNED static RandenPoolEntry* shared_pools[kPoolSize]; - -// Returns an id in the range [0 ... kPoolSize), which indexes into the -// pool of random engines. -// -// Each thread to access the pool is assigned a sequential ID (without reuse) -// from the pool-id space; the id is cached in a thread_local variable. -// This id is assigned based on the arrival-order of the thread to the -// GetPoolID call; this has no binary, CL, or runtime stability because -// on subsequent runs the order within the same program may be significantly -// different. However, as other thread IDs are not assigned sequentially, -// this is not expected to matter. -int GetPoolID() { - static_assert(kPoolSize >= 1, - "At least one urbg instance is required for PoolURBG"); - - ABSL_CONST_INIT static std::atomic<int64_t> sequence{0}; - -#ifdef ABSL_HAVE_THREAD_LOCAL - static thread_local int my_pool_id = -1; - if (ABSL_PREDICT_FALSE(my_pool_id < 0)) { - my_pool_id = (sequence++ % kPoolSize); - } - return my_pool_id; -#else - static pthread_key_t tid_key = [] { - pthread_key_t tmp_key; - int err = pthread_key_create(&tmp_key, nullptr); - if (err) { - ABSL_RAW_LOG(FATAL, "pthread_key_create failed with %d", err); - } - return tmp_key; - }(); - - // Store the value in the pthread_{get/set}specific. However an uninitialized - // value is 0, so add +1 to distinguish from the null value. - intptr_t my_pool_id = - reinterpret_cast<intptr_t>(pthread_getspecific(tid_key)); - if (ABSL_PREDICT_FALSE(my_pool_id == 0)) { - // No allocated ID, allocate the next value, cache it, and return. - my_pool_id = (sequence++ % kPoolSize) + 1; - int err = pthread_setspecific(tid_key, reinterpret_cast<void*>(my_pool_id)); - if (err) { - ABSL_RAW_LOG(FATAL, "pthread_setspecific failed with %d", err); - } - } - return my_pool_id - 1; -#endif -} - -// Allocate a RandenPoolEntry with at least 32-byte alignment, which is required -// by ARM platform code. -RandenPoolEntry* PoolAlignedAlloc() { - constexpr size_t kAlignment = - ABSL_CACHELINE_SIZE > 32 ? ABSL_CACHELINE_SIZE : 32; - - // Not all the platforms that we build for have std::aligned_alloc, however - // since we never free these objects, we can over allocate and munge the - // pointers to the correct alignment. +namespace random_internal { +namespace { + +// RandenPoolEntry is a thread-safe pseudorandom bit generator, implementing a +// single generator within a RandenPool<T>. It is an internal implementation +// detail, and does not aim to conform to [rand.req.urng]. +// +// NOTE: There are alignment issues when used on ARM, for instance. +// See the allocation code in PoolAlignedAlloc(). +class RandenPoolEntry { + public: + static constexpr size_t kState = RandenTraits::kStateBytes / sizeof(uint32_t); + static constexpr size_t kCapacity = + RandenTraits::kCapacityBytes / sizeof(uint32_t); + + void Init(absl::Span<const uint32_t> data) { + SpinLockHolder l(&mu_); // Always uncontested. + std::copy(data.begin(), data.end(), std::begin(state_)); + next_ = kState; + } + + // Copy bytes into out. + void Fill(uint8_t* out, size_t bytes) ABSL_LOCKS_EXCLUDED(mu_); + + // Returns random bits from the buffer in units of T. + template <typename T> + inline T Generate() ABSL_LOCKS_EXCLUDED(mu_); + + inline void MaybeRefill() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_) { + if (next_ >= kState) { + next_ = kCapacity; + impl_.Generate(state_); + } + } + + private: + // Randen URBG state. + uint32_t state_[kState] ABSL_GUARDED_BY(mu_); // First to satisfy alignment. + SpinLock mu_; + const Randen impl_; + size_t next_ ABSL_GUARDED_BY(mu_); +}; + +template <> +inline uint8_t RandenPoolEntry::Generate<uint8_t>() { + SpinLockHolder l(&mu_); + MaybeRefill(); + return static_cast<uint8_t>(state_[next_++]); +} + +template <> +inline uint16_t RandenPoolEntry::Generate<uint16_t>() { + SpinLockHolder l(&mu_); + MaybeRefill(); + return static_cast<uint16_t>(state_[next_++]); +} + +template <> +inline uint32_t RandenPoolEntry::Generate<uint32_t>() { + SpinLockHolder l(&mu_); + MaybeRefill(); + return state_[next_++]; +} + +template <> +inline uint64_t RandenPoolEntry::Generate<uint64_t>() { + SpinLockHolder l(&mu_); + if (next_ >= kState - 1) { + next_ = kCapacity; + impl_.Generate(state_); + } + auto p = state_ + next_; + next_ += 2; + + uint64_t result; + std::memcpy(&result, p, sizeof(result)); + return result; +} + +void RandenPoolEntry::Fill(uint8_t* out, size_t bytes) { + SpinLockHolder l(&mu_); + while (bytes > 0) { + MaybeRefill(); + size_t remaining = (kState - next_) * sizeof(state_[0]); + size_t to_copy = std::min(bytes, remaining); + std::memcpy(out, &state_[next_], to_copy); + out += to_copy; + bytes -= to_copy; + next_ += (to_copy + sizeof(state_[0]) - 1) / sizeof(state_[0]); + } +} + +// Number of pooled urbg entries. +static constexpr int kPoolSize = 8; + +// Shared pool entries. +static absl::once_flag pool_once; +ABSL_CACHELINE_ALIGNED static RandenPoolEntry* shared_pools[kPoolSize]; + +// Returns an id in the range [0 ... kPoolSize), which indexes into the +// pool of random engines. +// +// Each thread to access the pool is assigned a sequential ID (without reuse) +// from the pool-id space; the id is cached in a thread_local variable. +// This id is assigned based on the arrival-order of the thread to the +// GetPoolID call; this has no binary, CL, or runtime stability because +// on subsequent runs the order within the same program may be significantly +// different. However, as other thread IDs are not assigned sequentially, +// this is not expected to matter. +int GetPoolID() { + static_assert(kPoolSize >= 1, + "At least one urbg instance is required for PoolURBG"); + + ABSL_CONST_INIT static std::atomic<int64_t> sequence{0}; + +#ifdef ABSL_HAVE_THREAD_LOCAL + static thread_local int my_pool_id = -1; + if (ABSL_PREDICT_FALSE(my_pool_id < 0)) { + my_pool_id = (sequence++ % kPoolSize); + } + return my_pool_id; +#else + static pthread_key_t tid_key = [] { + pthread_key_t tmp_key; + int err = pthread_key_create(&tmp_key, nullptr); + if (err) { + ABSL_RAW_LOG(FATAL, "pthread_key_create failed with %d", err); + } + return tmp_key; + }(); + + // Store the value in the pthread_{get/set}specific. However an uninitialized + // value is 0, so add +1 to distinguish from the null value. + intptr_t my_pool_id = + reinterpret_cast<intptr_t>(pthread_getspecific(tid_key)); + if (ABSL_PREDICT_FALSE(my_pool_id == 0)) { + // No allocated ID, allocate the next value, cache it, and return. + my_pool_id = (sequence++ % kPoolSize) + 1; + int err = pthread_setspecific(tid_key, reinterpret_cast<void*>(my_pool_id)); + if (err) { + ABSL_RAW_LOG(FATAL, "pthread_setspecific failed with %d", err); + } + } + return my_pool_id - 1; +#endif +} + +// Allocate a RandenPoolEntry with at least 32-byte alignment, which is required +// by ARM platform code. +RandenPoolEntry* PoolAlignedAlloc() { + constexpr size_t kAlignment = + ABSL_CACHELINE_SIZE > 32 ? ABSL_CACHELINE_SIZE : 32; + + // Not all the platforms that we build for have std::aligned_alloc, however + // since we never free these objects, we can over allocate and munge the + // pointers to the correct alignment. intptr_t x = reinterpret_cast<intptr_t>( new char[sizeof(RandenPoolEntry) + kAlignment]); - auto y = x % kAlignment; + auto y = x % kAlignment; void* aligned = reinterpret_cast<void*>(y == 0 ? x : (x + kAlignment - y)); - return new (aligned) RandenPoolEntry(); -} - -// Allocate and initialize kPoolSize objects of type RandenPoolEntry. -// -// The initialization strategy is to initialize one object directly from -// OS entropy, then to use that object to seed all of the individual -// pool instances. -void InitPoolURBG() { - static constexpr size_t kSeedSize = - RandenTraits::kStateBytes / sizeof(uint32_t); - // Read the seed data from OS entropy once. - uint32_t seed_material[kPoolSize * kSeedSize]; - if (!random_internal::ReadSeedMaterialFromOSEntropy( - absl::MakeSpan(seed_material))) { - random_internal::ThrowSeedGenException(); - } - for (int i = 0; i < kPoolSize; i++) { - shared_pools[i] = PoolAlignedAlloc(); - shared_pools[i]->Init( - absl::MakeSpan(&seed_material[i * kSeedSize], kSeedSize)); - } -} - -// Returns the pool entry for the current thread. -RandenPoolEntry* GetPoolForCurrentThread() { - absl::call_once(pool_once, InitPoolURBG); - return shared_pools[GetPoolID()]; -} - -} // namespace - -template <typename T> -typename RandenPool<T>::result_type RandenPool<T>::Generate() { - auto* pool = GetPoolForCurrentThread(); - return pool->Generate<T>(); -} - -template <typename T> -void RandenPool<T>::Fill(absl::Span<result_type> data) { - auto* pool = GetPoolForCurrentThread(); - pool->Fill(reinterpret_cast<uint8_t*>(data.data()), - data.size() * sizeof(result_type)); -} - -template class RandenPool<uint8_t>; -template class RandenPool<uint16_t>; -template class RandenPool<uint32_t>; -template class RandenPool<uint64_t>; - -} // namespace random_internal + return new (aligned) RandenPoolEntry(); +} + +// Allocate and initialize kPoolSize objects of type RandenPoolEntry. +// +// The initialization strategy is to initialize one object directly from +// OS entropy, then to use that object to seed all of the individual +// pool instances. +void InitPoolURBG() { + static constexpr size_t kSeedSize = + RandenTraits::kStateBytes / sizeof(uint32_t); + // Read the seed data from OS entropy once. + uint32_t seed_material[kPoolSize * kSeedSize]; + if (!random_internal::ReadSeedMaterialFromOSEntropy( + absl::MakeSpan(seed_material))) { + random_internal::ThrowSeedGenException(); + } + for (int i = 0; i < kPoolSize; i++) { + shared_pools[i] = PoolAlignedAlloc(); + shared_pools[i]->Init( + absl::MakeSpan(&seed_material[i * kSeedSize], kSeedSize)); + } +} + +// Returns the pool entry for the current thread. +RandenPoolEntry* GetPoolForCurrentThread() { + absl::call_once(pool_once, InitPoolURBG); + return shared_pools[GetPoolID()]; +} + +} // namespace + +template <typename T> +typename RandenPool<T>::result_type RandenPool<T>::Generate() { + auto* pool = GetPoolForCurrentThread(); + return pool->Generate<T>(); +} + +template <typename T> +void RandenPool<T>::Fill(absl::Span<result_type> data) { + auto* pool = GetPoolForCurrentThread(); + pool->Fill(reinterpret_cast<uint8_t*>(data.data()), + data.size() * sizeof(result_type)); +} + +template class RandenPool<uint8_t>; +template class RandenPool<uint16_t>; +template class RandenPool<uint32_t>; +template class RandenPool<uint64_t>; + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl +} // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/pool_urbg.h b/contrib/restricted/abseil-cpp/absl/random/internal/pool_urbg.h index f4fd5e166a..05721929f5 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/pool_urbg.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/pool_urbg.h @@ -1,131 +1,131 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_INTERNAL_POOL_URBG_H_ -#define ABSL_RANDOM_INTERNAL_POOL_URBG_H_ - -#include <cinttypes> -#include <limits> - -#include "absl/random/internal/traits.h" -#include "absl/types/span.h" - -namespace absl { +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_INTERNAL_POOL_URBG_H_ +#define ABSL_RANDOM_INTERNAL_POOL_URBG_H_ + +#include <cinttypes> +#include <limits> + +#include "absl/random/internal/traits.h" +#include "absl/types/span.h" + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - -// RandenPool is a thread-safe random number generator [random.req.urbg] that -// uses an underlying pool of Randen generators to generate values. Each thread -// has affinity to one instance of the underlying pool generators. Concurrent -// access is guarded by a spin-lock. -template <typename T> -class RandenPool { - public: - using result_type = T; - static_assert(std::is_unsigned<result_type>::value, - "RandenPool template argument must be a built-in unsigned " - "integer type"); - - static constexpr result_type(min)() { - return (std::numeric_limits<result_type>::min)(); - } - - static constexpr result_type(max)() { - return (std::numeric_limits<result_type>::max)(); - } - - RandenPool() {} - - // Returns a single value. - inline result_type operator()() { return Generate(); } - - // Fill data with random values. - static void Fill(absl::Span<result_type> data); - - protected: - // Generate returns a single value. - static result_type Generate(); -}; - -extern template class RandenPool<uint8_t>; -extern template class RandenPool<uint16_t>; -extern template class RandenPool<uint32_t>; -extern template class RandenPool<uint64_t>; - -// PoolURBG uses an underlying pool of random generators to implement a -// thread-compatible [random.req.urbg] interface with an internal cache of -// values. -template <typename T, size_t kBufferSize> -class PoolURBG { - // Inheritance to access the protected static members of RandenPool. - using unsigned_type = typename make_unsigned_bits<T>::type; - using PoolType = RandenPool<unsigned_type>; - using SpanType = absl::Span<unsigned_type>; - - static constexpr size_t kInitialBuffer = kBufferSize + 1; - static constexpr size_t kHalfBuffer = kBufferSize / 2; - - public: - using result_type = T; - - static_assert(std::is_unsigned<result_type>::value, - "PoolURBG must be parameterized by an unsigned integer type"); - - static_assert(kBufferSize > 1, - "PoolURBG must be parameterized by a buffer-size > 1"); - - static_assert(kBufferSize <= 256, - "PoolURBG must be parameterized by a buffer-size <= 256"); - - static constexpr result_type(min)() { - return (std::numeric_limits<result_type>::min)(); - } - - static constexpr result_type(max)() { - return (std::numeric_limits<result_type>::max)(); - } - - PoolURBG() : next_(kInitialBuffer) {} - - // copy-constructor does not copy cache. - PoolURBG(const PoolURBG&) : next_(kInitialBuffer) {} - const PoolURBG& operator=(const PoolURBG&) { - next_ = kInitialBuffer; - return *this; - } - - // move-constructor does move cache. - PoolURBG(PoolURBG&&) = default; - PoolURBG& operator=(PoolURBG&&) = default; - - inline result_type operator()() { - if (next_ >= kBufferSize) { - next_ = (kBufferSize > 2 && next_ > kBufferSize) ? kHalfBuffer : 0; - PoolType::Fill(SpanType(reinterpret_cast<unsigned_type*>(state_ + next_), - kBufferSize - next_)); - } - return state_[next_++]; - } - - private: - // Buffer size. - size_t next_; // index within state_ - result_type state_[kBufferSize]; -}; - -} // namespace random_internal +namespace random_internal { + +// RandenPool is a thread-safe random number generator [random.req.urbg] that +// uses an underlying pool of Randen generators to generate values. Each thread +// has affinity to one instance of the underlying pool generators. Concurrent +// access is guarded by a spin-lock. +template <typename T> +class RandenPool { + public: + using result_type = T; + static_assert(std::is_unsigned<result_type>::value, + "RandenPool template argument must be a built-in unsigned " + "integer type"); + + static constexpr result_type(min)() { + return (std::numeric_limits<result_type>::min)(); + } + + static constexpr result_type(max)() { + return (std::numeric_limits<result_type>::max)(); + } + + RandenPool() {} + + // Returns a single value. + inline result_type operator()() { return Generate(); } + + // Fill data with random values. + static void Fill(absl::Span<result_type> data); + + protected: + // Generate returns a single value. + static result_type Generate(); +}; + +extern template class RandenPool<uint8_t>; +extern template class RandenPool<uint16_t>; +extern template class RandenPool<uint32_t>; +extern template class RandenPool<uint64_t>; + +// PoolURBG uses an underlying pool of random generators to implement a +// thread-compatible [random.req.urbg] interface with an internal cache of +// values. +template <typename T, size_t kBufferSize> +class PoolURBG { + // Inheritance to access the protected static members of RandenPool. + using unsigned_type = typename make_unsigned_bits<T>::type; + using PoolType = RandenPool<unsigned_type>; + using SpanType = absl::Span<unsigned_type>; + + static constexpr size_t kInitialBuffer = kBufferSize + 1; + static constexpr size_t kHalfBuffer = kBufferSize / 2; + + public: + using result_type = T; + + static_assert(std::is_unsigned<result_type>::value, + "PoolURBG must be parameterized by an unsigned integer type"); + + static_assert(kBufferSize > 1, + "PoolURBG must be parameterized by a buffer-size > 1"); + + static_assert(kBufferSize <= 256, + "PoolURBG must be parameterized by a buffer-size <= 256"); + + static constexpr result_type(min)() { + return (std::numeric_limits<result_type>::min)(); + } + + static constexpr result_type(max)() { + return (std::numeric_limits<result_type>::max)(); + } + + PoolURBG() : next_(kInitialBuffer) {} + + // copy-constructor does not copy cache. + PoolURBG(const PoolURBG&) : next_(kInitialBuffer) {} + const PoolURBG& operator=(const PoolURBG&) { + next_ = kInitialBuffer; + return *this; + } + + // move-constructor does move cache. + PoolURBG(PoolURBG&&) = default; + PoolURBG& operator=(PoolURBG&&) = default; + + inline result_type operator()() { + if (next_ >= kBufferSize) { + next_ = (kBufferSize > 2 && next_ > kBufferSize) ? kHalfBuffer : 0; + PoolType::Fill(SpanType(reinterpret_cast<unsigned_type*>(state_ + next_), + kBufferSize - next_)); + } + return state_[next_++]; + } + + private: + // Buffer size. + size_t next_; // index within state_ + result_type state_[kBufferSize]; +}; + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_POOL_URBG_H_ +} // namespace absl + +#endif // ABSL_RANDOM_INTERNAL_POOL_URBG_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/pool_urbg/ya.make b/contrib/restricted/abseil-cpp/absl/random/internal/pool_urbg/ya.make index 98183380de..fd4e1c1f4d 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/pool_urbg/ya.make +++ b/contrib/restricted/abseil-cpp/absl/random/internal/pool_urbg/ya.make @@ -1,48 +1,48 @@ -# Generated by devtools/yamaker. - -LIBRARY() - +# Generated by devtools/yamaker. + +LIBRARY() + WITHOUT_LICENSE_TEXTS() -OWNER(g:cpp-contrib) - -LICENSE(Apache-2.0) - -PEERDIR( - contrib/restricted/abseil-cpp/absl/base - contrib/restricted/abseil-cpp/absl/base/internal/raw_logging - contrib/restricted/abseil-cpp/absl/base/internal/spinlock_wait - contrib/restricted/abseil-cpp/absl/base/internal/throw_delegate - contrib/restricted/abseil-cpp/absl/base/log_severity - contrib/restricted/abseil-cpp/absl/numeric - contrib/restricted/abseil-cpp/absl/random/internal/randen - contrib/restricted/abseil-cpp/absl/random/internal/randen_detect - contrib/restricted/abseil-cpp/absl/random/internal/randen_hwaes +OWNER(g:cpp-contrib) + +LICENSE(Apache-2.0) + +PEERDIR( + contrib/restricted/abseil-cpp/absl/base + contrib/restricted/abseil-cpp/absl/base/internal/raw_logging + contrib/restricted/abseil-cpp/absl/base/internal/spinlock_wait + contrib/restricted/abseil-cpp/absl/base/internal/throw_delegate + contrib/restricted/abseil-cpp/absl/base/log_severity + contrib/restricted/abseil-cpp/absl/numeric + contrib/restricted/abseil-cpp/absl/random/internal/randen + contrib/restricted/abseil-cpp/absl/random/internal/randen_detect + contrib/restricted/abseil-cpp/absl/random/internal/randen_hwaes contrib/restricted/abseil-cpp/absl/random/internal/randen_round_keys - contrib/restricted/abseil-cpp/absl/random/internal/randen_slow - contrib/restricted/abseil-cpp/absl/random/internal/seed_material - contrib/restricted/abseil-cpp/absl/random/seed_gen_exception - contrib/restricted/abseil-cpp/absl/strings + contrib/restricted/abseil-cpp/absl/random/internal/randen_slow + contrib/restricted/abseil-cpp/absl/random/internal/seed_material + contrib/restricted/abseil-cpp/absl/random/seed_gen_exception + contrib/restricted/abseil-cpp/absl/strings contrib/restricted/abseil-cpp/absl/strings/internal/absl_strings_internal - contrib/restricted/abseil-cpp/absl/types/bad_optional_access -) - -ADDINCL( - GLOBAL contrib/restricted/abseil-cpp -) - -NO_COMPILER_WARNINGS() - -NO_UTIL() - + contrib/restricted/abseil-cpp/absl/types/bad_optional_access +) + +ADDINCL( + GLOBAL contrib/restricted/abseil-cpp +) + +NO_COMPILER_WARNINGS() + +NO_UTIL() + CFLAGS( -DNOMINMAX ) -SRCDIR(contrib/restricted/abseil-cpp/absl/random/internal) - -SRCS( - pool_urbg.cc -) - -END() +SRCDIR(contrib/restricted/abseil-cpp/absl/random/internal) + +SRCS( + pool_urbg.cc +) + +END() diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/randen.cc b/contrib/restricted/abseil-cpp/absl/random/internal/randen.cc index 996b489bb6..c1bc044435 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/randen.cc +++ b/contrib/restricted/abseil-cpp/absl/random/internal/randen.cc @@ -1,91 +1,91 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "absl/random/internal/randen.h" - -#include "absl/base/internal/raw_logging.h" -#include "absl/random/internal/randen_detect.h" - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/random/internal/randen.h" + +#include "absl/base/internal/raw_logging.h" +#include "absl/random/internal/randen_detect.h" + // RANDen = RANDom generator or beetroots in Swiss High German. -// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random -// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32. -// -// High-level summary: -// 1) Reverie (see "A Robust and Sponge-Like PRNG with Improved Efficiency") is -// a sponge-like random generator that requires a cryptographic permutation. -// It improves upon "Provably Robust Sponge-Based PRNGs and KDFs" by -// achieving backtracking resistance with only one Permute() per buffer. -// -// 2) "Simpira v2: A Family of Efficient Permutations Using the AES Round -// Function" constructs up to 1024-bit permutations using an improved -// Generalized Feistel network with 2-round AES-128 functions. This Feistel -// block shuffle achieves diffusion faster and is less vulnerable to -// sliced-biclique attacks than the Type-2 cyclic shuffle. -// -// 3) "Improving the Generalized Feistel" and "New criterion for diffusion -// property" extends the same kind of improved Feistel block shuffle to 16 -// branches, which enables a 2048-bit permutation. -// -// We combine these three ideas and also change Simpira's subround keys from -// structured/low-entropy counters to digits of Pi. - -namespace absl { +// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random +// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32. +// +// High-level summary: +// 1) Reverie (see "A Robust and Sponge-Like PRNG with Improved Efficiency") is +// a sponge-like random generator that requires a cryptographic permutation. +// It improves upon "Provably Robust Sponge-Based PRNGs and KDFs" by +// achieving backtracking resistance with only one Permute() per buffer. +// +// 2) "Simpira v2: A Family of Efficient Permutations Using the AES Round +// Function" constructs up to 1024-bit permutations using an improved +// Generalized Feistel network with 2-round AES-128 functions. This Feistel +// block shuffle achieves diffusion faster and is less vulnerable to +// sliced-biclique attacks than the Type-2 cyclic shuffle. +// +// 3) "Improving the Generalized Feistel" and "New criterion for diffusion +// property" extends the same kind of improved Feistel block shuffle to 16 +// branches, which enables a 2048-bit permutation. +// +// We combine these three ideas and also change Simpira's subround keys from +// structured/low-entropy counters to digits of Pi. + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { -namespace { - -struct RandenState { - const void* keys; - bool has_crypto; -}; - -RandenState GetRandenState() { - static const RandenState state = []() { - RandenState tmp; -#if ABSL_RANDOM_INTERNAL_AES_DISPATCH - // HW AES Dispatch. - if (HasRandenHwAesImplementation() && CPUSupportsRandenHwAes()) { - tmp.has_crypto = true; - tmp.keys = RandenHwAes::GetKeys(); - } else { - tmp.has_crypto = false; - tmp.keys = RandenSlow::GetKeys(); - } -#elif ABSL_HAVE_ACCELERATED_AES - // HW AES is enabled. - tmp.has_crypto = true; - tmp.keys = RandenHwAes::GetKeys(); -#else - // HW AES is disabled. - tmp.has_crypto = false; - tmp.keys = RandenSlow::GetKeys(); -#endif - return tmp; - }(); - return state; -} - -} // namespace - -Randen::Randen() { - auto tmp = GetRandenState(); - keys_ = tmp.keys; -#if ABSL_RANDOM_INTERNAL_AES_DISPATCH - has_crypto_ = tmp.has_crypto; -#endif -} - -} // namespace random_internal +namespace random_internal { +namespace { + +struct RandenState { + const void* keys; + bool has_crypto; +}; + +RandenState GetRandenState() { + static const RandenState state = []() { + RandenState tmp; +#if ABSL_RANDOM_INTERNAL_AES_DISPATCH + // HW AES Dispatch. + if (HasRandenHwAesImplementation() && CPUSupportsRandenHwAes()) { + tmp.has_crypto = true; + tmp.keys = RandenHwAes::GetKeys(); + } else { + tmp.has_crypto = false; + tmp.keys = RandenSlow::GetKeys(); + } +#elif ABSL_HAVE_ACCELERATED_AES + // HW AES is enabled. + tmp.has_crypto = true; + tmp.keys = RandenHwAes::GetKeys(); +#else + // HW AES is disabled. + tmp.has_crypto = false; + tmp.keys = RandenSlow::GetKeys(); +#endif + return tmp; + }(); + return state; +} + +} // namespace + +Randen::Randen() { + auto tmp = GetRandenState(); + keys_ = tmp.keys; +#if ABSL_RANDOM_INTERNAL_AES_DISPATCH + has_crypto_ = tmp.has_crypto; +#endif +} + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl +} // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/randen.h b/contrib/restricted/abseil-cpp/absl/random/internal/randen.h index 6c2d53e210..9a3840b8f1 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/randen.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/randen.h @@ -1,102 +1,102 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_INTERNAL_RANDEN_H_ -#define ABSL_RANDOM_INTERNAL_RANDEN_H_ - -#include <cstddef> - -#include "absl/random/internal/platform.h" -#include "absl/random/internal/randen_hwaes.h" -#include "absl/random/internal/randen_slow.h" -#include "absl/random/internal/randen_traits.h" - -namespace absl { +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_INTERNAL_RANDEN_H_ +#define ABSL_RANDOM_INTERNAL_RANDEN_H_ + +#include <cstddef> + +#include "absl/random/internal/platform.h" +#include "absl/random/internal/randen_hwaes.h" +#include "absl/random/internal/randen_slow.h" +#include "absl/random/internal/randen_traits.h" + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - +namespace random_internal { + // RANDen = RANDom generator or beetroots in Swiss High German. -// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random -// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32. -// -// Randen implements the basic state manipulation methods. -class Randen { - public: - static constexpr size_t kStateBytes = RandenTraits::kStateBytes; - static constexpr size_t kCapacityBytes = RandenTraits::kCapacityBytes; - static constexpr size_t kSeedBytes = RandenTraits::kSeedBytes; - - ~Randen() = default; - - Randen(); - - // Generate updates the randen sponge. The outer portion of the sponge - // (kCapacityBytes .. kStateBytes) may be consumed as PRNG state. - template <typename T, size_t N> - void Generate(T (&state)[N]) const { - static_assert(N * sizeof(T) == kStateBytes, - "Randen::Generate() requires kStateBytes of state"); -#if ABSL_RANDOM_INTERNAL_AES_DISPATCH - // HW AES Dispatch. - if (has_crypto_) { - RandenHwAes::Generate(keys_, state); - } else { - RandenSlow::Generate(keys_, state); - } -#elif ABSL_HAVE_ACCELERATED_AES - // HW AES is enabled. - RandenHwAes::Generate(keys_, state); -#else - // HW AES is disabled. - RandenSlow::Generate(keys_, state); -#endif - } - - // Absorb incorporates additional seed material into the randen sponge. After - // absorb returns, Generate must be called before the state may be consumed. - template <typename S, size_t M, typename T, size_t N> - void Absorb(const S (&seed)[M], T (&state)[N]) const { - static_assert(M * sizeof(S) == RandenTraits::kSeedBytes, - "Randen::Absorb() requires kSeedBytes of seed"); - - static_assert(N * sizeof(T) == RandenTraits::kStateBytes, - "Randen::Absorb() requires kStateBytes of state"); -#if ABSL_RANDOM_INTERNAL_AES_DISPATCH - // HW AES Dispatch. - if (has_crypto_) { - RandenHwAes::Absorb(seed, state); - } else { - RandenSlow::Absorb(seed, state); - } -#elif ABSL_HAVE_ACCELERATED_AES - // HW AES is enabled. - RandenHwAes::Absorb(seed, state); -#else - // HW AES is disabled. - RandenSlow::Absorb(seed, state); -#endif - } - - private: - const void* keys_; -#if ABSL_RANDOM_INTERNAL_AES_DISPATCH - bool has_crypto_; -#endif -}; - -} // namespace random_internal +// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random +// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32. +// +// Randen implements the basic state manipulation methods. +class Randen { + public: + static constexpr size_t kStateBytes = RandenTraits::kStateBytes; + static constexpr size_t kCapacityBytes = RandenTraits::kCapacityBytes; + static constexpr size_t kSeedBytes = RandenTraits::kSeedBytes; + + ~Randen() = default; + + Randen(); + + // Generate updates the randen sponge. The outer portion of the sponge + // (kCapacityBytes .. kStateBytes) may be consumed as PRNG state. + template <typename T, size_t N> + void Generate(T (&state)[N]) const { + static_assert(N * sizeof(T) == kStateBytes, + "Randen::Generate() requires kStateBytes of state"); +#if ABSL_RANDOM_INTERNAL_AES_DISPATCH + // HW AES Dispatch. + if (has_crypto_) { + RandenHwAes::Generate(keys_, state); + } else { + RandenSlow::Generate(keys_, state); + } +#elif ABSL_HAVE_ACCELERATED_AES + // HW AES is enabled. + RandenHwAes::Generate(keys_, state); +#else + // HW AES is disabled. + RandenSlow::Generate(keys_, state); +#endif + } + + // Absorb incorporates additional seed material into the randen sponge. After + // absorb returns, Generate must be called before the state may be consumed. + template <typename S, size_t M, typename T, size_t N> + void Absorb(const S (&seed)[M], T (&state)[N]) const { + static_assert(M * sizeof(S) == RandenTraits::kSeedBytes, + "Randen::Absorb() requires kSeedBytes of seed"); + + static_assert(N * sizeof(T) == RandenTraits::kStateBytes, + "Randen::Absorb() requires kStateBytes of state"); +#if ABSL_RANDOM_INTERNAL_AES_DISPATCH + // HW AES Dispatch. + if (has_crypto_) { + RandenHwAes::Absorb(seed, state); + } else { + RandenSlow::Absorb(seed, state); + } +#elif ABSL_HAVE_ACCELERATED_AES + // HW AES is enabled. + RandenHwAes::Absorb(seed, state); +#else + // HW AES is disabled. + RandenSlow::Absorb(seed, state); +#endif + } + + private: + const void* keys_; +#if ABSL_RANDOM_INTERNAL_AES_DISPATCH + bool has_crypto_; +#endif +}; + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_RANDEN_H_ +} // namespace absl + +#endif // ABSL_RANDOM_INTERNAL_RANDEN_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/randen/ya.make b/contrib/restricted/abseil-cpp/absl/random/internal/randen/ya.make index 22f85e42ee..150b9e0714 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/randen/ya.make +++ b/contrib/restricted/abseil-cpp/absl/random/internal/randen/ya.make @@ -1,36 +1,36 @@ -# Generated by devtools/yamaker. - -LIBRARY() - +# Generated by devtools/yamaker. + +LIBRARY() + WITHOUT_LICENSE_TEXTS() -OWNER(g:cpp-contrib) - -LICENSE(Apache-2.0) - -PEERDIR( - contrib/restricted/abseil-cpp/absl/random/internal/randen_detect - contrib/restricted/abseil-cpp/absl/random/internal/randen_hwaes +OWNER(g:cpp-contrib) + +LICENSE(Apache-2.0) + +PEERDIR( + contrib/restricted/abseil-cpp/absl/random/internal/randen_detect + contrib/restricted/abseil-cpp/absl/random/internal/randen_hwaes contrib/restricted/abseil-cpp/absl/random/internal/randen_round_keys - contrib/restricted/abseil-cpp/absl/random/internal/randen_slow -) - -ADDINCL( - GLOBAL contrib/restricted/abseil-cpp -) - -NO_COMPILER_WARNINGS() - -NO_UTIL() - + contrib/restricted/abseil-cpp/absl/random/internal/randen_slow +) + +ADDINCL( + GLOBAL contrib/restricted/abseil-cpp +) + +NO_COMPILER_WARNINGS() + +NO_UTIL() + CFLAGS( -DNOMINMAX ) -SRCDIR(contrib/restricted/abseil-cpp/absl/random/internal) - -SRCS( - randen.cc -) - -END() +SRCDIR(contrib/restricted/abseil-cpp/absl/random/internal) + +SRCS( + randen.cc +) + +END() diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/randen_detect.cc b/contrib/restricted/abseil-cpp/absl/random/internal/randen_detect.cc index 991512b18a..bbe7b96532 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/randen_detect.cc +++ b/contrib/restricted/abseil-cpp/absl/random/internal/randen_detect.cc @@ -1,221 +1,221 @@ -// Copyright 2017 The Abseil Authors. -// +// Copyright 2017 The Abseil Authors. +// // Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// HERMETIC NOTE: The randen_hwaes target must not introduce duplicate -// symbols from arbitrary system and other headers, since it may be built -// with different flags from other targets, using different levels of -// optimization, potentially introducing ODR violations. - -#include "absl/random/internal/randen_detect.h" - -#include <cstdint> -#include <cstring> - -#include "absl/random/internal/platform.h" - -#if defined(ABSL_ARCH_X86_64) -#define ABSL_INTERNAL_USE_X86_CPUID -#elif defined(ABSL_ARCH_PPC) || defined(ABSL_ARCH_ARM) || \ - defined(ABSL_ARCH_AARCH64) -#if defined(__ANDROID__) -#define ABSL_INTERNAL_USE_ANDROID_GETAUXVAL -#define ABSL_INTERNAL_USE_GETAUXVAL -#elif defined(__linux__) -#define ABSL_INTERNAL_USE_LINUX_GETAUXVAL -#define ABSL_INTERNAL_USE_GETAUXVAL -#endif -#endif - -#if defined(ABSL_INTERNAL_USE_X86_CPUID) -#if defined(_WIN32) || defined(_WIN64) -#include <intrin.h> // NOLINT(build/include_order) -#pragma intrinsic(__cpuid) -#else -// MSVC-equivalent __cpuid intrinsic function. -static void __cpuid(int cpu_info[4], int info_type) { - __asm__ volatile("cpuid \n\t" - : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), - "=d"(cpu_info[3]) - : "a"(info_type), "c"(0)); -} -#endif -#endif // ABSL_INTERNAL_USE_X86_CPUID - -// On linux, just use the c-library getauxval call. -#if defined(ABSL_INTERNAL_USE_LINUX_GETAUXVAL) - -extern "C" unsigned long getauxval(unsigned long type); // NOLINT(runtime/int) - -static uint32_t GetAuxval(uint32_t hwcap_type) { - return static_cast<uint32_t>(getauxval(hwcap_type)); -} - -#endif - -// On android, probe the system's C library for getauxval(). -// This is the same technique used by the android NDK cpu features library -// as well as the google open-source cpu_features library. -// -// TODO(absl-team): Consider implementing a fallback of directly reading -// /proc/self/auxval. -#if defined(ABSL_INTERNAL_USE_ANDROID_GETAUXVAL) -#include <dlfcn.h> - -static uint32_t GetAuxval(uint32_t hwcap_type) { - // NOLINTNEXTLINE(runtime/int) - typedef unsigned long (*getauxval_func_t)(unsigned long); - - dlerror(); // Cleaning error state before calling dlopen. - void* libc_handle = dlopen("libc.so", RTLD_NOW); - if (!libc_handle) { - return 0; - } - uint32_t result = 0; - void* sym = dlsym(libc_handle, "getauxval"); - if (sym) { - getauxval_func_t func; - memcpy(&func, &sym, sizeof(func)); - result = static_cast<uint32_t>((*func)(hwcap_type)); - } - dlclose(libc_handle); - return result; -} - -#endif - -namespace absl { +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// HERMETIC NOTE: The randen_hwaes target must not introduce duplicate +// symbols from arbitrary system and other headers, since it may be built +// with different flags from other targets, using different levels of +// optimization, potentially introducing ODR violations. + +#include "absl/random/internal/randen_detect.h" + +#include <cstdint> +#include <cstring> + +#include "absl/random/internal/platform.h" + +#if defined(ABSL_ARCH_X86_64) +#define ABSL_INTERNAL_USE_X86_CPUID +#elif defined(ABSL_ARCH_PPC) || defined(ABSL_ARCH_ARM) || \ + defined(ABSL_ARCH_AARCH64) +#if defined(__ANDROID__) +#define ABSL_INTERNAL_USE_ANDROID_GETAUXVAL +#define ABSL_INTERNAL_USE_GETAUXVAL +#elif defined(__linux__) +#define ABSL_INTERNAL_USE_LINUX_GETAUXVAL +#define ABSL_INTERNAL_USE_GETAUXVAL +#endif +#endif + +#if defined(ABSL_INTERNAL_USE_X86_CPUID) +#if defined(_WIN32) || defined(_WIN64) +#include <intrin.h> // NOLINT(build/include_order) +#pragma intrinsic(__cpuid) +#else +// MSVC-equivalent __cpuid intrinsic function. +static void __cpuid(int cpu_info[4], int info_type) { + __asm__ volatile("cpuid \n\t" + : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), + "=d"(cpu_info[3]) + : "a"(info_type), "c"(0)); +} +#endif +#endif // ABSL_INTERNAL_USE_X86_CPUID + +// On linux, just use the c-library getauxval call. +#if defined(ABSL_INTERNAL_USE_LINUX_GETAUXVAL) + +extern "C" unsigned long getauxval(unsigned long type); // NOLINT(runtime/int) + +static uint32_t GetAuxval(uint32_t hwcap_type) { + return static_cast<uint32_t>(getauxval(hwcap_type)); +} + +#endif + +// On android, probe the system's C library for getauxval(). +// This is the same technique used by the android NDK cpu features library +// as well as the google open-source cpu_features library. +// +// TODO(absl-team): Consider implementing a fallback of directly reading +// /proc/self/auxval. +#if defined(ABSL_INTERNAL_USE_ANDROID_GETAUXVAL) +#include <dlfcn.h> + +static uint32_t GetAuxval(uint32_t hwcap_type) { + // NOLINTNEXTLINE(runtime/int) + typedef unsigned long (*getauxval_func_t)(unsigned long); + + dlerror(); // Cleaning error state before calling dlopen. + void* libc_handle = dlopen("libc.so", RTLD_NOW); + if (!libc_handle) { + return 0; + } + uint32_t result = 0; + void* sym = dlsym(libc_handle, "getauxval"); + if (sym) { + getauxval_func_t func; + memcpy(&func, &sym, sizeof(func)); + result = static_cast<uint32_t>((*func)(hwcap_type)); + } + dlclose(libc_handle); + return result; +} + +#endif + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - -// The default return at the end of the function might be unreachable depending -// on the configuration. Ignore that warning. -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunreachable-code-return" -#endif - -// CPUSupportsRandenHwAes returns whether the CPU is a microarchitecture -// which supports the crpyto/aes instructions or extensions necessary to use the -// accelerated RandenHwAes implementation. -// -// 1. For x86 it is sufficient to use the CPUID instruction to detect whether -// the cpu supports AES instructions. Done. -// -// Fon non-x86 it is much more complicated. -// -// 2. When ABSL_INTERNAL_USE_GETAUXVAL is defined, use getauxval() (either -// the direct c-library version, or the android probing version which loads -// libc), and read the hardware capability bits. -// This is based on the technique used by boringssl uses to detect -// cpu capabilities, and should allow us to enable crypto in the android -// builds where it is supported. -// -// 3. Use the default for the compiler architecture. -// - -bool CPUSupportsRandenHwAes() { -#if defined(ABSL_INTERNAL_USE_X86_CPUID) - // 1. For x86: Use CPUID to detect the required AES instruction set. - int regs[4]; - __cpuid(reinterpret_cast<int*>(regs), 1); - return regs[2] & (1 << 25); // AES - -#elif defined(ABSL_INTERNAL_USE_GETAUXVAL) - // 2. Use getauxval() to read the hardware bits and determine - // cpu capabilities. - -#define AT_HWCAP 16 -#define AT_HWCAP2 26 -#if defined(ABSL_ARCH_PPC) - // For Power / PPC: Expect that the cpu supports VCRYPTO - // See https://members.openpowerfoundation.org/document/dl/576 - // VCRYPTO should be present in POWER8 >= 2.07. - // Uses Linux kernel constants from arch/powerpc/include/uapi/asm/cputable.h - static const uint32_t kVCRYPTO = 0x02000000; - const uint32_t hwcap = GetAuxval(AT_HWCAP2); - return (hwcap & kVCRYPTO) != 0; - -#elif defined(ABSL_ARCH_ARM) - // For ARM: Require crypto+neon - // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0500f/CIHBIBBA.html - // Uses Linux kernel constants from arch/arm64/include/asm/hwcap.h - static const uint32_t kNEON = 1 << 12; - uint32_t hwcap = GetAuxval(AT_HWCAP); - if ((hwcap & kNEON) == 0) { - return false; - } - - // And use it again to detect AES. - static const uint32_t kAES = 1 << 0; - const uint32_t hwcap2 = GetAuxval(AT_HWCAP2); - return (hwcap2 & kAES) != 0; - -#elif defined(ABSL_ARCH_AARCH64) - // For AARCH64: Require crypto+neon - // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0500f/CIHBIBBA.html - static const uint32_t kNEON = 1 << 1; - static const uint32_t kAES = 1 << 3; - const uint32_t hwcap = GetAuxval(AT_HWCAP); - return ((hwcap & kNEON) != 0) && ((hwcap & kAES) != 0); -#endif - -#else // ABSL_INTERNAL_USE_GETAUXVAL - // 3. By default, assume that the compiler default. - return ABSL_HAVE_ACCELERATED_AES ? true : false; - -#endif - // NOTE: There are some other techniques that may be worth trying: - // - // * Use an environment variable: ABSL_RANDOM_USE_HWAES - // - // * Rely on compiler-generated target-based dispatch. - // Using x86/gcc it might look something like this: - // - // int __attribute__((target("aes"))) HasAes() { return 1; } - // int __attribute__((target("default"))) HasAes() { return 0; } - // - // This does not work on all architecture/compiler combinations. - // - // * On Linux consider reading /proc/cpuinfo and/or /proc/self/auxv. - // These files have lines which are easy to parse; for ARM/AARCH64 it is quite - // easy to find the Features: line and extract aes / neon. Likewise for - // PPC. - // - // * Fork a process and test for SIGILL: - // - // * Many architectures have instructions to read the ISA. Unfortunately - // most of those require that the code is running in ring 0 / - // protected-mode. - // - // There are several examples. e.g. Valgrind detects PPC ISA 2.07: - // https://github.com/lu-zero/valgrind/blob/master/none/tests/ppc64/test_isa_2_07_part1.c - // - // MRS <Xt>, ID_AA64ISAR0_EL1 ; Read ID_AA64ISAR0_EL1 into Xt - // - // uint64_t val; - // __asm __volatile("mrs %0, id_aa64isar0_el1" :"=&r" (val)); - // - // * Use a CPUID-style heuristic database. - // - // * On Apple (__APPLE__), AES is available on Arm v8. - // https://stackoverflow.com/questions/45637888/how-to-determine-armv8-features-at-runtime-on-ios -} - -#if defined(__clang__) -#pragma clang diagnostic pop -#endif - -} // namespace random_internal +namespace random_internal { + +// The default return at the end of the function might be unreachable depending +// on the configuration. Ignore that warning. +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code-return" +#endif + +// CPUSupportsRandenHwAes returns whether the CPU is a microarchitecture +// which supports the crpyto/aes instructions or extensions necessary to use the +// accelerated RandenHwAes implementation. +// +// 1. For x86 it is sufficient to use the CPUID instruction to detect whether +// the cpu supports AES instructions. Done. +// +// Fon non-x86 it is much more complicated. +// +// 2. When ABSL_INTERNAL_USE_GETAUXVAL is defined, use getauxval() (either +// the direct c-library version, or the android probing version which loads +// libc), and read the hardware capability bits. +// This is based on the technique used by boringssl uses to detect +// cpu capabilities, and should allow us to enable crypto in the android +// builds where it is supported. +// +// 3. Use the default for the compiler architecture. +// + +bool CPUSupportsRandenHwAes() { +#if defined(ABSL_INTERNAL_USE_X86_CPUID) + // 1. For x86: Use CPUID to detect the required AES instruction set. + int regs[4]; + __cpuid(reinterpret_cast<int*>(regs), 1); + return regs[2] & (1 << 25); // AES + +#elif defined(ABSL_INTERNAL_USE_GETAUXVAL) + // 2. Use getauxval() to read the hardware bits and determine + // cpu capabilities. + +#define AT_HWCAP 16 +#define AT_HWCAP2 26 +#if defined(ABSL_ARCH_PPC) + // For Power / PPC: Expect that the cpu supports VCRYPTO + // See https://members.openpowerfoundation.org/document/dl/576 + // VCRYPTO should be present in POWER8 >= 2.07. + // Uses Linux kernel constants from arch/powerpc/include/uapi/asm/cputable.h + static const uint32_t kVCRYPTO = 0x02000000; + const uint32_t hwcap = GetAuxval(AT_HWCAP2); + return (hwcap & kVCRYPTO) != 0; + +#elif defined(ABSL_ARCH_ARM) + // For ARM: Require crypto+neon + // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0500f/CIHBIBBA.html + // Uses Linux kernel constants from arch/arm64/include/asm/hwcap.h + static const uint32_t kNEON = 1 << 12; + uint32_t hwcap = GetAuxval(AT_HWCAP); + if ((hwcap & kNEON) == 0) { + return false; + } + + // And use it again to detect AES. + static const uint32_t kAES = 1 << 0; + const uint32_t hwcap2 = GetAuxval(AT_HWCAP2); + return (hwcap2 & kAES) != 0; + +#elif defined(ABSL_ARCH_AARCH64) + // For AARCH64: Require crypto+neon + // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0500f/CIHBIBBA.html + static const uint32_t kNEON = 1 << 1; + static const uint32_t kAES = 1 << 3; + const uint32_t hwcap = GetAuxval(AT_HWCAP); + return ((hwcap & kNEON) != 0) && ((hwcap & kAES) != 0); +#endif + +#else // ABSL_INTERNAL_USE_GETAUXVAL + // 3. By default, assume that the compiler default. + return ABSL_HAVE_ACCELERATED_AES ? true : false; + +#endif + // NOTE: There are some other techniques that may be worth trying: + // + // * Use an environment variable: ABSL_RANDOM_USE_HWAES + // + // * Rely on compiler-generated target-based dispatch. + // Using x86/gcc it might look something like this: + // + // int __attribute__((target("aes"))) HasAes() { return 1; } + // int __attribute__((target("default"))) HasAes() { return 0; } + // + // This does not work on all architecture/compiler combinations. + // + // * On Linux consider reading /proc/cpuinfo and/or /proc/self/auxv. + // These files have lines which are easy to parse; for ARM/AARCH64 it is quite + // easy to find the Features: line and extract aes / neon. Likewise for + // PPC. + // + // * Fork a process and test for SIGILL: + // + // * Many architectures have instructions to read the ISA. Unfortunately + // most of those require that the code is running in ring 0 / + // protected-mode. + // + // There are several examples. e.g. Valgrind detects PPC ISA 2.07: + // https://github.com/lu-zero/valgrind/blob/master/none/tests/ppc64/test_isa_2_07_part1.c + // + // MRS <Xt>, ID_AA64ISAR0_EL1 ; Read ID_AA64ISAR0_EL1 into Xt + // + // uint64_t val; + // __asm __volatile("mrs %0, id_aa64isar0_el1" :"=&r" (val)); + // + // * Use a CPUID-style heuristic database. + // + // * On Apple (__APPLE__), AES is available on Arm v8. + // https://stackoverflow.com/questions/45637888/how-to-determine-armv8-features-at-runtime-on-ios +} + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl +} // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/randen_detect.h b/contrib/restricted/abseil-cpp/absl/random/internal/randen_detect.h index 40ca2a2860..f283f43226 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/randen_detect.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/randen_detect.h @@ -1,33 +1,33 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_INTERNAL_RANDEN_DETECT_H_ -#define ABSL_RANDOM_INTERNAL_RANDEN_DETECT_H_ - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_INTERNAL_RANDEN_DETECT_H_ +#define ABSL_RANDOM_INTERNAL_RANDEN_DETECT_H_ + #include "absl/base/config.h" -namespace absl { +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - -// Returns whether the current CPU supports RandenHwAes implementation. -// This typically involves supporting cryptographic extensions on whichever -// platform is currently running. -bool CPUSupportsRandenHwAes(); - -} // namespace random_internal +namespace random_internal { + +// Returns whether the current CPU supports RandenHwAes implementation. +// This typically involves supporting cryptographic extensions on whichever +// platform is currently running. +bool CPUSupportsRandenHwAes(); + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_RANDEN_DETECT_H_ +} // namespace absl + +#endif // ABSL_RANDOM_INTERNAL_RANDEN_DETECT_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/randen_detect/ya.make b/contrib/restricted/abseil-cpp/absl/random/internal/randen_detect/ya.make index 8191995ddf..62059877ba 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/randen_detect/ya.make +++ b/contrib/restricted/abseil-cpp/absl/random/internal/randen_detect/ya.make @@ -1,34 +1,34 @@ -# Generated by devtools/yamaker. - -LIBRARY() - +# Generated by devtools/yamaker. + +LIBRARY() + WITHOUT_LICENSE_TEXTS() -OWNER(g:cpp-contrib) - -LICENSE(Apache-2.0) - -PEERDIR( - contrib/restricted/abseil-cpp/absl/random/internal/randen_hwaes +OWNER(g:cpp-contrib) + +LICENSE(Apache-2.0) + +PEERDIR( + contrib/restricted/abseil-cpp/absl/random/internal/randen_hwaes contrib/restricted/abseil-cpp/absl/random/internal/randen_round_keys -) - -ADDINCL( - GLOBAL contrib/restricted/abseil-cpp -) - -NO_COMPILER_WARNINGS() - -NO_UTIL() - +) + +ADDINCL( + GLOBAL contrib/restricted/abseil-cpp +) + +NO_COMPILER_WARNINGS() + +NO_UTIL() + CFLAGS( -DNOMINMAX ) -SRCDIR(contrib/restricted/abseil-cpp/absl/random/internal) - -SRCS( - randen_detect.cc -) - -END() +SRCDIR(contrib/restricted/abseil-cpp/absl/random/internal) + +SRCS( + randen_detect.cc +) + +END() diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/randen_engine.h b/contrib/restricted/abseil-cpp/absl/random/internal/randen_engine.h index 053c258550..372c3ac2bd 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/randen_engine.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/randen_engine.h @@ -1,126 +1,126 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_INTERNAL_RANDEN_ENGINE_H_ -#define ABSL_RANDOM_INTERNAL_RANDEN_ENGINE_H_ - -#include <algorithm> -#include <cinttypes> -#include <cstdlib> -#include <iostream> -#include <iterator> -#include <limits> -#include <type_traits> - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_INTERNAL_RANDEN_ENGINE_H_ +#define ABSL_RANDOM_INTERNAL_RANDEN_ENGINE_H_ + +#include <algorithm> +#include <cinttypes> +#include <cstdlib> +#include <iostream> +#include <iterator> +#include <limits> +#include <type_traits> + #include "absl/base/internal/endian.h" -#include "absl/meta/type_traits.h" -#include "absl/random/internal/iostream_state_saver.h" -#include "absl/random/internal/randen.h" - -namespace absl { +#include "absl/meta/type_traits.h" +#include "absl/random/internal/iostream_state_saver.h" +#include "absl/random/internal/randen.h" + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - -// Deterministic pseudorandom byte generator with backtracking resistance -// (leaking the state does not compromise prior outputs). Based on Reverie -// (see "A Robust and Sponge-Like PRNG with Improved Efficiency") instantiated -// with an improved Simpira-like permutation. -// Returns values of type "T" (must be a built-in unsigned integer type). -// -// RANDen = RANDom generator or beetroots in Swiss High German. -// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random -// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32. -template <typename T> -class alignas(16) randen_engine { - public: - // C++11 URBG interface: - using result_type = T; - static_assert(std::is_unsigned<result_type>::value, - "randen_engine template argument must be a built-in unsigned " - "integer type"); - - static constexpr result_type(min)() { - return (std::numeric_limits<result_type>::min)(); - } - - static constexpr result_type(max)() { - return (std::numeric_limits<result_type>::max)(); - } - - explicit randen_engine(result_type seed_value = 0) { seed(seed_value); } - - template <class SeedSequence, - typename = typename absl::enable_if_t< - !std::is_same<SeedSequence, randen_engine>::value>> - explicit randen_engine(SeedSequence&& seq) { - seed(seq); - } - - randen_engine(const randen_engine&) = default; - - // Returns random bits from the buffer in units of result_type. - result_type operator()() { - // Refill the buffer if needed (unlikely). - if (next_ >= kStateSizeT) { - next_ = kCapacityT; - impl_.Generate(state_); - } - +namespace random_internal { + +// Deterministic pseudorandom byte generator with backtracking resistance +// (leaking the state does not compromise prior outputs). Based on Reverie +// (see "A Robust and Sponge-Like PRNG with Improved Efficiency") instantiated +// with an improved Simpira-like permutation. +// Returns values of type "T" (must be a built-in unsigned integer type). +// +// RANDen = RANDom generator or beetroots in Swiss High German. +// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random +// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32. +template <typename T> +class alignas(16) randen_engine { + public: + // C++11 URBG interface: + using result_type = T; + static_assert(std::is_unsigned<result_type>::value, + "randen_engine template argument must be a built-in unsigned " + "integer type"); + + static constexpr result_type(min)() { + return (std::numeric_limits<result_type>::min)(); + } + + static constexpr result_type(max)() { + return (std::numeric_limits<result_type>::max)(); + } + + explicit randen_engine(result_type seed_value = 0) { seed(seed_value); } + + template <class SeedSequence, + typename = typename absl::enable_if_t< + !std::is_same<SeedSequence, randen_engine>::value>> + explicit randen_engine(SeedSequence&& seq) { + seed(seq); + } + + randen_engine(const randen_engine&) = default; + + // Returns random bits from the buffer in units of result_type. + result_type operator()() { + // Refill the buffer if needed (unlikely). + if (next_ >= kStateSizeT) { + next_ = kCapacityT; + impl_.Generate(state_); + } + return little_endian::ToHost(state_[next_++]); - } - - template <class SeedSequence> - typename absl::enable_if_t< - !std::is_convertible<SeedSequence, result_type>::value> - seed(SeedSequence&& seq) { - // Zeroes the state. - seed(); - reseed(seq); - } - - void seed(result_type seed_value = 0) { - next_ = kStateSizeT; - // Zeroes the inner state and fills the outer state with seed_value to - // mimics behaviour of reseed - std::fill(std::begin(state_), std::begin(state_) + kCapacityT, 0); - std::fill(std::begin(state_) + kCapacityT, std::end(state_), seed_value); - } - - // Inserts entropy into (part of) the state. Calling this periodically with - // sufficient entropy ensures prediction resistance (attackers cannot predict - // future outputs even if state is compromised). - template <class SeedSequence> - void reseed(SeedSequence& seq) { - using sequence_result_type = typename SeedSequence::result_type; - static_assert(sizeof(sequence_result_type) == 4, - "SeedSequence::result_type must be 32-bit"); - - constexpr size_t kBufferSize = - Randen::kSeedBytes / sizeof(sequence_result_type); - alignas(16) sequence_result_type buffer[kBufferSize]; - - // Randen::Absorb XORs the seed into state, which is then mixed by a call - // to Randen::Generate. Seeding with only the provided entropy is preferred - // to using an arbitrary generate() call, so use [rand.req.seed_seq] - // size as a proxy for the number of entropy units that can be generated - // without relying on seed sequence mixing... - const size_t entropy_size = seq.size(); - if (entropy_size < kBufferSize) { - // ... and only request that many values, or 256-bits, when unspecified. - const size_t requested_entropy = (entropy_size == 0) ? 8u : entropy_size; - std::fill(std::begin(buffer) + requested_entropy, std::end(buffer), 0); - seq.generate(std::begin(buffer), std::begin(buffer) + requested_entropy); + } + + template <class SeedSequence> + typename absl::enable_if_t< + !std::is_convertible<SeedSequence, result_type>::value> + seed(SeedSequence&& seq) { + // Zeroes the state. + seed(); + reseed(seq); + } + + void seed(result_type seed_value = 0) { + next_ = kStateSizeT; + // Zeroes the inner state and fills the outer state with seed_value to + // mimics behaviour of reseed + std::fill(std::begin(state_), std::begin(state_) + kCapacityT, 0); + std::fill(std::begin(state_) + kCapacityT, std::end(state_), seed_value); + } + + // Inserts entropy into (part of) the state. Calling this periodically with + // sufficient entropy ensures prediction resistance (attackers cannot predict + // future outputs even if state is compromised). + template <class SeedSequence> + void reseed(SeedSequence& seq) { + using sequence_result_type = typename SeedSequence::result_type; + static_assert(sizeof(sequence_result_type) == 4, + "SeedSequence::result_type must be 32-bit"); + + constexpr size_t kBufferSize = + Randen::kSeedBytes / sizeof(sequence_result_type); + alignas(16) sequence_result_type buffer[kBufferSize]; + + // Randen::Absorb XORs the seed into state, which is then mixed by a call + // to Randen::Generate. Seeding with only the provided entropy is preferred + // to using an arbitrary generate() call, so use [rand.req.seed_seq] + // size as a proxy for the number of entropy units that can be generated + // without relying on seed sequence mixing... + const size_t entropy_size = seq.size(); + if (entropy_size < kBufferSize) { + // ... and only request that many values, or 256-bits, when unspecified. + const size_t requested_entropy = (entropy_size == 0) ? 8u : entropy_size; + std::fill(std::begin(buffer) + requested_entropy, std::end(buffer), 0); + seq.generate(std::begin(buffer), std::begin(buffer) + requested_entropy); #ifdef ABSL_IS_BIG_ENDIAN // Randen expects the seed buffer to be in Little Endian; reverse it on // Big Endian platforms. @@ -128,112 +128,112 @@ class alignas(16) randen_engine { e = absl::little_endian::FromHost(e); } #endif - // The Randen paper suggests preferentially initializing even-numbered - // 128-bit vectors of the randen state (there are 16 such vectors). - // The seed data is merged into the state offset by 128-bits, which - // implies prefering seed bytes [16..31, ..., 208..223]. Since the - // buffer is 32-bit values, we swap the corresponding buffer positions in - // 128-bit chunks. - size_t dst = kBufferSize; - while (dst > 7) { - // leave the odd bucket as-is. - dst -= 4; - size_t src = dst >> 1; - // swap 128-bits into the even bucket - std::swap(buffer[--dst], buffer[--src]); - std::swap(buffer[--dst], buffer[--src]); - std::swap(buffer[--dst], buffer[--src]); - std::swap(buffer[--dst], buffer[--src]); - } - } else { - seq.generate(std::begin(buffer), std::end(buffer)); - } - impl_.Absorb(buffer, state_); - - // Generate will be called when operator() is called - next_ = kStateSizeT; - } - - void discard(uint64_t count) { - uint64_t step = std::min<uint64_t>(kStateSizeT - next_, count); - count -= step; - - constexpr uint64_t kRateT = kStateSizeT - kCapacityT; - while (count > 0) { - next_ = kCapacityT; - impl_.Generate(state_); - step = std::min<uint64_t>(kRateT, count); - count -= step; - } - next_ += step; - } - - bool operator==(const randen_engine& other) const { - return next_ == other.next_ && - std::equal(std::begin(state_), std::end(state_), - std::begin(other.state_)); - } - - bool operator!=(const randen_engine& other) const { - return !(*this == other); - } - - template <class CharT, class Traits> - friend std::basic_ostream<CharT, Traits>& operator<<( - std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) - const randen_engine<T>& engine) { // NOLINT(runtime/references) - using numeric_type = - typename random_internal::stream_format_type<result_type>::type; - auto saver = random_internal::make_ostream_state_saver(os); - for (const auto& elem : engine.state_) { - // In the case that `elem` is `uint8_t`, it must be cast to something - // larger so that it prints as an integer rather than a character. For - // simplicity, apply the cast all circumstances. + // The Randen paper suggests preferentially initializing even-numbered + // 128-bit vectors of the randen state (there are 16 such vectors). + // The seed data is merged into the state offset by 128-bits, which + // implies prefering seed bytes [16..31, ..., 208..223]. Since the + // buffer is 32-bit values, we swap the corresponding buffer positions in + // 128-bit chunks. + size_t dst = kBufferSize; + while (dst > 7) { + // leave the odd bucket as-is. + dst -= 4; + size_t src = dst >> 1; + // swap 128-bits into the even bucket + std::swap(buffer[--dst], buffer[--src]); + std::swap(buffer[--dst], buffer[--src]); + std::swap(buffer[--dst], buffer[--src]); + std::swap(buffer[--dst], buffer[--src]); + } + } else { + seq.generate(std::begin(buffer), std::end(buffer)); + } + impl_.Absorb(buffer, state_); + + // Generate will be called when operator() is called + next_ = kStateSizeT; + } + + void discard(uint64_t count) { + uint64_t step = std::min<uint64_t>(kStateSizeT - next_, count); + count -= step; + + constexpr uint64_t kRateT = kStateSizeT - kCapacityT; + while (count > 0) { + next_ = kCapacityT; + impl_.Generate(state_); + step = std::min<uint64_t>(kRateT, count); + count -= step; + } + next_ += step; + } + + bool operator==(const randen_engine& other) const { + return next_ == other.next_ && + std::equal(std::begin(state_), std::end(state_), + std::begin(other.state_)); + } + + bool operator!=(const randen_engine& other) const { + return !(*this == other); + } + + template <class CharT, class Traits> + friend std::basic_ostream<CharT, Traits>& operator<<( + std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) + const randen_engine<T>& engine) { // NOLINT(runtime/references) + using numeric_type = + typename random_internal::stream_format_type<result_type>::type; + auto saver = random_internal::make_ostream_state_saver(os); + for (const auto& elem : engine.state_) { + // In the case that `elem` is `uint8_t`, it must be cast to something + // larger so that it prints as an integer rather than a character. For + // simplicity, apply the cast all circumstances. os << static_cast<numeric_type>(little_endian::FromHost(elem)) << os.fill(); - } - os << engine.next_; - return os; - } - - template <class CharT, class Traits> - friend std::basic_istream<CharT, Traits>& operator>>( - std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) - randen_engine<T>& engine) { // NOLINT(runtime/references) - using numeric_type = - typename random_internal::stream_format_type<result_type>::type; - result_type state[kStateSizeT]; - size_t next; - for (auto& elem : state) { - // It is not possible to read uint8_t from wide streams, so it is - // necessary to read a wider type and then cast it to uint8_t. - numeric_type value; - is >> value; + } + os << engine.next_; + return os; + } + + template <class CharT, class Traits> + friend std::basic_istream<CharT, Traits>& operator>>( + std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) + randen_engine<T>& engine) { // NOLINT(runtime/references) + using numeric_type = + typename random_internal::stream_format_type<result_type>::type; + result_type state[kStateSizeT]; + size_t next; + for (auto& elem : state) { + // It is not possible to read uint8_t from wide streams, so it is + // necessary to read a wider type and then cast it to uint8_t. + numeric_type value; + is >> value; elem = little_endian::ToHost(static_cast<result_type>(value)); - } - is >> next; - if (is.fail()) { - return is; - } - std::memcpy(engine.state_, state, sizeof(engine.state_)); - engine.next_ = next; - return is; - } - - private: - static constexpr size_t kStateSizeT = - Randen::kStateBytes / sizeof(result_type); - static constexpr size_t kCapacityT = - Randen::kCapacityBytes / sizeof(result_type); - - // First kCapacityT are `inner', the others are accessible random bits. - alignas(16) result_type state_[kStateSizeT]; - size_t next_; // index within state_ - Randen impl_; -}; - -} // namespace random_internal + } + is >> next; + if (is.fail()) { + return is; + } + std::memcpy(engine.state_, state, sizeof(engine.state_)); + engine.next_ = next; + return is; + } + + private: + static constexpr size_t kStateSizeT = + Randen::kStateBytes / sizeof(result_type); + static constexpr size_t kCapacityT = + Randen::kCapacityBytes / sizeof(result_type); + + // First kCapacityT are `inner', the others are accessible random bits. + alignas(16) result_type state_[kStateSizeT]; + size_t next_; // index within state_ + Randen impl_; +}; + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_RANDEN_ENGINE_H_ +} // namespace absl + +#endif // ABSL_RANDOM_INTERNAL_RANDEN_ENGINE_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/randen_hwaes.cc b/contrib/restricted/abseil-cpp/absl/random/internal/randen_hwaes.cc index 6758243a27..fee6677cb4 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/randen_hwaes.cc +++ b/contrib/restricted/abseil-cpp/absl/random/internal/randen_hwaes.cc @@ -1,289 +1,289 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// HERMETIC NOTE: The randen_hwaes target must not introduce duplicate -// symbols from arbitrary system and other headers, since it may be built -// with different flags from other targets, using different levels of -// optimization, potentially introducing ODR violations. - -#include "absl/random/internal/randen_hwaes.h" - -#include <cstdint> -#include <cstring> - -#include "absl/base/attributes.h" +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// HERMETIC NOTE: The randen_hwaes target must not introduce duplicate +// symbols from arbitrary system and other headers, since it may be built +// with different flags from other targets, using different levels of +// optimization, potentially introducing ODR violations. + +#include "absl/random/internal/randen_hwaes.h" + +#include <cstdint> +#include <cstring> + +#include "absl/base/attributes.h" #include "absl/numeric/int128.h" -#include "absl/random/internal/platform.h" +#include "absl/random/internal/platform.h" #include "absl/random/internal/randen_traits.h" - -// ABSL_RANDEN_HWAES_IMPL indicates whether this file will contain -// a hardware accelerated implementation of randen, or whether it -// will contain stubs that exit the process. -#if ABSL_HAVE_ACCELERATED_AES + +// ABSL_RANDEN_HWAES_IMPL indicates whether this file will contain +// a hardware accelerated implementation of randen, or whether it +// will contain stubs that exit the process. +#if ABSL_HAVE_ACCELERATED_AES // The following plaforms have implemented RandenHwAes. #if defined(ABSL_ARCH_X86_64) || defined(ABSL_ARCH_X86_32) || \ defined(ABSL_ARCH_PPC) || defined(ABSL_ARCH_ARM) || \ defined(ABSL_ARCH_AARCH64) -#define ABSL_RANDEN_HWAES_IMPL 1 -#endif -#endif - -#if !defined(ABSL_RANDEN_HWAES_IMPL) -// No accelerated implementation is supported. -// The RandenHwAes functions are stubs that print an error and exit. - -#include <cstdio> -#include <cstdlib> - -namespace absl { +#define ABSL_RANDEN_HWAES_IMPL 1 +#endif +#endif + +#if !defined(ABSL_RANDEN_HWAES_IMPL) +// No accelerated implementation is supported. +// The RandenHwAes functions are stubs that print an error and exit. + +#include <cstdio> +#include <cstdlib> + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - -// No accelerated implementation. -bool HasRandenHwAesImplementation() { return false; } - -// NOLINTNEXTLINE -const void* RandenHwAes::GetKeys() { - // Attempted to dispatch to an unsupported dispatch target. - const int d = ABSL_RANDOM_INTERNAL_AES_DISPATCH; - fprintf(stderr, "AES Hardware detection failed (%d).\n", d); - exit(1); - return nullptr; -} - -// NOLINTNEXTLINE -void RandenHwAes::Absorb(const void*, void*) { - // Attempted to dispatch to an unsupported dispatch target. - const int d = ABSL_RANDOM_INTERNAL_AES_DISPATCH; - fprintf(stderr, "AES Hardware detection failed (%d).\n", d); - exit(1); -} - -// NOLINTNEXTLINE -void RandenHwAes::Generate(const void*, void*) { - // Attempted to dispatch to an unsupported dispatch target. - const int d = ABSL_RANDOM_INTERNAL_AES_DISPATCH; - fprintf(stderr, "AES Hardware detection failed (%d).\n", d); - exit(1); -} - -} // namespace random_internal +namespace random_internal { + +// No accelerated implementation. +bool HasRandenHwAesImplementation() { return false; } + +// NOLINTNEXTLINE +const void* RandenHwAes::GetKeys() { + // Attempted to dispatch to an unsupported dispatch target. + const int d = ABSL_RANDOM_INTERNAL_AES_DISPATCH; + fprintf(stderr, "AES Hardware detection failed (%d).\n", d); + exit(1); + return nullptr; +} + +// NOLINTNEXTLINE +void RandenHwAes::Absorb(const void*, void*) { + // Attempted to dispatch to an unsupported dispatch target. + const int d = ABSL_RANDOM_INTERNAL_AES_DISPATCH; + fprintf(stderr, "AES Hardware detection failed (%d).\n", d); + exit(1); +} + +// NOLINTNEXTLINE +void RandenHwAes::Generate(const void*, void*) { + // Attempted to dispatch to an unsupported dispatch target. + const int d = ABSL_RANDOM_INTERNAL_AES_DISPATCH; + fprintf(stderr, "AES Hardware detection failed (%d).\n", d); + exit(1); +} + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#else // defined(ABSL_RANDEN_HWAES_IMPL) -// -// Accelerated implementations are supported. -// We need the per-architecture includes and defines. -// +} // namespace absl + +#else // defined(ABSL_RANDEN_HWAES_IMPL) +// +// Accelerated implementations are supported. +// We need the per-architecture includes and defines. +// namespace { - + using absl::random_internal::RandenTraits; - + } // namespace -// TARGET_CRYPTO defines a crypto attribute for each architecture. -// -// NOTE: Evaluate whether we should eliminate ABSL_TARGET_CRYPTO. -#if (defined(__clang__) || defined(__GNUC__)) -#if defined(ABSL_ARCH_X86_64) || defined(ABSL_ARCH_X86_32) -#define ABSL_TARGET_CRYPTO __attribute__((target("aes"))) -#elif defined(ABSL_ARCH_PPC) -#define ABSL_TARGET_CRYPTO __attribute__((target("crypto"))) -#else -#define ABSL_TARGET_CRYPTO -#endif -#else -#define ABSL_TARGET_CRYPTO -#endif - -#if defined(ABSL_ARCH_PPC) -// NOTE: Keep in mind that PPC can operate in little-endian or big-endian mode, -// however the PPC altivec vector registers (and thus the AES instructions) -// always operate in big-endian mode. - -#include <altivec.h> -// <altivec.h> #defines vector __vector; in C++, this is bad form. -#undef vector +// TARGET_CRYPTO defines a crypto attribute for each architecture. +// +// NOTE: Evaluate whether we should eliminate ABSL_TARGET_CRYPTO. +#if (defined(__clang__) || defined(__GNUC__)) +#if defined(ABSL_ARCH_X86_64) || defined(ABSL_ARCH_X86_32) +#define ABSL_TARGET_CRYPTO __attribute__((target("aes"))) +#elif defined(ABSL_ARCH_PPC) +#define ABSL_TARGET_CRYPTO __attribute__((target("crypto"))) +#else +#define ABSL_TARGET_CRYPTO +#endif +#else +#define ABSL_TARGET_CRYPTO +#endif + +#if defined(ABSL_ARCH_PPC) +// NOTE: Keep in mind that PPC can operate in little-endian or big-endian mode, +// however the PPC altivec vector registers (and thus the AES instructions) +// always operate in big-endian mode. + +#include <altivec.h> +// <altivec.h> #defines vector __vector; in C++, this is bad form. +#undef vector #undef bool - -// Rely on the PowerPC AltiVec vector operations for accelerated AES -// instructions. GCC support of the PPC vector types is described in: -// https://gcc.gnu.org/onlinedocs/gcc-4.9.0/gcc/PowerPC-AltiVec_002fVSX-Built-in-Functions.html -// -// Already provides operator^=. -using Vector128 = __vector unsigned long long; // NOLINT(runtime/int) - -namespace { -inline ABSL_TARGET_CRYPTO Vector128 ReverseBytes(const Vector128& v) { - // Reverses the bytes of the vector. - const __vector unsigned char perm = {15, 14, 13, 12, 11, 10, 9, 8, - 7, 6, 5, 4, 3, 2, 1, 0}; - return vec_perm(v, v, perm); -} - -// WARNING: these load/store in native byte order. It is OK to load and then -// store an unchanged vector, but interpreting the bits as a number or input -// to AES will have undefined results. -inline ABSL_TARGET_CRYPTO Vector128 Vector128Load(const void* from) { - return vec_vsx_ld(0, reinterpret_cast<const Vector128*>(from)); -} - -inline ABSL_TARGET_CRYPTO void Vector128Store(const Vector128& v, void* to) { - vec_vsx_st(v, 0, reinterpret_cast<Vector128*>(to)); -} - -// One round of AES. "round_key" is a public constant for breaking the -// symmetry of AES (ensures previously equal columns differ afterwards). -inline ABSL_TARGET_CRYPTO Vector128 AesRound(const Vector128& state, - const Vector128& round_key) { - return Vector128(__builtin_crypto_vcipher(state, round_key)); -} - -// Enables native loads in the round loop by pre-swapping. + +// Rely on the PowerPC AltiVec vector operations for accelerated AES +// instructions. GCC support of the PPC vector types is described in: +// https://gcc.gnu.org/onlinedocs/gcc-4.9.0/gcc/PowerPC-AltiVec_002fVSX-Built-in-Functions.html +// +// Already provides operator^=. +using Vector128 = __vector unsigned long long; // NOLINT(runtime/int) + +namespace { +inline ABSL_TARGET_CRYPTO Vector128 ReverseBytes(const Vector128& v) { + // Reverses the bytes of the vector. + const __vector unsigned char perm = {15, 14, 13, 12, 11, 10, 9, 8, + 7, 6, 5, 4, 3, 2, 1, 0}; + return vec_perm(v, v, perm); +} + +// WARNING: these load/store in native byte order. It is OK to load and then +// store an unchanged vector, but interpreting the bits as a number or input +// to AES will have undefined results. +inline ABSL_TARGET_CRYPTO Vector128 Vector128Load(const void* from) { + return vec_vsx_ld(0, reinterpret_cast<const Vector128*>(from)); +} + +inline ABSL_TARGET_CRYPTO void Vector128Store(const Vector128& v, void* to) { + vec_vsx_st(v, 0, reinterpret_cast<Vector128*>(to)); +} + +// One round of AES. "round_key" is a public constant for breaking the +// symmetry of AES (ensures previously equal columns differ afterwards). +inline ABSL_TARGET_CRYPTO Vector128 AesRound(const Vector128& state, + const Vector128& round_key) { + return Vector128(__builtin_crypto_vcipher(state, round_key)); +} + +// Enables native loads in the round loop by pre-swapping. inline ABSL_TARGET_CRYPTO void SwapEndian(absl::uint128* state) { for (uint32_t block = 0; block < RandenTraits::kFeistelBlocks; ++block) { Vector128Store(ReverseBytes(Vector128Load(state + block)), state + block); - } -} - -} // namespace - -#elif defined(ABSL_ARCH_ARM) || defined(ABSL_ARCH_AARCH64) - -// Rely on the ARM NEON+Crypto advanced simd types, defined in <arm_neon.h>. -// uint8x16_t is the user alias for underlying __simd128_uint8_t type. -// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0073a/IHI0073A_arm_neon_intrinsics_ref.pdf -// -// <arm_neon> defines the following -// -// typedef __attribute__((neon_vector_type(16))) uint8_t uint8x16_t; -// typedef __attribute__((neon_vector_type(16))) int8_t int8x16_t; -// typedef __attribute__((neon_polyvector_type(16))) int8_t poly8x16_t; -// -// vld1q_v -// vst1q_v -// vaeseq_v -// vaesmcq_v -#include <arm_neon.h> - -// Already provides operator^=. -using Vector128 = uint8x16_t; - -namespace { - -inline ABSL_TARGET_CRYPTO Vector128 Vector128Load(const void* from) { - return vld1q_u8(reinterpret_cast<const uint8_t*>(from)); -} - -inline ABSL_TARGET_CRYPTO void Vector128Store(const Vector128& v, void* to) { - vst1q_u8(reinterpret_cast<uint8_t*>(to), v); -} - -// One round of AES. "round_key" is a public constant for breaking the -// symmetry of AES (ensures previously equal columns differ afterwards). -inline ABSL_TARGET_CRYPTO Vector128 AesRound(const Vector128& state, - const Vector128& round_key) { - // It is important to always use the full round function - omitting the - // final MixColumns reduces security [https://eprint.iacr.org/2010/041.pdf] - // and does not help because we never decrypt. - // - // Note that ARM divides AES instructions differently than x86 / PPC, - // And we need to skip the first AddRoundKey step and add an extra - // AddRoundKey step to the end. Lucky for us this is just XOR. - return vaesmcq_u8(vaeseq_u8(state, uint8x16_t{})) ^ round_key; -} - + } +} + +} // namespace + +#elif defined(ABSL_ARCH_ARM) || defined(ABSL_ARCH_AARCH64) + +// Rely on the ARM NEON+Crypto advanced simd types, defined in <arm_neon.h>. +// uint8x16_t is the user alias for underlying __simd128_uint8_t type. +// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0073a/IHI0073A_arm_neon_intrinsics_ref.pdf +// +// <arm_neon> defines the following +// +// typedef __attribute__((neon_vector_type(16))) uint8_t uint8x16_t; +// typedef __attribute__((neon_vector_type(16))) int8_t int8x16_t; +// typedef __attribute__((neon_polyvector_type(16))) int8_t poly8x16_t; +// +// vld1q_v +// vst1q_v +// vaeseq_v +// vaesmcq_v +#include <arm_neon.h> + +// Already provides operator^=. +using Vector128 = uint8x16_t; + +namespace { + +inline ABSL_TARGET_CRYPTO Vector128 Vector128Load(const void* from) { + return vld1q_u8(reinterpret_cast<const uint8_t*>(from)); +} + +inline ABSL_TARGET_CRYPTO void Vector128Store(const Vector128& v, void* to) { + vst1q_u8(reinterpret_cast<uint8_t*>(to), v); +} + +// One round of AES. "round_key" is a public constant for breaking the +// symmetry of AES (ensures previously equal columns differ afterwards). +inline ABSL_TARGET_CRYPTO Vector128 AesRound(const Vector128& state, + const Vector128& round_key) { + // It is important to always use the full round function - omitting the + // final MixColumns reduces security [https://eprint.iacr.org/2010/041.pdf] + // and does not help because we never decrypt. + // + // Note that ARM divides AES instructions differently than x86 / PPC, + // And we need to skip the first AddRoundKey step and add an extra + // AddRoundKey step to the end. Lucky for us this is just XOR. + return vaesmcq_u8(vaeseq_u8(state, uint8x16_t{})) ^ round_key; +} + inline ABSL_TARGET_CRYPTO void SwapEndian(void*) {} - -} // namespace - -#elif defined(ABSL_ARCH_X86_64) || defined(ABSL_ARCH_X86_32) -// On x86 we rely on the aesni instructions + +} // namespace + +#elif defined(ABSL_ARCH_X86_64) || defined(ABSL_ARCH_X86_32) +// On x86 we rely on the aesni instructions #include <immintrin.h> - -namespace { - -// Vector128 class is only wrapper for __m128i, benchmark indicates that it's -// faster than using __m128i directly. -class Vector128 { - public: - // Convert from/to intrinsics. + +namespace { + +// Vector128 class is only wrapper for __m128i, benchmark indicates that it's +// faster than using __m128i directly. +class Vector128 { + public: + // Convert from/to intrinsics. inline explicit Vector128(const __m128i& v) : data_(v) {} - - inline __m128i data() const { return data_; } - - inline Vector128& operator^=(const Vector128& other) { - data_ = _mm_xor_si128(data_, other.data()); - return *this; - } - - private: - __m128i data_; -}; - -inline ABSL_TARGET_CRYPTO Vector128 Vector128Load(const void* from) { - return Vector128(_mm_load_si128(reinterpret_cast<const __m128i*>(from))); -} - -inline ABSL_TARGET_CRYPTO void Vector128Store(const Vector128& v, void* to) { - _mm_store_si128(reinterpret_cast<__m128i*>(to), v.data()); -} - -// One round of AES. "round_key" is a public constant for breaking the -// symmetry of AES (ensures previously equal columns differ afterwards). -inline ABSL_TARGET_CRYPTO Vector128 AesRound(const Vector128& state, - const Vector128& round_key) { - // It is important to always use the full round function - omitting the - // final MixColumns reduces security [https://eprint.iacr.org/2010/041.pdf] - // and does not help because we never decrypt. - return Vector128(_mm_aesenc_si128(state.data(), round_key.data())); -} - + + inline __m128i data() const { return data_; } + + inline Vector128& operator^=(const Vector128& other) { + data_ = _mm_xor_si128(data_, other.data()); + return *this; + } + + private: + __m128i data_; +}; + +inline ABSL_TARGET_CRYPTO Vector128 Vector128Load(const void* from) { + return Vector128(_mm_load_si128(reinterpret_cast<const __m128i*>(from))); +} + +inline ABSL_TARGET_CRYPTO void Vector128Store(const Vector128& v, void* to) { + _mm_store_si128(reinterpret_cast<__m128i*>(to), v.data()); +} + +// One round of AES. "round_key" is a public constant for breaking the +// symmetry of AES (ensures previously equal columns differ afterwards). +inline ABSL_TARGET_CRYPTO Vector128 AesRound(const Vector128& state, + const Vector128& round_key) { + // It is important to always use the full round function - omitting the + // final MixColumns reduces security [https://eprint.iacr.org/2010/041.pdf] + // and does not help because we never decrypt. + return Vector128(_mm_aesenc_si128(state.data(), round_key.data())); +} + inline ABSL_TARGET_CRYPTO void SwapEndian(void*) {} - -} // namespace - -#endif - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunknown-pragmas" -#endif - -// At this point, all of the platform-specific features have been defined / -// implemented. -// -// REQUIRES: using Vector128 = ... -// REQUIRES: Vector128 Vector128Load(void*) {...} -// REQUIRES: void Vector128Store(Vector128, void*) {...} -// REQUIRES: Vector128 AesRound(Vector128, Vector128) {...} -// REQUIRES: void SwapEndian(uint64_t*) {...} -// -// PROVIDES: absl::random_internal::RandenHwAes::Absorb -// PROVIDES: absl::random_internal::RandenHwAes::Generate + +} // namespace + +#endif + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#endif + +// At this point, all of the platform-specific features have been defined / +// implemented. +// +// REQUIRES: using Vector128 = ... +// REQUIRES: Vector128 Vector128Load(void*) {...} +// REQUIRES: void Vector128Store(Vector128, void*) {...} +// REQUIRES: Vector128 AesRound(Vector128, Vector128) {...} +// REQUIRES: void SwapEndian(uint64_t*) {...} +// +// PROVIDES: absl::random_internal::RandenHwAes::Absorb +// PROVIDES: absl::random_internal::RandenHwAes::Generate namespace { - -// Block shuffles applies a shuffle to the entire state between AES rounds. -// Improved odd-even shuffle from "New criterion for diffusion property". + +// Block shuffles applies a shuffle to the entire state between AES rounds. +// Improved odd-even shuffle from "New criterion for diffusion property". inline ABSL_TARGET_CRYPTO void BlockShuffle(absl::uint128* state) { static_assert(RandenTraits::kFeistelBlocks == 16, "Expecting 16 FeistelBlocks."); - + constexpr size_t shuffle[RandenTraits::kFeistelBlocks] = { 7, 2, 13, 4, 11, 8, 3, 6, 15, 0, 9, 10, 1, 14, 5, 12}; - + const Vector128 v0 = Vector128Load(state + shuffle[0]); const Vector128 v1 = Vector128Load(state + shuffle[1]); const Vector128 v2 = Vector128Load(state + shuffle[2]); @@ -300,7 +300,7 @@ inline ABSL_TARGET_CRYPTO void BlockShuffle(absl::uint128* state) { const Vector128 w5 = Vector128Load(state + shuffle[13]); const Vector128 w6 = Vector128Load(state + shuffle[14]); const Vector128 w7 = Vector128Load(state + shuffle[15]); - + Vector128Store(v0, state + 0); Vector128Store(v1, state + 1); Vector128Store(v2, state + 2); @@ -317,21 +317,21 @@ inline ABSL_TARGET_CRYPTO void BlockShuffle(absl::uint128* state) { Vector128Store(w5, state + 13); Vector128Store(w6, state + 14); Vector128Store(w7, state + 15); -} - -// Feistel round function using two AES subrounds. Very similar to F() -// from Simpira v2, but with independent subround keys. Uses 17 AES rounds -// per 16 bytes (vs. 10 for AES-CTR). Computing eight round functions in -// parallel hides the 7-cycle AESNI latency on HSW. Note that the Feistel -// XORs are 'free' (included in the second AES instruction). +} + +// Feistel round function using two AES subrounds. Very similar to F() +// from Simpira v2, but with independent subround keys. Uses 17 AES rounds +// per 16 bytes (vs. 10 for AES-CTR). Computing eight round functions in +// parallel hides the 7-cycle AESNI latency on HSW. Note that the Feistel +// XORs are 'free' (included in the second AES instruction). inline ABSL_TARGET_CRYPTO const absl::uint128* FeistelRound( absl::uint128* state, const absl::uint128* ABSL_RANDOM_INTERNAL_RESTRICT keys) { static_assert(RandenTraits::kFeistelBlocks == 16, "Expecting 16 FeistelBlocks."); - - // MSVC does a horrible job at unrolling loops. - // So we unroll the loop by hand to improve the performance. + + // MSVC does a horrible job at unrolling loops. + // So we unroll the loop by hand to improve the performance. const Vector128 s0 = Vector128Load(state + 0); const Vector128 s1 = Vector128Load(state + 1); const Vector128 s2 = Vector128Load(state + 2); @@ -348,28 +348,28 @@ inline ABSL_TARGET_CRYPTO const absl::uint128* FeistelRound( const Vector128 s13 = Vector128Load(state + 13); const Vector128 s14 = Vector128Load(state + 14); const Vector128 s15 = Vector128Load(state + 15); - - // Encode even blocks with keys. - const Vector128 e0 = AesRound(s0, Vector128Load(keys + 0)); - const Vector128 e2 = AesRound(s2, Vector128Load(keys + 1)); - const Vector128 e4 = AesRound(s4, Vector128Load(keys + 2)); - const Vector128 e6 = AesRound(s6, Vector128Load(keys + 3)); - const Vector128 e8 = AesRound(s8, Vector128Load(keys + 4)); - const Vector128 e10 = AesRound(s10, Vector128Load(keys + 5)); - const Vector128 e12 = AesRound(s12, Vector128Load(keys + 6)); - const Vector128 e14 = AesRound(s14, Vector128Load(keys + 7)); - - // Encode odd blocks with even output from above. - const Vector128 o1 = AesRound(e0, s1); - const Vector128 o3 = AesRound(e2, s3); - const Vector128 o5 = AesRound(e4, s5); - const Vector128 o7 = AesRound(e6, s7); - const Vector128 o9 = AesRound(e8, s9); - const Vector128 o11 = AesRound(e10, s11); - const Vector128 o13 = AesRound(e12, s13); - const Vector128 o15 = AesRound(e14, s15); - - // Store odd blocks. (These will be shuffled later). + + // Encode even blocks with keys. + const Vector128 e0 = AesRound(s0, Vector128Load(keys + 0)); + const Vector128 e2 = AesRound(s2, Vector128Load(keys + 1)); + const Vector128 e4 = AesRound(s4, Vector128Load(keys + 2)); + const Vector128 e6 = AesRound(s6, Vector128Load(keys + 3)); + const Vector128 e8 = AesRound(s8, Vector128Load(keys + 4)); + const Vector128 e10 = AesRound(s10, Vector128Load(keys + 5)); + const Vector128 e12 = AesRound(s12, Vector128Load(keys + 6)); + const Vector128 e14 = AesRound(s14, Vector128Load(keys + 7)); + + // Encode odd blocks with even output from above. + const Vector128 o1 = AesRound(e0, s1); + const Vector128 o3 = AesRound(e2, s3); + const Vector128 o5 = AesRound(e4, s5); + const Vector128 o7 = AesRound(e6, s7); + const Vector128 o9 = AesRound(e8, s9); + const Vector128 o11 = AesRound(e10, s11); + const Vector128 o13 = AesRound(e12, s13); + const Vector128 o15 = AesRound(e14, s15); + + // Store odd blocks. (These will be shuffled later). Vector128Store(o1, state + 1); Vector128Store(o3, state + 3); Vector128Store(o5, state + 5); @@ -378,149 +378,149 @@ inline ABSL_TARGET_CRYPTO const absl::uint128* FeistelRound( Vector128Store(o11, state + 11); Vector128Store(o13, state + 13); Vector128Store(o15, state + 15); - - return keys + 8; -} - -// Cryptographic permutation based via type-2 Generalized Feistel Network. -// Indistinguishable from ideal by chosen-ciphertext adversaries using less than -// 2^64 queries if the round function is a PRF. This is similar to the b=8 case -// of Simpira v2, but more efficient than its generic construction for b=16. -inline ABSL_TARGET_CRYPTO void Permute( + + return keys + 8; +} + +// Cryptographic permutation based via type-2 Generalized Feistel Network. +// Indistinguishable from ideal by chosen-ciphertext adversaries using less than +// 2^64 queries if the round function is a PRF. This is similar to the b=8 case +// of Simpira v2, but more efficient than its generic construction for b=16. +inline ABSL_TARGET_CRYPTO void Permute( absl::uint128* state, const absl::uint128* ABSL_RANDOM_INTERNAL_RESTRICT keys) { - // (Successfully unrolled; the first iteration jumps into the second half) -#ifdef __clang__ -#pragma clang loop unroll_count(2) -#endif + // (Successfully unrolled; the first iteration jumps into the second half) +#ifdef __clang__ +#pragma clang loop unroll_count(2) +#endif for (size_t round = 0; round < RandenTraits::kFeistelRounds; ++round) { keys = FeistelRound(state, keys); - BlockShuffle(state); - } -} - -} // namespace - -namespace absl { + BlockShuffle(state); + } +} + +} // namespace + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - -bool HasRandenHwAesImplementation() { return true; } - -const void* ABSL_TARGET_CRYPTO RandenHwAes::GetKeys() { - // Round keys for one AES per Feistel round and branch. - // The canonical implementation uses first digits of Pi. +namespace random_internal { + +bool HasRandenHwAesImplementation() { return true; } + +const void* ABSL_TARGET_CRYPTO RandenHwAes::GetKeys() { + // Round keys for one AES per Feistel round and branch. + // The canonical implementation uses first digits of Pi. #if defined(ABSL_ARCH_PPC) return kRandenRoundKeysBE; #else return kRandenRoundKeys; #endif -} - -// NOLINTNEXTLINE -void ABSL_TARGET_CRYPTO RandenHwAes::Absorb(const void* seed_void, - void* state_void) { +} + +// NOLINTNEXTLINE +void ABSL_TARGET_CRYPTO RandenHwAes::Absorb(const void* seed_void, + void* state_void) { static_assert(RandenTraits::kCapacityBytes / sizeof(Vector128) == 1, "Unexpected Randen kCapacityBlocks"); static_assert(RandenTraits::kStateBytes / sizeof(Vector128) == 16, "Unexpected Randen kStateBlocks"); - + auto* state = reinterpret_cast<absl::uint128 * ABSL_RANDOM_INTERNAL_RESTRICT>( state_void); const auto* seed = reinterpret_cast<const absl::uint128 * ABSL_RANDOM_INTERNAL_RESTRICT>( seed_void); - + Vector128 b1 = Vector128Load(state + 1); b1 ^= Vector128Load(seed + 0); Vector128Store(b1, state + 1); - + Vector128 b2 = Vector128Load(state + 2); b2 ^= Vector128Load(seed + 1); Vector128Store(b2, state + 2); - + Vector128 b3 = Vector128Load(state + 3); b3 ^= Vector128Load(seed + 2); Vector128Store(b3, state + 3); - + Vector128 b4 = Vector128Load(state + 4); b4 ^= Vector128Load(seed + 3); Vector128Store(b4, state + 4); - + Vector128 b5 = Vector128Load(state + 5); b5 ^= Vector128Load(seed + 4); Vector128Store(b5, state + 5); - + Vector128 b6 = Vector128Load(state + 6); b6 ^= Vector128Load(seed + 5); Vector128Store(b6, state + 6); - + Vector128 b7 = Vector128Load(state + 7); b7 ^= Vector128Load(seed + 6); Vector128Store(b7, state + 7); - + Vector128 b8 = Vector128Load(state + 8); b8 ^= Vector128Load(seed + 7); Vector128Store(b8, state + 8); - + Vector128 b9 = Vector128Load(state + 9); b9 ^= Vector128Load(seed + 8); Vector128Store(b9, state + 9); - + Vector128 b10 = Vector128Load(state + 10); b10 ^= Vector128Load(seed + 9); Vector128Store(b10, state + 10); - + Vector128 b11 = Vector128Load(state + 11); b11 ^= Vector128Load(seed + 10); Vector128Store(b11, state + 11); - + Vector128 b12 = Vector128Load(state + 12); b12 ^= Vector128Load(seed + 11); Vector128Store(b12, state + 12); - + Vector128 b13 = Vector128Load(state + 13); b13 ^= Vector128Load(seed + 12); Vector128Store(b13, state + 13); - + Vector128 b14 = Vector128Load(state + 14); b14 ^= Vector128Load(seed + 13); Vector128Store(b14, state + 14); - + Vector128 b15 = Vector128Load(state + 15); b15 ^= Vector128Load(seed + 14); Vector128Store(b15, state + 15); -} - -// NOLINTNEXTLINE +} + +// NOLINTNEXTLINE void ABSL_TARGET_CRYPTO RandenHwAes::Generate(const void* keys_void, - void* state_void) { + void* state_void) { static_assert(RandenTraits::kCapacityBytes == sizeof(Vector128), "Capacity mismatch"); - + auto* state = reinterpret_cast<absl::uint128*>(state_void); const auto* keys = reinterpret_cast<const absl::uint128*>(keys_void); - - const Vector128 prev_inner = Vector128Load(state); - - SwapEndian(state); - + + const Vector128 prev_inner = Vector128Load(state); + + SwapEndian(state); + Permute(state, keys); - - SwapEndian(state); - - // Ensure backtracking resistance. - Vector128 inner = Vector128Load(state); - inner ^= prev_inner; - Vector128Store(inner, state); -} - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -} // namespace random_internal + + SwapEndian(state); + + // Ensure backtracking resistance. + Vector128 inner = Vector128Load(state); + inner ^= prev_inner; + Vector128Store(inner, state); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // (ABSL_RANDEN_HWAES_IMPL) +} // namespace absl + +#endif // (ABSL_RANDEN_HWAES_IMPL) diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/randen_hwaes.h b/contrib/restricted/abseil-cpp/absl/random/internal/randen_hwaes.h index c56f8cad5e..71a7f69f25 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/randen_hwaes.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/randen_hwaes.h @@ -1,50 +1,50 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_INTERNAL_RANDEN_HWAES_H_ -#define ABSL_RANDOM_INTERNAL_RANDEN_HWAES_H_ - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_INTERNAL_RANDEN_HWAES_H_ +#define ABSL_RANDOM_INTERNAL_RANDEN_HWAES_H_ + #include "absl/base/config.h" -// HERMETIC NOTE: The randen_hwaes target must not introduce duplicate -// symbols from arbitrary system and other headers, since it may be built -// with different flags from other targets, using different levels of -// optimization, potentially introducing ODR violations. - -namespace absl { +// HERMETIC NOTE: The randen_hwaes target must not introduce duplicate +// symbols from arbitrary system and other headers, since it may be built +// with different flags from other targets, using different levels of +// optimization, potentially introducing ODR violations. + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - +namespace random_internal { + // RANDen = RANDom generator or beetroots in Swiss High German. -// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random -// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32. -// -// RandenHwAes implements the basic state manipulation methods. -class RandenHwAes { - public: - static void Generate(const void* keys, void* state_void); - static void Absorb(const void* seed_void, void* state_void); - static const void* GetKeys(); -}; - -// HasRandenHwAesImplementation returns true when there is an accelerated -// implementation, and false otherwise. If there is no implementation, -// then attempting to use it will abort the program. -bool HasRandenHwAesImplementation(); - -} // namespace random_internal +// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random +// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32. +// +// RandenHwAes implements the basic state manipulation methods. +class RandenHwAes { + public: + static void Generate(const void* keys, void* state_void); + static void Absorb(const void* seed_void, void* state_void); + static const void* GetKeys(); +}; + +// HasRandenHwAesImplementation returns true when there is an accelerated +// implementation, and false otherwise. If there is no implementation, +// then attempting to use it will abort the program. +bool HasRandenHwAesImplementation(); + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_RANDEN_HWAES_H_ +} // namespace absl + +#endif // ABSL_RANDOM_INTERNAL_RANDEN_HWAES_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/randen_hwaes/ya.make b/contrib/restricted/abseil-cpp/absl/random/internal/randen_hwaes/ya.make index 14ef865fd2..267ce26c5f 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/randen_hwaes/ya.make +++ b/contrib/restricted/abseil-cpp/absl/random/internal/randen_hwaes/ya.make @@ -1,33 +1,33 @@ -# Generated by devtools/yamaker. - -LIBRARY() - +# Generated by devtools/yamaker. + +LIBRARY() + WITHOUT_LICENSE_TEXTS() -OWNER(g:cpp-contrib) - -LICENSE(Apache-2.0) - +OWNER(g:cpp-contrib) + +LICENSE(Apache-2.0) + PEERDIR( contrib/restricted/abseil-cpp/absl/random/internal/randen_round_keys ) -ADDINCL( - GLOBAL contrib/restricted/abseil-cpp -) - -NO_COMPILER_WARNINGS() - -NO_UTIL() - +ADDINCL( + GLOBAL contrib/restricted/abseil-cpp +) + +NO_COMPILER_WARNINGS() + +NO_UTIL() + CFLAGS( -DNOMINMAX ) -SRCDIR(contrib/restricted/abseil-cpp/absl/random/internal) - -SRCS( - randen_hwaes.cc -) - -END() +SRCDIR(contrib/restricted/abseil-cpp/absl/random/internal) + +SRCS( + randen_hwaes.cc +) + +END() diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/randen_slow.cc b/contrib/restricted/abseil-cpp/absl/random/internal/randen_slow.cc index 35446ef214..9bfd2a4092 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/randen_slow.cc +++ b/contrib/restricted/abseil-cpp/absl/random/internal/randen_slow.cc @@ -1,51 +1,51 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "absl/random/internal/randen_slow.h" - -#include <cstddef> -#include <cstdint> -#include <cstring> - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/random/internal/randen_slow.h" + +#include <cstddef> +#include <cstdint> +#include <cstring> + #include "absl/base/attributes.h" #include "absl/base/internal/endian.h" #include "absl/numeric/int128.h" -#include "absl/random/internal/platform.h" +#include "absl/random/internal/platform.h" #include "absl/random/internal/randen_traits.h" - -#if ABSL_HAVE_ATTRIBUTE(always_inline) || \ - (defined(__GNUC__) && !defined(__clang__)) -#define ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE \ - __attribute__((always_inline)) -#elif defined(_MSC_VER) -// We can achieve something similar to attribute((always_inline)) with MSVC by -// using the __forceinline keyword, however this is not perfect. MSVC is -// much less aggressive about inlining, and even with the __forceinline keyword. -#define ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE __forceinline -#else -#define ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE -#endif - -namespace { - -// AES portions based on rijndael-alg-fst.c, + +#if ABSL_HAVE_ATTRIBUTE(always_inline) || \ + (defined(__GNUC__) && !defined(__clang__)) +#define ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE \ + __attribute__((always_inline)) +#elif defined(_MSC_VER) +// We can achieve something similar to attribute((always_inline)) with MSVC by +// using the __forceinline keyword, however this is not perfect. MSVC is +// much less aggressive about inlining, and even with the __forceinline keyword. +#define ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE __forceinline +#else +#define ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE +#endif + +namespace { + +// AES portions based on rijndael-alg-fst.c, // https://fastcrypto.org/front/misc/rijndael-alg-fst.c, and modified for // platform-endianness. -// -// Implementation of -// http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf -constexpr uint32_t te0[256] = { +// +// Implementation of +// http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf +constexpr uint32_t te0[256] = { 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec, 0x45caca8f, 0x9d82821f, @@ -89,9 +89,9 @@ constexpr uint32_t te0[256] = { 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c, -}; - -constexpr uint32_t te1[256] = { +}; + +constexpr uint32_t te1[256] = { 0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, 0x30306050, 0x01010203, 0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a, 0xcaca8f45, 0x82821f9d, @@ -135,9 +135,9 @@ constexpr uint32_t te1[256] = { 0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, 0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8, 0x414182c3, 0x999929b0, 0x2d2d5a77, 0x0f0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a, -}; - -constexpr uint32_t te2[256] = { +}; + +constexpr uint32_t te2[256] = { 0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, 0x30605030, 0x01020301, 0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76, 0xca8f45ca, 0x821f9d82, @@ -181,9 +181,9 @@ constexpr uint32_t te2[256] = { 0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, 0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868, 0x4182c341, 0x9929b099, 0x2d5a772d, 0x0f1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16, -}; - -constexpr uint32_t te3[256] = { +}; + +constexpr uint32_t te3[256] = { 0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, 0x60503030, 0x02030101, 0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676, 0x8f45caca, 0x1f9d8282, @@ -227,31 +227,31 @@ constexpr uint32_t te3[256] = { 0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, 0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868, 0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616, -}; - -// Software implementation of the Vector128 class, using uint32_t -// as an underlying vector register. +}; + +// Software implementation of the Vector128 class, using uint32_t +// as an underlying vector register. struct alignas(16) Vector128 { - uint32_t s[4]; -}; - -inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128 + uint32_t s[4]; +}; + +inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128 Vector128Load(const void* from) { - Vector128 result; + Vector128 result; std::memcpy(result.s, from, sizeof(Vector128)); - return result; -} - -inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void Vector128Store( + return result; +} + +inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void Vector128Store( const Vector128& v, void* to) { std::memcpy(to, v.s, sizeof(Vector128)); -} - -// One round of AES. "round_key" is a public constant for breaking the -// symmetry of AES (ensures previously equal columns differ afterwards). -inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128 -AesRound(const Vector128& state, const Vector128& round_key) { - Vector128 result; +} + +// One round of AES. "round_key" is a public constant for breaking the +// symmetry of AES (ensures previously equal columns differ afterwards). +inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128 +AesRound(const Vector128& state, const Vector128& round_key) { + Vector128 result; #ifdef ABSL_IS_LITTLE_ENDIAN result.s[0] = round_key.s[0] ^ // te0[uint8_t(state.s[0])] ^ // @@ -295,21 +295,21 @@ AesRound(const Vector128& state, const Vector128& round_key) { te2[uint8_t(state.s[1] >> 16)] ^ // te3[uint8_t(state.s[0] >> 24)]; #endif - return result; -} - + return result; +} + using ::absl::random_internal::RandenTraits; - -// The improved Feistel block shuffle function for 16 blocks. -inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void BlockShuffle( + +// The improved Feistel block shuffle function for 16 blocks. +inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void BlockShuffle( absl::uint128* state) { static_assert(RandenTraits::kFeistelBlocks == 16, - "Feistel block shuffle only works for 16 blocks."); - + "Feistel block shuffle only works for 16 blocks."); + constexpr size_t shuffle[RandenTraits::kFeistelBlocks] = { 7, 2, 13, 4, 11, 8, 3, 6, 15, 0, 9, 10, 1, 14, 5, 12}; - - // The fully unrolled loop without the memcpy improves the speed by about + + // The fully unrolled loop without the memcpy improves the speed by about // 30% over the equivalent: #if 0 absl::uint128 source[RandenTraits::kFeistelBlocks]; @@ -317,10 +317,10 @@ inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void BlockShuffle( for (size_t i = 0; i < RandenTraits::kFeistelBlocks; i++) { const absl::uint128 v0 = source[shuffle[i]]; state[i] = v0; - } + } return; #endif - + const absl::uint128 v0 = state[shuffle[0]]; const absl::uint128 v1 = state[shuffle[1]]; const absl::uint128 v2 = state[shuffle[2]]; @@ -337,64 +337,64 @@ inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void BlockShuffle( const absl::uint128 w5 = state[shuffle[13]]; const absl::uint128 w6 = state[shuffle[14]]; const absl::uint128 w7 = state[shuffle[15]]; - state[0] = v0; - state[1] = v1; - state[2] = v2; - state[3] = v3; - state[4] = v4; - state[5] = v5; - state[6] = v6; - state[7] = v7; - state[8] = w0; - state[9] = w1; - state[10] = w2; - state[11] = w3; - state[12] = w4; - state[13] = w5; - state[14] = w6; - state[15] = w7; -} - -// Feistel round function using two AES subrounds. Very similar to F() -// from Simpira v2, but with independent subround keys. Uses 17 AES rounds -// per 16 bytes (vs. 10 for AES-CTR). Computing eight round functions in -// parallel hides the 7-cycle AESNI latency on HSW. Note that the Feistel -// XORs are 'free' (included in the second AES instruction). + state[0] = v0; + state[1] = v1; + state[2] = v2; + state[3] = v3; + state[4] = v4; + state[5] = v5; + state[6] = v6; + state[7] = v7; + state[8] = w0; + state[9] = w1; + state[10] = w2; + state[11] = w3; + state[12] = w4; + state[13] = w5; + state[14] = w6; + state[15] = w7; +} + +// Feistel round function using two AES subrounds. Very similar to F() +// from Simpira v2, but with independent subround keys. Uses 17 AES rounds +// per 16 bytes (vs. 10 for AES-CTR). Computing eight round functions in +// parallel hides the 7-cycle AESNI latency on HSW. Note that the Feistel +// XORs are 'free' (included in the second AES instruction). inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE const absl::uint128* FeistelRound(absl::uint128* ABSL_RANDOM_INTERNAL_RESTRICT state, const absl::uint128* ABSL_RANDOM_INTERNAL_RESTRICT keys) { for (size_t branch = 0; branch < RandenTraits::kFeistelBlocks; branch += 4) { const Vector128 s0 = Vector128Load(state + branch); const Vector128 s1 = Vector128Load(state + branch + 1); - const Vector128 f0 = AesRound(s0, Vector128Load(keys)); - keys++; - const Vector128 o1 = AesRound(f0, s1); + const Vector128 f0 = AesRound(s0, Vector128Load(keys)); + keys++; + const Vector128 o1 = AesRound(f0, s1); Vector128Store(o1, state + branch + 1); - - // Manually unroll this loop once. about 10% better than not unrolled. + + // Manually unroll this loop once. about 10% better than not unrolled. const Vector128 s2 = Vector128Load(state + branch + 2); const Vector128 s3 = Vector128Load(state + branch + 3); - const Vector128 f2 = AesRound(s2, Vector128Load(keys)); - keys++; - const Vector128 o3 = AesRound(f2, s3); + const Vector128 f2 = AesRound(s2, Vector128Load(keys)); + keys++; + const Vector128 o3 = AesRound(f2, s3); Vector128Store(o3, state + branch + 3); - } - return keys; -} - -// Cryptographic permutation based via type-2 Generalized Feistel Network. -// Indistinguishable from ideal by chosen-ciphertext adversaries using less than -// 2^64 queries if the round function is a PRF. This is similar to the b=8 case -// of Simpira v2, but more efficient than its generic construction for b=16. -inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void Permute( + } + return keys; +} + +// Cryptographic permutation based via type-2 Generalized Feistel Network. +// Indistinguishable from ideal by chosen-ciphertext adversaries using less than +// 2^64 queries if the round function is a PRF. This is similar to the b=8 case +// of Simpira v2, but more efficient than its generic construction for b=16. +inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void Permute( absl::uint128* state, const absl::uint128* ABSL_RANDOM_INTERNAL_RESTRICT keys) { for (size_t round = 0; round < RandenTraits::kFeistelRounds; ++round) { keys = FeistelRound(state, keys); - BlockShuffle(state); - } -} - + BlockShuffle(state); + } +} + // Enables native loads in the round loop by pre-swapping. inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void SwapEndian( absl::uint128* state) { @@ -412,29 +412,29 @@ inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void SwapEndian( #endif } -} // namespace - -namespace absl { +} // namespace + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - -const void* RandenSlow::GetKeys() { - // Round keys for one AES per Feistel round and branch. - // The canonical implementation uses first digits of Pi. +namespace random_internal { + +const void* RandenSlow::GetKeys() { + // Round keys for one AES per Feistel round and branch. + // The canonical implementation uses first digits of Pi. #ifdef ABSL_IS_LITTLE_ENDIAN return kRandenRoundKeys; #else return kRandenRoundKeysBE; #endif -} - -void RandenSlow::Absorb(const void* seed_void, void* state_void) { +} + +void RandenSlow::Absorb(const void* seed_void, void* state_void) { auto* state = reinterpret_cast<uint64_t * ABSL_RANDOM_INTERNAL_RESTRICT>(state_void); const auto* seed = reinterpret_cast<const uint64_t * ABSL_RANDOM_INTERNAL_RESTRICT>( seed_void); - + constexpr size_t kCapacityBlocks = RandenTraits::kCapacityBytes / sizeof(uint64_t); static_assert( @@ -443,29 +443,29 @@ void RandenSlow::Absorb(const void* seed_void, void* state_void) { for (size_t i = kCapacityBlocks; i < RandenTraits::kStateBytes / sizeof(uint64_t); ++i) { - state[i] ^= seed[i - kCapacityBlocks]; - } -} - + state[i] ^= seed[i - kCapacityBlocks]; + } +} + void RandenSlow::Generate(const void* keys_void, void* state_void) { static_assert(RandenTraits::kCapacityBytes == sizeof(absl::uint128), "Capacity mismatch"); - + auto* state = reinterpret_cast<absl::uint128*>(state_void); const auto* keys = reinterpret_cast<const absl::uint128*>(keys_void); - + const absl::uint128 prev_inner = state[0]; - + SwapEndian(state); Permute(state, keys); - + SwapEndian(state); - // Ensure backtracking resistance. + // Ensure backtracking resistance. *state ^= prev_inner; -} - -} // namespace random_internal +} + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl +} // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/randen_slow.h b/contrib/restricted/abseil-cpp/absl/random/internal/randen_slow.h index efa9c4c144..532c3a8991 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/randen_slow.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/randen_slow.h @@ -1,40 +1,40 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_INTERNAL_RANDEN_SLOW_H_ -#define ABSL_RANDOM_INTERNAL_RANDEN_SLOW_H_ - -#include <cstddef> - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_INTERNAL_RANDEN_SLOW_H_ +#define ABSL_RANDOM_INTERNAL_RANDEN_SLOW_H_ + +#include <cstddef> + #include "absl/base/config.h" -namespace absl { +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - +namespace random_internal { + // RANDen = RANDom generator or beetroots in Swiss High German. -// RandenSlow implements the basic state manipulation methods for -// architectures lacking AES hardware acceleration intrinsics. -class RandenSlow { - public: - static void Generate(const void* keys, void* state_void); - static void Absorb(const void* seed_void, void* state_void); - static const void* GetKeys(); -}; - -} // namespace random_internal +// RandenSlow implements the basic state manipulation methods for +// architectures lacking AES hardware acceleration intrinsics. +class RandenSlow { + public: + static void Generate(const void* keys, void* state_void); + static void Absorb(const void* seed_void, void* state_void); + static const void* GetKeys(); +}; + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_RANDEN_SLOW_H_ +} // namespace absl + +#endif // ABSL_RANDOM_INTERNAL_RANDEN_SLOW_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/randen_slow/ya.make b/contrib/restricted/abseil-cpp/absl/random/internal/randen_slow/ya.make index a0cfde87e4..af124ae798 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/randen_slow/ya.make +++ b/contrib/restricted/abseil-cpp/absl/random/internal/randen_slow/ya.make @@ -1,33 +1,33 @@ -# Generated by devtools/yamaker. - -LIBRARY() - +# Generated by devtools/yamaker. + +LIBRARY() + WITHOUT_LICENSE_TEXTS() -OWNER(g:cpp-contrib) - -LICENSE(Apache-2.0) - +OWNER(g:cpp-contrib) + +LICENSE(Apache-2.0) + PEERDIR( contrib/restricted/abseil-cpp/absl/random/internal/randen_round_keys ) -ADDINCL( - GLOBAL contrib/restricted/abseil-cpp -) - -NO_COMPILER_WARNINGS() - -NO_UTIL() - +ADDINCL( + GLOBAL contrib/restricted/abseil-cpp +) + +NO_COMPILER_WARNINGS() + +NO_UTIL() + CFLAGS( -DNOMINMAX ) -SRCDIR(contrib/restricted/abseil-cpp/absl/random/internal) - -SRCS( - randen_slow.cc -) - -END() +SRCDIR(contrib/restricted/abseil-cpp/absl/random/internal) + +SRCS( + randen_slow.cc +) + +END() diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/randen_traits.h b/contrib/restricted/abseil-cpp/absl/random/internal/randen_traits.h index 92b1937b3e..120022c9fb 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/randen_traits.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/randen_traits.h @@ -1,37 +1,37 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_INTERNAL_RANDEN_TRAITS_H_ -#define ABSL_RANDOM_INTERNAL_RANDEN_TRAITS_H_ - -// HERMETIC NOTE: The randen_hwaes target must not introduce duplicate -// symbols from arbitrary system and other headers, since it may be built -// with different flags from other targets, using different levels of -// optimization, potentially introducing ODR violations. - -#include <cstddef> - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_INTERNAL_RANDEN_TRAITS_H_ +#define ABSL_RANDOM_INTERNAL_RANDEN_TRAITS_H_ + +// HERMETIC NOTE: The randen_hwaes target must not introduce duplicate +// symbols from arbitrary system and other headers, since it may be built +// with different flags from other targets, using different levels of +// optimization, potentially introducing ODR violations. + +#include <cstddef> + #include "absl/base/config.h" -namespace absl { +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - +namespace random_internal { + // RANDen = RANDom generator or beetroots in Swiss High German. -// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random -// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32. -// +// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random +// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32. +// // High-level summary: // 1) Reverie (see "A Robust and Sponge-Like PRNG with Improved Efficiency") is // a sponge-like random generator that requires a cryptographic permutation. @@ -51,38 +51,38 @@ namespace random_internal { // Combine these three ideas and also change Simpira's subround keys from // structured/low-entropy counters to digits of Pi (or other random source). -// RandenTraits contains the basic algorithm traits, such as the size of the -// state, seed, sponge, etc. -struct RandenTraits { - // Size of the entire sponge / state for the randen PRNG. - static constexpr size_t kStateBytes = 256; // 2048-bit - - // Size of the 'inner' (inaccessible) part of the sponge. Larger values would - // require more frequent calls to RandenGenerate. - static constexpr size_t kCapacityBytes = 16; // 128-bit - - // Size of the default seed consumed by the sponge. - static constexpr size_t kSeedBytes = kStateBytes - kCapacityBytes; - +// RandenTraits contains the basic algorithm traits, such as the size of the +// state, seed, sponge, etc. +struct RandenTraits { + // Size of the entire sponge / state for the randen PRNG. + static constexpr size_t kStateBytes = 256; // 2048-bit + + // Size of the 'inner' (inaccessible) part of the sponge. Larger values would + // require more frequent calls to RandenGenerate. + static constexpr size_t kCapacityBytes = 16; // 128-bit + + // Size of the default seed consumed by the sponge. + static constexpr size_t kSeedBytes = kStateBytes - kCapacityBytes; + // Assuming 128-bit blocks, the number of blocks in the state. - // Largest size for which security proofs are known. - static constexpr size_t kFeistelBlocks = 16; - - // Ensures SPRP security and two full subblock diffusions. - // Must be > 4 * log2(kFeistelBlocks). - static constexpr size_t kFeistelRounds = 16 + 1; + // Largest size for which security proofs are known. + static constexpr size_t kFeistelBlocks = 16; + + // Ensures SPRP security and two full subblock diffusions. + // Must be > 4 * log2(kFeistelBlocks). + static constexpr size_t kFeistelRounds = 16 + 1; // Size of the key. A 128-bit key block is used for every-other // feistel block (Type-2 generalized Feistel network) in each round. static constexpr size_t kKeyBytes = 16 * kFeistelRounds * kFeistelBlocks / 2; -}; - +}; + // Randen key arrays. In randen_round_keys.cc extern const unsigned char kRandenRoundKeys[RandenTraits::kKeyBytes]; extern const unsigned char kRandenRoundKeysBE[RandenTraits::kKeyBytes]; -} // namespace random_internal +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_RANDEN_TRAITS_H_ +} // namespace absl + +#endif // ABSL_RANDOM_INTERNAL_RANDEN_TRAITS_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/salted_seed_seq.h b/contrib/restricted/abseil-cpp/absl/random/internal/salted_seed_seq.h index 67ead19418..5953a090f8 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/salted_seed_seq.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/salted_seed_seq.h @@ -1,167 +1,167 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_INTERNAL_SALTED_SEED_SEQ_H_ -#define ABSL_RANDOM_INTERNAL_SALTED_SEED_SEQ_H_ - -#include <cstdint> -#include <cstdlib> -#include <initializer_list> -#include <iterator> -#include <memory> -#include <type_traits> -#include <utility> - -#include "absl/container/inlined_vector.h" -#include "absl/meta/type_traits.h" -#include "absl/random/internal/seed_material.h" -#include "absl/types/optional.h" -#include "absl/types/span.h" - -namespace absl { +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_INTERNAL_SALTED_SEED_SEQ_H_ +#define ABSL_RANDOM_INTERNAL_SALTED_SEED_SEQ_H_ + +#include <cstdint> +#include <cstdlib> +#include <initializer_list> +#include <iterator> +#include <memory> +#include <type_traits> +#include <utility> + +#include "absl/container/inlined_vector.h" +#include "absl/meta/type_traits.h" +#include "absl/random/internal/seed_material.h" +#include "absl/types/optional.h" +#include "absl/types/span.h" + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - -// This class conforms to the C++ Standard "Seed Sequence" concept -// [rand.req.seedseq]. -// -// A `SaltedSeedSeq` is meant to wrap an existing seed sequence and modify -// generated sequence by mixing with extra entropy. This entropy may be -// build-dependent or process-dependent. The implementation may change to be -// have either or both kinds of entropy. If salt is not available sequence is -// not modified. -template <typename SSeq> -class SaltedSeedSeq { - public: - using inner_sequence_type = SSeq; - using result_type = typename SSeq::result_type; - - SaltedSeedSeq() : seq_(absl::make_unique<SSeq>()) {} - - template <typename Iterator> - SaltedSeedSeq(Iterator begin, Iterator end) - : seq_(absl::make_unique<SSeq>(begin, end)) {} - - template <typename T> - SaltedSeedSeq(std::initializer_list<T> il) - : SaltedSeedSeq(il.begin(), il.end()) {} - - SaltedSeedSeq(const SaltedSeedSeq&) = delete; - SaltedSeedSeq& operator=(const SaltedSeedSeq&) = delete; - - SaltedSeedSeq(SaltedSeedSeq&&) = default; - SaltedSeedSeq& operator=(SaltedSeedSeq&&) = default; - - template <typename RandomAccessIterator> - void generate(RandomAccessIterator begin, RandomAccessIterator end) { - // The common case is that generate is called with ContiguousIterators - // to uint arrays. Such contiguous memory regions may be optimized, - // which we detect here. - using tag = absl::conditional_t< - (std::is_pointer<RandomAccessIterator>::value && - std::is_same<absl::decay_t<decltype(*begin)>, uint32_t>::value), - ContiguousAndUint32Tag, DefaultTag>; - if (begin != end) { - generate_impl(begin, end, tag{}); - } - } - - template <typename OutIterator> - void param(OutIterator out) const { - seq_->param(out); - } - - size_t size() const { return seq_->size(); } - - private: - struct ContiguousAndUint32Tag {}; - struct DefaultTag {}; - - // Generate which requires the iterators are contiguous pointers to uint32_t. - void generate_impl(uint32_t* begin, uint32_t* end, ContiguousAndUint32Tag) { - generate_contiguous(absl::MakeSpan(begin, end)); - } - - // The uncommon case for generate is that it is called with iterators over - // some other buffer type which is assignable from a 32-bit value. In this - // case we allocate a temporary 32-bit buffer and then copy-assign back - // to the initial inputs. - template <typename RandomAccessIterator> - void generate_impl(RandomAccessIterator begin, RandomAccessIterator end, - DefaultTag) { - return generate_and_copy(std::distance(begin, end), begin); - } - - // Fills the initial seed buffer the underlying SSeq::generate() call, - // mixing in the salt material. - void generate_contiguous(absl::Span<uint32_t> buffer) { - seq_->generate(buffer.begin(), buffer.end()); - const uint32_t salt = absl::random_internal::GetSaltMaterial().value_or(0); - MixIntoSeedMaterial(absl::MakeConstSpan(&salt, 1), buffer); - } - - // Allocates a seed buffer of `n` elements, generates the seed, then - // copies the result into the `out` iterator. - template <typename Iterator> - void generate_and_copy(size_t n, Iterator out) { - // Allocate a temporary buffer, generate, and then copy. - absl::InlinedVector<uint32_t, 8> data(n, 0); - generate_contiguous(absl::MakeSpan(data.data(), data.size())); - std::copy(data.begin(), data.end(), out); - } - - // Because [rand.req.seedseq] is not required to be copy-constructible, - // copy-assignable nor movable, we wrap it with unique pointer to be able - // to move SaltedSeedSeq. - std::unique_ptr<SSeq> seq_; -}; - -// is_salted_seed_seq indicates whether the type is a SaltedSeedSeq. -template <typename T, typename = void> -struct is_salted_seed_seq : public std::false_type {}; - -template <typename T> -struct is_salted_seed_seq< - T, typename std::enable_if<std::is_same< - T, SaltedSeedSeq<typename T::inner_sequence_type>>::value>::type> - : public std::true_type {}; - -// MakeSaltedSeedSeq returns a salted variant of the seed sequence. -// When provided with an existing SaltedSeedSeq, returns the input parameter, -// otherwise constructs a new SaltedSeedSeq which embodies the original -// non-salted seed parameters. -template < - typename SSeq, // - typename EnableIf = absl::enable_if_t<is_salted_seed_seq<SSeq>::value>> -SSeq MakeSaltedSeedSeq(SSeq&& seq) { - return SSeq(std::forward<SSeq>(seq)); -} - -template < - typename SSeq, // - typename EnableIf = absl::enable_if_t<!is_salted_seed_seq<SSeq>::value>> -SaltedSeedSeq<typename std::decay<SSeq>::type> MakeSaltedSeedSeq(SSeq&& seq) { - using sseq_type = typename std::decay<SSeq>::type; - using result_type = typename sseq_type::result_type; - - absl::InlinedVector<result_type, 8> data; - seq.param(std::back_inserter(data)); - return SaltedSeedSeq<sseq_type>(data.begin(), data.end()); -} - -} // namespace random_internal +namespace random_internal { + +// This class conforms to the C++ Standard "Seed Sequence" concept +// [rand.req.seedseq]. +// +// A `SaltedSeedSeq` is meant to wrap an existing seed sequence and modify +// generated sequence by mixing with extra entropy. This entropy may be +// build-dependent or process-dependent. The implementation may change to be +// have either or both kinds of entropy. If salt is not available sequence is +// not modified. +template <typename SSeq> +class SaltedSeedSeq { + public: + using inner_sequence_type = SSeq; + using result_type = typename SSeq::result_type; + + SaltedSeedSeq() : seq_(absl::make_unique<SSeq>()) {} + + template <typename Iterator> + SaltedSeedSeq(Iterator begin, Iterator end) + : seq_(absl::make_unique<SSeq>(begin, end)) {} + + template <typename T> + SaltedSeedSeq(std::initializer_list<T> il) + : SaltedSeedSeq(il.begin(), il.end()) {} + + SaltedSeedSeq(const SaltedSeedSeq&) = delete; + SaltedSeedSeq& operator=(const SaltedSeedSeq&) = delete; + + SaltedSeedSeq(SaltedSeedSeq&&) = default; + SaltedSeedSeq& operator=(SaltedSeedSeq&&) = default; + + template <typename RandomAccessIterator> + void generate(RandomAccessIterator begin, RandomAccessIterator end) { + // The common case is that generate is called with ContiguousIterators + // to uint arrays. Such contiguous memory regions may be optimized, + // which we detect here. + using tag = absl::conditional_t< + (std::is_pointer<RandomAccessIterator>::value && + std::is_same<absl::decay_t<decltype(*begin)>, uint32_t>::value), + ContiguousAndUint32Tag, DefaultTag>; + if (begin != end) { + generate_impl(begin, end, tag{}); + } + } + + template <typename OutIterator> + void param(OutIterator out) const { + seq_->param(out); + } + + size_t size() const { return seq_->size(); } + + private: + struct ContiguousAndUint32Tag {}; + struct DefaultTag {}; + + // Generate which requires the iterators are contiguous pointers to uint32_t. + void generate_impl(uint32_t* begin, uint32_t* end, ContiguousAndUint32Tag) { + generate_contiguous(absl::MakeSpan(begin, end)); + } + + // The uncommon case for generate is that it is called with iterators over + // some other buffer type which is assignable from a 32-bit value. In this + // case we allocate a temporary 32-bit buffer and then copy-assign back + // to the initial inputs. + template <typename RandomAccessIterator> + void generate_impl(RandomAccessIterator begin, RandomAccessIterator end, + DefaultTag) { + return generate_and_copy(std::distance(begin, end), begin); + } + + // Fills the initial seed buffer the underlying SSeq::generate() call, + // mixing in the salt material. + void generate_contiguous(absl::Span<uint32_t> buffer) { + seq_->generate(buffer.begin(), buffer.end()); + const uint32_t salt = absl::random_internal::GetSaltMaterial().value_or(0); + MixIntoSeedMaterial(absl::MakeConstSpan(&salt, 1), buffer); + } + + // Allocates a seed buffer of `n` elements, generates the seed, then + // copies the result into the `out` iterator. + template <typename Iterator> + void generate_and_copy(size_t n, Iterator out) { + // Allocate a temporary buffer, generate, and then copy. + absl::InlinedVector<uint32_t, 8> data(n, 0); + generate_contiguous(absl::MakeSpan(data.data(), data.size())); + std::copy(data.begin(), data.end(), out); + } + + // Because [rand.req.seedseq] is not required to be copy-constructible, + // copy-assignable nor movable, we wrap it with unique pointer to be able + // to move SaltedSeedSeq. + std::unique_ptr<SSeq> seq_; +}; + +// is_salted_seed_seq indicates whether the type is a SaltedSeedSeq. +template <typename T, typename = void> +struct is_salted_seed_seq : public std::false_type {}; + +template <typename T> +struct is_salted_seed_seq< + T, typename std::enable_if<std::is_same< + T, SaltedSeedSeq<typename T::inner_sequence_type>>::value>::type> + : public std::true_type {}; + +// MakeSaltedSeedSeq returns a salted variant of the seed sequence. +// When provided with an existing SaltedSeedSeq, returns the input parameter, +// otherwise constructs a new SaltedSeedSeq which embodies the original +// non-salted seed parameters. +template < + typename SSeq, // + typename EnableIf = absl::enable_if_t<is_salted_seed_seq<SSeq>::value>> +SSeq MakeSaltedSeedSeq(SSeq&& seq) { + return SSeq(std::forward<SSeq>(seq)); +} + +template < + typename SSeq, // + typename EnableIf = absl::enable_if_t<!is_salted_seed_seq<SSeq>::value>> +SaltedSeedSeq<typename std::decay<SSeq>::type> MakeSaltedSeedSeq(SSeq&& seq) { + using sseq_type = typename std::decay<SSeq>::type; + using result_type = typename sseq_type::result_type; + + absl::InlinedVector<result_type, 8> data; + seq.param(std::back_inserter(data)); + return SaltedSeedSeq<sseq_type>(data.begin(), data.end()); +} + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_SALTED_SEED_SEQ_H_ +} // namespace absl + +#endif // ABSL_RANDOM_INTERNAL_SALTED_SEED_SEQ_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/seed_material.cc b/contrib/restricted/abseil-cpp/absl/random/internal/seed_material.cc index 6457ece3df..c03cad8502 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/seed_material.cc +++ b/contrib/restricted/abseil-cpp/absl/random/internal/seed_material.cc @@ -1,56 +1,56 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "absl/random/internal/seed_material.h" - -#include <fcntl.h> - -#ifndef _WIN32 -#include <unistd.h> -#else -#include <io.h> -#endif - -#include <algorithm> -#include <cerrno> -#include <cstdint> -#include <cstdlib> -#include <cstring> - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/random/internal/seed_material.h" + +#include <fcntl.h> + +#ifndef _WIN32 +#include <unistd.h> +#else +#include <io.h> +#endif + +#include <algorithm> +#include <cerrno> +#include <cstdint> +#include <cstdlib> +#include <cstring> + #include "absl/base/dynamic_annotations.h" -#include "absl/base/internal/raw_logging.h" -#include "absl/strings/ascii.h" -#include "absl/strings/escaping.h" -#include "absl/strings/string_view.h" -#include "absl/strings/strip.h" - -#if defined(__native_client__) - -#include <nacl/nacl_random.h> -#define ABSL_RANDOM_USE_NACL_SECURE_RANDOM 1 - -#elif defined(_WIN32) - -#include <windows.h> -#define ABSL_RANDOM_USE_BCRYPT 1 -#pragma comment(lib, "bcrypt.lib") - +#include "absl/base/internal/raw_logging.h" +#include "absl/strings/ascii.h" +#include "absl/strings/escaping.h" +#include "absl/strings/string_view.h" +#include "absl/strings/strip.h" + +#if defined(__native_client__) + +#include <nacl/nacl_random.h> +#define ABSL_RANDOM_USE_NACL_SECURE_RANDOM 1 + +#elif defined(_WIN32) + +#include <windows.h> +#define ABSL_RANDOM_USE_BCRYPT 1 +#pragma comment(lib, "bcrypt.lib") + #elif defined(__Fuchsia__) #include <zircon/syscalls.h> -#endif - +#endif + #if defined(__GLIBC__) && \ (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)) // glibc >= 2.25 has getentropy() @@ -63,67 +63,67 @@ #define ABSL_RANDOM_USE_GET_ENTROPY 1 #endif -#if defined(ABSL_RANDOM_USE_BCRYPT) -#include <bcrypt.h> - -#ifndef BCRYPT_SUCCESS -#define BCRYPT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) -#endif -// Also link bcrypt; this can be done via linker options or: -// #pragma comment(lib, "bcrypt.lib") -#endif - -namespace absl { +#if defined(ABSL_RANDOM_USE_BCRYPT) +#include <bcrypt.h> + +#ifndef BCRYPT_SUCCESS +#define BCRYPT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) +#endif +// Also link bcrypt; this can be done via linker options or: +// #pragma comment(lib, "bcrypt.lib") +#endif + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { -namespace { - -// Read OS Entropy for random number seeds. -// TODO(absl-team): Possibly place a cap on how much entropy may be read at a -// time. - -#if defined(ABSL_RANDOM_USE_BCRYPT) - -// On Windows potentially use the BCRYPT CNG API to read available entropy. -bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) { - BCRYPT_ALG_HANDLE hProvider; - NTSTATUS ret; - ret = BCryptOpenAlgorithmProvider(&hProvider, BCRYPT_RNG_ALGORITHM, - MS_PRIMITIVE_PROVIDER, 0); - if (!(BCRYPT_SUCCESS(ret))) { - ABSL_RAW_LOG(ERROR, "Failed to open crypto provider."); - return false; - } - ret = BCryptGenRandom( - hProvider, // provider - reinterpret_cast<UCHAR*>(values.data()), // buffer - static_cast<ULONG>(sizeof(uint32_t) * values.size()), // bytes - 0); // flags - BCryptCloseAlgorithmProvider(hProvider, 0); - return BCRYPT_SUCCESS(ret); -} - -#elif defined(ABSL_RANDOM_USE_NACL_SECURE_RANDOM) - -// On NaCL use nacl_secure_random to acquire bytes. -bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) { - auto buffer = reinterpret_cast<uint8_t*>(values.data()); - size_t buffer_size = sizeof(uint32_t) * values.size(); - - uint8_t* output_ptr = buffer; - while (buffer_size > 0) { - size_t nread = 0; - const int error = nacl_secure_random(output_ptr, buffer_size, &nread); - if (error != 0 || nread > buffer_size) { - ABSL_RAW_LOG(ERROR, "Failed to read secure_random seed data: %d", error); - return false; - } - output_ptr += nread; - buffer_size -= nread; - } - return true; -} - +namespace random_internal { +namespace { + +// Read OS Entropy for random number seeds. +// TODO(absl-team): Possibly place a cap on how much entropy may be read at a +// time. + +#if defined(ABSL_RANDOM_USE_BCRYPT) + +// On Windows potentially use the BCRYPT CNG API to read available entropy. +bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) { + BCRYPT_ALG_HANDLE hProvider; + NTSTATUS ret; + ret = BCryptOpenAlgorithmProvider(&hProvider, BCRYPT_RNG_ALGORITHM, + MS_PRIMITIVE_PROVIDER, 0); + if (!(BCRYPT_SUCCESS(ret))) { + ABSL_RAW_LOG(ERROR, "Failed to open crypto provider."); + return false; + } + ret = BCryptGenRandom( + hProvider, // provider + reinterpret_cast<UCHAR*>(values.data()), // buffer + static_cast<ULONG>(sizeof(uint32_t) * values.size()), // bytes + 0); // flags + BCryptCloseAlgorithmProvider(hProvider, 0); + return BCRYPT_SUCCESS(ret); +} + +#elif defined(ABSL_RANDOM_USE_NACL_SECURE_RANDOM) + +// On NaCL use nacl_secure_random to acquire bytes. +bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) { + auto buffer = reinterpret_cast<uint8_t*>(values.data()); + size_t buffer_size = sizeof(uint32_t) * values.size(); + + uint8_t* output_ptr = buffer; + while (buffer_size > 0) { + size_t nread = 0; + const int error = nacl_secure_random(output_ptr, buffer_size, &nread); + if (error != 0 || nread > buffer_size) { + ABSL_RAW_LOG(ERROR, "Failed to read secure_random seed data: %d", error); + return false; + } + output_ptr += nread; + buffer_size -= nread; + } + return true; +} + #elif defined(__Fuchsia__) bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) { @@ -133,8 +133,8 @@ bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) { return true; } -#else - +#else + #if defined(ABSL_RANDOM_USE_GET_ENTROPY) // On *nix, use getentropy() if supported. Note that libc may support // getentropy(), but the kernel may not, in which case this function will return @@ -159,109 +159,109 @@ bool ReadSeedMaterialFromGetEntropy(absl::Span<uint32_t> values) { } #endif // defined(ABSL_RANDOM_GETENTROPY) -// On *nix, read entropy from /dev/urandom. +// On *nix, read entropy from /dev/urandom. bool ReadSeedMaterialFromDevURandom(absl::Span<uint32_t> values) { - const char kEntropyFile[] = "/dev/urandom"; - - auto buffer = reinterpret_cast<uint8_t*>(values.data()); - size_t buffer_size = sizeof(uint32_t) * values.size(); - - int dev_urandom = open(kEntropyFile, O_RDONLY); - bool success = (-1 != dev_urandom); - if (!success) { - return false; - } - - while (success && buffer_size > 0) { - int bytes_read = read(dev_urandom, buffer, buffer_size); - int read_error = errno; - success = (bytes_read > 0); - if (success) { - buffer += bytes_read; - buffer_size -= bytes_read; - } else if (bytes_read == -1 && read_error == EINTR) { - success = true; // Need to try again. - } - } - close(dev_urandom); - return success; -} - + const char kEntropyFile[] = "/dev/urandom"; + + auto buffer = reinterpret_cast<uint8_t*>(values.data()); + size_t buffer_size = sizeof(uint32_t) * values.size(); + + int dev_urandom = open(kEntropyFile, O_RDONLY); + bool success = (-1 != dev_urandom); + if (!success) { + return false; + } + + while (success && buffer_size > 0) { + int bytes_read = read(dev_urandom, buffer, buffer_size); + int read_error = errno; + success = (bytes_read > 0); + if (success) { + buffer += bytes_read; + buffer_size -= bytes_read; + } else if (bytes_read == -1 && read_error == EINTR) { + success = true; // Need to try again. + } + } + close(dev_urandom); + return success; +} + bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) { #if defined(ABSL_RANDOM_USE_GET_ENTROPY) if (ReadSeedMaterialFromGetEntropy(values)) { return true; } -#endif +#endif // Libc may support getentropy, but the kernel may not, so we still have // to fallback to ReadSeedMaterialFromDevURandom(). return ReadSeedMaterialFromDevURandom(values); } - + #endif -} // namespace - -bool ReadSeedMaterialFromOSEntropy(absl::Span<uint32_t> values) { - assert(values.data() != nullptr); - if (values.data() == nullptr) { - return false; - } - if (values.empty()) { - return true; - } - return ReadSeedMaterialFromOSEntropyImpl(values); -} - -void MixIntoSeedMaterial(absl::Span<const uint32_t> sequence, - absl::Span<uint32_t> seed_material) { - // Algorithm is based on code available at - // https://gist.github.com/imneme/540829265469e673d045 - constexpr uint32_t kInitVal = 0x43b0d7e5; - constexpr uint32_t kHashMul = 0x931e8875; - constexpr uint32_t kMixMulL = 0xca01f9dd; - constexpr uint32_t kMixMulR = 0x4973f715; - constexpr uint32_t kShiftSize = sizeof(uint32_t) * 8 / 2; - - uint32_t hash_const = kInitVal; - auto hash = [&](uint32_t value) { - value ^= hash_const; - hash_const *= kHashMul; - value *= hash_const; - value ^= value >> kShiftSize; - return value; - }; - - auto mix = [&](uint32_t x, uint32_t y) { - uint32_t result = kMixMulL * x - kMixMulR * y; - result ^= result >> kShiftSize; - return result; - }; - - for (const auto& seq_val : sequence) { - for (auto& elem : seed_material) { - elem = mix(elem, hash(seq_val)); - } - } -} - -absl::optional<uint32_t> GetSaltMaterial() { - // Salt must be common for all generators within the same process so read it - // only once and store in static variable. - static const auto salt_material = []() -> absl::optional<uint32_t> { - uint32_t salt_value = 0; - - if (random_internal::ReadSeedMaterialFromOSEntropy( - MakeSpan(&salt_value, 1))) { - return salt_value; - } - - return absl::nullopt; - }(); - - return salt_material; -} - -} // namespace random_internal +} // namespace + +bool ReadSeedMaterialFromOSEntropy(absl::Span<uint32_t> values) { + assert(values.data() != nullptr); + if (values.data() == nullptr) { + return false; + } + if (values.empty()) { + return true; + } + return ReadSeedMaterialFromOSEntropyImpl(values); +} + +void MixIntoSeedMaterial(absl::Span<const uint32_t> sequence, + absl::Span<uint32_t> seed_material) { + // Algorithm is based on code available at + // https://gist.github.com/imneme/540829265469e673d045 + constexpr uint32_t kInitVal = 0x43b0d7e5; + constexpr uint32_t kHashMul = 0x931e8875; + constexpr uint32_t kMixMulL = 0xca01f9dd; + constexpr uint32_t kMixMulR = 0x4973f715; + constexpr uint32_t kShiftSize = sizeof(uint32_t) * 8 / 2; + + uint32_t hash_const = kInitVal; + auto hash = [&](uint32_t value) { + value ^= hash_const; + hash_const *= kHashMul; + value *= hash_const; + value ^= value >> kShiftSize; + return value; + }; + + auto mix = [&](uint32_t x, uint32_t y) { + uint32_t result = kMixMulL * x - kMixMulR * y; + result ^= result >> kShiftSize; + return result; + }; + + for (const auto& seq_val : sequence) { + for (auto& elem : seed_material) { + elem = mix(elem, hash(seq_val)); + } + } +} + +absl::optional<uint32_t> GetSaltMaterial() { + // Salt must be common for all generators within the same process so read it + // only once and store in static variable. + static const auto salt_material = []() -> absl::optional<uint32_t> { + uint32_t salt_value = 0; + + if (random_internal::ReadSeedMaterialFromOSEntropy( + MakeSpan(&salt_value, 1))) { + return salt_value; + } + + return absl::nullopt; + }(); + + return salt_material; +} + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl +} // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/seed_material.h b/contrib/restricted/abseil-cpp/absl/random/internal/seed_material.h index bddbb3cda1..4be10e9256 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/seed_material.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/seed_material.h @@ -1,104 +1,104 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_INTERNAL_SEED_MATERIAL_H_ -#define ABSL_RANDOM_INTERNAL_SEED_MATERIAL_H_ - -#include <cassert> -#include <cstdint> -#include <cstdlib> -#include <string> -#include <vector> - -#include "absl/base/attributes.h" -#include "absl/random/internal/fast_uniform_bits.h" -#include "absl/types/optional.h" -#include "absl/types/span.h" - -namespace absl { +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_INTERNAL_SEED_MATERIAL_H_ +#define ABSL_RANDOM_INTERNAL_SEED_MATERIAL_H_ + +#include <cassert> +#include <cstdint> +#include <cstdlib> +#include <string> +#include <vector> + +#include "absl/base/attributes.h" +#include "absl/random/internal/fast_uniform_bits.h" +#include "absl/types/optional.h" +#include "absl/types/span.h" + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - -// Returns the number of 32-bit blocks needed to contain the given number of -// bits. -constexpr size_t SeedBitsToBlocks(size_t seed_size) { - return (seed_size + 31) / 32; -} - -// Amount of entropy (measured in bits) used to instantiate a Seed Sequence, -// with which to create a URBG. -constexpr size_t kEntropyBitsNeeded = 256; - -// Amount of entropy (measured in 32-bit blocks) used to instantiate a Seed -// Sequence, with which to create a URBG. -constexpr size_t kEntropyBlocksNeeded = - random_internal::SeedBitsToBlocks(kEntropyBitsNeeded); - -static_assert(kEntropyBlocksNeeded > 0, - "Entropy used to seed URBGs must be nonzero."); - -// Attempts to fill a span of uint32_t-values using an OS-provided source of -// true entropy (eg. /dev/urandom) into an array of uint32_t blocks of data. The -// resulting array may be used to initialize an instance of a class conforming -// to the C++ Standard "Seed Sequence" concept [rand.req.seedseq]. -// -// If values.data() == nullptr, the behavior is undefined. -ABSL_MUST_USE_RESULT -bool ReadSeedMaterialFromOSEntropy(absl::Span<uint32_t> values); - -// Attempts to fill a span of uint32_t-values using variates generated by an -// existing instance of a class conforming to the C++ Standard "Uniform Random -// Bit Generator" concept [rand.req.urng]. The resulting data may be used to -// initialize an instance of a class conforming to the C++ Standard -// "Seed Sequence" concept [rand.req.seedseq]. -// -// If urbg == nullptr or values.data() == nullptr, the behavior is undefined. -template <typename URBG> -ABSL_MUST_USE_RESULT bool ReadSeedMaterialFromURBG( - URBG* urbg, absl::Span<uint32_t> values) { - random_internal::FastUniformBits<uint32_t> distr; - - assert(urbg != nullptr && values.data() != nullptr); - if (urbg == nullptr || values.data() == nullptr) { - return false; - } - - for (uint32_t& seed_value : values) { - seed_value = distr(*urbg); - } - return true; -} - -// Mixes given sequence of values with into given sequence of seed material. -// Time complexity of this function is O(sequence.size() * -// seed_material.size()). -// -// Algorithm is based on code available at -// https://gist.github.com/imneme/540829265469e673d045 -// by Melissa O'Neill. -void MixIntoSeedMaterial(absl::Span<const uint32_t> sequence, - absl::Span<uint32_t> seed_material); - -// Returns salt value. -// -// Salt is obtained only once and stored in static variable. -// -// May return empty value if optaining the salt was not possible. -absl::optional<uint32_t> GetSaltMaterial(); - -} // namespace random_internal +namespace random_internal { + +// Returns the number of 32-bit blocks needed to contain the given number of +// bits. +constexpr size_t SeedBitsToBlocks(size_t seed_size) { + return (seed_size + 31) / 32; +} + +// Amount of entropy (measured in bits) used to instantiate a Seed Sequence, +// with which to create a URBG. +constexpr size_t kEntropyBitsNeeded = 256; + +// Amount of entropy (measured in 32-bit blocks) used to instantiate a Seed +// Sequence, with which to create a URBG. +constexpr size_t kEntropyBlocksNeeded = + random_internal::SeedBitsToBlocks(kEntropyBitsNeeded); + +static_assert(kEntropyBlocksNeeded > 0, + "Entropy used to seed URBGs must be nonzero."); + +// Attempts to fill a span of uint32_t-values using an OS-provided source of +// true entropy (eg. /dev/urandom) into an array of uint32_t blocks of data. The +// resulting array may be used to initialize an instance of a class conforming +// to the C++ Standard "Seed Sequence" concept [rand.req.seedseq]. +// +// If values.data() == nullptr, the behavior is undefined. +ABSL_MUST_USE_RESULT +bool ReadSeedMaterialFromOSEntropy(absl::Span<uint32_t> values); + +// Attempts to fill a span of uint32_t-values using variates generated by an +// existing instance of a class conforming to the C++ Standard "Uniform Random +// Bit Generator" concept [rand.req.urng]. The resulting data may be used to +// initialize an instance of a class conforming to the C++ Standard +// "Seed Sequence" concept [rand.req.seedseq]. +// +// If urbg == nullptr or values.data() == nullptr, the behavior is undefined. +template <typename URBG> +ABSL_MUST_USE_RESULT bool ReadSeedMaterialFromURBG( + URBG* urbg, absl::Span<uint32_t> values) { + random_internal::FastUniformBits<uint32_t> distr; + + assert(urbg != nullptr && values.data() != nullptr); + if (urbg == nullptr || values.data() == nullptr) { + return false; + } + + for (uint32_t& seed_value : values) { + seed_value = distr(*urbg); + } + return true; +} + +// Mixes given sequence of values with into given sequence of seed material. +// Time complexity of this function is O(sequence.size() * +// seed_material.size()). +// +// Algorithm is based on code available at +// https://gist.github.com/imneme/540829265469e673d045 +// by Melissa O'Neill. +void MixIntoSeedMaterial(absl::Span<const uint32_t> sequence, + absl::Span<uint32_t> seed_material); + +// Returns salt value. +// +// Salt is obtained only once and stored in static variable. +// +// May return empty value if optaining the salt was not possible. +absl::optional<uint32_t> GetSaltMaterial(); + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_SEED_MATERIAL_H_ +} // namespace absl + +#endif // ABSL_RANDOM_INTERNAL_SEED_MATERIAL_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/seed_material/ya.make b/contrib/restricted/abseil-cpp/absl/random/internal/seed_material/ya.make index d4a024053f..65618b087d 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/seed_material/ya.make +++ b/contrib/restricted/abseil-cpp/absl/random/internal/seed_material/ya.make @@ -1,41 +1,41 @@ -# Generated by devtools/yamaker. - -LIBRARY() - +# Generated by devtools/yamaker. + +LIBRARY() + WITHOUT_LICENSE_TEXTS() -OWNER(g:cpp-contrib) - -LICENSE(Apache-2.0) - -PEERDIR( - contrib/restricted/abseil-cpp/absl/base - contrib/restricted/abseil-cpp/absl/base/internal/raw_logging - contrib/restricted/abseil-cpp/absl/base/internal/spinlock_wait - contrib/restricted/abseil-cpp/absl/base/internal/throw_delegate - contrib/restricted/abseil-cpp/absl/base/log_severity - contrib/restricted/abseil-cpp/absl/numeric +OWNER(g:cpp-contrib) + +LICENSE(Apache-2.0) + +PEERDIR( + contrib/restricted/abseil-cpp/absl/base + contrib/restricted/abseil-cpp/absl/base/internal/raw_logging + contrib/restricted/abseil-cpp/absl/base/internal/spinlock_wait + contrib/restricted/abseil-cpp/absl/base/internal/throw_delegate + contrib/restricted/abseil-cpp/absl/base/log_severity + contrib/restricted/abseil-cpp/absl/numeric contrib/restricted/abseil-cpp/absl/strings contrib/restricted/abseil-cpp/absl/strings/internal/absl_strings_internal contrib/restricted/abseil-cpp/absl/types/bad_optional_access -) - -ADDINCL( - GLOBAL contrib/restricted/abseil-cpp -) - -NO_COMPILER_WARNINGS() - -NO_UTIL() - +) + +ADDINCL( + GLOBAL contrib/restricted/abseil-cpp +) + +NO_COMPILER_WARNINGS() + +NO_UTIL() + CFLAGS( -DNOMINMAX ) SRCDIR(contrib/restricted/abseil-cpp/absl/random/internal) -SRCS( +SRCS( seed_material.cc -) - -END() +) + +END() diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/sequence_urbg.h b/contrib/restricted/abseil-cpp/absl/random/internal/sequence_urbg.h index 3ed7dfd6e0..bc96a12cd2 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/sequence_urbg.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/sequence_urbg.h @@ -1,60 +1,60 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_INTERNAL_SEQUENCE_URBG_H_ -#define ABSL_RANDOM_INTERNAL_SEQUENCE_URBG_H_ - -#include <cstdint> -#include <cstring> -#include <limits> -#include <type_traits> -#include <vector> - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_INTERNAL_SEQUENCE_URBG_H_ +#define ABSL_RANDOM_INTERNAL_SEQUENCE_URBG_H_ + +#include <cstdint> +#include <cstring> +#include <limits> +#include <type_traits> +#include <vector> + #include "absl/base/config.h" -namespace absl { +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - -// `sequence_urbg` is a simple random number generator which meets the -// requirements of [rand.req.urbg], and is solely for testing absl -// distributions. -class sequence_urbg { - public: - using result_type = uint64_t; - - static constexpr result_type(min)() { - return (std::numeric_limits<result_type>::min)(); - } - static constexpr result_type(max)() { - return (std::numeric_limits<result_type>::max)(); - } - - sequence_urbg(std::initializer_list<result_type> data) : i_(0), data_(data) {} - void reset() { i_ = 0; } - - result_type operator()() { return data_[i_++ % data_.size()]; } - - size_t invocations() const { return i_; } - - private: - size_t i_; - std::vector<result_type> data_; -}; - -} // namespace random_internal +namespace random_internal { + +// `sequence_urbg` is a simple random number generator which meets the +// requirements of [rand.req.urbg], and is solely for testing absl +// distributions. +class sequence_urbg { + public: + using result_type = uint64_t; + + static constexpr result_type(min)() { + return (std::numeric_limits<result_type>::min)(); + } + static constexpr result_type(max)() { + return (std::numeric_limits<result_type>::max)(); + } + + sequence_urbg(std::initializer_list<result_type> data) : i_(0), data_(data) {} + void reset() { i_ = 0; } + + result_type operator()() { return data_[i_++ % data_.size()]; } + + size_t invocations() const { return i_; } + + private: + size_t i_; + std::vector<result_type> data_; +}; + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_SEQUENCE_URBG_H_ +} // namespace absl + +#endif // ABSL_RANDOM_INTERNAL_SEQUENCE_URBG_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/traits.h b/contrib/restricted/abseil-cpp/absl/random/internal/traits.h index aa39823632..75772bd9ab 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/traits.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/traits.h @@ -1,101 +1,101 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_INTERNAL_TRAITS_H_ -#define ABSL_RANDOM_INTERNAL_TRAITS_H_ - -#include <cstdint> -#include <limits> -#include <type_traits> - -#include "absl/base/config.h" - -namespace absl { +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_INTERNAL_TRAITS_H_ +#define ABSL_RANDOM_INTERNAL_TRAITS_H_ + +#include <cstdint> +#include <limits> +#include <type_traits> + +#include "absl/base/config.h" + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - -// random_internal::is_widening_convertible<A, B> -// -// Returns whether a type A is widening-convertible to a type B. -// -// A is widening-convertible to B means: -// A a = <any number>; -// B b = a; -// A c = b; -// EXPECT_EQ(a, c); -template <typename A, typename B> -class is_widening_convertible { - // As long as there are enough bits in the exact part of a number: - // - unsigned can fit in float, signed, unsigned - // - signed can fit in float, signed - // - float can fit in float - // So we define rank to be: - // - rank(float) -> 2 - // - rank(signed) -> 1 - // - rank(unsigned) -> 0 - template <class T> - static constexpr int rank() { - return !std::numeric_limits<T>::is_integer + - std::numeric_limits<T>::is_signed; - } - - public: - // If an arithmetic-type B can represent at least as many digits as a type A, - // and B belongs to a rank no lower than A, then A can be safely represented - // by B through a widening-conversion. - static constexpr bool value = - std::numeric_limits<A>::digits <= std::numeric_limits<B>::digits && - rank<A>() <= rank<B>(); -}; - -// unsigned_bits<N>::type returns the unsigned int type with the indicated -// number of bits. -template <size_t N> -struct unsigned_bits; - -template <> -struct unsigned_bits<8> { - using type = uint8_t; -}; -template <> -struct unsigned_bits<16> { - using type = uint16_t; -}; -template <> -struct unsigned_bits<32> { - using type = uint32_t; -}; -template <> -struct unsigned_bits<64> { - using type = uint64_t; -}; - -#ifdef ABSL_HAVE_INTRINSIC_INT128 -template <> -struct unsigned_bits<128> { - using type = __uint128_t; -}; -#endif - -template <typename IntType> -struct make_unsigned_bits { - using type = typename unsigned_bits<std::numeric_limits< - typename std::make_unsigned<IntType>::type>::digits>::type; -}; - -} // namespace random_internal +namespace random_internal { + +// random_internal::is_widening_convertible<A, B> +// +// Returns whether a type A is widening-convertible to a type B. +// +// A is widening-convertible to B means: +// A a = <any number>; +// B b = a; +// A c = b; +// EXPECT_EQ(a, c); +template <typename A, typename B> +class is_widening_convertible { + // As long as there are enough bits in the exact part of a number: + // - unsigned can fit in float, signed, unsigned + // - signed can fit in float, signed + // - float can fit in float + // So we define rank to be: + // - rank(float) -> 2 + // - rank(signed) -> 1 + // - rank(unsigned) -> 0 + template <class T> + static constexpr int rank() { + return !std::numeric_limits<T>::is_integer + + std::numeric_limits<T>::is_signed; + } + + public: + // If an arithmetic-type B can represent at least as many digits as a type A, + // and B belongs to a rank no lower than A, then A can be safely represented + // by B through a widening-conversion. + static constexpr bool value = + std::numeric_limits<A>::digits <= std::numeric_limits<B>::digits && + rank<A>() <= rank<B>(); +}; + +// unsigned_bits<N>::type returns the unsigned int type with the indicated +// number of bits. +template <size_t N> +struct unsigned_bits; + +template <> +struct unsigned_bits<8> { + using type = uint8_t; +}; +template <> +struct unsigned_bits<16> { + using type = uint16_t; +}; +template <> +struct unsigned_bits<32> { + using type = uint32_t; +}; +template <> +struct unsigned_bits<64> { + using type = uint64_t; +}; + +#ifdef ABSL_HAVE_INTRINSIC_INT128 +template <> +struct unsigned_bits<128> { + using type = __uint128_t; +}; +#endif + +template <typename IntType> +struct make_unsigned_bits { + using type = typename unsigned_bits<std::numeric_limits< + typename std::make_unsigned<IntType>::type>::digits>::type; +}; + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_TRAITS_H_ +} // namespace absl + +#endif // ABSL_RANDOM_INTERNAL_TRAITS_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/uniform_helper.h b/contrib/restricted/abseil-cpp/absl/random/internal/uniform_helper.h index 30ae9d10f3..1243bc1c62 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/uniform_helper.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/uniform_helper.h @@ -1,66 +1,66 @@ -// Copyright 2019 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -#ifndef ABSL_RANDOM_INTERNAL_UNIFORM_HELPER_H_ -#define ABSL_RANDOM_INTERNAL_UNIFORM_HELPER_H_ - -#include <cmath> -#include <limits> -#include <type_traits> - +// Copyright 2019 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef ABSL_RANDOM_INTERNAL_UNIFORM_HELPER_H_ +#define ABSL_RANDOM_INTERNAL_UNIFORM_HELPER_H_ + +#include <cmath> +#include <limits> +#include <type_traits> + #include "absl/base/config.h" -#include "absl/meta/type_traits.h" +#include "absl/meta/type_traits.h" #include "absl/random/internal/traits.h" - -namespace absl { + +namespace absl { ABSL_NAMESPACE_BEGIN -template <typename IntType> -class uniform_int_distribution; - -template <typename RealType> -class uniform_real_distribution; - -// Interval tag types which specify whether the interval is open or closed -// on either boundary. - -namespace random_internal { -template <typename T> -struct TagTypeCompare {}; - -template <typename T> -constexpr bool operator==(TagTypeCompare<T>, TagTypeCompare<T>) { - // Tags are mono-states. They always compare equal. - return true; -} -template <typename T> -constexpr bool operator!=(TagTypeCompare<T>, TagTypeCompare<T>) { - return false; -} - -} // namespace random_internal - -struct IntervalClosedClosedTag - : public random_internal::TagTypeCompare<IntervalClosedClosedTag> {}; -struct IntervalClosedOpenTag - : public random_internal::TagTypeCompare<IntervalClosedOpenTag> {}; -struct IntervalOpenClosedTag - : public random_internal::TagTypeCompare<IntervalOpenClosedTag> {}; -struct IntervalOpenOpenTag - : public random_internal::TagTypeCompare<IntervalOpenOpenTag> {}; - -namespace random_internal { +template <typename IntType> +class uniform_int_distribution; + +template <typename RealType> +class uniform_real_distribution; + +// Interval tag types which specify whether the interval is open or closed +// on either boundary. + +namespace random_internal { +template <typename T> +struct TagTypeCompare {}; + +template <typename T> +constexpr bool operator==(TagTypeCompare<T>, TagTypeCompare<T>) { + // Tags are mono-states. They always compare equal. + return true; +} +template <typename T> +constexpr bool operator!=(TagTypeCompare<T>, TagTypeCompare<T>) { + return false; +} + +} // namespace random_internal + +struct IntervalClosedClosedTag + : public random_internal::TagTypeCompare<IntervalClosedClosedTag> {}; +struct IntervalClosedOpenTag + : public random_internal::TagTypeCompare<IntervalClosedOpenTag> {}; +struct IntervalOpenClosedTag + : public random_internal::TagTypeCompare<IntervalOpenClosedTag> {}; +struct IntervalOpenOpenTag + : public random_internal::TagTypeCompare<IntervalOpenOpenTag> {}; + +namespace random_internal { // In the absence of an explicitly provided return-type, the template // "uniform_inferred_return_t<A, B>" is used to derive a suitable type, based on @@ -81,97 +81,97 @@ using uniform_inferred_return_t = typename std::conditional< is_widening_convertible<A, B>::value, B, A>::type>; -// The functions -// uniform_lower_bound(tag, a, b) -// and -// uniform_upper_bound(tag, a, b) -// are used as implementation-details for absl::Uniform(). -// -// Conceptually, -// [a, b] == [uniform_lower_bound(IntervalClosedClosed, a, b), -// uniform_upper_bound(IntervalClosedClosed, a, b)] -// (a, b) == [uniform_lower_bound(IntervalOpenOpen, a, b), -// uniform_upper_bound(IntervalOpenOpen, a, b)] -// [a, b) == [uniform_lower_bound(IntervalClosedOpen, a, b), -// uniform_upper_bound(IntervalClosedOpen, a, b)] -// (a, b] == [uniform_lower_bound(IntervalOpenClosed, a, b), -// uniform_upper_bound(IntervalOpenClosed, a, b)] -// -template <typename IntType, typename Tag> -typename absl::enable_if_t< - absl::conjunction< - std::is_integral<IntType>, - absl::disjunction<std::is_same<Tag, IntervalOpenClosedTag>, - std::is_same<Tag, IntervalOpenOpenTag>>>::value, - IntType> -uniform_lower_bound(Tag, IntType a, IntType) { +// The functions +// uniform_lower_bound(tag, a, b) +// and +// uniform_upper_bound(tag, a, b) +// are used as implementation-details for absl::Uniform(). +// +// Conceptually, +// [a, b] == [uniform_lower_bound(IntervalClosedClosed, a, b), +// uniform_upper_bound(IntervalClosedClosed, a, b)] +// (a, b) == [uniform_lower_bound(IntervalOpenOpen, a, b), +// uniform_upper_bound(IntervalOpenOpen, a, b)] +// [a, b) == [uniform_lower_bound(IntervalClosedOpen, a, b), +// uniform_upper_bound(IntervalClosedOpen, a, b)] +// (a, b] == [uniform_lower_bound(IntervalOpenClosed, a, b), +// uniform_upper_bound(IntervalOpenClosed, a, b)] +// +template <typename IntType, typename Tag> +typename absl::enable_if_t< + absl::conjunction< + std::is_integral<IntType>, + absl::disjunction<std::is_same<Tag, IntervalOpenClosedTag>, + std::is_same<Tag, IntervalOpenOpenTag>>>::value, + IntType> +uniform_lower_bound(Tag, IntType a, IntType) { return a < (std::numeric_limits<IntType>::max)() ? (a + 1) : a; -} - -template <typename FloatType, typename Tag> -typename absl::enable_if_t< - absl::conjunction< - std::is_floating_point<FloatType>, - absl::disjunction<std::is_same<Tag, IntervalOpenClosedTag>, - std::is_same<Tag, IntervalOpenOpenTag>>>::value, - FloatType> -uniform_lower_bound(Tag, FloatType a, FloatType b) { - return std::nextafter(a, b); -} - -template <typename NumType, typename Tag> -typename absl::enable_if_t< - absl::disjunction<std::is_same<Tag, IntervalClosedClosedTag>, - std::is_same<Tag, IntervalClosedOpenTag>>::value, - NumType> -uniform_lower_bound(Tag, NumType a, NumType) { - return a; -} - -template <typename IntType, typename Tag> -typename absl::enable_if_t< - absl::conjunction< - std::is_integral<IntType>, - absl::disjunction<std::is_same<Tag, IntervalClosedOpenTag>, - std::is_same<Tag, IntervalOpenOpenTag>>>::value, - IntType> -uniform_upper_bound(Tag, IntType, IntType b) { +} + +template <typename FloatType, typename Tag> +typename absl::enable_if_t< + absl::conjunction< + std::is_floating_point<FloatType>, + absl::disjunction<std::is_same<Tag, IntervalOpenClosedTag>, + std::is_same<Tag, IntervalOpenOpenTag>>>::value, + FloatType> +uniform_lower_bound(Tag, FloatType a, FloatType b) { + return std::nextafter(a, b); +} + +template <typename NumType, typename Tag> +typename absl::enable_if_t< + absl::disjunction<std::is_same<Tag, IntervalClosedClosedTag>, + std::is_same<Tag, IntervalClosedOpenTag>>::value, + NumType> +uniform_lower_bound(Tag, NumType a, NumType) { + return a; +} + +template <typename IntType, typename Tag> +typename absl::enable_if_t< + absl::conjunction< + std::is_integral<IntType>, + absl::disjunction<std::is_same<Tag, IntervalClosedOpenTag>, + std::is_same<Tag, IntervalOpenOpenTag>>>::value, + IntType> +uniform_upper_bound(Tag, IntType, IntType b) { return b > (std::numeric_limits<IntType>::min)() ? (b - 1) : b; -} - -template <typename FloatType, typename Tag> -typename absl::enable_if_t< - absl::conjunction< - std::is_floating_point<FloatType>, - absl::disjunction<std::is_same<Tag, IntervalClosedOpenTag>, - std::is_same<Tag, IntervalOpenOpenTag>>>::value, - FloatType> -uniform_upper_bound(Tag, FloatType, FloatType b) { - return b; -} - -template <typename IntType, typename Tag> -typename absl::enable_if_t< - absl::conjunction< - std::is_integral<IntType>, - absl::disjunction<std::is_same<Tag, IntervalClosedClosedTag>, - std::is_same<Tag, IntervalOpenClosedTag>>>::value, - IntType> -uniform_upper_bound(Tag, IntType, IntType b) { - return b; -} - -template <typename FloatType, typename Tag> -typename absl::enable_if_t< - absl::conjunction< - std::is_floating_point<FloatType>, - absl::disjunction<std::is_same<Tag, IntervalClosedClosedTag>, - std::is_same<Tag, IntervalOpenClosedTag>>>::value, - FloatType> -uniform_upper_bound(Tag, FloatType, FloatType b) { - return std::nextafter(b, (std::numeric_limits<FloatType>::max)()); -} - +} + +template <typename FloatType, typename Tag> +typename absl::enable_if_t< + absl::conjunction< + std::is_floating_point<FloatType>, + absl::disjunction<std::is_same<Tag, IntervalClosedOpenTag>, + std::is_same<Tag, IntervalOpenOpenTag>>>::value, + FloatType> +uniform_upper_bound(Tag, FloatType, FloatType b) { + return b; +} + +template <typename IntType, typename Tag> +typename absl::enable_if_t< + absl::conjunction< + std::is_integral<IntType>, + absl::disjunction<std::is_same<Tag, IntervalClosedClosedTag>, + std::is_same<Tag, IntervalOpenClosedTag>>>::value, + IntType> +uniform_upper_bound(Tag, IntType, IntType b) { + return b; +} + +template <typename FloatType, typename Tag> +typename absl::enable_if_t< + absl::conjunction< + std::is_floating_point<FloatType>, + absl::disjunction<std::is_same<Tag, IntervalClosedClosedTag>, + std::is_same<Tag, IntervalOpenClosedTag>>>::value, + FloatType> +uniform_upper_bound(Tag, FloatType, FloatType b) { + return std::nextafter(b, (std::numeric_limits<FloatType>::max)()); +} + // Returns whether the bounds are valid for the underlying distribution. // Inputs must have already been resolved via uniform_*_bound calls. // @@ -208,37 +208,37 @@ is_uniform_range_valid(IntType a, IntType b) { // UniformDistribution selects either absl::uniform_int_distribution // or absl::uniform_real_distribution depending on the NumType parameter. -template <typename NumType> -using UniformDistribution = - typename std::conditional<std::is_integral<NumType>::value, - absl::uniform_int_distribution<NumType>, - absl::uniform_real_distribution<NumType>>::type; - +template <typename NumType> +using UniformDistribution = + typename std::conditional<std::is_integral<NumType>::value, + absl::uniform_int_distribution<NumType>, + absl::uniform_real_distribution<NumType>>::type; + // UniformDistributionWrapper is used as the underlying distribution type // by the absl::Uniform template function. It selects the proper Abseil // uniform distribution and provides constructor overloads that match the // expected parameter order as well as adjusting distribtuion bounds based // on the tag. -template <typename NumType> -struct UniformDistributionWrapper : public UniformDistribution<NumType> { - template <typename TagType> - explicit UniformDistributionWrapper(TagType, NumType lo, NumType hi) - : UniformDistribution<NumType>( - uniform_lower_bound<NumType>(TagType{}, lo, hi), - uniform_upper_bound<NumType>(TagType{}, lo, hi)) {} - - explicit UniformDistributionWrapper(NumType lo, NumType hi) - : UniformDistribution<NumType>( - uniform_lower_bound<NumType>(IntervalClosedOpenTag(), lo, hi), - uniform_upper_bound<NumType>(IntervalClosedOpenTag(), lo, hi)) {} - - explicit UniformDistributionWrapper() - : UniformDistribution<NumType>(std::numeric_limits<NumType>::lowest(), - (std::numeric_limits<NumType>::max)()) {} -}; - -} // namespace random_internal +template <typename NumType> +struct UniformDistributionWrapper : public UniformDistribution<NumType> { + template <typename TagType> + explicit UniformDistributionWrapper(TagType, NumType lo, NumType hi) + : UniformDistribution<NumType>( + uniform_lower_bound<NumType>(TagType{}, lo, hi), + uniform_upper_bound<NumType>(TagType{}, lo, hi)) {} + + explicit UniformDistributionWrapper(NumType lo, NumType hi) + : UniformDistribution<NumType>( + uniform_lower_bound<NumType>(IntervalClosedOpenTag(), lo, hi), + uniform_upper_bound<NumType>(IntervalClosedOpenTag(), lo, hi)) {} + + explicit UniformDistributionWrapper() + : UniformDistribution<NumType>(std::numeric_limits<NumType>::lowest(), + (std::numeric_limits<NumType>::max)()) {} +}; + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_UNIFORM_HELPER_H_ +} // namespace absl + +#endif // ABSL_RANDOM_INTERNAL_UNIFORM_HELPER_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/internal/wide_multiply.h b/contrib/restricted/abseil-cpp/absl/random/internal/wide_multiply.h index 04085c8411..b6e6c4b6aa 100644 --- a/contrib/restricted/abseil-cpp/absl/random/internal/wide_multiply.h +++ b/contrib/restricted/abseil-cpp/absl/random/internal/wide_multiply.h @@ -1,111 +1,111 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_INTERNAL_WIDE_MULTIPLY_H_ -#define ABSL_RANDOM_INTERNAL_WIDE_MULTIPLY_H_ - -#include <cstdint> -#include <limits> -#include <type_traits> - -#if (defined(_WIN32) || defined(_WIN64)) && defined(_M_IA64) -#include <intrin.h> // NOLINT(build/include_order) -#pragma intrinsic(_umul128) -#define ABSL_INTERNAL_USE_UMUL128 1 -#endif - -#include "absl/base/config.h" +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_INTERNAL_WIDE_MULTIPLY_H_ +#define ABSL_RANDOM_INTERNAL_WIDE_MULTIPLY_H_ + +#include <cstdint> +#include <limits> +#include <type_traits> + +#if (defined(_WIN32) || defined(_WIN64)) && defined(_M_IA64) +#include <intrin.h> // NOLINT(build/include_order) +#pragma intrinsic(_umul128) +#define ABSL_INTERNAL_USE_UMUL128 1 +#endif + +#include "absl/base/config.h" #include "absl/numeric/bits.h" -#include "absl/numeric/int128.h" -#include "absl/random/internal/traits.h" - -namespace absl { +#include "absl/numeric/int128.h" +#include "absl/random/internal/traits.h" + +namespace absl { ABSL_NAMESPACE_BEGIN -namespace random_internal { - -// Helper object to multiply two 64-bit values to a 128-bit value. -// MultiplyU64ToU128 multiplies two 64-bit values to a 128-bit value. -// If an intrinsic is available, it is used, otherwise use native 32-bit -// multiplies to construct the result. +namespace random_internal { + +// Helper object to multiply two 64-bit values to a 128-bit value. +// MultiplyU64ToU128 multiplies two 64-bit values to a 128-bit value. +// If an intrinsic is available, it is used, otherwise use native 32-bit +// multiplies to construct the result. inline absl::uint128 MultiplyU64ToU128(uint64_t a, uint64_t b) { -#if defined(ABSL_HAVE_INTRINSIC_INT128) +#if defined(ABSL_HAVE_INTRINSIC_INT128) return absl::uint128(static_cast<__uint128_t>(a) * b); -#elif defined(ABSL_INTERNAL_USE_UMUL128) - // uint64_t * uint64_t => uint128 multiply using imul intrinsic on MSVC. - uint64_t high = 0; - const uint64_t low = _umul128(a, b, &high); - return absl::MakeUint128(high, low); -#else - // uint128(a) * uint128(b) in emulated mode computes a full 128-bit x 128-bit - // multiply. However there are many cases where that is not necessary, and it - // is only necessary to support a 64-bit x 64-bit = 128-bit multiply. This is - // for those cases. - const uint64_t a00 = static_cast<uint32_t>(a); - const uint64_t a32 = a >> 32; - const uint64_t b00 = static_cast<uint32_t>(b); - const uint64_t b32 = b >> 32; - - const uint64_t c00 = a00 * b00; - const uint64_t c32a = a00 * b32; - const uint64_t c32b = a32 * b00; - const uint64_t c64 = a32 * b32; - - const uint32_t carry = - static_cast<uint32_t>(((c00 >> 32) + static_cast<uint32_t>(c32a) + - static_cast<uint32_t>(c32b)) >> - 32); - - return absl::MakeUint128(c64 + (c32a >> 32) + (c32b >> 32) + carry, - c00 + (c32a << 32) + (c32b << 32)); -#endif -} - -// wide_multiply<T> multiplies two N-bit values to a 2N-bit result. -template <typename UIntType> -struct wide_multiply { - static constexpr size_t kN = std::numeric_limits<UIntType>::digits; - using input_type = UIntType; - using result_type = typename random_internal::unsigned_bits<kN * 2>::type; - - static result_type multiply(input_type a, input_type b) { - return static_cast<result_type>(a) * b; - } - - static input_type hi(result_type r) { return r >> kN; } - static input_type lo(result_type r) { return r; } - - static_assert(std::is_unsigned<UIntType>::value, - "Class-template wide_multiply<> argument must be unsigned."); -}; - -#ifndef ABSL_HAVE_INTRINSIC_INT128 -template <> -struct wide_multiply<uint64_t> { - using input_type = uint64_t; +#elif defined(ABSL_INTERNAL_USE_UMUL128) + // uint64_t * uint64_t => uint128 multiply using imul intrinsic on MSVC. + uint64_t high = 0; + const uint64_t low = _umul128(a, b, &high); + return absl::MakeUint128(high, low); +#else + // uint128(a) * uint128(b) in emulated mode computes a full 128-bit x 128-bit + // multiply. However there are many cases where that is not necessary, and it + // is only necessary to support a 64-bit x 64-bit = 128-bit multiply. This is + // for those cases. + const uint64_t a00 = static_cast<uint32_t>(a); + const uint64_t a32 = a >> 32; + const uint64_t b00 = static_cast<uint32_t>(b); + const uint64_t b32 = b >> 32; + + const uint64_t c00 = a00 * b00; + const uint64_t c32a = a00 * b32; + const uint64_t c32b = a32 * b00; + const uint64_t c64 = a32 * b32; + + const uint32_t carry = + static_cast<uint32_t>(((c00 >> 32) + static_cast<uint32_t>(c32a) + + static_cast<uint32_t>(c32b)) >> + 32); + + return absl::MakeUint128(c64 + (c32a >> 32) + (c32b >> 32) + carry, + c00 + (c32a << 32) + (c32b << 32)); +#endif +} + +// wide_multiply<T> multiplies two N-bit values to a 2N-bit result. +template <typename UIntType> +struct wide_multiply { + static constexpr size_t kN = std::numeric_limits<UIntType>::digits; + using input_type = UIntType; + using result_type = typename random_internal::unsigned_bits<kN * 2>::type; + + static result_type multiply(input_type a, input_type b) { + return static_cast<result_type>(a) * b; + } + + static input_type hi(result_type r) { return r >> kN; } + static input_type lo(result_type r) { return r; } + + static_assert(std::is_unsigned<UIntType>::value, + "Class-template wide_multiply<> argument must be unsigned."); +}; + +#ifndef ABSL_HAVE_INTRINSIC_INT128 +template <> +struct wide_multiply<uint64_t> { + using input_type = uint64_t; using result_type = absl::uint128; - - static result_type multiply(uint64_t a, uint64_t b) { - return MultiplyU64ToU128(a, b); - } - + + static result_type multiply(uint64_t a, uint64_t b) { + return MultiplyU64ToU128(a, b); + } + static uint64_t hi(result_type r) { return absl::Uint128High64(r); } static uint64_t lo(result_type r) { return absl::Uint128Low64(r); } -}; -#endif - -} // namespace random_internal +}; +#endif + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_WIDE_MULTIPLY_H_ +} // namespace absl + +#endif // ABSL_RANDOM_INTERNAL_WIDE_MULTIPLY_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/log_uniform_int_distribution.h b/contrib/restricted/abseil-cpp/absl/random/log_uniform_int_distribution.h index e8b7b0cc3e..43e101169c 100644 --- a/contrib/restricted/abseil-cpp/absl/random/log_uniform_int_distribution.h +++ b/contrib/restricted/abseil-cpp/absl/random/log_uniform_int_distribution.h @@ -1,257 +1,257 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_LOG_UNIFORM_INT_DISTRIBUTION_H_ -#define ABSL_RANDOM_LOG_UNIFORM_INT_DISTRIBUTION_H_ - -#include <algorithm> -#include <cassert> -#include <cmath> -#include <istream> -#include <limits> -#include <ostream> -#include <type_traits> - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_LOG_UNIFORM_INT_DISTRIBUTION_H_ +#define ABSL_RANDOM_LOG_UNIFORM_INT_DISTRIBUTION_H_ + +#include <algorithm> +#include <cassert> +#include <cmath> +#include <istream> +#include <limits> +#include <ostream> +#include <type_traits> + #include "absl/numeric/bits.h" -#include "absl/random/internal/fastmath.h" -#include "absl/random/internal/generate_real.h" -#include "absl/random/internal/iostream_state_saver.h" -#include "absl/random/internal/traits.h" -#include "absl/random/uniform_int_distribution.h" - -namespace absl { +#include "absl/random/internal/fastmath.h" +#include "absl/random/internal/generate_real.h" +#include "absl/random/internal/iostream_state_saver.h" +#include "absl/random/internal/traits.h" +#include "absl/random/uniform_int_distribution.h" + +namespace absl { ABSL_NAMESPACE_BEGIN - -// log_uniform_int_distribution: -// -// Returns a random variate R in range [min, max] such that -// floor(log(R-min, base)) is uniformly distributed. -// We ensure uniformity by discretization using the -// boundary sets [0, 1, base, base * base, ... min(base*n, max)] -// -template <typename IntType = int> -class log_uniform_int_distribution { - private: - using unsigned_type = - typename random_internal::make_unsigned_bits<IntType>::type; - - public: - using result_type = IntType; - - class param_type { - public: - using distribution_type = log_uniform_int_distribution; - - explicit param_type( - result_type min = 0, - result_type max = (std::numeric_limits<result_type>::max)(), - result_type base = 2) - : min_(min), - max_(max), - base_(base), - range_(static_cast<unsigned_type>(max_) - - static_cast<unsigned_type>(min_)), - log_range_(0) { - assert(max_ >= min_); - assert(base_ > 1); - - if (base_ == 2) { - // Determine where the first set bit is on range(), giving a log2(range) - // value which can be used to construct bounds. + +// log_uniform_int_distribution: +// +// Returns a random variate R in range [min, max] such that +// floor(log(R-min, base)) is uniformly distributed. +// We ensure uniformity by discretization using the +// boundary sets [0, 1, base, base * base, ... min(base*n, max)] +// +template <typename IntType = int> +class log_uniform_int_distribution { + private: + using unsigned_type = + typename random_internal::make_unsigned_bits<IntType>::type; + + public: + using result_type = IntType; + + class param_type { + public: + using distribution_type = log_uniform_int_distribution; + + explicit param_type( + result_type min = 0, + result_type max = (std::numeric_limits<result_type>::max)(), + result_type base = 2) + : min_(min), + max_(max), + base_(base), + range_(static_cast<unsigned_type>(max_) - + static_cast<unsigned_type>(min_)), + log_range_(0) { + assert(max_ >= min_); + assert(base_ > 1); + + if (base_ == 2) { + // Determine where the first set bit is on range(), giving a log2(range) + // value which can be used to construct bounds. log_range_ = (std::min)(bit_width(range()), static_cast<unsigned_type>( std::numeric_limits<unsigned_type>::digits)); - } else { - // NOTE: Computing the logN(x) introduces error from 2 sources: - // 1. Conversion of int to double loses precision for values >= - // 2^53, which may cause some log() computations to operate on - // different values. - // 2. The error introduced by the division will cause the result - // to differ from the expected value. - // - // Thus a result which should equal K may equal K +/- epsilon, - // which can eliminate some values depending on where the bounds fall. - const double inv_log_base = 1.0 / std::log(base_); - const double log_range = std::log(static_cast<double>(range()) + 0.5); - log_range_ = static_cast<int>(std::ceil(inv_log_base * log_range)); - } - } - - result_type(min)() const { return min_; } - result_type(max)() const { return max_; } - result_type base() const { return base_; } - - friend bool operator==(const param_type& a, const param_type& b) { - return a.min_ == b.min_ && a.max_ == b.max_ && a.base_ == b.base_; - } - - friend bool operator!=(const param_type& a, const param_type& b) { - return !(a == b); - } - - private: - friend class log_uniform_int_distribution; - - int log_range() const { return log_range_; } - unsigned_type range() const { return range_; } - - result_type min_; - result_type max_; - result_type base_; - unsigned_type range_; // max - min - int log_range_; // ceil(logN(range_)) - - static_assert(std::is_integral<IntType>::value, - "Class-template absl::log_uniform_int_distribution<> must be " - "parameterized using an integral type."); - }; - - log_uniform_int_distribution() : log_uniform_int_distribution(0) {} - - explicit log_uniform_int_distribution( - result_type min, - result_type max = (std::numeric_limits<result_type>::max)(), - result_type base = 2) - : param_(min, max, base) {} - - explicit log_uniform_int_distribution(const param_type& p) : param_(p) {} - - void reset() {} - - // generating functions - template <typename URBG> - result_type operator()(URBG& g) { // NOLINT(runtime/references) - return (*this)(g, param_); - } - - template <typename URBG> - result_type operator()(URBG& g, // NOLINT(runtime/references) - const param_type& p) { - return (p.min)() + Generate(g, p); - } - - result_type(min)() const { return (param_.min)(); } - result_type(max)() const { return (param_.max)(); } - result_type base() const { return param_.base(); } - - param_type param() const { return param_; } - void param(const param_type& p) { param_ = p; } - - friend bool operator==(const log_uniform_int_distribution& a, - const log_uniform_int_distribution& b) { - return a.param_ == b.param_; - } - friend bool operator!=(const log_uniform_int_distribution& a, - const log_uniform_int_distribution& b) { - return a.param_ != b.param_; - } - - private: - // Returns a log-uniform variate in the range [0, p.range()]. The caller - // should add min() to shift the result to the correct range. - template <typename URNG> - unsigned_type Generate(URNG& g, // NOLINT(runtime/references) - const param_type& p); - - param_type param_; -}; - -template <typename IntType> -template <typename URBG> -typename log_uniform_int_distribution<IntType>::unsigned_type -log_uniform_int_distribution<IntType>::Generate( - URBG& g, // NOLINT(runtime/references) - const param_type& p) { - // sample e over [0, log_range]. Map the results of e to this: - // 0 => 0 - // 1 => [1, b-1] - // 2 => [b, (b^2)-1] - // n => [b^(n-1)..(b^n)-1] - const int e = absl::uniform_int_distribution<int>(0, p.log_range())(g); - if (e == 0) { - return 0; - } - const int d = e - 1; - - unsigned_type base_e, top_e; - if (p.base() == 2) { - base_e = static_cast<unsigned_type>(1) << d; - - top_e = (e >= std::numeric_limits<unsigned_type>::digits) - ? (std::numeric_limits<unsigned_type>::max)() - : (static_cast<unsigned_type>(1) << e) - 1; - } else { - const double r = std::pow(p.base(), d); - const double s = (r * p.base()) - 1.0; - - base_e = - (r > static_cast<double>((std::numeric_limits<unsigned_type>::max)())) - ? (std::numeric_limits<unsigned_type>::max)() - : static_cast<unsigned_type>(r); - - top_e = - (s > static_cast<double>((std::numeric_limits<unsigned_type>::max)())) - ? (std::numeric_limits<unsigned_type>::max)() - : static_cast<unsigned_type>(s); - } - - const unsigned_type lo = (base_e >= p.range()) ? p.range() : base_e; - const unsigned_type hi = (top_e >= p.range()) ? p.range() : top_e; - - // choose uniformly over [lo, hi] - return absl::uniform_int_distribution<result_type>(lo, hi)(g); -} - -template <typename CharT, typename Traits, typename IntType> -std::basic_ostream<CharT, Traits>& operator<<( - std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) - const log_uniform_int_distribution<IntType>& x) { - using stream_type = - typename random_internal::stream_format_type<IntType>::type; - auto saver = random_internal::make_ostream_state_saver(os); - os << static_cast<stream_type>((x.min)()) << os.fill() - << static_cast<stream_type>((x.max)()) << os.fill() - << static_cast<stream_type>(x.base()); - return os; -} - -template <typename CharT, typename Traits, typename IntType> -std::basic_istream<CharT, Traits>& operator>>( - std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) - log_uniform_int_distribution<IntType>& x) { // NOLINT(runtime/references) - using param_type = typename log_uniform_int_distribution<IntType>::param_type; - using result_type = - typename log_uniform_int_distribution<IntType>::result_type; - using stream_type = - typename random_internal::stream_format_type<IntType>::type; - - stream_type min; - stream_type max; - stream_type base; - - auto saver = random_internal::make_istream_state_saver(is); - is >> min >> max >> base; - if (!is.fail()) { - x.param(param_type(static_cast<result_type>(min), - static_cast<result_type>(max), - static_cast<result_type>(base))); - } - return is; -} - + } else { + // NOTE: Computing the logN(x) introduces error from 2 sources: + // 1. Conversion of int to double loses precision for values >= + // 2^53, which may cause some log() computations to operate on + // different values. + // 2. The error introduced by the division will cause the result + // to differ from the expected value. + // + // Thus a result which should equal K may equal K +/- epsilon, + // which can eliminate some values depending on where the bounds fall. + const double inv_log_base = 1.0 / std::log(base_); + const double log_range = std::log(static_cast<double>(range()) + 0.5); + log_range_ = static_cast<int>(std::ceil(inv_log_base * log_range)); + } + } + + result_type(min)() const { return min_; } + result_type(max)() const { return max_; } + result_type base() const { return base_; } + + friend bool operator==(const param_type& a, const param_type& b) { + return a.min_ == b.min_ && a.max_ == b.max_ && a.base_ == b.base_; + } + + friend bool operator!=(const param_type& a, const param_type& b) { + return !(a == b); + } + + private: + friend class log_uniform_int_distribution; + + int log_range() const { return log_range_; } + unsigned_type range() const { return range_; } + + result_type min_; + result_type max_; + result_type base_; + unsigned_type range_; // max - min + int log_range_; // ceil(logN(range_)) + + static_assert(std::is_integral<IntType>::value, + "Class-template absl::log_uniform_int_distribution<> must be " + "parameterized using an integral type."); + }; + + log_uniform_int_distribution() : log_uniform_int_distribution(0) {} + + explicit log_uniform_int_distribution( + result_type min, + result_type max = (std::numeric_limits<result_type>::max)(), + result_type base = 2) + : param_(min, max, base) {} + + explicit log_uniform_int_distribution(const param_type& p) : param_(p) {} + + void reset() {} + + // generating functions + template <typename URBG> + result_type operator()(URBG& g) { // NOLINT(runtime/references) + return (*this)(g, param_); + } + + template <typename URBG> + result_type operator()(URBG& g, // NOLINT(runtime/references) + const param_type& p) { + return (p.min)() + Generate(g, p); + } + + result_type(min)() const { return (param_.min)(); } + result_type(max)() const { return (param_.max)(); } + result_type base() const { return param_.base(); } + + param_type param() const { return param_; } + void param(const param_type& p) { param_ = p; } + + friend bool operator==(const log_uniform_int_distribution& a, + const log_uniform_int_distribution& b) { + return a.param_ == b.param_; + } + friend bool operator!=(const log_uniform_int_distribution& a, + const log_uniform_int_distribution& b) { + return a.param_ != b.param_; + } + + private: + // Returns a log-uniform variate in the range [0, p.range()]. The caller + // should add min() to shift the result to the correct range. + template <typename URNG> + unsigned_type Generate(URNG& g, // NOLINT(runtime/references) + const param_type& p); + + param_type param_; +}; + +template <typename IntType> +template <typename URBG> +typename log_uniform_int_distribution<IntType>::unsigned_type +log_uniform_int_distribution<IntType>::Generate( + URBG& g, // NOLINT(runtime/references) + const param_type& p) { + // sample e over [0, log_range]. Map the results of e to this: + // 0 => 0 + // 1 => [1, b-1] + // 2 => [b, (b^2)-1] + // n => [b^(n-1)..(b^n)-1] + const int e = absl::uniform_int_distribution<int>(0, p.log_range())(g); + if (e == 0) { + return 0; + } + const int d = e - 1; + + unsigned_type base_e, top_e; + if (p.base() == 2) { + base_e = static_cast<unsigned_type>(1) << d; + + top_e = (e >= std::numeric_limits<unsigned_type>::digits) + ? (std::numeric_limits<unsigned_type>::max)() + : (static_cast<unsigned_type>(1) << e) - 1; + } else { + const double r = std::pow(p.base(), d); + const double s = (r * p.base()) - 1.0; + + base_e = + (r > static_cast<double>((std::numeric_limits<unsigned_type>::max)())) + ? (std::numeric_limits<unsigned_type>::max)() + : static_cast<unsigned_type>(r); + + top_e = + (s > static_cast<double>((std::numeric_limits<unsigned_type>::max)())) + ? (std::numeric_limits<unsigned_type>::max)() + : static_cast<unsigned_type>(s); + } + + const unsigned_type lo = (base_e >= p.range()) ? p.range() : base_e; + const unsigned_type hi = (top_e >= p.range()) ? p.range() : top_e; + + // choose uniformly over [lo, hi] + return absl::uniform_int_distribution<result_type>(lo, hi)(g); +} + +template <typename CharT, typename Traits, typename IntType> +std::basic_ostream<CharT, Traits>& operator<<( + std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) + const log_uniform_int_distribution<IntType>& x) { + using stream_type = + typename random_internal::stream_format_type<IntType>::type; + auto saver = random_internal::make_ostream_state_saver(os); + os << static_cast<stream_type>((x.min)()) << os.fill() + << static_cast<stream_type>((x.max)()) << os.fill() + << static_cast<stream_type>(x.base()); + return os; +} + +template <typename CharT, typename Traits, typename IntType> +std::basic_istream<CharT, Traits>& operator>>( + std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) + log_uniform_int_distribution<IntType>& x) { // NOLINT(runtime/references) + using param_type = typename log_uniform_int_distribution<IntType>::param_type; + using result_type = + typename log_uniform_int_distribution<IntType>::result_type; + using stream_type = + typename random_internal::stream_format_type<IntType>::type; + + stream_type min; + stream_type max; + stream_type base; + + auto saver = random_internal::make_istream_state_saver(is); + is >> min >> max >> base; + if (!is.fail()) { + x.param(param_type(static_cast<result_type>(min), + static_cast<result_type>(max), + static_cast<result_type>(base))); + } + return is; +} + ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_LOG_UNIFORM_INT_DISTRIBUTION_H_ +} // namespace absl + +#endif // ABSL_RANDOM_LOG_UNIFORM_INT_DISTRIBUTION_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/poisson_distribution.h b/contrib/restricted/abseil-cpp/absl/random/poisson_distribution.h index 37389ead21..cb5f5d5d0f 100644 --- a/contrib/restricted/abseil-cpp/absl/random/poisson_distribution.h +++ b/contrib/restricted/abseil-cpp/absl/random/poisson_distribution.h @@ -1,258 +1,258 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_POISSON_DISTRIBUTION_H_ -#define ABSL_RANDOM_POISSON_DISTRIBUTION_H_ - -#include <cassert> -#include <cmath> -#include <istream> -#include <limits> -#include <ostream> -#include <type_traits> - -#include "absl/random/internal/fast_uniform_bits.h" -#include "absl/random/internal/fastmath.h" -#include "absl/random/internal/generate_real.h" -#include "absl/random/internal/iostream_state_saver.h" - -namespace absl { +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_POISSON_DISTRIBUTION_H_ +#define ABSL_RANDOM_POISSON_DISTRIBUTION_H_ + +#include <cassert> +#include <cmath> +#include <istream> +#include <limits> +#include <ostream> +#include <type_traits> + +#include "absl/random/internal/fast_uniform_bits.h" +#include "absl/random/internal/fastmath.h" +#include "absl/random/internal/generate_real.h" +#include "absl/random/internal/iostream_state_saver.h" + +namespace absl { ABSL_NAMESPACE_BEGIN - -// absl::poisson_distribution: -// Generates discrete variates conforming to a Poisson distribution. -// p(n) = (mean^n / n!) exp(-mean) -// -// Depending on the parameter, the distribution selects one of the following -// algorithms: -// * The standard algorithm, attributed to Knuth, extended using a split method -// for larger values -// * The "Ratio of Uniforms as a convenient method for sampling from classical -// discrete distributions", Stadlober, 1989. -// http://www.sciencedirect.com/science/article/pii/0377042790903495 -// -// NOTE: param_type.mean() is a double, which permits values larger than -// poisson_distribution<IntType>::max(), however this should be avoided and -// the distribution results are limited to the max() value. -// -// The goals of this implementation are to provide good performance while still -// beig thread-safe: This limits the implementation to not using lgamma provided -// by <math.h>. -// -template <typename IntType = int> -class poisson_distribution { - public: - using result_type = IntType; - - class param_type { - public: - using distribution_type = poisson_distribution; - explicit param_type(double mean = 1.0); - - double mean() const { return mean_; } - - friend bool operator==(const param_type& a, const param_type& b) { - return a.mean_ == b.mean_; - } - - friend bool operator!=(const param_type& a, const param_type& b) { - return !(a == b); - } - - private: - friend class poisson_distribution; - - double mean_; - double emu_; // e ^ -mean_ - double lmu_; // ln(mean_) - double s_; - double log_k_; - int split_; - - static_assert(std::is_integral<IntType>::value, - "Class-template absl::poisson_distribution<> must be " - "parameterized using an integral type."); - }; - - poisson_distribution() : poisson_distribution(1.0) {} - - explicit poisson_distribution(double mean) : param_(mean) {} - - explicit poisson_distribution(const param_type& p) : param_(p) {} - - void reset() {} - - // generating functions - template <typename URBG> - result_type operator()(URBG& g) { // NOLINT(runtime/references) - return (*this)(g, param_); - } - - template <typename URBG> - result_type operator()(URBG& g, // NOLINT(runtime/references) - const param_type& p); - - param_type param() const { return param_; } - void param(const param_type& p) { param_ = p; } - - result_type(min)() const { return 0; } - result_type(max)() const { return (std::numeric_limits<result_type>::max)(); } - - double mean() const { return param_.mean(); } - - friend bool operator==(const poisson_distribution& a, - const poisson_distribution& b) { - return a.param_ == b.param_; - } - friend bool operator!=(const poisson_distribution& a, - const poisson_distribution& b) { - return a.param_ != b.param_; - } - - private: - param_type param_; - random_internal::FastUniformBits<uint64_t> fast_u64_; -}; - -// ----------------------------------------------------------------------------- -// Implementation details follow -// ----------------------------------------------------------------------------- - -template <typename IntType> -poisson_distribution<IntType>::param_type::param_type(double mean) - : mean_(mean), split_(0) { - assert(mean >= 0); - assert(mean <= (std::numeric_limits<result_type>::max)()); - // As a defensive measure, avoid large values of the mean. The rejection - // algorithm used does not support very large values well. It my be worth - // changing algorithms to better deal with these cases. - assert(mean <= 1e10); - if (mean_ < 10) { - // For small lambda, use the knuth method. - split_ = 1; - emu_ = std::exp(-mean_); - } else if (mean_ <= 50) { - // Use split-knuth method. - split_ = 1 + static_cast<int>(mean_ / 10.0); - emu_ = std::exp(-mean_ / static_cast<double>(split_)); - } else { - // Use ratio of uniforms method. - constexpr double k2E = 0.7357588823428846; - constexpr double kSA = 0.4494580810294493; - - lmu_ = std::log(mean_); - double a = mean_ + 0.5; - s_ = kSA + std::sqrt(k2E * a); - const double mode = std::ceil(mean_) - 1; - log_k_ = lmu_ * mode - absl::random_internal::StirlingLogFactorial(mode); - } -} - -template <typename IntType> -template <typename URBG> -typename poisson_distribution<IntType>::result_type -poisson_distribution<IntType>::operator()( - URBG& g, // NOLINT(runtime/references) - const param_type& p) { - using random_internal::GeneratePositiveTag; - using random_internal::GenerateRealFromBits; - using random_internal::GenerateSignedTag; - - if (p.split_ != 0) { - // Use Knuth's algorithm with range splitting to avoid floating-point - // errors. Knuth's algorithm is: Ui is a sequence of uniform variates on - // (0,1); return the number of variates required for product(Ui) < - // exp(-lambda). - // - // The expected number of variates required for Knuth's method can be - // computed as follows: - // The expected value of U is 0.5, so solving for 0.5^n < exp(-lambda) gives - // the expected number of uniform variates - // required for a given lambda, which is: - // lambda = [2, 5, 9, 10, 11, 12, 13, 14, 15, 16, 17] - // n = [3, 8, 13, 15, 16, 18, 19, 21, 22, 24, 25] - // - result_type n = 0; - for (int split = p.split_; split > 0; --split) { - double r = 1.0; - do { - r *= GenerateRealFromBits<double, GeneratePositiveTag, true>( - fast_u64_(g)); // U(-1, 0) - ++n; - } while (r > p.emu_); - --n; - } - return n; - } - - // Use ratio of uniforms method. - // - // Let u ~ Uniform(0, 1), v ~ Uniform(-1, 1), - // a = lambda + 1/2, - // s = 1.5 - sqrt(3/e) + sqrt(2(lambda + 1/2)/e), - // x = s * v/u + a. - // P(floor(x) = k | u^2 < f(floor(x))/k), where - // f(m) = lambda^m exp(-lambda)/ m!, for 0 <= m, and f(m) = 0 otherwise, - // and k = max(f). - const double a = p.mean_ + 0.5; - for (;;) { - const double u = GenerateRealFromBits<double, GeneratePositiveTag, false>( - fast_u64_(g)); // U(0, 1) - const double v = GenerateRealFromBits<double, GenerateSignedTag, false>( - fast_u64_(g)); // U(-1, 1) - - const double x = std::floor(p.s_ * v / u + a); - if (x < 0) continue; // f(negative) = 0 - const double rhs = x * p.lmu_; - // clang-format off - double s = (x <= 1.0) ? 0.0 - : (x == 2.0) ? 0.693147180559945 - : absl::random_internal::StirlingLogFactorial(x); - // clang-format on - const double lhs = 2.0 * std::log(u) + p.log_k_ + s; - if (lhs < rhs) { - return x > (max)() ? (max)() - : static_cast<result_type>(x); // f(x)/k >= u^2 - } - } -} - -template <typename CharT, typename Traits, typename IntType> -std::basic_ostream<CharT, Traits>& operator<<( - std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) - const poisson_distribution<IntType>& x) { - auto saver = random_internal::make_ostream_state_saver(os); - os.precision(random_internal::stream_precision_helper<double>::kPrecision); - os << x.mean(); - return os; -} - -template <typename CharT, typename Traits, typename IntType> -std::basic_istream<CharT, Traits>& operator>>( - std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) - poisson_distribution<IntType>& x) { // NOLINT(runtime/references) - using param_type = typename poisson_distribution<IntType>::param_type; - - auto saver = random_internal::make_istream_state_saver(is); - double mean = random_internal::read_floating_point<double>(is); - if (!is.fail()) { - x.param(param_type(mean)); - } - return is; -} - + +// absl::poisson_distribution: +// Generates discrete variates conforming to a Poisson distribution. +// p(n) = (mean^n / n!) exp(-mean) +// +// Depending on the parameter, the distribution selects one of the following +// algorithms: +// * The standard algorithm, attributed to Knuth, extended using a split method +// for larger values +// * The "Ratio of Uniforms as a convenient method for sampling from classical +// discrete distributions", Stadlober, 1989. +// http://www.sciencedirect.com/science/article/pii/0377042790903495 +// +// NOTE: param_type.mean() is a double, which permits values larger than +// poisson_distribution<IntType>::max(), however this should be avoided and +// the distribution results are limited to the max() value. +// +// The goals of this implementation are to provide good performance while still +// beig thread-safe: This limits the implementation to not using lgamma provided +// by <math.h>. +// +template <typename IntType = int> +class poisson_distribution { + public: + using result_type = IntType; + + class param_type { + public: + using distribution_type = poisson_distribution; + explicit param_type(double mean = 1.0); + + double mean() const { return mean_; } + + friend bool operator==(const param_type& a, const param_type& b) { + return a.mean_ == b.mean_; + } + + friend bool operator!=(const param_type& a, const param_type& b) { + return !(a == b); + } + + private: + friend class poisson_distribution; + + double mean_; + double emu_; // e ^ -mean_ + double lmu_; // ln(mean_) + double s_; + double log_k_; + int split_; + + static_assert(std::is_integral<IntType>::value, + "Class-template absl::poisson_distribution<> must be " + "parameterized using an integral type."); + }; + + poisson_distribution() : poisson_distribution(1.0) {} + + explicit poisson_distribution(double mean) : param_(mean) {} + + explicit poisson_distribution(const param_type& p) : param_(p) {} + + void reset() {} + + // generating functions + template <typename URBG> + result_type operator()(URBG& g) { // NOLINT(runtime/references) + return (*this)(g, param_); + } + + template <typename URBG> + result_type operator()(URBG& g, // NOLINT(runtime/references) + const param_type& p); + + param_type param() const { return param_; } + void param(const param_type& p) { param_ = p; } + + result_type(min)() const { return 0; } + result_type(max)() const { return (std::numeric_limits<result_type>::max)(); } + + double mean() const { return param_.mean(); } + + friend bool operator==(const poisson_distribution& a, + const poisson_distribution& b) { + return a.param_ == b.param_; + } + friend bool operator!=(const poisson_distribution& a, + const poisson_distribution& b) { + return a.param_ != b.param_; + } + + private: + param_type param_; + random_internal::FastUniformBits<uint64_t> fast_u64_; +}; + +// ----------------------------------------------------------------------------- +// Implementation details follow +// ----------------------------------------------------------------------------- + +template <typename IntType> +poisson_distribution<IntType>::param_type::param_type(double mean) + : mean_(mean), split_(0) { + assert(mean >= 0); + assert(mean <= (std::numeric_limits<result_type>::max)()); + // As a defensive measure, avoid large values of the mean. The rejection + // algorithm used does not support very large values well. It my be worth + // changing algorithms to better deal with these cases. + assert(mean <= 1e10); + if (mean_ < 10) { + // For small lambda, use the knuth method. + split_ = 1; + emu_ = std::exp(-mean_); + } else if (mean_ <= 50) { + // Use split-knuth method. + split_ = 1 + static_cast<int>(mean_ / 10.0); + emu_ = std::exp(-mean_ / static_cast<double>(split_)); + } else { + // Use ratio of uniforms method. + constexpr double k2E = 0.7357588823428846; + constexpr double kSA = 0.4494580810294493; + + lmu_ = std::log(mean_); + double a = mean_ + 0.5; + s_ = kSA + std::sqrt(k2E * a); + const double mode = std::ceil(mean_) - 1; + log_k_ = lmu_ * mode - absl::random_internal::StirlingLogFactorial(mode); + } +} + +template <typename IntType> +template <typename URBG> +typename poisson_distribution<IntType>::result_type +poisson_distribution<IntType>::operator()( + URBG& g, // NOLINT(runtime/references) + const param_type& p) { + using random_internal::GeneratePositiveTag; + using random_internal::GenerateRealFromBits; + using random_internal::GenerateSignedTag; + + if (p.split_ != 0) { + // Use Knuth's algorithm with range splitting to avoid floating-point + // errors. Knuth's algorithm is: Ui is a sequence of uniform variates on + // (0,1); return the number of variates required for product(Ui) < + // exp(-lambda). + // + // The expected number of variates required for Knuth's method can be + // computed as follows: + // The expected value of U is 0.5, so solving for 0.5^n < exp(-lambda) gives + // the expected number of uniform variates + // required for a given lambda, which is: + // lambda = [2, 5, 9, 10, 11, 12, 13, 14, 15, 16, 17] + // n = [3, 8, 13, 15, 16, 18, 19, 21, 22, 24, 25] + // + result_type n = 0; + for (int split = p.split_; split > 0; --split) { + double r = 1.0; + do { + r *= GenerateRealFromBits<double, GeneratePositiveTag, true>( + fast_u64_(g)); // U(-1, 0) + ++n; + } while (r > p.emu_); + --n; + } + return n; + } + + // Use ratio of uniforms method. + // + // Let u ~ Uniform(0, 1), v ~ Uniform(-1, 1), + // a = lambda + 1/2, + // s = 1.5 - sqrt(3/e) + sqrt(2(lambda + 1/2)/e), + // x = s * v/u + a. + // P(floor(x) = k | u^2 < f(floor(x))/k), where + // f(m) = lambda^m exp(-lambda)/ m!, for 0 <= m, and f(m) = 0 otherwise, + // and k = max(f). + const double a = p.mean_ + 0.5; + for (;;) { + const double u = GenerateRealFromBits<double, GeneratePositiveTag, false>( + fast_u64_(g)); // U(0, 1) + const double v = GenerateRealFromBits<double, GenerateSignedTag, false>( + fast_u64_(g)); // U(-1, 1) + + const double x = std::floor(p.s_ * v / u + a); + if (x < 0) continue; // f(negative) = 0 + const double rhs = x * p.lmu_; + // clang-format off + double s = (x <= 1.0) ? 0.0 + : (x == 2.0) ? 0.693147180559945 + : absl::random_internal::StirlingLogFactorial(x); + // clang-format on + const double lhs = 2.0 * std::log(u) + p.log_k_ + s; + if (lhs < rhs) { + return x > (max)() ? (max)() + : static_cast<result_type>(x); // f(x)/k >= u^2 + } + } +} + +template <typename CharT, typename Traits, typename IntType> +std::basic_ostream<CharT, Traits>& operator<<( + std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) + const poisson_distribution<IntType>& x) { + auto saver = random_internal::make_ostream_state_saver(os); + os.precision(random_internal::stream_precision_helper<double>::kPrecision); + os << x.mean(); + return os; +} + +template <typename CharT, typename Traits, typename IntType> +std::basic_istream<CharT, Traits>& operator>>( + std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) + poisson_distribution<IntType>& x) { // NOLINT(runtime/references) + using param_type = typename poisson_distribution<IntType>::param_type; + + auto saver = random_internal::make_istream_state_saver(is); + double mean = random_internal::read_floating_point<double>(is); + if (!is.fail()) { + x.param(param_type(mean)); + } + return is; +} + ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_POISSON_DISTRIBUTION_H_ +} // namespace absl + +#endif // ABSL_RANDOM_POISSON_DISTRIBUTION_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/random.h b/contrib/restricted/abseil-cpp/absl/random/random.h index fc2da78cd5..71b6309288 100644 --- a/contrib/restricted/abseil-cpp/absl/random/random.h +++ b/contrib/restricted/abseil-cpp/absl/random/random.h @@ -1,189 +1,189 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// ----------------------------------------------------------------------------- -// File: random.h -// ----------------------------------------------------------------------------- -// -// This header defines the recommended Uniform Random Bit Generator (URBG) -// types for use within the Abseil Random library. These types are not -// suitable for security-related use-cases, but should suffice for most other -// uses of generating random values. -// -// The Abseil random library provides the following URBG types: -// -// * BitGen, a good general-purpose bit generator, optimized for generating -// random (but not cryptographically secure) values -// * InsecureBitGen, a slightly faster, though less random, bit generator, for -// cases where the existing BitGen is a drag on performance. - -#ifndef ABSL_RANDOM_RANDOM_H_ -#define ABSL_RANDOM_RANDOM_H_ - -#include <random> - -#include "absl/random/distributions.h" // IWYU pragma: export -#include "absl/random/internal/nonsecure_base.h" // IWYU pragma: export -#include "absl/random/internal/pcg_engine.h" // IWYU pragma: export -#include "absl/random/internal/pool_urbg.h" -#include "absl/random/internal/randen_engine.h" -#include "absl/random/seed_sequences.h" // IWYU pragma: export - -namespace absl { +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: random.h +// ----------------------------------------------------------------------------- +// +// This header defines the recommended Uniform Random Bit Generator (URBG) +// types for use within the Abseil Random library. These types are not +// suitable for security-related use-cases, but should suffice for most other +// uses of generating random values. +// +// The Abseil random library provides the following URBG types: +// +// * BitGen, a good general-purpose bit generator, optimized for generating +// random (but not cryptographically secure) values +// * InsecureBitGen, a slightly faster, though less random, bit generator, for +// cases where the existing BitGen is a drag on performance. + +#ifndef ABSL_RANDOM_RANDOM_H_ +#define ABSL_RANDOM_RANDOM_H_ + +#include <random> + +#include "absl/random/distributions.h" // IWYU pragma: export +#include "absl/random/internal/nonsecure_base.h" // IWYU pragma: export +#include "absl/random/internal/pcg_engine.h" // IWYU pragma: export +#include "absl/random/internal/pool_urbg.h" +#include "absl/random/internal/randen_engine.h" +#include "absl/random/seed_sequences.h" // IWYU pragma: export + +namespace absl { ABSL_NAMESPACE_BEGIN - -// ----------------------------------------------------------------------------- -// absl::BitGen -// ----------------------------------------------------------------------------- -// -// `absl::BitGen` is a general-purpose random bit generator for generating -// random values for use within the Abseil random library. Typically, you use a -// bit generator in combination with a distribution to provide random values. -// -// Example: -// -// // Create an absl::BitGen. There is no need to seed this bit generator. -// absl::BitGen gen; -// -// // Generate an integer value in the closed interval [1,6] -// int die_roll = absl::uniform_int_distribution<int>(1, 6)(gen); -// -// `absl::BitGen` is seeded by default with non-deterministic data to produce -// different sequences of random values across different instances, including -// different binary invocations. This behavior is different than the standard -// library bit generators, which use golden values as their seeds. Default -// construction intentionally provides no stability guarantees, to avoid -// accidental dependence on such a property. -// -// `absl::BitGen` may be constructed with an optional seed sequence type, -// conforming to [rand.req.seed_seq], which will be mixed with additional -// non-deterministic data. -// -// Example: -// -// // Create an absl::BitGen using an std::seed_seq seed sequence -// std::seed_seq seq{1,2,3}; -// absl::BitGen gen_with_seed(seq); -// -// // Generate an integer value in the closed interval [1,6] -// int die_roll2 = absl::uniform_int_distribution<int>(1, 6)(gen_with_seed); -// -// `absl::BitGen` meets the requirements of the Uniform Random Bit Generator -// (URBG) concept as per the C++17 standard [rand.req.urng] though differs -// slightly with [rand.req.eng]. Like its standard library equivalents (e.g. -// `std::mersenne_twister_engine`) `absl::BitGen` is not cryptographically -// secure. -// -// Constructing two `absl::BitGen`s with the same seed sequence in the same -// binary will produce the same sequence of variates within the same binary, but -// need not do so across multiple binary invocations. -// -// This type has been optimized to perform better than Mersenne Twister -// (https://en.wikipedia.org/wiki/Mersenne_Twister) and many other complex URBG -// types on modern x86, ARM, and PPC architectures. -// -// This type is thread-compatible, but not thread-safe. - -// --------------------------------------------------------------------------- -// absl::BitGen member functions -// --------------------------------------------------------------------------- - -// absl::BitGen::operator()() -// -// Calls the BitGen, returning a generated value. - -// absl::BitGen::min() -// -// Returns the smallest possible value from this bit generator. - -// absl::BitGen::max() -// + +// ----------------------------------------------------------------------------- +// absl::BitGen +// ----------------------------------------------------------------------------- +// +// `absl::BitGen` is a general-purpose random bit generator for generating +// random values for use within the Abseil random library. Typically, you use a +// bit generator in combination with a distribution to provide random values. +// +// Example: +// +// // Create an absl::BitGen. There is no need to seed this bit generator. +// absl::BitGen gen; +// +// // Generate an integer value in the closed interval [1,6] +// int die_roll = absl::uniform_int_distribution<int>(1, 6)(gen); +// +// `absl::BitGen` is seeded by default with non-deterministic data to produce +// different sequences of random values across different instances, including +// different binary invocations. This behavior is different than the standard +// library bit generators, which use golden values as their seeds. Default +// construction intentionally provides no stability guarantees, to avoid +// accidental dependence on such a property. +// +// `absl::BitGen` may be constructed with an optional seed sequence type, +// conforming to [rand.req.seed_seq], which will be mixed with additional +// non-deterministic data. +// +// Example: +// +// // Create an absl::BitGen using an std::seed_seq seed sequence +// std::seed_seq seq{1,2,3}; +// absl::BitGen gen_with_seed(seq); +// +// // Generate an integer value in the closed interval [1,6] +// int die_roll2 = absl::uniform_int_distribution<int>(1, 6)(gen_with_seed); +// +// `absl::BitGen` meets the requirements of the Uniform Random Bit Generator +// (URBG) concept as per the C++17 standard [rand.req.urng] though differs +// slightly with [rand.req.eng]. Like its standard library equivalents (e.g. +// `std::mersenne_twister_engine`) `absl::BitGen` is not cryptographically +// secure. +// +// Constructing two `absl::BitGen`s with the same seed sequence in the same +// binary will produce the same sequence of variates within the same binary, but +// need not do so across multiple binary invocations. +// +// This type has been optimized to perform better than Mersenne Twister +// (https://en.wikipedia.org/wiki/Mersenne_Twister) and many other complex URBG +// types on modern x86, ARM, and PPC architectures. +// +// This type is thread-compatible, but not thread-safe. + +// --------------------------------------------------------------------------- +// absl::BitGen member functions +// --------------------------------------------------------------------------- + +// absl::BitGen::operator()() +// +// Calls the BitGen, returning a generated value. + +// absl::BitGen::min() +// +// Returns the smallest possible value from this bit generator. + +// absl::BitGen::max() +// // Returns the largest possible value from this bit generator. - -// absl::BitGen::discard(num) -// -// Advances the internal state of this bit generator by `num` times, and -// discards the intermediate results. -// --------------------------------------------------------------------------- - -using BitGen = random_internal::NonsecureURBGBase< - random_internal::randen_engine<uint64_t>>; - -// ----------------------------------------------------------------------------- -// absl::InsecureBitGen -// ----------------------------------------------------------------------------- -// -// `absl::InsecureBitGen` is an efficient random bit generator for generating -// random values, recommended only for performance-sensitive use cases where -// `absl::BitGen` is not satisfactory when compute-bounded by bit generation -// costs. -// -// Example: -// -// // Create an absl::InsecureBitGen -// absl::InsecureBitGen gen; -// for (size_t i = 0; i < 1000000; i++) { -// -// // Generate a bunch of random values from some complex distribution -// auto my_rnd = some_distribution(gen, 1, 1000); -// } -// -// Like `absl::BitGen`, `absl::InsecureBitGen` is seeded by default with -// non-deterministic data to produce different sequences of random values across -// different instances, including different binary invocations. (This behavior -// is different than the standard library bit generators, which use golden -// values as their seeds.) -// -// `absl::InsecureBitGen` may be constructed with an optional seed sequence -// type, conforming to [rand.req.seed_seq], which will be mixed with additional -// non-deterministic data. (See std_seed_seq.h for more information.) -// -// `absl::InsecureBitGen` meets the requirements of the Uniform Random Bit -// Generator (URBG) concept as per the C++17 standard [rand.req.urng] though -// its implementation differs slightly with [rand.req.eng]. Like its standard -// library equivalents (e.g. `std::mersenne_twister_engine`) -// `absl::InsecureBitGen` is not cryptographically secure. -// -// Prefer `absl::BitGen` over `absl::InsecureBitGen` as the general type is -// often fast enough for the vast majority of applications. - -using InsecureBitGen = - random_internal::NonsecureURBGBase<random_internal::pcg64_2018_engine>; - -// --------------------------------------------------------------------------- -// absl::InsecureBitGen member functions -// --------------------------------------------------------------------------- - -// absl::InsecureBitGen::operator()() -// -// Calls the InsecureBitGen, returning a generated value. - -// absl::InsecureBitGen::min() -// -// Returns the smallest possible value from this bit generator. - -// absl::InsecureBitGen::max() -// -// Returns the largest possible value from this bit generator. - -// absl::InsecureBitGen::discard(num) -// -// Advances the internal state of this bit generator by `num` times, and -// discards the intermediate results. -// --------------------------------------------------------------------------- - + +// absl::BitGen::discard(num) +// +// Advances the internal state of this bit generator by `num` times, and +// discards the intermediate results. +// --------------------------------------------------------------------------- + +using BitGen = random_internal::NonsecureURBGBase< + random_internal::randen_engine<uint64_t>>; + +// ----------------------------------------------------------------------------- +// absl::InsecureBitGen +// ----------------------------------------------------------------------------- +// +// `absl::InsecureBitGen` is an efficient random bit generator for generating +// random values, recommended only for performance-sensitive use cases where +// `absl::BitGen` is not satisfactory when compute-bounded by bit generation +// costs. +// +// Example: +// +// // Create an absl::InsecureBitGen +// absl::InsecureBitGen gen; +// for (size_t i = 0; i < 1000000; i++) { +// +// // Generate a bunch of random values from some complex distribution +// auto my_rnd = some_distribution(gen, 1, 1000); +// } +// +// Like `absl::BitGen`, `absl::InsecureBitGen` is seeded by default with +// non-deterministic data to produce different sequences of random values across +// different instances, including different binary invocations. (This behavior +// is different than the standard library bit generators, which use golden +// values as their seeds.) +// +// `absl::InsecureBitGen` may be constructed with an optional seed sequence +// type, conforming to [rand.req.seed_seq], which will be mixed with additional +// non-deterministic data. (See std_seed_seq.h for more information.) +// +// `absl::InsecureBitGen` meets the requirements of the Uniform Random Bit +// Generator (URBG) concept as per the C++17 standard [rand.req.urng] though +// its implementation differs slightly with [rand.req.eng]. Like its standard +// library equivalents (e.g. `std::mersenne_twister_engine`) +// `absl::InsecureBitGen` is not cryptographically secure. +// +// Prefer `absl::BitGen` over `absl::InsecureBitGen` as the general type is +// often fast enough for the vast majority of applications. + +using InsecureBitGen = + random_internal::NonsecureURBGBase<random_internal::pcg64_2018_engine>; + +// --------------------------------------------------------------------------- +// absl::InsecureBitGen member functions +// --------------------------------------------------------------------------- + +// absl::InsecureBitGen::operator()() +// +// Calls the InsecureBitGen, returning a generated value. + +// absl::InsecureBitGen::min() +// +// Returns the smallest possible value from this bit generator. + +// absl::InsecureBitGen::max() +// +// Returns the largest possible value from this bit generator. + +// absl::InsecureBitGen::discard(num) +// +// Advances the internal state of this bit generator by `num` times, and +// discards the intermediate results. +// --------------------------------------------------------------------------- + ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_RANDOM_H_ +} // namespace absl + +#endif // ABSL_RANDOM_RANDOM_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/seed_gen_exception.cc b/contrib/restricted/abseil-cpp/absl/random/seed_gen_exception.cc index 31c2d992f1..fdcb54a86c 100644 --- a/contrib/restricted/abseil-cpp/absl/random/seed_gen_exception.cc +++ b/contrib/restricted/abseil-cpp/absl/random/seed_gen_exception.cc @@ -1,46 +1,46 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "absl/random/seed_gen_exception.h" - -#include <iostream> - -#include "absl/base/config.h" - -namespace absl { +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/random/seed_gen_exception.h" + +#include <iostream> + +#include "absl/base/config.h" + +namespace absl { ABSL_NAMESPACE_BEGIN - -static constexpr const char kExceptionMessage[] = - "Failed generating seed-material for URBG."; - -SeedGenException::~SeedGenException() = default; - -const char* SeedGenException::what() const noexcept { - return kExceptionMessage; -} - -namespace random_internal { - -void ThrowSeedGenException() { -#ifdef ABSL_HAVE_EXCEPTIONS - throw absl::SeedGenException(); -#else - std::cerr << kExceptionMessage << std::endl; - std::terminate(); -#endif -} - -} // namespace random_internal + +static constexpr const char kExceptionMessage[] = + "Failed generating seed-material for URBG."; + +SeedGenException::~SeedGenException() = default; + +const char* SeedGenException::what() const noexcept { + return kExceptionMessage; +} + +namespace random_internal { + +void ThrowSeedGenException() { +#ifdef ABSL_HAVE_EXCEPTIONS + throw absl::SeedGenException(); +#else + std::cerr << kExceptionMessage << std::endl; + std::terminate(); +#endif +} + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl +} // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/random/seed_gen_exception.h b/contrib/restricted/abseil-cpp/absl/random/seed_gen_exception.h index 9b1e783de5..5353900564 100644 --- a/contrib/restricted/abseil-cpp/absl/random/seed_gen_exception.h +++ b/contrib/restricted/abseil-cpp/absl/random/seed_gen_exception.h @@ -1,55 +1,55 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// ----------------------------------------------------------------------------- -// File: seed_gen_exception.h -// ----------------------------------------------------------------------------- -// -// This header defines an exception class which may be thrown if unpredictable -// events prevent the derivation of suitable seed-material for constructing a -// bit generator conforming to [rand.req.urng] (eg. entropy cannot be read from -// /dev/urandom on a Unix-based system). -// -// Note: if exceptions are disabled, `std::terminate()` is called instead. - -#ifndef ABSL_RANDOM_SEED_GEN_EXCEPTION_H_ -#define ABSL_RANDOM_SEED_GEN_EXCEPTION_H_ - -#include <exception> - +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: seed_gen_exception.h +// ----------------------------------------------------------------------------- +// +// This header defines an exception class which may be thrown if unpredictable +// events prevent the derivation of suitable seed-material for constructing a +// bit generator conforming to [rand.req.urng] (eg. entropy cannot be read from +// /dev/urandom on a Unix-based system). +// +// Note: if exceptions are disabled, `std::terminate()` is called instead. + +#ifndef ABSL_RANDOM_SEED_GEN_EXCEPTION_H_ +#define ABSL_RANDOM_SEED_GEN_EXCEPTION_H_ + +#include <exception> + #include "absl/base/config.h" -namespace absl { +namespace absl { ABSL_NAMESPACE_BEGIN - -//------------------------------------------------------------------------------ -// SeedGenException -//------------------------------------------------------------------------------ -class SeedGenException : public std::exception { - public: - SeedGenException() = default; - ~SeedGenException() override; - const char* what() const noexcept override; -}; - -namespace random_internal { - -// throw delegator -[[noreturn]] void ThrowSeedGenException(); - -} // namespace random_internal + +//------------------------------------------------------------------------------ +// SeedGenException +//------------------------------------------------------------------------------ +class SeedGenException : public std::exception { + public: + SeedGenException() = default; + ~SeedGenException() override; + const char* what() const noexcept override; +}; + +namespace random_internal { + +// throw delegator +[[noreturn]] void ThrowSeedGenException(); + +} // namespace random_internal ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_SEED_GEN_EXCEPTION_H_ +} // namespace absl + +#endif // ABSL_RANDOM_SEED_GEN_EXCEPTION_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/seed_gen_exception/ya.make b/contrib/restricted/abseil-cpp/absl/random/seed_gen_exception/ya.make index 988901e40b..6d9b4a7b19 100644 --- a/contrib/restricted/abseil-cpp/absl/random/seed_gen_exception/ya.make +++ b/contrib/restricted/abseil-cpp/absl/random/seed_gen_exception/ya.make @@ -1,29 +1,29 @@ -# Generated by devtools/yamaker. - -LIBRARY() - +# Generated by devtools/yamaker. + +LIBRARY() + WITHOUT_LICENSE_TEXTS() -OWNER(g:cpp-contrib) - -LICENSE(Apache-2.0) - -ADDINCL( - GLOBAL contrib/restricted/abseil-cpp -) - -NO_COMPILER_WARNINGS() - -NO_UTIL() - +OWNER(g:cpp-contrib) + +LICENSE(Apache-2.0) + +ADDINCL( + GLOBAL contrib/restricted/abseil-cpp +) + +NO_COMPILER_WARNINGS() + +NO_UTIL() + CFLAGS( -DNOMINMAX ) -SRCDIR(contrib/restricted/abseil-cpp/absl/random) - -SRCS( - seed_gen_exception.cc -) - -END() +SRCDIR(contrib/restricted/abseil-cpp/absl/random) + +SRCS( + seed_gen_exception.cc +) + +END() diff --git a/contrib/restricted/abseil-cpp/absl/random/seed_sequences.cc b/contrib/restricted/abseil-cpp/absl/random/seed_sequences.cc index b811932796..426eafd3c8 100644 --- a/contrib/restricted/abseil-cpp/absl/random/seed_sequences.cc +++ b/contrib/restricted/abseil-cpp/absl/random/seed_sequences.cc @@ -1,29 +1,29 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "absl/random/seed_sequences.h" - -#include "absl/random/internal/pool_urbg.h" - -namespace absl { +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/random/seed_sequences.h" + +#include "absl/random/internal/pool_urbg.h" + +namespace absl { ABSL_NAMESPACE_BEGIN - -SeedSeq MakeSeedSeq() { - SeedSeq::result_type seed_material[8]; - random_internal::RandenPool<uint32_t>::Fill(absl::MakeSpan(seed_material)); - return SeedSeq(std::begin(seed_material), std::end(seed_material)); -} - + +SeedSeq MakeSeedSeq() { + SeedSeq::result_type seed_material[8]; + random_internal::RandenPool<uint32_t>::Fill(absl::MakeSpan(seed_material)); + return SeedSeq(std::begin(seed_material), std::end(seed_material)); +} + ABSL_NAMESPACE_END -} // namespace absl +} // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/random/seed_sequences.h b/contrib/restricted/abseil-cpp/absl/random/seed_sequences.h index 48e98829e2..ff1340cc8e 100644 --- a/contrib/restricted/abseil-cpp/absl/random/seed_sequences.h +++ b/contrib/restricted/abseil-cpp/absl/random/seed_sequences.h @@ -1,110 +1,110 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// ----------------------------------------------------------------------------- -// File: seed_sequences.h -// ----------------------------------------------------------------------------- -// -// This header contains utilities for creating and working with seed sequences -// conforming to [rand.req.seedseq]. In general, direct construction of seed -// sequences is discouraged, but use-cases for construction of identical bit -// generators (using the same seed sequence) may be helpful (e.g. replaying a -// simulation whose state is derived from variates of a bit generator). - -#ifndef ABSL_RANDOM_SEED_SEQUENCES_H_ -#define ABSL_RANDOM_SEED_SEQUENCES_H_ - -#include <iterator> -#include <random> - -#include "absl/random/internal/salted_seed_seq.h" -#include "absl/random/internal/seed_material.h" -#include "absl/random/seed_gen_exception.h" -#include "absl/types/span.h" - -namespace absl { +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: seed_sequences.h +// ----------------------------------------------------------------------------- +// +// This header contains utilities for creating and working with seed sequences +// conforming to [rand.req.seedseq]. In general, direct construction of seed +// sequences is discouraged, but use-cases for construction of identical bit +// generators (using the same seed sequence) may be helpful (e.g. replaying a +// simulation whose state is derived from variates of a bit generator). + +#ifndef ABSL_RANDOM_SEED_SEQUENCES_H_ +#define ABSL_RANDOM_SEED_SEQUENCES_H_ + +#include <iterator> +#include <random> + +#include "absl/random/internal/salted_seed_seq.h" +#include "absl/random/internal/seed_material.h" +#include "absl/random/seed_gen_exception.h" +#include "absl/types/span.h" + +namespace absl { ABSL_NAMESPACE_BEGIN - -// ----------------------------------------------------------------------------- -// absl::SeedSeq -// ----------------------------------------------------------------------------- -// -// `absl::SeedSeq` constructs a seed sequence according to [rand.req.seedseq] -// for use within bit generators. `absl::SeedSeq`, unlike `std::seed_seq` -// additionally salts the generated seeds with extra implementation-defined -// entropy. For that reason, you can use `absl::SeedSeq` in combination with -// standard library bit generators (e.g. `std::mt19937`) to introduce -// non-determinism in your seeds. -// -// Example: -// -// absl::SeedSeq my_seed_seq({a, b, c}); -// std::mt19937 my_bitgen(my_seed_seq); -// -using SeedSeq = random_internal::SaltedSeedSeq<std::seed_seq>; - -// ----------------------------------------------------------------------------- -// absl::CreateSeedSeqFrom(bitgen*) -// ----------------------------------------------------------------------------- -// -// Constructs a seed sequence conforming to [rand.req.seedseq] using variates -// produced by a provided bit generator. -// -// You should generally avoid direct construction of seed sequences, but -// use-cases for reuse of a seed sequence to construct identical bit generators -// may be helpful (eg. replaying a simulation whose state is derived from bit -// generator values). -// -// If bitgen == nullptr, then behavior is undefined. -// -// Example: -// -// absl::BitGen my_bitgen; -// auto seed_seq = absl::CreateSeedSeqFrom(&my_bitgen); -// absl::BitGen new_engine(seed_seq); // derived from my_bitgen, but not -// // correlated. -// -template <typename URBG> -SeedSeq CreateSeedSeqFrom(URBG* urbg) { - SeedSeq::result_type - seed_material[random_internal::kEntropyBlocksNeeded]; - - if (!random_internal::ReadSeedMaterialFromURBG( - urbg, absl::MakeSpan(seed_material))) { - random_internal::ThrowSeedGenException(); - } - return SeedSeq(std::begin(seed_material), std::end(seed_material)); -} - -// ----------------------------------------------------------------------------- -// absl::MakeSeedSeq() -// ----------------------------------------------------------------------------- -// -// Constructs an `absl::SeedSeq` salting the generated values using -// implementation-defined entropy. The returned sequence can be used to create -// equivalent bit generators correlated using this sequence. -// -// Example: -// -// auto my_seed_seq = absl::MakeSeedSeq(); -// std::mt19937 rng1(my_seed_seq); -// std::mt19937 rng2(my_seed_seq); -// EXPECT_EQ(rng1(), rng2()); -// -SeedSeq MakeSeedSeq(); - + +// ----------------------------------------------------------------------------- +// absl::SeedSeq +// ----------------------------------------------------------------------------- +// +// `absl::SeedSeq` constructs a seed sequence according to [rand.req.seedseq] +// for use within bit generators. `absl::SeedSeq`, unlike `std::seed_seq` +// additionally salts the generated seeds with extra implementation-defined +// entropy. For that reason, you can use `absl::SeedSeq` in combination with +// standard library bit generators (e.g. `std::mt19937`) to introduce +// non-determinism in your seeds. +// +// Example: +// +// absl::SeedSeq my_seed_seq({a, b, c}); +// std::mt19937 my_bitgen(my_seed_seq); +// +using SeedSeq = random_internal::SaltedSeedSeq<std::seed_seq>; + +// ----------------------------------------------------------------------------- +// absl::CreateSeedSeqFrom(bitgen*) +// ----------------------------------------------------------------------------- +// +// Constructs a seed sequence conforming to [rand.req.seedseq] using variates +// produced by a provided bit generator. +// +// You should generally avoid direct construction of seed sequences, but +// use-cases for reuse of a seed sequence to construct identical bit generators +// may be helpful (eg. replaying a simulation whose state is derived from bit +// generator values). +// +// If bitgen == nullptr, then behavior is undefined. +// +// Example: +// +// absl::BitGen my_bitgen; +// auto seed_seq = absl::CreateSeedSeqFrom(&my_bitgen); +// absl::BitGen new_engine(seed_seq); // derived from my_bitgen, but not +// // correlated. +// +template <typename URBG> +SeedSeq CreateSeedSeqFrom(URBG* urbg) { + SeedSeq::result_type + seed_material[random_internal::kEntropyBlocksNeeded]; + + if (!random_internal::ReadSeedMaterialFromURBG( + urbg, absl::MakeSpan(seed_material))) { + random_internal::ThrowSeedGenException(); + } + return SeedSeq(std::begin(seed_material), std::end(seed_material)); +} + +// ----------------------------------------------------------------------------- +// absl::MakeSeedSeq() +// ----------------------------------------------------------------------------- +// +// Constructs an `absl::SeedSeq` salting the generated values using +// implementation-defined entropy. The returned sequence can be used to create +// equivalent bit generators correlated using this sequence. +// +// Example: +// +// auto my_seed_seq = absl::MakeSeedSeq(); +// std::mt19937 rng1(my_seed_seq); +// std::mt19937 rng2(my_seed_seq); +// EXPECT_EQ(rng1(), rng2()); +// +SeedSeq MakeSeedSeq(); + ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_SEED_SEQUENCES_H_ +} // namespace absl + +#endif // ABSL_RANDOM_SEED_SEQUENCES_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/seed_sequences/ya.make b/contrib/restricted/abseil-cpp/absl/random/seed_sequences/ya.make index c97e6d16e8..49cb3ff19c 100644 --- a/contrib/restricted/abseil-cpp/absl/random/seed_sequences/ya.make +++ b/contrib/restricted/abseil-cpp/absl/random/seed_sequences/ya.make @@ -1,49 +1,49 @@ -# Generated by devtools/yamaker. - -LIBRARY() - +# Generated by devtools/yamaker. + +LIBRARY() + WITHOUT_LICENSE_TEXTS() -OWNER(g:cpp-contrib) - -LICENSE(Apache-2.0) - -PEERDIR( - contrib/restricted/abseil-cpp/absl/base - contrib/restricted/abseil-cpp/absl/base/internal/raw_logging - contrib/restricted/abseil-cpp/absl/base/internal/spinlock_wait - contrib/restricted/abseil-cpp/absl/base/internal/throw_delegate - contrib/restricted/abseil-cpp/absl/base/log_severity - contrib/restricted/abseil-cpp/absl/numeric - contrib/restricted/abseil-cpp/absl/random/internal/pool_urbg - contrib/restricted/abseil-cpp/absl/random/internal/randen - contrib/restricted/abseil-cpp/absl/random/internal/randen_detect - contrib/restricted/abseil-cpp/absl/random/internal/randen_hwaes +OWNER(g:cpp-contrib) + +LICENSE(Apache-2.0) + +PEERDIR( + contrib/restricted/abseil-cpp/absl/base + contrib/restricted/abseil-cpp/absl/base/internal/raw_logging + contrib/restricted/abseil-cpp/absl/base/internal/spinlock_wait + contrib/restricted/abseil-cpp/absl/base/internal/throw_delegate + contrib/restricted/abseil-cpp/absl/base/log_severity + contrib/restricted/abseil-cpp/absl/numeric + contrib/restricted/abseil-cpp/absl/random/internal/pool_urbg + contrib/restricted/abseil-cpp/absl/random/internal/randen + contrib/restricted/abseil-cpp/absl/random/internal/randen_detect + contrib/restricted/abseil-cpp/absl/random/internal/randen_hwaes contrib/restricted/abseil-cpp/absl/random/internal/randen_round_keys - contrib/restricted/abseil-cpp/absl/random/internal/randen_slow - contrib/restricted/abseil-cpp/absl/random/internal/seed_material - contrib/restricted/abseil-cpp/absl/random/seed_gen_exception - contrib/restricted/abseil-cpp/absl/strings + contrib/restricted/abseil-cpp/absl/random/internal/randen_slow + contrib/restricted/abseil-cpp/absl/random/internal/seed_material + contrib/restricted/abseil-cpp/absl/random/seed_gen_exception + contrib/restricted/abseil-cpp/absl/strings contrib/restricted/abseil-cpp/absl/strings/internal/absl_strings_internal - contrib/restricted/abseil-cpp/absl/types/bad_optional_access -) - -ADDINCL( - GLOBAL contrib/restricted/abseil-cpp -) - -NO_COMPILER_WARNINGS() - -NO_UTIL() - + contrib/restricted/abseil-cpp/absl/types/bad_optional_access +) + +ADDINCL( + GLOBAL contrib/restricted/abseil-cpp +) + +NO_COMPILER_WARNINGS() + +NO_UTIL() + CFLAGS( -DNOMINMAX ) -SRCDIR(contrib/restricted/abseil-cpp/absl/random) - -SRCS( - seed_sequences.cc -) - -END() +SRCDIR(contrib/restricted/abseil-cpp/absl/random) + +SRCS( + seed_sequences.cc +) + +END() diff --git a/contrib/restricted/abseil-cpp/absl/random/uniform_int_distribution.h b/contrib/restricted/abseil-cpp/absl/random/uniform_int_distribution.h index df417a1ecf..c1f54ccebc 100644 --- a/contrib/restricted/abseil-cpp/absl/random/uniform_int_distribution.h +++ b/contrib/restricted/abseil-cpp/absl/random/uniform_int_distribution.h @@ -1,275 +1,275 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// ----------------------------------------------------------------------------- -// File: uniform_int_distribution.h -// ----------------------------------------------------------------------------- -// -// This header defines a class for representing a uniform integer distribution -// over the closed (inclusive) interval [a,b]. You use this distribution in -// combination with an Abseil random bit generator to produce random values -// according to the rules of the distribution. -// -// `absl::uniform_int_distribution` is a drop-in replacement for the C++11 -// `std::uniform_int_distribution` [rand.dist.uni.int] but is considerably -// faster than the libstdc++ implementation. - -#ifndef ABSL_RANDOM_UNIFORM_INT_DISTRIBUTION_H_ -#define ABSL_RANDOM_UNIFORM_INT_DISTRIBUTION_H_ - -#include <cassert> -#include <istream> -#include <limits> -#include <type_traits> - -#include "absl/base/optimization.h" -#include "absl/random/internal/fast_uniform_bits.h" -#include "absl/random/internal/iostream_state_saver.h" -#include "absl/random/internal/traits.h" -#include "absl/random/internal/wide_multiply.h" - -namespace absl { +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: uniform_int_distribution.h +// ----------------------------------------------------------------------------- +// +// This header defines a class for representing a uniform integer distribution +// over the closed (inclusive) interval [a,b]. You use this distribution in +// combination with an Abseil random bit generator to produce random values +// according to the rules of the distribution. +// +// `absl::uniform_int_distribution` is a drop-in replacement for the C++11 +// `std::uniform_int_distribution` [rand.dist.uni.int] but is considerably +// faster than the libstdc++ implementation. + +#ifndef ABSL_RANDOM_UNIFORM_INT_DISTRIBUTION_H_ +#define ABSL_RANDOM_UNIFORM_INT_DISTRIBUTION_H_ + +#include <cassert> +#include <istream> +#include <limits> +#include <type_traits> + +#include "absl/base/optimization.h" +#include "absl/random/internal/fast_uniform_bits.h" +#include "absl/random/internal/iostream_state_saver.h" +#include "absl/random/internal/traits.h" +#include "absl/random/internal/wide_multiply.h" + +namespace absl { ABSL_NAMESPACE_BEGIN - -// absl::uniform_int_distribution<T> -// -// This distribution produces random integer values uniformly distributed in the -// closed (inclusive) interval [a, b]. -// -// Example: -// -// absl::BitGen gen; -// -// // Use the distribution to produce a value between 1 and 6, inclusive. -// int die_roll = absl::uniform_int_distribution<int>(1, 6)(gen); -// -template <typename IntType = int> -class uniform_int_distribution { - private: - using unsigned_type = - typename random_internal::make_unsigned_bits<IntType>::type; - - public: - using result_type = IntType; - - class param_type { - public: - using distribution_type = uniform_int_distribution; - - explicit param_type( - result_type lo = 0, - result_type hi = (std::numeric_limits<result_type>::max)()) - : lo_(lo), - range_(static_cast<unsigned_type>(hi) - - static_cast<unsigned_type>(lo)) { - // [rand.dist.uni.int] precondition 2 - assert(lo <= hi); - } - - result_type a() const { return lo_; } - result_type b() const { - return static_cast<result_type>(static_cast<unsigned_type>(lo_) + range_); - } - - friend bool operator==(const param_type& a, const param_type& b) { - return a.lo_ == b.lo_ && a.range_ == b.range_; - } - - friend bool operator!=(const param_type& a, const param_type& b) { - return !(a == b); - } - - private: - friend class uniform_int_distribution; - unsigned_type range() const { return range_; } - - result_type lo_; - unsigned_type range_; - - static_assert(std::is_integral<result_type>::value, - "Class-template absl::uniform_int_distribution<> must be " - "parameterized using an integral type."); - }; // param_type - - uniform_int_distribution() : uniform_int_distribution(0) {} - - explicit uniform_int_distribution( - result_type lo, - result_type hi = (std::numeric_limits<result_type>::max)()) - : param_(lo, hi) {} - - explicit uniform_int_distribution(const param_type& param) : param_(param) {} - - // uniform_int_distribution<T>::reset() - // - // Resets the uniform int distribution. Note that this function has no effect - // because the distribution already produces independent values. - void reset() {} - - template <typename URBG> - result_type operator()(URBG& gen) { // NOLINT(runtime/references) - return (*this)(gen, param()); - } - - template <typename URBG> - result_type operator()( - URBG& gen, const param_type& param) { // NOLINT(runtime/references) - return param.a() + Generate(gen, param.range()); - } - - result_type a() const { return param_.a(); } - result_type b() const { return param_.b(); } - - param_type param() const { return param_; } - void param(const param_type& params) { param_ = params; } - - result_type(min)() const { return a(); } - result_type(max)() const { return b(); } - - friend bool operator==(const uniform_int_distribution& a, - const uniform_int_distribution& b) { - return a.param_ == b.param_; - } - friend bool operator!=(const uniform_int_distribution& a, - const uniform_int_distribution& b) { - return !(a == b); - } - - private: - // Generates a value in the *closed* interval [0, R] - template <typename URBG> - unsigned_type Generate(URBG& g, // NOLINT(runtime/references) - unsigned_type R); - param_type param_; -}; - -// ----------------------------------------------------------------------------- -// Implementation details follow -// ----------------------------------------------------------------------------- -template <typename CharT, typename Traits, typename IntType> -std::basic_ostream<CharT, Traits>& operator<<( - std::basic_ostream<CharT, Traits>& os, - const uniform_int_distribution<IntType>& x) { - using stream_type = - typename random_internal::stream_format_type<IntType>::type; - auto saver = random_internal::make_ostream_state_saver(os); - os << static_cast<stream_type>(x.a()) << os.fill() - << static_cast<stream_type>(x.b()); - return os; -} - -template <typename CharT, typename Traits, typename IntType> -std::basic_istream<CharT, Traits>& operator>>( - std::basic_istream<CharT, Traits>& is, - uniform_int_distribution<IntType>& x) { - using param_type = typename uniform_int_distribution<IntType>::param_type; - using result_type = typename uniform_int_distribution<IntType>::result_type; - using stream_type = - typename random_internal::stream_format_type<IntType>::type; - - stream_type a; - stream_type b; - - auto saver = random_internal::make_istream_state_saver(is); - is >> a >> b; - if (!is.fail()) { - x.param( - param_type(static_cast<result_type>(a), static_cast<result_type>(b))); - } - return is; -} - -template <typename IntType> -template <typename URBG> -typename random_internal::make_unsigned_bits<IntType>::type -uniform_int_distribution<IntType>::Generate( - URBG& g, // NOLINT(runtime/references) - typename random_internal::make_unsigned_bits<IntType>::type R) { + +// absl::uniform_int_distribution<T> +// +// This distribution produces random integer values uniformly distributed in the +// closed (inclusive) interval [a, b]. +// +// Example: +// +// absl::BitGen gen; +// +// // Use the distribution to produce a value between 1 and 6, inclusive. +// int die_roll = absl::uniform_int_distribution<int>(1, 6)(gen); +// +template <typename IntType = int> +class uniform_int_distribution { + private: + using unsigned_type = + typename random_internal::make_unsigned_bits<IntType>::type; + + public: + using result_type = IntType; + + class param_type { + public: + using distribution_type = uniform_int_distribution; + + explicit param_type( + result_type lo = 0, + result_type hi = (std::numeric_limits<result_type>::max)()) + : lo_(lo), + range_(static_cast<unsigned_type>(hi) - + static_cast<unsigned_type>(lo)) { + // [rand.dist.uni.int] precondition 2 + assert(lo <= hi); + } + + result_type a() const { return lo_; } + result_type b() const { + return static_cast<result_type>(static_cast<unsigned_type>(lo_) + range_); + } + + friend bool operator==(const param_type& a, const param_type& b) { + return a.lo_ == b.lo_ && a.range_ == b.range_; + } + + friend bool operator!=(const param_type& a, const param_type& b) { + return !(a == b); + } + + private: + friend class uniform_int_distribution; + unsigned_type range() const { return range_; } + + result_type lo_; + unsigned_type range_; + + static_assert(std::is_integral<result_type>::value, + "Class-template absl::uniform_int_distribution<> must be " + "parameterized using an integral type."); + }; // param_type + + uniform_int_distribution() : uniform_int_distribution(0) {} + + explicit uniform_int_distribution( + result_type lo, + result_type hi = (std::numeric_limits<result_type>::max)()) + : param_(lo, hi) {} + + explicit uniform_int_distribution(const param_type& param) : param_(param) {} + + // uniform_int_distribution<T>::reset() + // + // Resets the uniform int distribution. Note that this function has no effect + // because the distribution already produces independent values. + void reset() {} + + template <typename URBG> + result_type operator()(URBG& gen) { // NOLINT(runtime/references) + return (*this)(gen, param()); + } + + template <typename URBG> + result_type operator()( + URBG& gen, const param_type& param) { // NOLINT(runtime/references) + return param.a() + Generate(gen, param.range()); + } + + result_type a() const { return param_.a(); } + result_type b() const { return param_.b(); } + + param_type param() const { return param_; } + void param(const param_type& params) { param_ = params; } + + result_type(min)() const { return a(); } + result_type(max)() const { return b(); } + + friend bool operator==(const uniform_int_distribution& a, + const uniform_int_distribution& b) { + return a.param_ == b.param_; + } + friend bool operator!=(const uniform_int_distribution& a, + const uniform_int_distribution& b) { + return !(a == b); + } + + private: + // Generates a value in the *closed* interval [0, R] + template <typename URBG> + unsigned_type Generate(URBG& g, // NOLINT(runtime/references) + unsigned_type R); + param_type param_; +}; + +// ----------------------------------------------------------------------------- +// Implementation details follow +// ----------------------------------------------------------------------------- +template <typename CharT, typename Traits, typename IntType> +std::basic_ostream<CharT, Traits>& operator<<( + std::basic_ostream<CharT, Traits>& os, + const uniform_int_distribution<IntType>& x) { + using stream_type = + typename random_internal::stream_format_type<IntType>::type; + auto saver = random_internal::make_ostream_state_saver(os); + os << static_cast<stream_type>(x.a()) << os.fill() + << static_cast<stream_type>(x.b()); + return os; +} + +template <typename CharT, typename Traits, typename IntType> +std::basic_istream<CharT, Traits>& operator>>( + std::basic_istream<CharT, Traits>& is, + uniform_int_distribution<IntType>& x) { + using param_type = typename uniform_int_distribution<IntType>::param_type; + using result_type = typename uniform_int_distribution<IntType>::result_type; + using stream_type = + typename random_internal::stream_format_type<IntType>::type; + + stream_type a; + stream_type b; + + auto saver = random_internal::make_istream_state_saver(is); + is >> a >> b; + if (!is.fail()) { + x.param( + param_type(static_cast<result_type>(a), static_cast<result_type>(b))); + } + return is; +} + +template <typename IntType> +template <typename URBG> +typename random_internal::make_unsigned_bits<IntType>::type +uniform_int_distribution<IntType>::Generate( + URBG& g, // NOLINT(runtime/references) + typename random_internal::make_unsigned_bits<IntType>::type R) { random_internal::FastUniformBits<unsigned_type> fast_bits; - unsigned_type bits = fast_bits(g); - const unsigned_type Lim = R + 1; - if ((R & Lim) == 0) { - // If the interval's length is a power of two range, just take the low bits. - return bits & R; - } - - // Generates a uniform variate on [0, Lim) using fixed-point multiplication. - // The above fast-path guarantees that Lim is representable in unsigned_type. - // - // Algorithm adapted from - // http://lemire.me/blog/2016/06/30/fast-random-shuffling/, with added - // explanation. - // - // The algorithm creates a uniform variate `bits` in the interval [0, 2^N), - // and treats it as the fractional part of a fixed-point real value in [0, 1), - // multiplied by 2^N. For example, 0.25 would be represented as 2^(N - 2), - // because 2^N * 0.25 == 2^(N - 2). - // - // Next, `bits` and `Lim` are multiplied with a wide-multiply to bring the - // value into the range [0, Lim). The integral part (the high word of the - // multiplication result) is then very nearly the desired result. However, - // this is not quite accurate; viewing the multiplication result as one - // double-width integer, the resulting values for the sample are mapped as - // follows: - // - // If the result lies in this interval: Return this value: - // [0, 2^N) 0 - // [2^N, 2 * 2^N) 1 - // ... ... - // [K * 2^N, (K + 1) * 2^N) K - // ... ... - // [(Lim - 1) * 2^N, Lim * 2^N) Lim - 1 - // - // While all of these intervals have the same size, the result of `bits * Lim` - // must be a multiple of `Lim`, and not all of these intervals contain the - // same number of multiples of `Lim`. In particular, some contain - // `F = floor(2^N / Lim)` and some contain `F + 1 = ceil(2^N / Lim)`. This - // difference produces a small nonuniformity, which is corrected by applying - // rejection sampling to one of the values in the "larger intervals" (i.e., - // the intervals containing `F + 1` multiples of `Lim`. - // - // An interval contains `F + 1` multiples of `Lim` if and only if its smallest - // value modulo 2^N is less than `2^N % Lim`. The unique value satisfying - // this property is used as the one for rejection. That is, a value of - // `bits * Lim` is rejected if `(bit * Lim) % 2^N < (2^N % Lim)`. - - using helper = random_internal::wide_multiply<unsigned_type>; - auto product = helper::multiply(bits, Lim); - - // Two optimizations here: - // * Rejection occurs with some probability less than 1/2, and for reasonable - // ranges considerably less (in particular, less than 1/(F+1)), so - // ABSL_PREDICT_FALSE is apt. - // * `Lim` is an overestimate of `threshold`, and doesn't require a divide. - if (ABSL_PREDICT_FALSE(helper::lo(product) < Lim)) { - // This quantity is exactly equal to `2^N % Lim`, but does not require high - // precision calculations: `2^N % Lim` is congruent to `(2^N - Lim) % Lim`. - // Ideally this could be expressed simply as `-X` rather than `2^N - X`, but - // for types smaller than int, this calculation is incorrect due to integer - // promotion rules. - const unsigned_type threshold = - ((std::numeric_limits<unsigned_type>::max)() - Lim + 1) % Lim; - while (helper::lo(product) < threshold) { - bits = fast_bits(g); - product = helper::multiply(bits, Lim); - } - } - - return helper::hi(product); -} - + unsigned_type bits = fast_bits(g); + const unsigned_type Lim = R + 1; + if ((R & Lim) == 0) { + // If the interval's length is a power of two range, just take the low bits. + return bits & R; + } + + // Generates a uniform variate on [0, Lim) using fixed-point multiplication. + // The above fast-path guarantees that Lim is representable in unsigned_type. + // + // Algorithm adapted from + // http://lemire.me/blog/2016/06/30/fast-random-shuffling/, with added + // explanation. + // + // The algorithm creates a uniform variate `bits` in the interval [0, 2^N), + // and treats it as the fractional part of a fixed-point real value in [0, 1), + // multiplied by 2^N. For example, 0.25 would be represented as 2^(N - 2), + // because 2^N * 0.25 == 2^(N - 2). + // + // Next, `bits` and `Lim` are multiplied with a wide-multiply to bring the + // value into the range [0, Lim). The integral part (the high word of the + // multiplication result) is then very nearly the desired result. However, + // this is not quite accurate; viewing the multiplication result as one + // double-width integer, the resulting values for the sample are mapped as + // follows: + // + // If the result lies in this interval: Return this value: + // [0, 2^N) 0 + // [2^N, 2 * 2^N) 1 + // ... ... + // [K * 2^N, (K + 1) * 2^N) K + // ... ... + // [(Lim - 1) * 2^N, Lim * 2^N) Lim - 1 + // + // While all of these intervals have the same size, the result of `bits * Lim` + // must be a multiple of `Lim`, and not all of these intervals contain the + // same number of multiples of `Lim`. In particular, some contain + // `F = floor(2^N / Lim)` and some contain `F + 1 = ceil(2^N / Lim)`. This + // difference produces a small nonuniformity, which is corrected by applying + // rejection sampling to one of the values in the "larger intervals" (i.e., + // the intervals containing `F + 1` multiples of `Lim`. + // + // An interval contains `F + 1` multiples of `Lim` if and only if its smallest + // value modulo 2^N is less than `2^N % Lim`. The unique value satisfying + // this property is used as the one for rejection. That is, a value of + // `bits * Lim` is rejected if `(bit * Lim) % 2^N < (2^N % Lim)`. + + using helper = random_internal::wide_multiply<unsigned_type>; + auto product = helper::multiply(bits, Lim); + + // Two optimizations here: + // * Rejection occurs with some probability less than 1/2, and for reasonable + // ranges considerably less (in particular, less than 1/(F+1)), so + // ABSL_PREDICT_FALSE is apt. + // * `Lim` is an overestimate of `threshold`, and doesn't require a divide. + if (ABSL_PREDICT_FALSE(helper::lo(product) < Lim)) { + // This quantity is exactly equal to `2^N % Lim`, but does not require high + // precision calculations: `2^N % Lim` is congruent to `(2^N - Lim) % Lim`. + // Ideally this could be expressed simply as `-X` rather than `2^N - X`, but + // for types smaller than int, this calculation is incorrect due to integer + // promotion rules. + const unsigned_type threshold = + ((std::numeric_limits<unsigned_type>::max)() - Lim + 1) % Lim; + while (helper::lo(product) < threshold) { + bits = fast_bits(g); + product = helper::multiply(bits, Lim); + } + } + + return helper::hi(product); +} + ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_UNIFORM_INT_DISTRIBUTION_H_ +} // namespace absl + +#endif // ABSL_RANDOM_UNIFORM_INT_DISTRIBUTION_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/uniform_real_distribution.h b/contrib/restricted/abseil-cpp/absl/random/uniform_real_distribution.h index 4ebe0747c9..5ba17b2341 100644 --- a/contrib/restricted/abseil-cpp/absl/random/uniform_real_distribution.h +++ b/contrib/restricted/abseil-cpp/absl/random/uniform_real_distribution.h @@ -1,202 +1,202 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// ----------------------------------------------------------------------------- -// File: uniform_real_distribution.h -// ----------------------------------------------------------------------------- -// -// This header defines a class for representing a uniform floating-point -// distribution over a half-open interval [a,b). You use this distribution in -// combination with an Abseil random bit generator to produce random values -// according to the rules of the distribution. -// -// `absl::uniform_real_distribution` is a drop-in replacement for the C++11 -// `std::uniform_real_distribution` [rand.dist.uni.real] but is considerably -// faster than the libstdc++ implementation. -// -// Note: the standard-library version may occasionally return `1.0` when -// default-initialized. See https://bugs.llvm.org//show_bug.cgi?id=18767 -// `absl::uniform_real_distribution` does not exhibit this behavior. - -#ifndef ABSL_RANDOM_UNIFORM_REAL_DISTRIBUTION_H_ -#define ABSL_RANDOM_UNIFORM_REAL_DISTRIBUTION_H_ - -#include <cassert> -#include <cmath> -#include <cstdint> -#include <istream> -#include <limits> -#include <type_traits> - -#include "absl/meta/type_traits.h" -#include "absl/random/internal/fast_uniform_bits.h" -#include "absl/random/internal/generate_real.h" -#include "absl/random/internal/iostream_state_saver.h" - -namespace absl { +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: uniform_real_distribution.h +// ----------------------------------------------------------------------------- +// +// This header defines a class for representing a uniform floating-point +// distribution over a half-open interval [a,b). You use this distribution in +// combination with an Abseil random bit generator to produce random values +// according to the rules of the distribution. +// +// `absl::uniform_real_distribution` is a drop-in replacement for the C++11 +// `std::uniform_real_distribution` [rand.dist.uni.real] but is considerably +// faster than the libstdc++ implementation. +// +// Note: the standard-library version may occasionally return `1.0` when +// default-initialized. See https://bugs.llvm.org//show_bug.cgi?id=18767 +// `absl::uniform_real_distribution` does not exhibit this behavior. + +#ifndef ABSL_RANDOM_UNIFORM_REAL_DISTRIBUTION_H_ +#define ABSL_RANDOM_UNIFORM_REAL_DISTRIBUTION_H_ + +#include <cassert> +#include <cmath> +#include <cstdint> +#include <istream> +#include <limits> +#include <type_traits> + +#include "absl/meta/type_traits.h" +#include "absl/random/internal/fast_uniform_bits.h" +#include "absl/random/internal/generate_real.h" +#include "absl/random/internal/iostream_state_saver.h" + +namespace absl { ABSL_NAMESPACE_BEGIN - -// absl::uniform_real_distribution<T> -// -// This distribution produces random floating-point values uniformly distributed -// over the half-open interval [a, b). -// -// Example: -// -// absl::BitGen gen; -// -// // Use the distribution to produce a value between 0.0 (inclusive) -// // and 1.0 (exclusive). -// double value = absl::uniform_real_distribution<double>(0, 1)(gen); -// -template <typename RealType = double> -class uniform_real_distribution { - public: - using result_type = RealType; - - class param_type { - public: - using distribution_type = uniform_real_distribution; - - explicit param_type(result_type lo = 0, result_type hi = 1) - : lo_(lo), hi_(hi), range_(hi - lo) { - // [rand.dist.uni.real] preconditions 2 & 3 - assert(lo <= hi); - // NOTE: For integral types, we can promote the range to an unsigned type, - // which gives full width of the range. However for real (fp) types, this - // is not possible, so value generation cannot use the full range of the - // real type. - assert(range_ <= (std::numeric_limits<result_type>::max)()); - assert(std::isfinite(range_)); - } - - result_type a() const { return lo_; } - result_type b() const { return hi_; } - - friend bool operator==(const param_type& a, const param_type& b) { - return a.lo_ == b.lo_ && a.hi_ == b.hi_; - } - - friend bool operator!=(const param_type& a, const param_type& b) { - return !(a == b); - } - - private: - friend class uniform_real_distribution; - result_type lo_, hi_, range_; - - static_assert(std::is_floating_point<RealType>::value, - "Class-template absl::uniform_real_distribution<> must be " - "parameterized using a floating-point type."); - }; - - uniform_real_distribution() : uniform_real_distribution(0) {} - - explicit uniform_real_distribution(result_type lo, result_type hi = 1) - : param_(lo, hi) {} - - explicit uniform_real_distribution(const param_type& param) : param_(param) {} - - // uniform_real_distribution<T>::reset() - // - // Resets the uniform real distribution. Note that this function has no effect - // because the distribution already produces independent values. - void reset() {} - - template <typename URBG> - result_type operator()(URBG& gen) { // NOLINT(runtime/references) - return operator()(gen, param_); - } - - template <typename URBG> - result_type operator()(URBG& gen, // NOLINT(runtime/references) - const param_type& p); - - result_type a() const { return param_.a(); } - result_type b() const { return param_.b(); } - - param_type param() const { return param_; } - void param(const param_type& params) { param_ = params; } - - result_type(min)() const { return a(); } - result_type(max)() const { return b(); } - - friend bool operator==(const uniform_real_distribution& a, - const uniform_real_distribution& b) { - return a.param_ == b.param_; - } - friend bool operator!=(const uniform_real_distribution& a, - const uniform_real_distribution& b) { - return a.param_ != b.param_; - } - - private: - param_type param_; - random_internal::FastUniformBits<uint64_t> fast_u64_; -}; - -// ----------------------------------------------------------------------------- -// Implementation details follow -// ----------------------------------------------------------------------------- -template <typename RealType> -template <typename URBG> -typename uniform_real_distribution<RealType>::result_type -uniform_real_distribution<RealType>::operator()( - URBG& gen, const param_type& p) { // NOLINT(runtime/references) - using random_internal::GeneratePositiveTag; - using random_internal::GenerateRealFromBits; - using real_type = - absl::conditional_t<std::is_same<RealType, float>::value, float, double>; - - while (true) { - const result_type sample = - GenerateRealFromBits<real_type, GeneratePositiveTag, true>( - fast_u64_(gen)); - const result_type res = p.a() + (sample * p.range_); - if (res < p.b() || p.range_ <= 0 || !std::isfinite(p.range_)) { - return res; - } - // else sample rejected, try again. - } -} - -template <typename CharT, typename Traits, typename RealType> -std::basic_ostream<CharT, Traits>& operator<<( - std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) - const uniform_real_distribution<RealType>& x) { - auto saver = random_internal::make_ostream_state_saver(os); - os.precision(random_internal::stream_precision_helper<RealType>::kPrecision); - os << x.a() << os.fill() << x.b(); - return os; -} - -template <typename CharT, typename Traits, typename RealType> -std::basic_istream<CharT, Traits>& operator>>( - std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) - uniform_real_distribution<RealType>& x) { // NOLINT(runtime/references) - using param_type = typename uniform_real_distribution<RealType>::param_type; - using result_type = typename uniform_real_distribution<RealType>::result_type; - auto saver = random_internal::make_istream_state_saver(is); - auto a = random_internal::read_floating_point<result_type>(is); - if (is.fail()) return is; - auto b = random_internal::read_floating_point<result_type>(is); - if (!is.fail()) { - x.param(param_type(a, b)); - } - return is; -} + +// absl::uniform_real_distribution<T> +// +// This distribution produces random floating-point values uniformly distributed +// over the half-open interval [a, b). +// +// Example: +// +// absl::BitGen gen; +// +// // Use the distribution to produce a value between 0.0 (inclusive) +// // and 1.0 (exclusive). +// double value = absl::uniform_real_distribution<double>(0, 1)(gen); +// +template <typename RealType = double> +class uniform_real_distribution { + public: + using result_type = RealType; + + class param_type { + public: + using distribution_type = uniform_real_distribution; + + explicit param_type(result_type lo = 0, result_type hi = 1) + : lo_(lo), hi_(hi), range_(hi - lo) { + // [rand.dist.uni.real] preconditions 2 & 3 + assert(lo <= hi); + // NOTE: For integral types, we can promote the range to an unsigned type, + // which gives full width of the range. However for real (fp) types, this + // is not possible, so value generation cannot use the full range of the + // real type. + assert(range_ <= (std::numeric_limits<result_type>::max)()); + assert(std::isfinite(range_)); + } + + result_type a() const { return lo_; } + result_type b() const { return hi_; } + + friend bool operator==(const param_type& a, const param_type& b) { + return a.lo_ == b.lo_ && a.hi_ == b.hi_; + } + + friend bool operator!=(const param_type& a, const param_type& b) { + return !(a == b); + } + + private: + friend class uniform_real_distribution; + result_type lo_, hi_, range_; + + static_assert(std::is_floating_point<RealType>::value, + "Class-template absl::uniform_real_distribution<> must be " + "parameterized using a floating-point type."); + }; + + uniform_real_distribution() : uniform_real_distribution(0) {} + + explicit uniform_real_distribution(result_type lo, result_type hi = 1) + : param_(lo, hi) {} + + explicit uniform_real_distribution(const param_type& param) : param_(param) {} + + // uniform_real_distribution<T>::reset() + // + // Resets the uniform real distribution. Note that this function has no effect + // because the distribution already produces independent values. + void reset() {} + + template <typename URBG> + result_type operator()(URBG& gen) { // NOLINT(runtime/references) + return operator()(gen, param_); + } + + template <typename URBG> + result_type operator()(URBG& gen, // NOLINT(runtime/references) + const param_type& p); + + result_type a() const { return param_.a(); } + result_type b() const { return param_.b(); } + + param_type param() const { return param_; } + void param(const param_type& params) { param_ = params; } + + result_type(min)() const { return a(); } + result_type(max)() const { return b(); } + + friend bool operator==(const uniform_real_distribution& a, + const uniform_real_distribution& b) { + return a.param_ == b.param_; + } + friend bool operator!=(const uniform_real_distribution& a, + const uniform_real_distribution& b) { + return a.param_ != b.param_; + } + + private: + param_type param_; + random_internal::FastUniformBits<uint64_t> fast_u64_; +}; + +// ----------------------------------------------------------------------------- +// Implementation details follow +// ----------------------------------------------------------------------------- +template <typename RealType> +template <typename URBG> +typename uniform_real_distribution<RealType>::result_type +uniform_real_distribution<RealType>::operator()( + URBG& gen, const param_type& p) { // NOLINT(runtime/references) + using random_internal::GeneratePositiveTag; + using random_internal::GenerateRealFromBits; + using real_type = + absl::conditional_t<std::is_same<RealType, float>::value, float, double>; + + while (true) { + const result_type sample = + GenerateRealFromBits<real_type, GeneratePositiveTag, true>( + fast_u64_(gen)); + const result_type res = p.a() + (sample * p.range_); + if (res < p.b() || p.range_ <= 0 || !std::isfinite(p.range_)) { + return res; + } + // else sample rejected, try again. + } +} + +template <typename CharT, typename Traits, typename RealType> +std::basic_ostream<CharT, Traits>& operator<<( + std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) + const uniform_real_distribution<RealType>& x) { + auto saver = random_internal::make_ostream_state_saver(os); + os.precision(random_internal::stream_precision_helper<RealType>::kPrecision); + os << x.a() << os.fill() << x.b(); + return os; +} + +template <typename CharT, typename Traits, typename RealType> +std::basic_istream<CharT, Traits>& operator>>( + std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) + uniform_real_distribution<RealType>& x) { // NOLINT(runtime/references) + using param_type = typename uniform_real_distribution<RealType>::param_type; + using result_type = typename uniform_real_distribution<RealType>::result_type; + auto saver = random_internal::make_istream_state_saver(is); + auto a = random_internal::read_floating_point<result_type>(is); + if (is.fail()) return is; + auto b = random_internal::read_floating_point<result_type>(is); + if (!is.fail()) { + x.param(param_type(a, b)); + } + return is; +} ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_UNIFORM_REAL_DISTRIBUTION_H_ +} // namespace absl + +#endif // ABSL_RANDOM_UNIFORM_REAL_DISTRIBUTION_H_ diff --git a/contrib/restricted/abseil-cpp/absl/random/zipf_distribution.h b/contrib/restricted/abseil-cpp/absl/random/zipf_distribution.h index 31212412df..22ebc756cf 100644 --- a/contrib/restricted/abseil-cpp/absl/random/zipf_distribution.h +++ b/contrib/restricted/abseil-cpp/absl/random/zipf_distribution.h @@ -1,271 +1,271 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_RANDOM_ZIPF_DISTRIBUTION_H_ -#define ABSL_RANDOM_ZIPF_DISTRIBUTION_H_ - -#include <cassert> -#include <cmath> -#include <istream> -#include <limits> -#include <ostream> -#include <type_traits> - -#include "absl/random/internal/iostream_state_saver.h" -#include "absl/random/uniform_real_distribution.h" - -namespace absl { +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_RANDOM_ZIPF_DISTRIBUTION_H_ +#define ABSL_RANDOM_ZIPF_DISTRIBUTION_H_ + +#include <cassert> +#include <cmath> +#include <istream> +#include <limits> +#include <ostream> +#include <type_traits> + +#include "absl/random/internal/iostream_state_saver.h" +#include "absl/random/uniform_real_distribution.h" + +namespace absl { ABSL_NAMESPACE_BEGIN - -// absl::zipf_distribution produces random integer-values in the range [0, k], -// distributed according to the discrete probability function: -// -// P(x) = (v + x) ^ -q -// -// The parameter `v` must be greater than 0 and the parameter `q` must be -// greater than 1. If either of these parameters take invalid values then the -// behavior is undefined. -// -// IntType is the result_type generated by the generator. It must be of integral -// type; a static_assert ensures this is the case. -// -// The implementation is based on W.Hormann, G.Derflinger: -// -// "Rejection-Inversion to Generate Variates from Monotone Discrete -// Distributions" -// -// http://eeyore.wu-wien.ac.at/papers/96-04-04.wh-der.ps.gz -// -template <typename IntType = int> -class zipf_distribution { - public: - using result_type = IntType; - - class param_type { - public: - using distribution_type = zipf_distribution; - - // Preconditions: k > 0, v > 0, q > 1 - // The precondidtions are validated when NDEBUG is not defined via - // a pair of assert() directives. - // If NDEBUG is defined and either or both of these parameters take invalid - // values, the behavior of the class is undefined. - explicit param_type(result_type k = (std::numeric_limits<IntType>::max)(), - double q = 2.0, double v = 1.0); - - result_type k() const { return k_; } - double q() const { return q_; } - double v() const { return v_; } - - friend bool operator==(const param_type& a, const param_type& b) { - return a.k_ == b.k_ && a.q_ == b.q_ && a.v_ == b.v_; - } - friend bool operator!=(const param_type& a, const param_type& b) { - return !(a == b); - } - - private: - friend class zipf_distribution; - inline double h(double x) const; - inline double hinv(double x) const; - inline double compute_s() const; - inline double pow_negative_q(double x) const; - - // Parameters here are exactly the same as the parameters of Algorithm ZRI - // in the paper. - IntType k_; - double q_; - double v_; - - double one_minus_q_; // 1-q - double s_; - double one_minus_q_inv_; // 1 / 1-q - double hxm_; // h(k + 0.5) - double hx0_minus_hxm_; // h(x0) - h(k + 0.5) - - static_assert(std::is_integral<IntType>::value, - "Class-template absl::zipf_distribution<> must be " - "parameterized using an integral type."); - }; - - zipf_distribution() - : zipf_distribution((std::numeric_limits<IntType>::max)()) {} - - explicit zipf_distribution(result_type k, double q = 2.0, double v = 1.0) - : param_(k, q, v) {} - - explicit zipf_distribution(const param_type& p) : param_(p) {} - - void reset() {} - - template <typename URBG> - result_type operator()(URBG& g) { // NOLINT(runtime/references) - return (*this)(g, param_); - } - - template <typename URBG> - result_type operator()(URBG& g, // NOLINT(runtime/references) - const param_type& p); - - result_type k() const { return param_.k(); } - double q() const { return param_.q(); } - double v() const { return param_.v(); } - - param_type param() const { return param_; } - void param(const param_type& p) { param_ = p; } - - result_type(min)() const { return 0; } - result_type(max)() const { return k(); } - - friend bool operator==(const zipf_distribution& a, - const zipf_distribution& b) { - return a.param_ == b.param_; - } - friend bool operator!=(const zipf_distribution& a, - const zipf_distribution& b) { - return a.param_ != b.param_; - } - - private: - param_type param_; -}; - -// -------------------------------------------------------------------------- -// Implementation details follow -// -------------------------------------------------------------------------- - -template <typename IntType> -zipf_distribution<IntType>::param_type::param_type( - typename zipf_distribution<IntType>::result_type k, double q, double v) - : k_(k), q_(q), v_(v), one_minus_q_(1 - q) { - assert(q > 1); - assert(v > 0); - assert(k > 0); - one_minus_q_inv_ = 1 / one_minus_q_; - - // Setup for the ZRI algorithm (pg 17 of the paper). - // Compute: h(i max) => h(k + 0.5) - constexpr double kMax = 18446744073709549568.0; - double kd = static_cast<double>(k); - // TODO(absl-team): Determine if this check is needed, and if so, add a test - // that fails for k > kMax - if (kd > kMax) { - // Ensure that our maximum value is capped to a value which will - // round-trip back through double. - kd = kMax; - } - hxm_ = h(kd + 0.5); - - // Compute: h(0) - const bool use_precomputed = (v == 1.0 && q == 2.0); - const double h0x5 = use_precomputed ? (-1.0 / 1.5) // exp(-log(1.5)) - : h(0.5); - const double elogv_q = (v_ == 1.0) ? 1 : pow_negative_q(v_); - - // h(0) = h(0.5) - exp(log(v) * -q) - hx0_minus_hxm_ = (h0x5 - elogv_q) - hxm_; - - // And s - s_ = use_precomputed ? 0.46153846153846123 : compute_s(); -} - -template <typename IntType> -double zipf_distribution<IntType>::param_type::h(double x) const { - // std::exp(one_minus_q_ * std::log(v_ + x)) * one_minus_q_inv_; - x += v_; - return (one_minus_q_ == -1.0) - ? (-1.0 / x) // -exp(-log(x)) - : (std::exp(std::log(x) * one_minus_q_) * one_minus_q_inv_); -} - -template <typename IntType> -double zipf_distribution<IntType>::param_type::hinv(double x) const { - // std::exp(one_minus_q_inv_ * std::log(one_minus_q_ * x)) - v_; - return -v_ + ((one_minus_q_ == -1.0) - ? (-1.0 / x) // exp(-log(-x)) - : std::exp(one_minus_q_inv_ * std::log(one_minus_q_ * x))); -} - -template <typename IntType> -double zipf_distribution<IntType>::param_type::compute_s() const { - // 1 - hinv(h(1.5) - std::exp(std::log(v_ + 1) * -q_)); - return 1.0 - hinv(h(1.5) - pow_negative_q(v_ + 1.0)); -} - -template <typename IntType> -double zipf_distribution<IntType>::param_type::pow_negative_q(double x) const { - // std::exp(std::log(x) * -q_); - return q_ == 2.0 ? (1.0 / (x * x)) : std::exp(std::log(x) * -q_); -} - -template <typename IntType> -template <typename URBG> -typename zipf_distribution<IntType>::result_type -zipf_distribution<IntType>::operator()( - URBG& g, const param_type& p) { // NOLINT(runtime/references) - absl::uniform_real_distribution<double> uniform_double; - double k; - for (;;) { - const double v = uniform_double(g); - const double u = p.hxm_ + v * p.hx0_minus_hxm_; - const double x = p.hinv(u); - k = rint(x); // std::floor(x + 0.5); - if (k > p.k()) continue; // reject k > max_k - if (k - x <= p.s_) break; - const double h = p.h(k + 0.5); - const double r = p.pow_negative_q(p.v_ + k); - if (u >= h - r) break; - } - IntType ki = static_cast<IntType>(k); - assert(ki <= p.k_); - return ki; -} - -template <typename CharT, typename Traits, typename IntType> -std::basic_ostream<CharT, Traits>& operator<<( - std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) - const zipf_distribution<IntType>& x) { - using stream_type = - typename random_internal::stream_format_type<IntType>::type; - auto saver = random_internal::make_ostream_state_saver(os); - os.precision(random_internal::stream_precision_helper<double>::kPrecision); - os << static_cast<stream_type>(x.k()) << os.fill() << x.q() << os.fill() - << x.v(); - return os; -} - -template <typename CharT, typename Traits, typename IntType> -std::basic_istream<CharT, Traits>& operator>>( - std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) - zipf_distribution<IntType>& x) { // NOLINT(runtime/references) - using result_type = typename zipf_distribution<IntType>::result_type; - using param_type = typename zipf_distribution<IntType>::param_type; - using stream_type = - typename random_internal::stream_format_type<IntType>::type; - stream_type k; - double q; - double v; - - auto saver = random_internal::make_istream_state_saver(is); - is >> k >> q >> v; - if (!is.fail()) { - x.param(param_type(static_cast<result_type>(k), q, v)); - } - return is; -} - + +// absl::zipf_distribution produces random integer-values in the range [0, k], +// distributed according to the discrete probability function: +// +// P(x) = (v + x) ^ -q +// +// The parameter `v` must be greater than 0 and the parameter `q` must be +// greater than 1. If either of these parameters take invalid values then the +// behavior is undefined. +// +// IntType is the result_type generated by the generator. It must be of integral +// type; a static_assert ensures this is the case. +// +// The implementation is based on W.Hormann, G.Derflinger: +// +// "Rejection-Inversion to Generate Variates from Monotone Discrete +// Distributions" +// +// http://eeyore.wu-wien.ac.at/papers/96-04-04.wh-der.ps.gz +// +template <typename IntType = int> +class zipf_distribution { + public: + using result_type = IntType; + + class param_type { + public: + using distribution_type = zipf_distribution; + + // Preconditions: k > 0, v > 0, q > 1 + // The precondidtions are validated when NDEBUG is not defined via + // a pair of assert() directives. + // If NDEBUG is defined and either or both of these parameters take invalid + // values, the behavior of the class is undefined. + explicit param_type(result_type k = (std::numeric_limits<IntType>::max)(), + double q = 2.0, double v = 1.0); + + result_type k() const { return k_; } + double q() const { return q_; } + double v() const { return v_; } + + friend bool operator==(const param_type& a, const param_type& b) { + return a.k_ == b.k_ && a.q_ == b.q_ && a.v_ == b.v_; + } + friend bool operator!=(const param_type& a, const param_type& b) { + return !(a == b); + } + + private: + friend class zipf_distribution; + inline double h(double x) const; + inline double hinv(double x) const; + inline double compute_s() const; + inline double pow_negative_q(double x) const; + + // Parameters here are exactly the same as the parameters of Algorithm ZRI + // in the paper. + IntType k_; + double q_; + double v_; + + double one_minus_q_; // 1-q + double s_; + double one_minus_q_inv_; // 1 / 1-q + double hxm_; // h(k + 0.5) + double hx0_minus_hxm_; // h(x0) - h(k + 0.5) + + static_assert(std::is_integral<IntType>::value, + "Class-template absl::zipf_distribution<> must be " + "parameterized using an integral type."); + }; + + zipf_distribution() + : zipf_distribution((std::numeric_limits<IntType>::max)()) {} + + explicit zipf_distribution(result_type k, double q = 2.0, double v = 1.0) + : param_(k, q, v) {} + + explicit zipf_distribution(const param_type& p) : param_(p) {} + + void reset() {} + + template <typename URBG> + result_type operator()(URBG& g) { // NOLINT(runtime/references) + return (*this)(g, param_); + } + + template <typename URBG> + result_type operator()(URBG& g, // NOLINT(runtime/references) + const param_type& p); + + result_type k() const { return param_.k(); } + double q() const { return param_.q(); } + double v() const { return param_.v(); } + + param_type param() const { return param_; } + void param(const param_type& p) { param_ = p; } + + result_type(min)() const { return 0; } + result_type(max)() const { return k(); } + + friend bool operator==(const zipf_distribution& a, + const zipf_distribution& b) { + return a.param_ == b.param_; + } + friend bool operator!=(const zipf_distribution& a, + const zipf_distribution& b) { + return a.param_ != b.param_; + } + + private: + param_type param_; +}; + +// -------------------------------------------------------------------------- +// Implementation details follow +// -------------------------------------------------------------------------- + +template <typename IntType> +zipf_distribution<IntType>::param_type::param_type( + typename zipf_distribution<IntType>::result_type k, double q, double v) + : k_(k), q_(q), v_(v), one_minus_q_(1 - q) { + assert(q > 1); + assert(v > 0); + assert(k > 0); + one_minus_q_inv_ = 1 / one_minus_q_; + + // Setup for the ZRI algorithm (pg 17 of the paper). + // Compute: h(i max) => h(k + 0.5) + constexpr double kMax = 18446744073709549568.0; + double kd = static_cast<double>(k); + // TODO(absl-team): Determine if this check is needed, and if so, add a test + // that fails for k > kMax + if (kd > kMax) { + // Ensure that our maximum value is capped to a value which will + // round-trip back through double. + kd = kMax; + } + hxm_ = h(kd + 0.5); + + // Compute: h(0) + const bool use_precomputed = (v == 1.0 && q == 2.0); + const double h0x5 = use_precomputed ? (-1.0 / 1.5) // exp(-log(1.5)) + : h(0.5); + const double elogv_q = (v_ == 1.0) ? 1 : pow_negative_q(v_); + + // h(0) = h(0.5) - exp(log(v) * -q) + hx0_minus_hxm_ = (h0x5 - elogv_q) - hxm_; + + // And s + s_ = use_precomputed ? 0.46153846153846123 : compute_s(); +} + +template <typename IntType> +double zipf_distribution<IntType>::param_type::h(double x) const { + // std::exp(one_minus_q_ * std::log(v_ + x)) * one_minus_q_inv_; + x += v_; + return (one_minus_q_ == -1.0) + ? (-1.0 / x) // -exp(-log(x)) + : (std::exp(std::log(x) * one_minus_q_) * one_minus_q_inv_); +} + +template <typename IntType> +double zipf_distribution<IntType>::param_type::hinv(double x) const { + // std::exp(one_minus_q_inv_ * std::log(one_minus_q_ * x)) - v_; + return -v_ + ((one_minus_q_ == -1.0) + ? (-1.0 / x) // exp(-log(-x)) + : std::exp(one_minus_q_inv_ * std::log(one_minus_q_ * x))); +} + +template <typename IntType> +double zipf_distribution<IntType>::param_type::compute_s() const { + // 1 - hinv(h(1.5) - std::exp(std::log(v_ + 1) * -q_)); + return 1.0 - hinv(h(1.5) - pow_negative_q(v_ + 1.0)); +} + +template <typename IntType> +double zipf_distribution<IntType>::param_type::pow_negative_q(double x) const { + // std::exp(std::log(x) * -q_); + return q_ == 2.0 ? (1.0 / (x * x)) : std::exp(std::log(x) * -q_); +} + +template <typename IntType> +template <typename URBG> +typename zipf_distribution<IntType>::result_type +zipf_distribution<IntType>::operator()( + URBG& g, const param_type& p) { // NOLINT(runtime/references) + absl::uniform_real_distribution<double> uniform_double; + double k; + for (;;) { + const double v = uniform_double(g); + const double u = p.hxm_ + v * p.hx0_minus_hxm_; + const double x = p.hinv(u); + k = rint(x); // std::floor(x + 0.5); + if (k > p.k()) continue; // reject k > max_k + if (k - x <= p.s_) break; + const double h = p.h(k + 0.5); + const double r = p.pow_negative_q(p.v_ + k); + if (u >= h - r) break; + } + IntType ki = static_cast<IntType>(k); + assert(ki <= p.k_); + return ki; +} + +template <typename CharT, typename Traits, typename IntType> +std::basic_ostream<CharT, Traits>& operator<<( + std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) + const zipf_distribution<IntType>& x) { + using stream_type = + typename random_internal::stream_format_type<IntType>::type; + auto saver = random_internal::make_ostream_state_saver(os); + os.precision(random_internal::stream_precision_helper<double>::kPrecision); + os << static_cast<stream_type>(x.k()) << os.fill() << x.q() << os.fill() + << x.v(); + return os; +} + +template <typename CharT, typename Traits, typename IntType> +std::basic_istream<CharT, Traits>& operator>>( + std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) + zipf_distribution<IntType>& x) { // NOLINT(runtime/references) + using result_type = typename zipf_distribution<IntType>::result_type; + using param_type = typename zipf_distribution<IntType>::param_type; + using stream_type = + typename random_internal::stream_format_type<IntType>::type; + stream_type k; + double q; + double v; + + auto saver = random_internal::make_istream_state_saver(is); + is >> k >> q >> v; + if (!is.fail()) { + x.param(param_type(static_cast<result_type>(k), q, v)); + } + return is; +} + ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_ZIPF_DISTRIBUTION_H_ +} // namespace absl + +#endif // ABSL_RANDOM_ZIPF_DISTRIBUTION_H_ |