diff options
author | anastasy888 <anastasy888@yandex-team.ru> | 2022-02-10 16:45:54 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:54 +0300 |
commit | 49f765d71da452ea93138a25559dfa68dd76c7f3 (patch) | |
tree | 1016041feb637349e401dcc0fa85217dd2c2c639 /contrib/restricted/abseil-cpp/absl/random/internal | |
parent | 7353a3fdea9c67c256980c00a2b3b67f09b23a27 (diff) | |
download | ydb-49f765d71da452ea93138a25559dfa68dd76c7f3.tar.gz |
Restoring authorship annotation for <anastasy888@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/restricted/abseil-cpp/absl/random/internal')
40 files changed, 5149 insertions, 5149 deletions
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 340d08c827..c19fb5333a 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 640d48cea6..6796cb8db4 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 07f4fbe522..aedeec4f11 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 fc81b787eb..3e2dfed99d 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 e9005658c0..6796322a1b 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 6d94cf6c97..ea44666b4b 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 25f791535f..01db58444a 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 425aaf7d83..3717a3904d 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 963b7690f1..83115715dd 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 d5fbb44c24..46ff913090 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 e6e242ee1e..aaef9f476c 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 a5097ba27b..103c05f156 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 730fa2ea12..2635b75d70 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 8efaf2e09a..5a8340020e 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 bbdb4e6208..fcd5d461a7 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 725100a415..a715397110 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 05721929f5..f4fd5e166a 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 fd4e1c1f4d..98183380de 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 c1bc044435..996b489bb6 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 9a3840b8f1..6c2d53e210 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 150b9e0714..22f85e42ee 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 bbe7b96532..991512b18a 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 f283f43226..40ca2a2860 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 62059877ba..8191995ddf 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 372c3ac2bd..053c258550 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 fee6677cb4..6758243a27 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 71a7f69f25..c56f8cad5e 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 267ce26c5f..14ef865fd2 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 9bfd2a4092..35446ef214 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 532c3a8991..efa9c4c144 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 af124ae798..a0cfde87e4 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 120022c9fb..92b1937b3e 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 5953a090f8..67ead19418 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 c03cad8502..6457ece3df 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 4be10e9256..bddbb3cda1 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 65618b087d..d4a024053f 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 bc96a12cd2..3ed7dfd6e0 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 75772bd9ab..aa39823632 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 1243bc1c62..30ae9d10f3 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 b6e6c4b6aa..04085c8411 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_ |