Commit 1995c6a3 by Abseil Team Committed by Derek Mauro

Export of internal Abseil changes

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

Add support for rvalue reference to function types.

PiperOrigin-RevId: 324508531

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

Cleaning up function comment style; no substantive change.

PiperOrigin-RevId: 324497401

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

Add support for demangling GNU vector types.

PiperOrigin-RevId: 324494559

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

Add support for thread-local types.

PiperOrigin-RevId: 324491183

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

Add support for demangling "Du" (char8_t).

PiperOrigin-RevId: 324441607

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

Update doc comments in header of `any.h` to reflect that `absl::variant` has been released.

PiperOrigin-RevId: 324431690

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

Bugfix: Fix bounds in absl::Uniform where one of the bounds is min/max.

When absl::Uniform(rng, tag, a, b) is called, the tag is used in conjunction with the type to determine whether or not to manipulate the bounds to make them inclusive or exclusive through the uniform_*_bound functions. Unfortunately, at limits of the interval the function was not well behaved.

The previous implementation used wrapping arithmetic. This causes incorrect bounds computation at the extremes (numeric_limits::min / numeric_limits::max) the bound would wrap.

Improve this situation by:

1/ Changing the uniform_*_bound functions to use saturating arithmetic instead of wrapping, thus in the unsigned case, the upper_bound of IntervalOpenOpen for 0 is now 0, rather than numeric_limits::max, likewise for the lower bound.

2/ Adjusting the hi/lo checks in the distributions. When the interval is empty, such as for absl::Uniform(absl::IntervalOpenOpen, gen, 1, 0), the return value is somewhat nonsensical. Now absl::Uniform more consistently returns the low input rather than any adjusted input. In the above case, that means that 1 is returned rather than 2.

NOTE: Calls to absl::Uniform where the resolved upper bound is < the lower bound  are still ill-formed and should be avoided.

3/ Adding better tests.

The underlying uniform_*_distribution classes are not affected.

