Commit 768eb2ca by Abseil Team Committed by Mark Barolak

Export of internal Abseil changes

--
f012012ef78234a6a4585321b67d7b7c92ebc266 by Laramie Leavitt <lar@google.com>:

Slight restructuring of absl/random/internal randen implementation.

Convert round-keys.inc into randen_round_keys.cc file.

Consistently use a 128-bit pointer type for internal method parameters. This allows simpler pointer arithmetic in C++ & permits removal of some constants and casts.

Remove some redundancy in comments & constexpr variables. Specifically, all references to Randen algorithm parameters use RandenTraits; duplication in RandenSlow removed.

PiperOrigin-RevId: 312190313

--
dc8b42e054046741e9ed65335bfdface997c6063 by Abseil Team <absl-team@google.com>:

Internal change.

PiperOrigin-RevId: 312167304

--
f13d248fafaf206492c1362c3574031aea3abaf7 by Matthew Brown <matthewbr@google.com>:

Cleanup StrFormat extensions a little.

PiperOrigin-RevId: 312166336

--
9d9117589667afe2332bb7ad42bc967ca7c54502 by Derek Mauro <dmauro@google.com>:

Internal change

PiperOrigin-RevId: 312105213

--
9a12b9b3aa0e59b8ee6cf9408ed0029045543a9b by Abseil Team <absl-team@google.com>:

Complete IGNORE_TYPE macro renaming.

PiperOrigin-RevId: 311999699

--
64756f20d61021d999bd0d4c15e9ad3857382f57 by Gennadiy Rozental <rogeeff@google.com>:

Switch to fixed bytes specific default value.

This fixes the Abseil Flags for big endian platforms.

PiperOrigin-RevId: 311844448

--
bdbe6b5b29791dbc3816ada1828458b3010ff1e9 by Laramie Leavitt <lar@google.com>:

Change many distribution tests to use pcg_engine as a deterministic source of entropy.

It's reasonable to test that the BitGen itself has good entropy, however when testing the cross product of all random distributions x all the architecture variations x all submitted changes results in a large number of tests. In order to account for these failures while still using good entropy requires that our allowed sigma need to account for all of these independent tests.

Our current sigma values are too restrictive, and we see a lot of failures, so we have to either relax the sigma values or convert some of the statistical tests to use deterministic values.

This changelist does the latter.