PiperOrigin-RevId: 324240873
GitOrigin-RevId: 790f9061df340cd900e8da70e66c363f7af3c2eb
Change-Id: I2a2208650ea3135c575e200b868ce1d275069fc8
parent 184cf252
...@@ -126,6 +126,7 @@ static const AbbrevPair kBuiltinTypeList[] = { ...@@ -126,6 +126,7 @@ static const AbbrevPair kBuiltinTypeList[] = {
{"Dn", "std::nullptr_t", 0}, // i.e., decltype(nullptr) {"Dn", "std::nullptr_t", 0}, // i.e., decltype(nullptr)
{"Df", "decimal32", 0}, // IEEE 754r decimal floating point (32 bits) {"Df", "decimal32", 0}, // IEEE 754r decimal floating point (32 bits)
{"Di", "char32_t", 0}, {"Di", "char32_t", 0},
{"Du", "char8_t", 0},
{"Ds", "char16_t", 0}, {"Ds", "char16_t", 0},
{"Dh", "float16", 0}, // IEEE 754r half-precision float (16 bits) {"Dh", "float16", 0}, // IEEE 754r half-precision float (16 bits)
{nullptr, nullptr, 0}, {nullptr, nullptr, 0},
...@@ -965,6 +966,7 @@ static bool ParseOperatorName(State *state, int *arity) { ...@@ -965,6 +966,7 @@ static bool ParseOperatorName(State *state, int *arity) {
// ::= TT <type> // ::= TT <type>
// ::= TI <type> // ::= TI <type>
// ::= TS <type> // ::= TS <type>
// ::= TH <type> # thread-local
// ::= Tc <call-offset> <call-offset> <(base) encoding> // ::= Tc <call-offset> <call-offset> <(base) encoding>
// ::= GV <(object) name> // ::= GV <(object) name>
// ::= T <call-offset> <(base) encoding> // ::= T <call-offset> <(base) encoding>
...@@ -983,7 +985,7 @@ static bool ParseSpecialName(State *state) { ...@@ -983,7 +985,7 @@ static bool ParseSpecialName(State *state) {
ComplexityGuard guard(state); ComplexityGuard guard(state);
if (guard.IsTooComplex()) return false; if (guard.IsTooComplex()) return false;
ParseState copy = state->parse_state; ParseState copy = state->parse_state;
if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "VTIS") && if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "VTISH") &&
ParseType(state)) { ParseType(state)) {
return true; return true;
} }
...@@ -1142,6 +1144,7 @@ static bool ParseDecltype(State *state) { ...@@ -1142,6 +1144,7 @@ static bool ParseDecltype(State *state) {
// ::= <decltype> // ::= <decltype>
// ::= <substitution> // ::= <substitution>
// ::= Dp <type> # pack expansion of (C++0x) // ::= Dp <type> # pack expansion of (C++0x)
// ::= Dv <num-elems> _ # GNU vector extension
// //
static bool ParseType(State *state) { static bool ParseType(State *state) {
ComplexityGuard guard(state); ComplexityGuard guard(state);
...@@ -1208,6 +1211,12 @@ static bool ParseType(State *state) { ...@@ -1208,6 +1211,12 @@ static bool ParseType(State *state) {
return true; return true;
} }
if (ParseTwoCharToken(state, "Dv") && ParseNumber(state, nullptr) &&
ParseOneCharToken(state, '_')) {
return true;
}
state->parse_state = copy;
return false; return false;
} }
...@@ -1256,13 +1265,14 @@ static bool ParseBuiltinType(State *state) { ...@@ -1256,13 +1265,14 @@ static bool ParseBuiltinType(State *state) {
return false; return false;
} }
// <function-type> ::= F [Y] <bare-function-type> E // <function-type> ::= F [Y] <bare-function-type> [O] E
static bool ParseFunctionType(State *state) { static bool ParseFunctionType(State *state) {
ComplexityGuard guard(state); ComplexityGuard guard(state);
if (guard.IsTooComplex()) return false; if (guard.IsTooComplex()) return false;
ParseState copy = state->parse_state; ParseState copy = state->parse_state;
if (ParseOneCharToken(state, 'F') && if (ParseOneCharToken(state, 'F') &&
Optional(ParseOneCharToken(state, 'Y')) && ParseBareFunctionType(state) && Optional(ParseOneCharToken(state, 'Y')) && ParseBareFunctionType(state) &&
Optional(ParseOneCharToken(state, 'O')) &&
ParseOneCharToken(state, 'E')) { ParseOneCharToken(state, 'E')) {
return true; return true;
} }
......
...@@ -1162,6 +1162,21 @@ absl_cc_library( ...@@ -1162,6 +1162,21 @@ absl_cc_library(
# Internal-only target, do not depend on directly. # Internal-only target, do not depend on directly.
absl_cc_test( absl_cc_test(
NAME NAME
random_internal_uniform_helper_test
SRCS
"internal/uniform_helper_test.cc"
COPTS
${ABSL_TEST_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::random_internal_uniform_helper
gtest_main
)
# Internal-only target, do not depend on directly.
absl_cc_test(
NAME
random_internal_iostream_state_saver_test random_internal_iostream_state_saver_test
SRCS SRCS
"internal/iostream_state_saver_test.cc" "internal/iostream_state_saver_test.cc"
......
...@@ -128,7 +128,7 @@ Uniform(TagType tag, ...@@ -128,7 +128,7 @@ Uniform(TagType tag,
auto a = random_internal::uniform_lower_bound(tag, lo, hi); auto a = random_internal::uniform_lower_bound(tag, lo, hi);
auto b = random_internal::uniform_upper_bound(tag, lo, hi); auto b = random_internal::uniform_upper_bound(tag, lo, hi);
if (a > b) return a; if (!random_internal::is_uniform_range_valid(a, b)) return lo;
return random_internal::DistributionCaller<gen_t>::template Call< return random_internal::DistributionCaller<gen_t>::template Call<
distribution_t>(&urbg, tag, lo, hi); distribution_t>(&urbg, tag, lo, hi);
...@@ -144,11 +144,11 @@ Uniform(URBG&& urbg, // NOLINT(runtime/references) ...@@ -144,11 +144,11 @@ Uniform(URBG&& urbg, // NOLINT(runtime/references)
R lo, R hi) { R lo, R hi) {
using gen_t = absl::decay_t<URBG>; using gen_t = absl::decay_t<URBG>;
using distribution_t = random_internal::UniformDistributionWrapper<R>; using distribution_t = random_internal::UniformDistributionWrapper<R>;
constexpr auto tag = absl::IntervalClosedOpen; constexpr auto tag = absl::IntervalClosedOpen;
auto a = random_internal::uniform_lower_bound(tag, lo, hi); auto a = random_internal::uniform_lower_bound(tag, lo, hi);
auto b = random_internal::uniform_upper_bound(tag, lo, hi); auto b = random_internal::uniform_upper_bound(tag, lo, hi);
if (a > b) return a; if (!random_internal::is_uniform_range_valid(a, b)) return lo;
return random_internal::DistributionCaller<gen_t>::template Call< return random_internal::DistributionCaller<gen_t>::template Call<
distribution_t>(&urbg, lo, hi); distribution_t>(&urbg, lo, hi);
...@@ -172,7 +172,7 @@ Uniform(TagType tag, ...@@ -172,7 +172,7 @@ Uniform(TagType tag,
auto a = random_internal::uniform_lower_bound<return_t>(tag, lo, hi); auto a = random_internal::uniform_lower_bound<return_t>(tag, lo, hi);
auto b = random_internal::uniform_upper_bound<return_t>(tag, lo, hi); auto b = random_internal::uniform_upper_bound<return_t>(tag, lo, hi);
if (a > b) return a; if (!random_internal::is_uniform_range_valid(a, b)) return lo;
return random_internal::DistributionCaller<gen_t>::template Call< return random_internal::DistributionCaller<gen_t>::template Call<
distribution_t>(&urbg, tag, static_cast<return_t>(lo), distribution_t>(&urbg, tag, static_cast<return_t>(lo),
...@@ -196,7 +196,7 @@ Uniform(URBG&& urbg, // NOLINT(runtime/references) ...@@ -196,7 +196,7 @@ Uniform(URBG&& urbg, // NOLINT(runtime/references)
constexpr auto tag = absl::IntervalClosedOpen; constexpr auto tag = absl::IntervalClosedOpen;
auto a = random_internal::uniform_lower_bound<return_t>(tag, lo, hi); auto a = random_internal::uniform_lower_bound<return_t>(tag, lo, hi);
auto b = random_internal::uniform_upper_bound<return_t>(tag, lo, hi); auto b = random_internal::uniform_upper_bound<return_t>(tag, lo, hi);
if (a > b) return a; if (!random_internal::is_uniform_range_valid(a, b)) return lo;
return random_internal::DistributionCaller<gen_t>::template Call< return random_internal::DistributionCaller<gen_t>::template Call<
distribution_t>(&urbg, static_cast<return_t>(lo), distribution_t>(&urbg, static_cast<return_t>(lo),
......
...@@ -29,94 +29,6 @@ constexpr int kSize = 400000; ...@@ -29,94 +29,6 @@ constexpr int kSize = 400000;
class RandomDistributionsTest : public testing::Test {}; class RandomDistributionsTest : public testing::Test {};
TEST_F(RandomDistributionsTest, UniformBoundFunctions) {
using absl::IntervalClosedClosed;
using absl::IntervalClosedOpen;
using absl::IntervalOpenClosed;
using absl::IntervalOpenOpen;
using absl::random_internal::uniform_lower_bound;
using absl::random_internal::uniform_upper_bound;
// absl::uniform_int_distribution natively assumes IntervalClosedClosed
// absl::uniform_real_distribution natively assumes IntervalClosedOpen
EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, 0, 100), 1);
EXPECT_EQ(uniform_lower_bound(IntervalOpenOpen, 0, 100), 1);
EXPECT_GT(uniform_lower_bound<float>(IntervalOpenClosed, 0, 1.0), 0);
EXPECT_GT(uniform_lower_bound<float>(IntervalOpenOpen, 0, 1.0), 0);
EXPECT_GT(uniform_lower_bound<double>(IntervalOpenClosed, 0, 1.0), 0);
EXPECT_GT(uniform_lower_bound<double>(IntervalOpenOpen, 0, 1.0), 0);
EXPECT_EQ(uniform_lower_bound(IntervalClosedClosed, 0, 100), 0);
EXPECT_EQ(uniform_lower_bound(IntervalClosedOpen, 0, 100), 0);
EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedClosed, 0, 1.0), 0);
EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedOpen, 0, 1.0), 0);
EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedClosed, 0, 1.0), 0);
EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedOpen, 0, 1.0), 0);
EXPECT_EQ(uniform_upper_bound(IntervalOpenOpen, 0, 100), 99);
EXPECT_EQ(uniform_upper_bound(IntervalClosedOpen, 0, 100), 99);
EXPECT_EQ(uniform_upper_bound<float>(IntervalOpenOpen, 0, 1.0), 1.0);
EXPECT_EQ(uniform_upper_bound<float>(IntervalClosedOpen, 0, 1.0), 1.0);
EXPECT_EQ(uniform_upper_bound<double>(IntervalOpenOpen, 0, 1.0), 1.0);
EXPECT_EQ(uniform_upper_bound<double>(IntervalClosedOpen, 0, 1.0), 1.0);
EXPECT_EQ(uniform_upper_bound(IntervalOpenClosed, 0, 100), 100);
EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, 0, 100), 100);
EXPECT_GT(uniform_upper_bound<float>(IntervalOpenClosed, 0, 1.0), 1.0);
EXPECT_GT(uniform_upper_bound<float>(IntervalClosedClosed, 0, 1.0), 1.0);
EXPECT_GT(uniform_upper_bound<double>(IntervalOpenClosed, 0, 1.0), 1.0);
EXPECT_GT(uniform_upper_bound<double>(IntervalClosedClosed, 0, 1.0), 1.0);
// Negative value tests
EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, -100, -1), -99);
EXPECT_EQ(uniform_lower_bound(IntervalOpenOpen, -100, -1), -99);
EXPECT_GT(uniform_lower_bound<float>(IntervalOpenClosed, -2.0, -1.0), -2.0);
EXPECT_GT(uniform_lower_bound<float>(IntervalOpenOpen, -2.0, -1.0), -2.0);
EXPECT_GT(uniform_lower_bound<double>(IntervalOpenClosed, -2.0, -1.0), -2.0);
EXPECT_GT(uniform_lower_bound<double>(IntervalOpenOpen, -2.0, -1.0), -2.0);
EXPECT_EQ(uniform_lower_bound(IntervalClosedClosed, -100, -1), -100);
EXPECT_EQ(uniform_lower_bound(IntervalClosedOpen, -100, -1), -100);
EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedClosed, -2.0, -1.0), -2.0);
EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedOpen, -2.0, -1.0), -2.0);
EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedClosed, -2.0, -1.0),
-2.0);
EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedOpen, -2.0, -1.0), -2.0);
EXPECT_EQ(uniform_upper_bound(IntervalOpenOpen, -100, -1), -2);
EXPECT_EQ(uniform_upper_bound(IntervalClosedOpen, -100, -1), -2);
EXPECT_EQ(uniform_upper_bound<float>(IntervalOpenOpen, -2.0, -1.0), -1.0);
EXPECT_EQ(uniform_upper_bound<float>(IntervalClosedOpen, -2.0, -1.0), -1.0);
EXPECT_EQ(uniform_upper_bound<double>(IntervalOpenOpen, -2.0, -1.0), -1.0);
EXPECT_EQ(uniform_upper_bound<double>(IntervalClosedOpen, -2.0, -1.0), -1.0);
EXPECT_EQ(uniform_upper_bound(IntervalOpenClosed, -100, -1), -1);
EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, -100, -1), -1);
EXPECT_GT(uniform_upper_bound<float>(IntervalOpenClosed, -2.0, -1.0), -1.0);
EXPECT_GT(uniform_upper_bound<float>(IntervalClosedClosed, -2.0, -1.0), -1.0);
EXPECT_GT(uniform_upper_bound<double>(IntervalOpenClosed, -2.0, -1.0), -1.0);
EXPECT_GT(uniform_upper_bound<double>(IntervalClosedClosed, -2.0, -1.0),
-1.0);
// Edge cases: the next value toward itself is itself.
const double d = 1.0;
const float f = 1.0;
EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, d, d), d);
EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, f, f), f);
EXPECT_GT(uniform_lower_bound(IntervalOpenClosed, 1.0, 2.0), 1.0);
EXPECT_LT(uniform_lower_bound(IntervalOpenClosed, 1.0, +0.0), 1.0);
EXPECT_LT(uniform_lower_bound(IntervalOpenClosed, 1.0, -0.0), 1.0);
EXPECT_LT(uniform_lower_bound(IntervalOpenClosed, 1.0, -1.0), 1.0);
EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, 0.0f,
std::numeric_limits<float>::max()),
std::numeric_limits<float>::max());
EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, 0.0,
std::numeric_limits<double>::max()),
std::numeric_limits<double>::max());
}
struct Invalid {}; struct Invalid {};
...@@ -284,7 +196,9 @@ TEST_F(RandomDistributionsTest, UniformTypeInference) { ...@@ -284,7 +196,9 @@ TEST_F(RandomDistributionsTest, UniformTypeInference) {
// Properly promotes float. // Properly promotes float.
CheckArgsInferType<float, double, double>(); CheckArgsInferType<float, double, double>();
}
TEST_F(RandomDistributionsTest, UniformExamples) {
// Examples. // Examples.
absl::InsecureBitGen gen; absl::InsecureBitGen gen;
EXPECT_NE(1, absl::Uniform(gen, static_cast<uint16_t>(0), 1.0f)); EXPECT_NE(1, absl::Uniform(gen, static_cast<uint16_t>(0), 1.0f));
...@@ -307,6 +221,58 @@ TEST_F(RandomDistributionsTest, UniformNoBounds) { ...@@ -307,6 +221,58 @@ TEST_F(RandomDistributionsTest, UniformNoBounds) {
absl::Uniform<uint64_t>(gen); absl::Uniform<uint64_t>(gen);
} }
TEST_F(RandomDistributionsTest, UniformNonsenseRanges) {
// The ranges used in this test are undefined behavior.
// The results are arbitrary and subject to future changes.
absl::InsecureBitGen gen;
// <uint>
EXPECT_EQ(0, absl::Uniform<uint64_t>(gen, 0, 0));
EXPECT_EQ(1, absl::Uniform<uint64_t>(gen, 1, 0));
EXPECT_EQ(0, absl::Uniform<uint64_t>(absl::IntervalOpenOpen, gen, 0, 0));
EXPECT_EQ(1, absl::Uniform<uint64_t>(absl::IntervalOpenOpen, gen, 1, 0));
constexpr auto m = (std::numeric_limits<uint64_t>::max)();
EXPECT_EQ(m, absl::Uniform(gen, m, m));
EXPECT_EQ(m, absl::Uniform(gen, m, m - 1));
EXPECT_EQ(m - 1, absl::Uniform(gen, m - 1, m));
EXPECT_EQ(m, absl::Uniform(absl::IntervalOpenOpen, gen, m, m));
EXPECT_EQ(m, absl::Uniform(absl::IntervalOpenOpen, gen, m, m - 1));
EXPECT_EQ(m - 1, absl::Uniform(absl::IntervalOpenOpen, gen, m - 1, m));
// <int>
EXPECT_EQ(0, absl::Uniform<int64_t>(gen, 0, 0));
EXPECT_EQ(1, absl::Uniform<int64_t>(gen, 1, 0));
EXPECT_EQ(0, absl::Uniform<int64_t>(absl::IntervalOpenOpen, gen, 0, 0));
EXPECT_EQ(1, absl::Uniform<int64_t>(absl::IntervalOpenOpen, gen, 1, 0));
constexpr auto l = (std::numeric_limits<int64_t>::min)();
constexpr auto r = (std::numeric_limits<int64_t>::max)();
EXPECT_EQ(l, absl::Uniform(gen, l, l));
EXPECT_EQ(r, absl::Uniform(gen, r, r));
EXPECT_EQ(r, absl::Uniform(gen, r, r - 1));
EXPECT_EQ(r - 1, absl::Uniform(gen, r - 1, r));
EXPECT_EQ(l, absl::Uniform(absl::IntervalOpenOpen, gen, l, l));
EXPECT_EQ(r, absl::Uniform(absl::IntervalOpenOpen, gen, r, r));
EXPECT_EQ(r, absl::Uniform(absl::IntervalOpenOpen, gen, r, r - 1));
EXPECT_EQ(r - 1, absl::Uniform(absl::IntervalOpenOpen, gen, r - 1, r));
// <double>
const double e = std::nextafter(1.0, 2.0); // 1 + epsilon
const double f = std::nextafter(1.0, 0.0); // 1 - epsilon
const double g = std::numeric_limits<double>::denorm_min();
EXPECT_EQ(1.0, absl::Uniform(gen, 1.0, e));
EXPECT_EQ(1.0, absl::Uniform(gen, 1.0, f));
EXPECT_EQ(0.0, absl::Uniform(gen, 0.0, g));
EXPECT_EQ(e, absl::Uniform(absl::IntervalOpenOpen, gen, 1.0, e));
EXPECT_EQ(f, absl::Uniform(absl::IntervalOpenOpen, gen, 1.0, f));
EXPECT_EQ(g, absl::Uniform(absl::IntervalOpenOpen, gen, 0.0, g));
}
// TODO(lar): Validate properties of non-default interval-semantics. // TODO(lar): Validate properties of non-default interval-semantics.
TEST_F(RandomDistributionsTest, UniformReal) { TEST_F(RandomDistributionsTest, UniformReal) {
std::vector<double> values(kSize); std::vector<double> values(kSize);
......
...@@ -716,3 +716,15 @@ cc_test( ...@@ -716,3 +716,15 @@ cc_test(
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
], ],
) )
cc_test(
name = "uniform_helper_test",
size = "small",
srcs = ["uniform_helper_test.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":uniform_helper",
"@com_google_googletest//:gtest_main",
],
)
...@@ -105,7 +105,7 @@ typename absl::enable_if_t< ...@@ -105,7 +105,7 @@ typename absl::enable_if_t<
std::is_same<Tag, IntervalOpenOpenTag>>>::value, std::is_same<Tag, IntervalOpenOpenTag>>>::value,
IntType> IntType>
uniform_lower_bound(Tag, IntType a, IntType) { uniform_lower_bound(Tag, IntType a, IntType) {
return a + 1; return a < (std::numeric_limits<IntType>::max)() ? (a + 1) : a;
} }
template <typename FloatType, typename Tag> template <typename FloatType, typename Tag>
...@@ -136,7 +136,7 @@ typename absl::enable_if_t< ...@@ -136,7 +136,7 @@ typename absl::enable_if_t<
std::is_same<Tag, IntervalOpenOpenTag>>>::value, std::is_same<Tag, IntervalOpenOpenTag>>>::value,
IntType> IntType>
uniform_upper_bound(Tag, IntType, IntType b) { uniform_upper_bound(Tag, IntType, IntType b) {
return b - 1; return b > (std::numeric_limits<IntType>::min)() ? (b - 1) : b;
} }
template <typename FloatType, typename Tag> template <typename FloatType, typename Tag>
...@@ -172,6 +172,40 @@ uniform_upper_bound(Tag, FloatType, FloatType b) { ...@@ -172,6 +172,40 @@ uniform_upper_bound(Tag, FloatType, FloatType b) {
return std::nextafter(b, (std::numeric_limits<FloatType>::max)()); 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.
//
// The c++ standard constraints in [rand.dist.uni.int] are listed as:
// requires: lo <= hi.
//
// In the uniform_int_distrubtion, {lo, hi} are closed, closed. Thus:
// [0, 0] is legal.
// [0, 0) is not legal, but [0, 1) is, which translates to [0, 0].
// (0, 1) is not legal, but (0, 2) is, which translates to [1, 1].
// (0, 0] is not legal, but (0, 1] is, which translates to [1, 1].
//
// The c++ standard constraints in [rand.dist.uni.real] are listed as:
// requires: lo <= hi.
// requires: (hi - lo) <= numeric_limits<T>::max()
//
// In the uniform_real_distribution, {lo, hi} are closed, open, Thus:
// [0, 0] is legal, which is [0, 0+epsilon).
// [0, 0) is legal.
// (0, 0) is not legal, but (0-epsilon, 0+epsilon) is.
// (0, 0] is not legal, but (0, 0+epsilon] is.
//
template <typename FloatType>
absl::enable_if_t<std::is_floating_point<FloatType>::value, bool>
is_uniform_range_valid(FloatType a, FloatType b) {
return a <= b && std::isfinite(b - a);
}
template <typename IntType>
absl::enable_if_t<std::is_integral<IntType>::value, bool>
is_uniform_range_valid(IntType a, IntType b) {
return a <= b;
}
// UniformDistribution selects either absl::uniform_int_distribution // UniformDistribution selects either absl::uniform_int_distribution
// or absl::uniform_real_distribution depending on the NumType parameter. // or absl::uniform_real_distribution depending on the NumType parameter.
template <typename NumType> template <typename NumType>
......
...@@ -125,9 +125,9 @@ class Cord { ...@@ -125,9 +125,9 @@ class Cord {
absl::enable_if_t<std::is_same<T, std::string>::value, int>; absl::enable_if_t<std::is_same<T, std::string>::value, int>;
public: public:
// Cord::Cord() Constructors // Cord::Cord() Constructors.
// Creates an empty Cord // Creates an empty Cord.
constexpr Cord() noexcept; constexpr Cord() noexcept;
// Creates a Cord from an existing Cord. Cord is copyable and efficiently // Creates a Cord from an existing Cord. Cord is copyable and efficiently
...@@ -153,7 +153,7 @@ class Cord { ...@@ -153,7 +153,7 @@ class Cord {
// Cord::~Cord() // Cord::~Cord()
// //
// Destructs the Cord // Destructs the Cord.
~Cord() { ~Cord() {
if (contents_.is_tree()) DestroyCordSlow(); if (contents_.is_tree()) DestroyCordSlow();
} }
...@@ -587,7 +587,7 @@ class Cord { ...@@ -587,7 +587,7 @@ class Cord {
// Cord::operator[] // Cord::operator[]
// //
// Get the "i"th character of the Cord and returns it, provided that // Gets the "i"th character of the Cord and returns it, provided that
// 0 <= i < Cord.size(). // 0 <= i < Cord.size().
// //
// NOTE: This routine is reasonably efficient. It is roughly // NOTE: This routine is reasonably efficient. It is roughly
...@@ -599,8 +599,8 @@ class Cord { ...@@ -599,8 +599,8 @@ class Cord {
// Cord::TryFlat() // Cord::TryFlat()
// //
// If this cord's representation is a single flat array, return a // If this cord's representation is a single flat array, returns a
// string_view referencing that array. Otherwise return nullopt. // string_view referencing that array. Otherwise returns nullopt.
absl::optional<absl::string_view> TryFlat() const; absl::optional<absl::string_view> TryFlat() const;
// Cord::Flatten() // Cord::Flatten()
...@@ -610,7 +610,7 @@ class Cord { ...@@ -610,7 +610,7 @@ class Cord {
// If the cord was already flat, the contents are not modified. // If the cord was already flat, the contents are not modified.
absl::string_view Flatten(); absl::string_view Flatten();
// Support absl::Cord as a sink object for absl::Format(). // Supports absl::Cord as a sink object for absl::Format().
friend void AbslFormatFlush(absl::Cord* cord, absl::string_view part) { friend void AbslFormatFlush(absl::Cord* cord, absl::string_view part) {
cord->Append(part); cord->Append(part);
} }
...@@ -629,7 +629,7 @@ class Cord { ...@@ -629,7 +629,7 @@ class Cord {
friend bool operator==(const Cord& lhs, const Cord& rhs); friend bool operator==(const Cord& lhs, const Cord& rhs);
friend bool operator==(const Cord& lhs, absl::string_view rhs); friend bool operator==(const Cord& lhs, absl::string_view rhs);
// Call the provided function once for each cord chunk, in order. Unlike // Calls the provided function once for each cord chunk, in order. Unlike
// Chunks(), this API will not allocate memory. // Chunks(), this API will not allocate memory.
void ForEachChunk(absl::FunctionRef<void(absl::string_view)>) const; void ForEachChunk(absl::FunctionRef<void(absl::string_view)>) const;
...@@ -673,7 +673,7 @@ class Cord { ...@@ -673,7 +673,7 @@ class Cord {
void replace_tree(absl::cord_internal::CordRep* rep); void replace_tree(absl::cord_internal::CordRep* rep);
// Returns non-null iff was holding a pointer // Returns non-null iff was holding a pointer
absl::cord_internal::CordRep* clear(); absl::cord_internal::CordRep* clear();
// Convert to pointer if necessary // Converts to pointer if necessary.
absl::cord_internal::CordRep* force_tree(size_t extra_hint); absl::cord_internal::CordRep* force_tree(size_t extra_hint);
void reduce_size(size_t n); // REQUIRES: holding data void reduce_size(size_t n); // REQUIRES: holding data
void remove_prefix(size_t n); // REQUIRES: holding data void remove_prefix(size_t n); // REQUIRES: holding data
...@@ -731,14 +731,14 @@ class Cord { ...@@ -731,14 +731,14 @@ class Cord {
}; };
InlineRep contents_; InlineRep contents_;
// Helper for MemoryUsage() // Helper for MemoryUsage().
static size_t MemoryUsageAux(const absl::cord_internal::CordRep* rep); static size_t MemoryUsageAux(const absl::cord_internal::CordRep* rep);
// Helper for GetFlat() and TryFlat() // Helper for GetFlat() and TryFlat().
static bool GetFlatAux(absl::cord_internal::CordRep* rep, static bool GetFlatAux(absl::cord_internal::CordRep* rep,
absl::string_view* fragment); absl::string_view* fragment);
// Helper for ForEachChunk() // Helper for ForEachChunk().
static void ForEachChunkAux( static void ForEachChunkAux(
absl::cord_internal::CordRep* rep, absl::cord_internal::CordRep* rep,
absl::FunctionRef<void(absl::string_view)> callback); absl::FunctionRef<void(absl::string_view)> callback);
...@@ -767,11 +767,11 @@ class Cord { ...@@ -767,11 +767,11 @@ class Cord {
absl::cord_internal::CordRep* TakeRep() const&; absl::cord_internal::CordRep* TakeRep() const&;
absl::cord_internal::CordRep* TakeRep() &&; absl::cord_internal::CordRep* TakeRep() &&;
// Helper for Append() // Helper for Append().
template <typename C> template <typename C>
void AppendImpl(C&& src); void AppendImpl(C&& src);
// Helper for AbslHashValue() // Helper for AbslHashValue().
template <typename H> template <typename H>
H HashFragmented(H hash_state) const { H HashFragmented(H hash_state) const {
typename H::AbslInternalPiecewiseCombiner combiner; typename H::AbslInternalPiecewiseCombiner combiner;
......
...@@ -47,9 +47,9 @@ ...@@ -47,9 +47,9 @@
// this abstraction, make sure that you should not instead be rewriting your // this abstraction, make sure that you should not instead be rewriting your
// code to be more specific. // code to be more specific.
// //
// Abseil expects to release an `absl::variant` type shortly (a C++11 compatible // Abseil has also released an `absl::variant` type (a C++11 compatible version
// version of the C++17 `std::variant), which is generally preferred for use // of the C++17 `std::variant`), which is generally preferred for use over
// over `absl::any`. // `absl::any`.
#ifndef ABSL_TYPES_ANY_H_ #ifndef ABSL_TYPES_ANY_H_
#define ABSL_TYPES_ANY_H_ #define ABSL_TYPES_ANY_H_
......
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