PiperOrigin-RevId: 311840096
GitOrigin-RevId: f012012ef78234a6a4585321b67d7b7c92ebc266
Change-Id: Ic84886f38ff30d7d72c126e9b63c9a61eb729a1a
parent 3f347c46
......@@ -147,6 +147,7 @@ set(ABSL_INTERNAL_DLL_FILES
"random/internal/platform.h"
"random/internal/pool_urbg.cc"
"random/internal/pool_urbg.h"
"random/internal/randen_round_keys.cc"
"random/internal/randen.cc"
"random/internal/randen.h"
"random/internal/randen_detect.cc"
......
......@@ -64,4 +64,24 @@
#define ABSL_FLAGS_INTERNAL_HAS_RTTI 1
#endif // !defined(__GNUC__) || defined(__GXX_RTTI)
// These macros represent the "source of truth" for the list of supported
// built-in types.
#define ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(A) \
A(bool, bool) \
A(short, short) \
A(unsigned short, unsigned_short) \
A(int, int) \
A(unsigned int, unsigned_int) \
A(long, long) \
A(unsigned long, unsigned_long) \
A(long long, long_long) \
A(unsigned long long, unsigned_long_long) \
A(double, double) \
A(float, float)
#define ABSL_FLAGS_INTERNAL_SUPPORTED_TYPES(A) \
ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(A) \
A(std::string, std_string) \
A(std::vector<std::string>, std_vector_of_string)
#endif // ABSL_FLAGS_CONFIG_H_
......@@ -145,8 +145,8 @@ DEFINE_CONSTRUCTED_FLAG(int32_t, 3, kOneWord);
DEFINE_CONSTRUCTED_FLAG(uint32_t, 4, kOneWord);
DEFINE_CONSTRUCTED_FLAG(int64_t, 5, kOneWord);
DEFINE_CONSTRUCTED_FLAG(uint64_t, 6, kOneWord);
DEFINE_CONSTRUCTED_FLAG(float, 7.8, kFloat);
DEFINE_CONSTRUCTED_FLAG(double, 9.10, kDouble);
DEFINE_CONSTRUCTED_FLAG(float, 7.8, kOneWord);
DEFINE_CONSTRUCTED_FLAG(double, 9.10, kOneWord);
DEFINE_CONSTRUCTED_FLAG(String, &TestMakeDflt<String>, kGenFunc);
DEFINE_CONSTRUCTED_FLAG(UDT, &TestMakeDflt<UDT>, kGenFunc);
......
......@@ -178,23 +178,6 @@ class CommandLineFlag {
virtual void CheckDefaultValueParsingRoundtrip() const = 0;
};
// This macro is the "source of truth" for the list of supported flag built-in
// types.
#define ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(A) \
A(bool) \
A(short) \
A(unsigned short) \
A(int) \
A(unsigned int) \
A(long) \
A(unsigned long) \
A(long long) \
A(unsigned long long) \
A(double) \
A(float) \
A(std::string) \
A(std::vector<std::string>)
} // namespace flags_internal
ABSL_NAMESPACE_END
} // namespace absl
......
......@@ -49,9 +49,9 @@ namespace {
// Currently we only validate flag values for user-defined flag types.
bool ShouldValidateFlagValue(FlagFastTypeId flag_type_id) {
#define DONT_VALIDATE(T) \
#define DONT_VALIDATE(T, _) \
if (flag_type_id == base_internal::FastTypeId<T>()) return false;
ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(DONT_VALIDATE)
ABSL_FLAGS_INTERNAL_SUPPORTED_TYPES(DONT_VALIDATE)
#undef DONT_VALIDATE
return true;
......@@ -150,23 +150,11 @@ void FlagImpl::Init() {
break;
case FlagValueStorageKind::kOneWordAtomic: {
alignas(int64_t) std::array<char, sizeof(int64_t)> buf{};
switch (def_kind) {
case FlagDefaultKind::kOneWord:
std::memcpy(buf.data(), &default_value_.one_word,
sizeof(default_value_.one_word));
break;
case FlagDefaultKind::kFloat:
std::memcpy(buf.data(), &default_value_.float_value,
sizeof(default_value_.float_value));
break;
case FlagDefaultKind::kDouble:
std::memcpy(buf.data(), &default_value_.double_value,
sizeof(default_value_.double_value));
break;
default:
assert(def_kind == FlagDefaultKind::kGenFunc);
(*default_value_.gen_func)(buf.data());
break;
if (def_kind == FlagDefaultKind::kGenFunc) {
(*default_value_.gen_func)(buf.data());
} else {
assert(def_kind != FlagDefaultKind::kDynamicValue);
std::memcpy(buf.data(), &default_value_, Sizeof(op_));
}
OneWordValue().store(absl::bit_cast<int64_t>(buf),
std::memory_order_release);
......@@ -228,14 +216,8 @@ std::unique_ptr<void, DynValueDeleter> FlagImpl::MakeInitValue() const {
res = flags_internal::Alloc(op_);
(*default_value_.gen_func)(res);
break;
case FlagDefaultKind::kOneWord:
res = flags_internal::Clone(op_, &default_value_.one_word);
break;
case FlagDefaultKind::kFloat:
res = flags_internal::Clone(op_, &default_value_.float_value);
break;
case FlagDefaultKind::kDouble:
res = flags_internal::Clone(op_, &default_value_.double_value);
default:
res = flags_internal::Clone(op_, &default_value_);
break;
}
return {res, DynValueDeleter{op_}};
......
......@@ -231,25 +231,21 @@ using FlagDfltGenFunc = void (*)(void*);
union FlagDefaultSrc {
constexpr explicit FlagDefaultSrc(FlagDfltGenFunc gen_func_arg)
: gen_func(gen_func_arg) {}
template <typename T>
constexpr explicit FlagDefaultSrc(T one_word_value)
: one_word(static_cast<int64_t>(one_word_value)) {}
constexpr explicit FlagDefaultSrc(float f) : float_value(f) {}
constexpr explicit FlagDefaultSrc(double d) : double_value(d) {}
#define ABSL_FLAGS_INTERNAL_DFLT_FOR_TYPE(T, name) \
T name##_value; \
constexpr explicit FlagDefaultSrc(T value) : name##_value(value) {} // NOLINT
ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(ABSL_FLAGS_INTERNAL_DFLT_FOR_TYPE)
#undef ABSL_FLAGS_INTERNAL_DFLT_FOR_TYPE
void* dynamic_value;
FlagDfltGenFunc gen_func;
int64_t one_word;
float float_value;
double double_value;
};
enum class FlagDefaultKind : uint8_t {
kDynamicValue = 0,
kGenFunc = 1,
kOneWord = 2,
kFloat = 3,
kDouble = 4
kOneWord = 2 // for default values UP to one word in size
};
struct FlagDefaultArg {
......@@ -279,20 +275,6 @@ constexpr FlagDefaultArg DefaultArg(int) {
return {FlagDefaultSrc(GenT{}.value), FlagDefaultKind::kOneWord};
}
template <typename ValueT, typename GenT,
typename std::enable_if<std::is_same<ValueT, float>::value,
int>::type = (GenT{}, 0)>
constexpr FlagDefaultArg DefaultArg(int) {
return {FlagDefaultSrc(GenT{}.value), FlagDefaultKind::kFloat};
}
template <typename ValueT, typename GenT,
typename std::enable_if<std::is_same<ValueT, double>::value,
int>::type = (GenT{}, 0)>
constexpr FlagDefaultArg DefaultArg(int) {
return {FlagDefaultSrc(GenT{}.value), FlagDefaultKind::kDouble};
}
template <typename ValueT, typename GenT>
constexpr FlagDefaultArg DefaultArg(char) {
return {FlagDefaultSrc(&GenT::Gen), FlagDefaultKind::kGenFunc};
......@@ -576,9 +558,8 @@ class FlagImpl final : public flags_internal::CommandLineFlag {
// Mutable flag's state (guarded by `data_guard_`).
// def_kind_ is not guard by DataGuard() since it is accessed in Init without
// locks. If necessary we can decrease number of bits used to 2 by folding
// one_word storage cases.
uint8_t def_kind_ : 3;
// locks.
uint8_t def_kind_ : 2;
// Has this flag's value been modified?
bool modified_ : 1 ABSL_GUARDED_BY(*DataGuard());
// Has this flag been specified on command line.
......
......@@ -309,11 +309,11 @@ void CheckDefaultValuesParsingRoundtrip() {
flags_internal::ForEachFlag([&](CommandLineFlag* flag) {
if (flag->IsRetired()) return;
#define IGNORE_TYPE(T) \
#define ABSL_FLAGS_INTERNAL_IGNORE_TYPE(T, _) \
if (flag->IsOfType<T>()) return;
ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(IGNORE_TYPE)
#undef IGNORE_TYPE
ABSL_FLAGS_INTERNAL_SUPPORTED_TYPES(ABSL_FLAGS_INTERNAL_IGNORE_TYPE)
#undef ABSL_FLAGS_INTERNAL_IGNORE_TYPE
flags_internal::PrivateHandleAccessor::CheckDefaultValueParsingRoundtrip(
*flag);
......
......@@ -168,6 +168,7 @@ cc_test(
deps = [
":distributions",
":random",
"//absl/random/internal:pcg_engine",
"//absl/random/internal:sequence_urbg",
"@com_google_googletest//:gtest_main",
],
......@@ -186,6 +187,7 @@ cc_test(
":random",
"//absl/base:raw_logging_internal",
"//absl/random/internal:distribution_test_util",
"//absl/random/internal:pcg_engine",
"//absl/random/internal:sequence_urbg",
"//absl/strings",
"//absl/strings:str_format",
......@@ -233,9 +235,9 @@ cc_test(
deps = [
":distributions",
":random",
"//absl/base:core_headers",
"//absl/base:raw_logging_internal",
"//absl/random/internal:distribution_test_util",
"//absl/random/internal:pcg_engine",
"//absl/random/internal:sequence_urbg",
"//absl/strings",
"//absl/strings:str_format",
......@@ -256,6 +258,7 @@ cc_test(
":random",
"//absl/base:raw_logging_internal",
"//absl/random/internal:distribution_test_util",
"//absl/random/internal:pcg_engine",
"//absl/random/internal:sequence_urbg",
"//absl/strings",
"@com_google_googletest//:gtest_main",
......@@ -283,6 +286,7 @@ cc_test(
"//absl/base:raw_logging_internal",
"//absl/container:flat_hash_map",
"//absl/random/internal:distribution_test_util",
"//absl/random/internal:pcg_engine",
"//absl/random/internal:sequence_urbg",
"//absl/strings",
"//absl/strings:str_format",
......@@ -302,6 +306,7 @@ cc_test(
"//absl/base:core_headers",
"//absl/base:raw_logging_internal",
"//absl/random/internal:distribution_test_util",
"//absl/random/internal:pcg_engine",
"//absl/random/internal:sequence_urbg",
"//absl/strings",
"//absl/strings:str_format",
......@@ -345,6 +350,7 @@ cc_test(
":random",
"//absl/base:raw_logging_internal",
"//absl/random/internal:distribution_test_util",
"//absl/random/internal:pcg_engine",
"//absl/random/internal:sequence_urbg",
"//absl/strings",
"@com_google_googletest//:gtest_main",
......@@ -369,6 +375,7 @@ cc_test(
":random",
"//absl/base:raw_logging_internal",
"//absl/random/internal:distribution_test_util",
"//absl/random/internal:pcg_engine",
"//absl/random/internal:sequence_urbg",
"//absl/strings",
"@com_google_googletest//:gtest_main",
......@@ -388,6 +395,7 @@ cc_test(
":random",
"//absl/base:raw_logging_internal",
"//absl/random/internal:distribution_test_util",
"//absl/random/internal:pcg_engine",
"//absl/random/internal:sequence_urbg",
"//absl/strings",
"@com_google_googletest//:gtest_main",
......
......@@ -244,6 +244,7 @@ absl_cc_test(
absl::random_distributions
absl::random_random
absl::random_internal_sequence_urbg
absl::random_internal_pcg_engine
gmock
gtest_main
)
......@@ -262,6 +263,7 @@ absl_cc_test(
absl::random_random
absl::random_internal_distribution_test_util
absl::random_internal_sequence_urbg
absl::random_internal_pcg_engine
absl::raw_logging_internal
absl::strings
absl::str_format
......@@ -311,9 +313,9 @@ absl_cc_test(
${ABSL_TEST_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
absl::core_headers
absl::random_distributions
absl::random_internal_distribution_test_util
absl::random_internal_pcg_engine
absl::random_internal_sequence_urbg
absl::random_random
absl::raw_logging_internal
......@@ -335,6 +337,7 @@ absl_cc_test(
DEPS
absl::random_distributions
absl::random_internal_distribution_test_util
absl::random_internal_pcg_engine
absl::random_internal_sequence_urbg
absl::random_random
absl::raw_logging_internal
......@@ -358,6 +361,7 @@ absl_cc_test(
absl::core_headers
absl::flat_hash_map
absl::random_internal_distribution_test_util
absl::random_internal_pcg_engine
absl::random_internal_sequence_urbg
absl::raw_logging_internal
absl::strings
......@@ -379,6 +383,7 @@ absl_cc_test(
absl::core_headers
absl::random_distributions
absl::random_internal_distribution_test_util
absl::random_internal_pcg_engine
absl::random_internal_sequence_urbg
absl::random_random
absl::raw_logging_internal
......@@ -422,6 +427,7 @@ absl_cc_test(
DEPS
absl::random_distributions
absl::random_internal_distribution_test_util
absl::random_internal_pcg_engine
absl::random_internal_sequence_urbg
absl::random_random
absl::raw_logging_internal
......@@ -442,6 +448,7 @@ absl_cc_test(
DEPS
absl::random_distributions
absl::random_internal_distribution_test_util
absl::random_internal_pcg_engine
absl::random_internal_sequence_urbg
absl::random_random
absl::strings
......@@ -461,6 +468,7 @@ absl_cc_test(
DEPS
absl::random_distributions
absl::random_internal_distribution_test_util
absl::random_internal_pcg_engine
absl::random_internal_sequence_urbg
absl::random_random
absl::raw_logging_internal
......@@ -782,8 +790,9 @@ absl_cc_library(
random_internal_platform
HDRS
"internal/randen_traits.h"
"internal/randen-keys.inc"
"internal/platform.h"
SRCS
"internal/randen_round_keys.cc"
COPTS
${ABSL_DEFAULT_COPTS}
LINKOPTS
......
......@@ -21,6 +21,7 @@
#include <utility>
#include "gtest/gtest.h"
#include "absl/random/internal/pcg_engine.h"
#include "absl/random/internal/sequence_urbg.h"
#include "absl/random/random.h"
......@@ -63,7 +64,10 @@ TEST_P(BernoulliTest, Accuracy) {
size_t trials = para.second;
double p = para.first;
absl::InsecureBitGen rng;
// We use a fixed bit generator for distribution accuracy tests. This allows
// these tests to be deterministic, while still testing the qualify of the
// implementation.
absl::random_internal::pcg64_2018_engine rng(0x2B7E151628AED2A6);
size_t yes = 0;
absl::bernoulli_distribution dist(p);
......
......@@ -29,6 +29,7 @@
#include "absl/base/internal/raw_logging.h"
#include "absl/random/internal/chi_square.h"
#include "absl/random/internal/distribution_test_util.h"
#include "absl/random/internal/pcg_engine.h"
#include "absl/random/internal/sequence_urbg.h"
#include "absl/random/random.h"
#include "absl/strings/str_cat.h"
......@@ -159,8 +160,12 @@ TYPED_TEST(BetaDistributionInterfaceTest, SerializeTest) {
}
TYPED_TEST(BetaDistributionInterfaceTest, DegenerateCases) {
// We use a fixed bit generator for distribution accuracy tests. This allows
// these tests to be deterministic, while still testing the qualify of the
// implementation.
absl::random_internal::pcg64_2018_engine rng(0x2B7E151628AED2A6);
// Extreme cases when the params are abnormal.
absl::InsecureBitGen gen;
constexpr int kCount = 1000;
const TypeParam kSmallValues[] = {
std::numeric_limits<TypeParam>::min(),
......@@ -186,7 +191,7 @@ TYPED_TEST(BetaDistributionInterfaceTest, DegenerateCases) {
int ones = 0;
absl::beta_distribution<TypeParam> d(alpha, beta);
for (int i = 0; i < kCount; ++i) {
TypeParam x = d(gen);
TypeParam x = d(rng);
if (x == 0.0) {
zeros++;
} else if (x == 1.0) {
......@@ -212,7 +217,7 @@ TYPED_TEST(BetaDistributionInterfaceTest, DegenerateCases) {
for (TypeParam beta : kLargeValues) {
absl::beta_distribution<TypeParam> d(alpha, beta);
for (int i = 0; i < kCount; ++i) {
EXPECT_EQ(d(gen), 0.0);
EXPECT_EQ(d(rng), 0.0);
}
}
}
......@@ -227,7 +232,7 @@ TYPED_TEST(BetaDistributionInterfaceTest, DegenerateCases) {
for (TypeParam beta : kSmallValues) {
absl::beta_distribution<TypeParam> d(alpha, beta);
for (int i = 0; i < kCount; ++i) {
EXPECT_EQ(d(gen), 1.0);
EXPECT_EQ(d(rng), 1.0);
}
}
}
......@@ -237,7 +242,7 @@ TYPED_TEST(BetaDistributionInterfaceTest, DegenerateCases) {
absl::beta_distribution<TypeParam> d(std::numeric_limits<TypeParam>::max(),
std::numeric_limits<TypeParam>::max());
for (int i = 0; i < kCount; ++i) {
EXPECT_EQ(d(gen), 0.5);
EXPECT_EQ(d(rng), 0.5);
}
}
{
......@@ -246,7 +251,7 @@ TYPED_TEST(BetaDistributionInterfaceTest, DegenerateCases) {
std::numeric_limits<TypeParam>::max(),
std::numeric_limits<TypeParam>::max() * 0.9999);
for (int i = 0; i < kCount; ++i) {
TypeParam x = d(gen);
TypeParam x = d(rng);
EXPECT_NE(x, 0.5f);
EXPECT_FLOAT_EQ(x, 0.500025f);
}
......
......@@ -29,6 +29,7 @@
#include "absl/base/internal/raw_logging.h"
#include "absl/random/internal/chi_square.h"
#include "absl/random/internal/distribution_test_util.h"
#include "absl/random/internal/pcg_engine.h"
#include "absl/random/internal/sequence_urbg.h"
#include "absl/random/random.h"
#include "absl/strings/str_cat.h"
......@@ -156,7 +157,10 @@ TEST(DiscreteDistributionTest, ChiSquaredTest50) {
std::iota(std::begin(weights), std::end(weights), 1);
absl::discrete_distribution<int> dist(std::begin(weights), std::end(weights));
absl::InsecureBitGen rng;
// We use a fixed bit generator for distribution accuracy tests. This allows
// these tests to be deterministic, while still testing the qualify of the
// implementation.
absl::random_internal::pcg64_2018_engine rng(0x2B7E151628AED2A6);
std::vector<int32_t> counts(kBuckets, 0);
for (size_t i = 0; i < kTrials; i++) {
......
......@@ -32,6 +32,7 @@
#include "absl/base/macros.h"
#include "absl/random/internal/chi_square.h"
#include "absl/random/internal/distribution_test_util.h"
#include "absl/random/internal/pcg_engine.h"
#include "absl/random/internal/sequence_urbg.h"
#include "absl/random/random.h"
#include "absl/strings/str_cat.h"
......@@ -205,7 +206,10 @@ class ExponentialDistributionTests : public testing::TestWithParam<Param>,
template <typename D>
double SingleChiSquaredTest();
absl::InsecureBitGen rng_;
// We use a fixed bit generator for distribution accuracy tests. This allows
// these tests to be deterministic, while still testing the qualify of the
// implementation.
absl::random_internal::pcg64_2018_engine rng_{0x2B7E151628AED2A6};
};
template <typename D>
......
......@@ -216,7 +216,10 @@ class GaussianDistributionTests : public testing::TestWithParam<Param>,
template <typename D>
double SingleChiSquaredTest();
absl::InsecureBitGen rng_;
// We use a fixed bit generator for distribution accuracy tests. This allows
// these tests to be deterministic, while still testing the qualify of the
// implementation.
absl::random_internal::pcg64_2018_engine rng_{0x2B7E151628AED2A6};
};
template <typename D>
......
......@@ -255,13 +255,15 @@ cc_library(
cc_library(
name = "platform",
srcs = [
"randen_round_keys.cc",
],
hdrs = [
"randen_traits.h",
],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
textual_hdrs = [
"randen-keys.inc",
"platform.h",
],
deps = ["//absl/base:config"],
......@@ -613,6 +615,7 @@ cc_test(
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":platform",
":randen_slow",
"@com_google_googletest//:gtest_main",
],
......
// 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_KEYS_INC_
#define ABSL_RANDOM_INTERNAL_RANDEN_KEYS_INC_
// Textual header to include the randen_keys where necessary.
// REQUIRES: struct u64x2{}
//
// PROVIDES: kKeys
// PROVIDES: round_keys[]
// "Nothing up my sleeve" numbers from the first hex digits of Pi, obtained
// from http://hexpi.sourceforge.net/. The array was generated by following
// Python script:
/*
python << EOF
"""Generates Randen round keys array from pi-hex.62500.txt file."""
import binascii
KEYS = 136
def chunks(l, n):
"""Yield successive n-sized chunks from l."""
for i in range(0, len(l), n):
yield l[i:i + n]
def pairwise(t):
"""Transforms sequence into sequence of pairs."""
it = iter(t)
return zip(it,it)
def digits_from_pi():
"""Reads digits from hexpi.sourceforge.net file."""
with open("pi-hex.62500.txt") as file:
return file.read()
def digits_from_urandom():
"""Reads digits from /dev/urandom."""
with open("/dev/urandom") as file:
return binascii.hexlify(file.read(KEYS * 16))
digits = digits_from_pi()
print("static constexpr const size_t kRoundKeys = {0};\n".format(KEYS))
print("alignas(16) constexpr const u64x2 round_keys[kRoundKeys] = {")
for i, (hi, lo) in zip(range(KEYS), pairwise(chunks(digits, 16))):
hi = "0x{0}ull".format(hi)
lo = "0x{0}ull".format(lo)
print(" u64x2({0}, {1}){2}".format(hi, lo, ',' if i+1 < KEYS else ''))
print("};")
EOF
*/
static constexpr const size_t kRoundKeys = 136;
alignas(16) constexpr u64x2 round_keys[kRoundKeys] = {
u64x2(0x243F6A8885A308D3ull, 0x13198A2E03707344ull),
u64x2(0xA4093822299F31D0ull, 0x082EFA98EC4E6C89ull),
u64x2(0x452821E638D01377ull, 0xBE5466CF34E90C6Cull),
u64x2(0xC0AC29B7C97C50DDull, 0x3F84D5B5B5470917ull),
u64x2(0x9216D5D98979FB1Bull, 0xD1310BA698DFB5ACull),
u64x2(0x2FFD72DBD01ADFB7ull, 0xB8E1AFED6A267E96ull),
u64x2(0xBA7C9045F12C7F99ull, 0x24A19947B3916CF7ull),
u64x2(0x0801F2E2858EFC16ull, 0x636920D871574E69ull),
u64x2(0xA458FEA3F4933D7Eull, 0x0D95748F728EB658ull),
u64x2(0x718BCD5882154AEEull, 0x7B54A41DC25A59B5ull),
u64x2(0x9C30D5392AF26013ull, 0xC5D1B023286085F0ull),
u64x2(0xCA417918B8DB38EFull, 0x8E79DCB0603A180Eull),
u64x2(0x6C9E0E8BB01E8A3Eull, 0xD71577C1BD314B27ull),
u64x2(0x78AF2FDA55605C60ull, 0xE65525F3AA55AB94ull),
u64x2(0x5748986263E81440ull, 0x55CA396A2AAB10B6ull),
u64x2(0xB4CC5C341141E8CEull, 0xA15486AF7C72E993ull),
u64x2(0xB3EE1411636FBC2Aull, 0x2BA9C55D741831F6ull),
u64x2(0xCE5C3E169B87931Eull, 0xAFD6BA336C24CF5Cull),
u64x2(0x7A32538128958677ull, 0x3B8F48986B4BB9AFull),
u64x2(0xC4BFE81B66282193ull, 0x61D809CCFB21A991ull),
u64x2(0x487CAC605DEC8032ull, 0xEF845D5DE98575B1ull),
u64x2(0xDC262302EB651B88ull, 0x23893E81D396ACC5ull),
u64x2(0x0F6D6FF383F44239ull, 0x2E0B4482A4842004ull),
u64x2(0x69C8F04A9E1F9B5Eull, 0x21C66842F6E96C9Aull),
u64x2(0x670C9C61ABD388F0ull, 0x6A51A0D2D8542F68ull),
u64x2(0x960FA728AB5133A3ull, 0x6EEF0B6C137A3BE4ull),
u64x2(0xBA3BF0507EFB2A98ull, 0xA1F1651D39AF0176ull),
u64x2(0x66CA593E82430E88ull, 0x8CEE8619456F9FB4ull),
u64x2(0x7D84A5C33B8B5EBEull, 0xE06F75D885C12073ull),
u64x2(0x401A449F56C16AA6ull, 0x4ED3AA62363F7706ull),
u64x2(0x1BFEDF72429B023Dull, 0x37D0D724D00A1248ull),
u64x2(0xDB0FEAD349F1C09Bull, 0x075372C980991B7Bull),
u64x2(0x25D479D8F6E8DEF7ull, 0xE3FE501AB6794C3Bull),
u64x2(0x976CE0BD04C006BAull, 0xC1A94FB6409F60C4ull),
u64x2(0x5E5C9EC2196A2463ull, 0x68FB6FAF3E6C53B5ull),
u64x2(0x1339B2EB3B52EC6Full, 0x6DFC511F9B30952Cull),
u64x2(0xCC814544AF5EBD09ull, 0xBEE3D004DE334AFDull),
u64x2(0x660F2807192E4BB3ull, 0xC0CBA85745C8740Full),
u64x2(0xD20B5F39B9D3FBDBull, 0x5579C0BD1A60320Aull),
u64x2(0xD6A100C6402C7279ull, 0x679F25FEFB1FA3CCull),
u64x2(0x8EA5E9F8DB3222F8ull, 0x3C7516DFFD616B15ull),
u64x2(0x2F501EC8AD0552ABull, 0x323DB5FAFD238760ull),
u64x2(0x53317B483E00DF82ull, 0x9E5C57BBCA6F8CA0ull),
u64x2(0x1A87562EDF1769DBull, 0xD542A8F6287EFFC3ull),
u64x2(0xAC6732C68C4F5573ull, 0x695B27B0BBCA58C8ull),
u64x2(0xE1FFA35DB8F011A0ull, 0x10FA3D98FD2183B8ull),
u64x2(0x4AFCB56C2DD1D35Bull, 0x9A53E479B6F84565ull),
u64x2(0xD28E49BC4BFB9790ull, 0xE1DDF2DAA4CB7E33ull),
u64x2(0x62FB1341CEE4C6E8ull, 0xEF20CADA36774C01ull),
u64x2(0xD07E9EFE2BF11FB4ull, 0x95DBDA4DAE909198ull),
u64x2(0xEAAD8E716B93D5A0ull, 0xD08ED1D0AFC725E0ull),
u64x2(0x8E3C5B2F8E7594B7ull, 0x8FF6E2FBF2122B64ull),
u64x2(0x8888B812900DF01Cull, 0x4FAD5EA0688FC31Cull),
u64x2(0xD1CFF191B3A8C1ADull, 0x2F2F2218BE0E1777ull),
u64x2(0xEA752DFE8B021FA1ull, 0xE5A0CC0FB56F74E8ull),
u64x2(0x18ACF3D6CE89E299ull, 0xB4A84FE0FD13E0B7ull),
u64x2(0x7CC43B81D2ADA8D9ull, 0x165FA26680957705ull),
u64x2(0x93CC7314211A1477ull, 0xE6AD206577B5FA86ull),
u64x2(0xC75442F5FB9D35CFull, 0xEBCDAF0C7B3E89A0ull),
u64x2(0xD6411BD3AE1E7E49ull, 0x00250E2D2071B35Eull),
u64x2(0x226800BB57B8E0AFull, 0x2464369BF009B91Eull),
u64x2(0x5563911D59DFA6AAull, 0x78C14389D95A537Full),
u64x2(0x207D5BA202E5B9C5ull, 0x832603766295CFA9ull),
u64x2(0x11C819684E734A41ull, 0xB3472DCA7B14A94Aull),
u64x2(0x1B5100529A532915ull, 0xD60F573FBC9BC6E4ull),
u64x2(0x2B60A47681E67400ull, 0x08BA6FB5571BE91Full),
u64x2(0xF296EC6B2A0DD915ull, 0xB6636521E7B9F9B6ull),
u64x2(0xFF34052EC5855664ull, 0x53B02D5DA99F8FA1ull),
u64x2(0x08BA47996E85076Aull, 0x4B7A70E9B5B32944ull),
u64x2(0xDB75092EC4192623ull, 0xAD6EA6B049A7DF7Dull),
u64x2(0x9CEE60B88FEDB266ull, 0xECAA8C71699A18FFull),
u64x2(0x5664526CC2B19EE1ull, 0x193602A575094C29ull),
u64x2(0xA0591340E4183A3Eull, 0x3F54989A5B429D65ull),
u64x2(0x6B8FE4D699F73FD6ull, 0xA1D29C07EFE830F5ull),
u64x2(0x4D2D38E6F0255DC1ull, 0x4CDD20868470EB26ull),
u64x2(0x6382E9C6021ECC5Eull, 0x09686B3F3EBAEFC9ull),
u64x2(0x3C9718146B6A70A1ull, 0x687F358452A0E286ull),
u64x2(0xB79C5305AA500737ull, 0x3E07841C7FDEAE5Cull),
u64x2(0x8E7D44EC5716F2B8ull, 0xB03ADA37F0500C0Dull),
u64x2(0xF01C1F040200B3FFull, 0xAE0CF51A3CB574B2ull),
u64x2(0x25837A58DC0921BDull, 0xD19113F97CA92FF6ull),
u64x2(0x9432477322F54701ull, 0x3AE5E58137C2DADCull),
u64x2(0xC8B576349AF3DDA7ull, 0xA94461460FD0030Eull),
u64x2(0xECC8C73EA4751E41ull, 0xE238CD993BEA0E2Full),
u64x2(0x3280BBA1183EB331ull, 0x4E548B384F6DB908ull),
u64x2(0x6F420D03F60A04BFull, 0x2CB8129024977C79ull),
u64x2(0x5679B072BCAF89AFull, 0xDE9A771FD9930810ull),
u64x2(0xB38BAE12DCCF3F2Eull, 0x5512721F2E6B7124ull),
u64x2(0x501ADDE69F84CD87ull, 0x7A5847187408DA17ull),
u64x2(0xBC9F9ABCE94B7D8Cull, 0xEC7AEC3ADB851DFAull),
u64x2(0x63094366C464C3D2ull, 0xEF1C18473215D808ull),
u64x2(0xDD433B3724C2BA16ull, 0x12A14D432A65C451ull),
u64x2(0x50940002133AE4DDull, 0x71DFF89E10314E55ull),
u64x2(0x81AC77D65F11199Bull, 0x043556F1D7A3C76Bull),
u64x2(0x3C11183B5924A509ull, 0xF28FE6ED97F1FBFAull),
u64x2(0x9EBABF2C1E153C6Eull, 0x86E34570EAE96FB1ull),
u64x2(0x860E5E0A5A3E2AB3ull, 0x771FE71C4E3D06FAull),
u64x2(0x2965DCB999E71D0Full, 0x803E89D65266C825ull),
u64x2(0x2E4CC9789C10B36Aull, 0xC6150EBA94E2EA78ull),
u64x2(0xA6FC3C531E0A2DF4ull, 0xF2F74EA7361D2B3Dull),
u64x2(0x1939260F19C27960ull, 0x5223A708F71312B6ull),
u64x2(0xEBADFE6EEAC31F66ull, 0xE3BC4595A67BC883ull),
u64x2(0xB17F37D1018CFF28ull, 0xC332DDEFBE6C5AA5ull),
u64x2(0x6558218568AB9702ull, 0xEECEA50FDB2F953Bull),
u64x2(0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull),
u64x2(0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull),
u64x2(0x0334FE1EAA0363CFull, 0xB5735C904C70A239ull),
u64x2(0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull),
u64x2(0x9CAB5CABB2F3846Eull, 0x648B1EAF19BDF0CAull),
u64x2(0xA02369B9655ABB50ull, 0x40685A323C2AB4B3ull),
u64x2(0x319EE9D5C021B8F7ull, 0x9B540B19875FA099ull),
u64x2(0x95F7997E623D7DA8ull, 0xF837889A97E32D77ull),
u64x2(0x11ED935F16681281ull, 0x0E358829C7E61FD6ull),
u64x2(0x96DEDFA17858BA99ull, 0x57F584A51B227263ull),
u64x2(0x9B83C3FF1AC24696ull, 0xCDB30AEB532E3054ull),
u64x2(0x8FD948E46DBC3128ull, 0x58EBF2EF34C6FFEAull),
u64x2(0xFE28ED61EE7C3C73ull, 0x5D4A14D9E864B7E3ull),
u64x2(0x42105D14203E13E0ull, 0x45EEE2B6A3AAABEAull),
u64x2(0xDB6C4F15FACB4FD0ull, 0xC742F442EF6ABBB5ull),
u64x2(0x654F3B1D41CD2105ull, 0xD81E799E86854DC7ull),
u64x2(0xE44B476A3D816250ull, 0xCF62A1F25B8D2646ull),
u64x2(0xFC8883A0C1C7B6A3ull, 0x7F1524C369CB7492ull),
u64x2(0x47848A0B5692B285ull, 0x095BBF00AD19489Dull),
u64x2(0x1462B17423820D00ull, 0x58428D2A0C55F5EAull),
u64x2(0x1DADF43E233F7061ull, 0x3372F0928D937E41ull),
u64x2(0xD65FECF16C223BDBull, 0x7CDE3759CBEE7460ull),
u64x2(0x4085F2A7CE77326Eull, 0xA607808419F8509Eull),
u64x2(0xE8EFD85561D99735ull, 0xA969A7AAC50C06C2ull),
u64x2(0x5A04ABFC800BCADCull, 0x9E447A2EC3453484ull),
u64x2(0xFDD567050E1E9EC9ull, 0xDB73DBD3105588CDull),
u64x2(0x675FDA79E3674340ull, 0xC5C43465713E38D8ull),
u64x2(0x3D28F89EF16DFF20ull, 0x153E21E78FB03D4Aull),
u64x2(0xE6E39F2BDB83ADF7ull, 0xE93D5A68948140F7ull),
u64x2(0xF64C261C94692934ull, 0x411520F77602D4F7ull),
u64x2(0xBCF46B2ED4A10068ull, 0xD40824713320F46Aull),
u64x2(0x43B7D4B7500061AFull, 0x1E39F62E97244546ull)};
#endif // ABSL_RANDOM_INTERNAL_RANDEN_KEYS_INC_
......@@ -27,12 +27,14 @@ namespace {
using absl::random_internal::RandenHwAes;
using absl::random_internal::RandenTraits;
struct randen {
static constexpr size_t kStateSizeT =
RandenTraits::kStateBytes / sizeof(uint64_t);
// Local state parameters.
constexpr size_t kSeedBytes =
RandenTraits::kStateBytes - RandenTraits::kCapacityBytes;
constexpr size_t kStateSizeT = RandenTraits::kStateBytes / sizeof(uint64_t);
constexpr size_t kSeedSizeT = kSeedBytes / sizeof(uint32_t);
struct alignas(16) randen {
uint64_t state[kStateSizeT];
static constexpr size_t kSeedSizeT =
RandenTraits::kSeedBytes / sizeof(uint32_t);
uint32_t seed[kSeedSizeT];
};
......
......@@ -28,13 +28,6 @@ namespace random_internal {
// architectures lacking AES hardware acceleration intrinsics.
class RandenSlow {
public:
// 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
static void Generate(const void* keys, void* state_void);
static void Absorb(const void* seed_void, void* state_void);
static const void* GetKeys();
......
......@@ -17,18 +17,20 @@
#include <cstring>
#include "gtest/gtest.h"
#include "absl/random/internal/randen_traits.h"
namespace {
using absl::random_internal::RandenSlow;
using absl::random_internal::RandenTraits;
// Local state parameters.
constexpr size_t kSeedBytes =
RandenSlow::kStateBytes - RandenSlow::kCapacityBytes;
constexpr size_t kStateSizeT = RandenSlow::kStateBytes / sizeof(uint64_t);
RandenTraits::kStateBytes - RandenTraits::kCapacityBytes;
constexpr size_t kStateSizeT = RandenTraits::kStateBytes / sizeof(uint64_t);
constexpr size_t kSeedSizeT = kSeedBytes / sizeof(uint32_t);
struct randen {
struct alignas(16) randen {
uint64_t state[kStateSizeT];
uint32_t seed[kSeedSizeT];
};
......
......@@ -32,6 +32,25 @@ namespace random_internal {
// '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.
//
// 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 {
......@@ -45,17 +64,23 @@ struct RandenTraits {
// 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;
// Type-2 generalized Feistel => one round function for every two blocks.
static constexpr size_t kFeistelFunctions = kFeistelBlocks / 2; // = 8
// 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
ABSL_NAMESPACE_END
} // namespace absl
......
......@@ -27,6 +27,7 @@
#include "absl/base/internal/raw_logging.h"
#include "absl/random/internal/chi_square.h"
#include "absl/random/internal/distribution_test_util.h"
#include "absl/random/internal/pcg_engine.h"
#include "absl/random/internal/sequence_urbg.h"
#include "absl/random/random.h"
#include "absl/strings/str_cat.h"
......@@ -121,7 +122,10 @@ class LogUniformIntChiSquaredTest
// data generated by the log-uniform-int distribution.
double ChiSquaredTestImpl();
absl::InsecureBitGen rng_;
// We use a fixed bit generator for distribution accuracy tests. This allows
// these tests to be deterministic, while still testing the qualify of the
// implementation.
absl::random_internal::pcg64_2018_engine rng_{0x2B7E151628AED2A6};
};
double LogUniformIntChiSquaredTest::ChiSquaredTestImpl() {
......@@ -194,7 +198,6 @@ double LogUniformIntChiSquaredTest::ChiSquaredTestImpl() {
TEST_P(LogUniformIntChiSquaredTest, MultiTest) {
const int kTrials = 5;
int failures = 0;
for (int i = 0; i < kTrials; i++) {
double p_value = ChiSquaredTestImpl();
......
......@@ -30,6 +30,7 @@
#include "absl/container/flat_hash_map.h"
#include "absl/random/internal/chi_square.h"
#include "absl/random/internal/distribution_test_util.h"
#include "absl/random/internal/pcg_engine.h"
#include "absl/random/internal/sequence_urbg.h"
#include "absl/random/random.h"
#include "absl/strings/str_cat.h"
......@@ -257,7 +258,10 @@ class PoissonDistributionZTest : public testing::TestWithParam<ZParam>,
template <typename D>
bool SingleZTest(const double p, const size_t samples);
absl::InsecureBitGen rng_;
// We use a fixed bit generator for distribution accuracy tests. This allows
// these tests to be deterministic, while still testing the qualify of the
// implementation.
absl::random_internal::pcg64_2018_engine rng_{0x2B7E151628AED2A6};
};
template <typename D>
......@@ -357,9 +361,13 @@ class PoissonDistributionChiSquaredTest : public testing::TestWithParam<double>,
private:
void InitChiSquaredTest(const double buckets);
absl::InsecureBitGen rng_;
std::vector<size_t> cutoffs_;
std::vector<double> expected_;
// We use a fixed bit generator for distribution accuracy tests. This allows
// these tests to be deterministic, while still testing the qualify of the
// implementation.
absl::random_internal::pcg64_2018_engine rng_{0x2B7E151628AED2A6};
};
void PoissonDistributionChiSquaredTest::InitChiSquaredTest(
......
......@@ -26,6 +26,7 @@
#include "absl/base/internal/raw_logging.h"
#include "absl/random/internal/chi_square.h"
#include "absl/random/internal/distribution_test_util.h"
#include "absl/random/internal/pcg_engine.h"
#include "absl/random/internal/sequence_urbg.h"
#include "absl/random/random.h"
#include "absl/strings/str_cat.h"
......@@ -134,7 +135,11 @@ TYPED_TEST(UniformIntDistributionTest, TestMoments) {
using param_type =
typename absl::uniform_int_distribution<TypeParam>::param_type;
absl::InsecureBitGen rng;
// We use a fixed bit generator for distribution accuracy tests. This allows
// these tests to be deterministic, while still testing the qualify of the
// implementation.
absl::random_internal::pcg64_2018_engine rng{0x2B7E151628AED2A6};
std::vector<double> values(kSize);
for (const auto& param :
{param_type(0, Limits::max()), param_type(13, 127)}) {
......@@ -178,7 +183,11 @@ TYPED_TEST(UniformIntDistributionTest, ChiSquaredTest50) {
const TypeParam min = std::is_unsigned<TypeParam>::value ? 37 : -37;
const TypeParam max = min + kBuckets;
absl::InsecureBitGen rng;
// We use a fixed bit generator for distribution accuracy tests. This allows
// these tests to be deterministic, while still testing the qualify of the
// implementation.
absl::random_internal::pcg64_2018_engine rng{0x2B7E151628AED2A6};
absl::uniform_int_distribution<TypeParam> dist(min, max);
std::vector<int32_t> counts(kBuckets + 1, 0);
......
......@@ -27,6 +27,7 @@
#include "absl/base/internal/raw_logging.h"
#include "absl/random/internal/chi_square.h"
#include "absl/random/internal/distribution_test_util.h"
#include "absl/random/internal/pcg_engine.h"
#include "absl/random/internal/sequence_urbg.h"
#include "absl/random/random.h"
#include "absl/strings/str_cat.h"
......@@ -207,7 +208,11 @@ TYPED_TEST(UniformRealDistributionTest, TestMoments) {
constexpr int kSize = 1000000;
std::vector<double> values(kSize);
absl::InsecureBitGen rng;
// We use a fixed bit generator for distribution accuracy tests. This allows
// these tests to be deterministic, while still testing the qualify of the
// implementation.
absl::random_internal::pcg64_2018_engine rng{0x2B7E151628AED2A6};
absl::uniform_real_distribution<TypeParam> dist;
for (int i = 0; i < kSize; i++) {
values[i] = dist(rng);
......@@ -237,7 +242,11 @@ TYPED_TEST(UniformRealDistributionTest, ChiSquaredTest50) {
const int kThreshold =
absl::random_internal::ChiSquareValue(kBuckets - 1, 0.999999);
absl::InsecureBitGen rng;
// We use a fixed bit generator for distribution accuracy tests. This allows
// these tests to be deterministic, while still testing the qualify of the
// implementation.
absl::random_internal::pcg64_2018_engine rng{0x2B7E151628AED2A6};
for (const auto& param : {param_type(0, 1), param_type(5, 12),
param_type(-5, 13), param_type(-5, -2)}) {
const double min_val = param.a();
......
......@@ -27,6 +27,7 @@
#include "gtest/gtest.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/random/internal/chi_square.h"
#include "absl/random/internal/pcg_engine.h"
#include "absl/random/internal/sequence_urbg.h"
#include "absl/random/random.h"
#include "absl/strings/str_cat.h"
......@@ -213,7 +214,10 @@ class ZipfTest : public testing::TestWithParam<zipf_u64::param_type>,
public:
ZipfTest() : ZipfModel(GetParam().k(), GetParam().q(), GetParam().v()) {}
absl::InsecureBitGen rng_;
// We use a fixed bit generator for distribution accuracy tests. This allows
// these tests to be deterministic, while still testing the qualify of the
// implementation.
absl::random_internal::pcg64_2018_engine rng_{0x2B7E151628AED2A6};
};
TEST_P(ZipfTest, ChiSquaredTest) {
......
......@@ -267,38 +267,42 @@ bool ConvertIntArg(T v, const FormatConversionSpecImpl conv,
using U = typename MakeUnsigned<T>::type;
IntDigits as_digits;
switch (conv.conversion_char()) {
case FormatConversionCharInternal::c:
// This odd casting is due to a bug in -Wswitch behavior in gcc49 which causes
// it to complain about a switch/case type mismatch, even though both are
// FormatConverionChar. Likely this is because at this point
// FormatConversionChar is declared, but not defined.
switch (static_cast<uint8_t>(conv.conversion_char())) {
case static_cast<uint8_t>(FormatConversionCharInternal::c):
return ConvertCharImpl(static_cast<unsigned char>(v), conv, sink);
case FormatConversionCharInternal::o:
case static_cast<uint8_t>(FormatConversionCharInternal::o):
as_digits.PrintAsOct(static_cast<U>(v));
break;
case FormatConversionCharInternal::x:
case static_cast<uint8_t>(FormatConversionCharInternal::x):
as_digits.PrintAsHexLower(static_cast<U>(v));
break;
case FormatConversionCharInternal::X:
case static_cast<uint8_t>(FormatConversionCharInternal::X):
as_digits.PrintAsHexUpper(static_cast<U>(v));
break;
case FormatConversionCharInternal::u:
case static_cast<uint8_t>(FormatConversionCharInternal::u):
as_digits.PrintAsDec(static_cast<U>(v));
break;
case FormatConversionCharInternal::d:
case FormatConversionCharInternal::i:
case static_cast<uint8_t>(FormatConversionCharInternal::d):
case static_cast<uint8_t>(FormatConversionCharInternal::i):
as_digits.PrintAsDec(v);
break;
case FormatConversionCharInternal::a:
case FormatConversionCharInternal::e:
case FormatConversionCharInternal::f:
case FormatConversionCharInternal::g:
case FormatConversionCharInternal::A:
case FormatConversionCharInternal::E:
case FormatConversionCharInternal::F:
case FormatConversionCharInternal::G:
case static_cast<uint8_t>(FormatConversionCharInternal::a):
case static_cast<uint8_t>(FormatConversionCharInternal::e):
case static_cast<uint8_t>(FormatConversionCharInternal::f):
case static_cast<uint8_t>(FormatConversionCharInternal::g):
case static_cast<uint8_t>(FormatConversionCharInternal::A):
case static_cast<uint8_t>(FormatConversionCharInternal::E):
case static_cast<uint8_t>(FormatConversionCharInternal::F):
case static_cast<uint8_t>(FormatConversionCharInternal::G):
return ConvertFloatImpl(static_cast<double>(v), conv, sink);
default:
......
......@@ -27,6 +27,8 @@ class FormatSink;
namespace str_format_internal {
class FormatConversionSpec;
template <typename T, typename = void>
struct HasUserDefinedConvert : std::false_type {};
......
......@@ -96,8 +96,8 @@ TEST_F(FormatArgImplTest, WorksWithCharArraysOfUnknownSize) {
std::string s;
FormatSinkImpl sink(&s);
FormatConversionSpecImpl conv;
FormatConversionSpecImplFriend::SetConversionChar(FormatConversionChar::s,
&conv);
FormatConversionSpecImplFriend::SetConversionChar(
FormatConversionCharInternal::s, &conv);
FormatConversionSpecImplFriend::SetFlags(Flags(), &conv);
FormatConversionSpecImplFriend::SetWidth(-1, &conv);
FormatConversionSpecImplFriend::SetPrecision(-1, &conv);
......
......@@ -11,13 +11,13 @@ namespace {
std::string ConvToString(FormatConversionCharSet conv) {
std::string out;
#define CONV_SET_CASE(c) \
if (Contains(conv, FormatConversionCharSet::c)) { \
out += #c; \
#define CONV_SET_CASE(c) \
if (Contains(conv, FormatConversionCharSetInternal::c)) { \
out += #c; \
}
ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(CONV_SET_CASE, )
#undef CONV_SET_CASE
if (Contains(conv, FormatConversionCharSet::kStar)) {
if (Contains(conv, FormatConversionCharSetInternal::kStar)) {
out += "*";
}
return out;
......
......@@ -33,16 +33,17 @@ std::string Flags::ToString() const {
return s;
}
bool FormatSinkImpl::PutPaddedString(string_view v, int w, int p, bool l) {
bool FormatSinkImpl::PutPaddedString(string_view value, int width,
int precision, bool left) {
size_t space_remaining = 0;
if (w >= 0) space_remaining = w;
size_t n = v.size();
if (p >= 0) n = std::min(n, static_cast<size_t>(p));
string_view shown(v.data(), n);
if (width >= 0) space_remaining = width;
size_t n = value.size();
if (precision >= 0) n = std::min(n, static_cast<size_t>(precision));
string_view shown(value.data(), n);
space_remaining = Excess(shown.size(), space_remaining);
if (!l) Append(space_remaining, ' ');
if (!left) Append(space_remaining, ' ');
Append(shown);
if (l) Append(space_remaining, ' ');
if (left) Append(space_remaining, ' ');
return true;
}
......
......@@ -32,8 +32,9 @@ namespace absl {
ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
enum class FormatConversionCharSet : uint64_t;
enum class FormatConversionChar : uint8_t;
enum class FormatConversionCharSet : uint64_t;
class FormatRawSinkImpl {
public:
......@@ -106,7 +107,7 @@ class FormatSinkImpl {
size_t size() const { return size_; }
// Put 'v' to 'sink' with specified width, precision, and left flag.
bool PutPaddedString(string_view v, int w, int p, bool l);
bool PutPaddedString(string_view v, int width, int precision, bool left);
template <typename T>
T Wrap() {
......@@ -420,81 +421,6 @@ inline size_t Excess(size_t used, size_t capacity) {
return used < capacity ? capacity - used : 0;
}
class FormatConversionSpec {
public:
// Width and precison are not specified, no flags are set.
bool is_basic() const { return impl_.is_basic(); }
bool has_left_flag() const { return impl_.has_left_flag(); }
bool has_show_pos_flag() const { return impl_.has_show_pos_flag(); }
bool has_sign_col_flag() const { return impl_.has_sign_col_flag(); }
bool has_alt_flag() const { return impl_.has_alt_flag(); }
bool has_zero_flag() const { return impl_.has_zero_flag(); }
FormatConversionChar conversion_char() const {
return impl_.conversion_char();
}
// Returns the specified width. If width is unspecfied, it returns a negative
// value.
int width() const { return impl_.width(); }
// Returns the specified precision. If precision is unspecfied, it returns a
// negative value.
int precision() const { return impl_.precision(); }
private:
explicit FormatConversionSpec(
str_format_internal::FormatConversionSpecImpl impl)
: impl_(impl) {}
friend str_format_internal::FormatConversionSpecImpl;
absl::str_format_internal::FormatConversionSpecImpl impl_;
};
// clang-format off
enum class FormatConversionChar : uint8_t {
c, s, // text
d, i, o, u, x, X, // int
f, F, e, E, g, G, a, A, // float
n, p // misc
};
// clang-format on
enum class FormatConversionCharSet : uint64_t {
// text
c = str_format_internal::FormatConversionCharToConvInt('c'),
s = str_format_internal::FormatConversionCharToConvInt('s'),
// integer
d = str_format_internal::FormatConversionCharToConvInt('d'),
i = str_format_internal::FormatConversionCharToConvInt('i'),
o = str_format_internal::FormatConversionCharToConvInt('o'),
u = str_format_internal::FormatConversionCharToConvInt('u'),
x = str_format_internal::FormatConversionCharToConvInt('x'),
X = str_format_internal::FormatConversionCharToConvInt('X'),
// Float
f = str_format_internal::FormatConversionCharToConvInt('f'),
F = str_format_internal::FormatConversionCharToConvInt('F'),
e = str_format_internal::FormatConversionCharToConvInt('e'),
E = str_format_internal::FormatConversionCharToConvInt('E'),
g = str_format_internal::FormatConversionCharToConvInt('g'),
G = str_format_internal::FormatConversionCharToConvInt('G'),
a = str_format_internal::FormatConversionCharToConvInt('a'),
A = str_format_internal::FormatConversionCharToConvInt('A'),
// misc
n = str_format_internal::FormatConversionCharToConvInt('n'),
p = str_format_internal::FormatConversionCharToConvInt('p'),
// Used for width/precision '*' specification.
kStar = str_format_internal::FormatConversionCharToConvInt('*'),
// Some predefined values:
kIntegral = d | i | u | o | x | X,
kFloating = a | e | f | g | A | E | F | G,
kNumeric = kIntegral | kFloating,
kString = s,
kPointer = p,
};
} // namespace str_format_internal
ABSL_NAMESPACE_END
......
......@@ -63,10 +63,6 @@
// loosely typed. `FormatUntyped()` is not a template and does not perform
// any compile-time checking of the format string; instead, it returns a
// boolean from a runtime check.
//
// In addition, the `str_format` library provides extension points for
// augmenting formatting to new types. These extensions are fully documented
// within the `str_format_extension.h` header file.
#ifndef ABSL_STRINGS_STR_FORMAT_H_
#define ABSL_STRINGS_STR_FORMAT_H_
......
#include "absl/strings/str_format.h"
#include <cstdarg>
#include <cstdint>
#include <cstdio>
......@@ -6,13 +8,14 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace {
using str_format_internal::FormatArgImpl;
using str_format_internal::FormatConversionCharSetInternal;
using FormatEntryPointTest = ::testing::Test;
......@@ -535,100 +538,106 @@ TEST_F(ParsedFormatTest, SimpleUncheckedIncorrect) {
using absl::str_format_internal::FormatConversionCharSet;
TEST_F(ParsedFormatTest, UncheckedCorrect) {
auto f = ExtendedParsedFormat<FormatConversionCharSet::d>::New("ABC%dDEF");
auto f =
ExtendedParsedFormat<FormatConversionCharSetInternal::d>::New("ABC%dDEF");
ASSERT_TRUE(f);
EXPECT_EQ("[ABC]{d:1$d}[DEF]", SummarizeParsedFormat(*f));
std::string format = "%sFFF%dZZZ%f";
auto f2 =
ExtendedParsedFormat<FormatConversionCharSet::kString,
FormatConversionCharSet::d,
FormatConversionCharSet::kFloating>::New(format);
auto f2 = ExtendedParsedFormat<
FormatConversionCharSetInternal::kString,
FormatConversionCharSetInternal::d,
FormatConversionCharSetInternal::kFloating>::New(format);
ASSERT_TRUE(f2);
EXPECT_EQ("{s:1$s}[FFF]{d:2$d}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2));
f2 =
ExtendedParsedFormat<FormatConversionCharSet::kString,
FormatConversionCharSet::d,
FormatConversionCharSet::kFloating>::New("%s %d %f");
f2 = ExtendedParsedFormat<
FormatConversionCharSetInternal::kString,
FormatConversionCharSetInternal::d,
FormatConversionCharSetInternal::kFloating>::New("%s %d %f");
ASSERT_TRUE(f2);
EXPECT_EQ("{s:1$s}[ ]{d:2$d}[ ]{f:3$f}", SummarizeParsedFormat(*f2));
auto star = ExtendedParsedFormat<FormatConversionCharSet::kStar,
FormatConversionCharSet::d>::New("%*d");
auto star =
ExtendedParsedFormat<FormatConversionCharSetInternal::kStar,
FormatConversionCharSetInternal::d>::New("%*d");
ASSERT_TRUE(star);
EXPECT_EQ("{*d:2$1$*d}", SummarizeParsedFormat(*star));
auto dollar =
ExtendedParsedFormat<FormatConversionCharSet::d,
FormatConversionCharSet::s>::New("%2$s %1$d");
auto dollar = ExtendedParsedFormat<
FormatConversionCharSetInternal::d,
FormatConversionCharSetInternal::s>::New("%2$s %1$d");
ASSERT_TRUE(dollar);
EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}", SummarizeParsedFormat(*dollar));
// with reuse
dollar =
ExtendedParsedFormat<FormatConversionCharSet::d,
FormatConversionCharSet::s>::New("%2$s %1$d %1$d");
dollar = ExtendedParsedFormat<
FormatConversionCharSetInternal::d,
FormatConversionCharSetInternal::s>::New("%2$s %1$d %1$d");
ASSERT_TRUE(dollar);
EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}[ ]{1$d:1$d}",
SummarizeParsedFormat(*dollar));
}
TEST_F(ParsedFormatTest, UncheckedIgnoredArgs) {
EXPECT_FALSE((ExtendedParsedFormat<FormatConversionCharSet::d,
FormatConversionCharSet::s>::New("ABC")));
EXPECT_FALSE(
(ExtendedParsedFormat<FormatConversionCharSet::d,
FormatConversionCharSet::s>::New("%dABC")));
(ExtendedParsedFormat<FormatConversionCharSetInternal::d,
FormatConversionCharSetInternal::s>::New("ABC")));
EXPECT_FALSE(
(ExtendedParsedFormat<FormatConversionCharSet::d,
FormatConversionCharSet::s>::New("ABC%2$s")));
auto f =
ExtendedParsedFormat<FormatConversionCharSet::d,
FormatConversionCharSet::s>::NewAllowIgnored("ABC");
(ExtendedParsedFormat<FormatConversionCharSetInternal::d,
FormatConversionCharSetInternal::s>::New("%dABC")));
EXPECT_FALSE((ExtendedParsedFormat<
FormatConversionCharSetInternal::d,
FormatConversionCharSetInternal::s>::New("ABC%2$s")));
auto f = ExtendedParsedFormat<
FormatConversionCharSetInternal::d,
FormatConversionCharSetInternal::s>::NewAllowIgnored("ABC");
ASSERT_TRUE(f);
EXPECT_EQ("[ABC]", SummarizeParsedFormat(*f));
f = ExtendedParsedFormat<
FormatConversionCharSet::d,
FormatConversionCharSet::s>::NewAllowIgnored("%dABC");
FormatConversionCharSetInternal::d,
FormatConversionCharSetInternal::s>::NewAllowIgnored("%dABC");
ASSERT_TRUE(f);
EXPECT_EQ("{d:1$d}[ABC]", SummarizeParsedFormat(*f));
f = ExtendedParsedFormat<
FormatConversionCharSet::d,
FormatConversionCharSet::s>::NewAllowIgnored("ABC%2$s");
FormatConversionCharSetInternal::d,
FormatConversionCharSetInternal::s>::NewAllowIgnored("ABC%2$s");
ASSERT_TRUE(f);
EXPECT_EQ("[ABC]{2$s:2$s}", SummarizeParsedFormat(*f));
}
TEST_F(ParsedFormatTest, UncheckedMultipleTypes) {
auto dx = ExtendedParsedFormat<FormatConversionCharSet::d |
FormatConversionCharSet::x>::New("%1$d %1$x");
auto dx = ExtendedParsedFormat<
FormatConversionCharSetInternal::d |
FormatConversionCharSetInternal::x>::New("%1$d %1$x");
EXPECT_TRUE(dx);
EXPECT_EQ("{1$d:1$d}[ ]{1$x:1$x}", SummarizeParsedFormat(*dx));
dx = ExtendedParsedFormat<FormatConversionCharSet::d |
FormatConversionCharSet::x>::New("%1$d");
dx = ExtendedParsedFormat<FormatConversionCharSetInternal::d |
FormatConversionCharSetInternal::x>::New("%1$d");
EXPECT_TRUE(dx);
EXPECT_EQ("{1$d:1$d}", SummarizeParsedFormat(*dx));
}
TEST_F(ParsedFormatTest, UncheckedIncorrect) {
EXPECT_FALSE(ExtendedParsedFormat<FormatConversionCharSet::d>::New(""));
EXPECT_FALSE(
ExtendedParsedFormat<FormatConversionCharSet::d>::New("ABC%dDEF%d"));
ExtendedParsedFormat<FormatConversionCharSetInternal::d>::New(""));
EXPECT_FALSE(ExtendedParsedFormat<FormatConversionCharSetInternal::d>::New(
"ABC%dDEF%d"));
std::string format = "%sFFF%dZZZ%f";
EXPECT_FALSE((ExtendedParsedFormat<FormatConversionCharSet::s,
FormatConversionCharSet::d,
FormatConversionCharSet::g>::New(format)));
EXPECT_FALSE(
(ExtendedParsedFormat<FormatConversionCharSetInternal::s,
FormatConversionCharSetInternal::d,
FormatConversionCharSetInternal::g>::New(format)));
}
TEST_F(ParsedFormatTest, RegressionMixPositional) {
EXPECT_FALSE(
(ExtendedParsedFormat<FormatConversionCharSet::d,
FormatConversionCharSet::o>::New("%1$d %o")));
EXPECT_FALSE((ExtendedParsedFormat<
FormatConversionCharSetInternal::d,
FormatConversionCharSetInternal::o>::New("%1$d %o")));
}
using FormatWrapperTest = ::testing::Test;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment