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
pull/754/head
Abseil Team 5 years ago committed by Derek Mauro
parent 184cf25241
commit 1995c6a3c2
  1. 14
      absl/debugging/internal/demangle.cc
  2. 15
      absl/random/CMakeLists.txt
  3. 10
      absl/random/distributions.h
  4. 142
      absl/random/distributions_test.cc
  5. 12
      absl/random/internal/BUILD.bazel
  6. 38
      absl/random/internal/uniform_helper.h
  7. 279
      absl/random/internal/uniform_helper_test.cc
  8. 28
      absl/strings/cord.h
  9. 6
      absl/types/any.h

@ -126,6 +126,7 @@ static const AbbrevPair kBuiltinTypeList[] = {
{"Dn", "std::nullptr_t", 0}, // i.e., decltype(nullptr)
{"Df", "decimal32", 0}, // IEEE 754r decimal floating point (32 bits)
{"Di", "char32_t", 0},
{"Du", "char8_t", 0},
{"Ds", "char16_t", 0},
{"Dh", "float16", 0}, // IEEE 754r half-precision float (16 bits)
{nullptr, nullptr, 0},
@ -965,6 +966,7 @@ static bool ParseOperatorName(State *state, int *arity) {
// ::= TT <type>
// ::= TI <type>
// ::= TS <type>
// ::= TH <type> # thread-local
// ::= Tc <call-offset> <call-offset> <(base) encoding>
// ::= GV <(object) name>
// ::= T <call-offset> <(base) encoding>
@ -983,7 +985,7 @@ static bool ParseSpecialName(State *state) {
ComplexityGuard guard(state);
if (guard.IsTooComplex()) return false;
ParseState copy = state->parse_state;
if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "VTIS") &&
if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "VTISH") &&
ParseType(state)) {
return true;
}
@ -1142,6 +1144,7 @@ static bool ParseDecltype(State *state) {
// ::= <decltype>
// ::= <substitution>
// ::= Dp <type> # pack expansion of (C++0x)
// ::= Dv <num-elems> _ # GNU vector extension
//
static bool ParseType(State *state) {
ComplexityGuard guard(state);
@ -1208,6 +1211,12 @@ static bool ParseType(State *state) {
return true;
}
if (ParseTwoCharToken(state, "Dv") && ParseNumber(state, nullptr) &&
ParseOneCharToken(state, '_')) {
return true;
}
state->parse_state = copy;
return false;
}
@ -1256,13 +1265,14 @@ static bool ParseBuiltinType(State *state) {
return false;
}
// <function-type> ::= F [Y] <bare-function-type> E
// <function-type> ::= F [Y] <bare-function-type> [O] E
static bool ParseFunctionType(State *state) {
ComplexityGuard guard(state);
if (guard.IsTooComplex()) return false;
ParseState copy = state->parse_state;
if (ParseOneCharToken(state, 'F') &&
Optional(ParseOneCharToken(state, 'Y')) && ParseBareFunctionType(state) &&
Optional(ParseOneCharToken(state, 'O')) &&
ParseOneCharToken(state, 'E')) {
return true;
}

@ -1159,6 +1159,21 @@ absl_cc_library(
absl::type_traits
)
# Internal-only target, do not depend on directly.
absl_cc_test(
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

@ -128,7 +128,7 @@ Uniform(TagType tag,
auto a = random_internal::uniform_lower_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<
distribution_t>(&urbg, tag, lo, hi);
@ -144,11 +144,11 @@ Uniform(URBG&& urbg, // NOLINT(runtime/references)
R lo, R hi) {
using gen_t = absl::decay_t<URBG>;
using distribution_t = random_internal::UniformDistributionWrapper<R>;
constexpr auto tag = absl::IntervalClosedOpen;
auto a = random_internal::uniform_lower_bound(tag, lo, hi);
auto b = random_internal::uniform_upper_bound(tag, lo, hi);
if (a > b) return a;
if (!random_internal::is_uniform_range_valid(a, b)) return lo;
return random_internal::DistributionCaller<gen_t>::template Call<
distribution_t>(&urbg, lo, hi);
@ -172,7 +172,7 @@ Uniform(TagType tag,
auto a = random_internal::uniform_lower_bound<return_t>(tag, lo, hi);
auto b = random_internal::uniform_upper_bound<return_t>(tag, lo, hi);
if (a > b) return a;
if (!random_internal::is_uniform_range_valid(a, b)) return lo;
return random_internal::DistributionCaller<gen_t>::template Call<
distribution_t>(&urbg, tag, static_cast<return_t>(lo),
@ -196,7 +196,7 @@ Uniform(URBG&& urbg, // NOLINT(runtime/references)
constexpr auto tag = absl::IntervalClosedOpen;
auto a = random_internal::uniform_lower_bound<return_t>(tag, lo, hi);
auto b = random_internal::uniform_upper_bound<return_t>(tag, lo, hi);
if (a > b) return a;
if (!random_internal::is_uniform_range_valid(a, b)) return lo;
return random_internal::DistributionCaller<gen_t>::template Call<
distribution_t>(&urbg, static_cast<return_t>(lo),

@ -29,94 +29,6 @@ constexpr int kSize = 400000;
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 {};
@ -284,7 +196,9 @@ TEST_F(RandomDistributionsTest, UniformTypeInference) {
// Properly promotes float.
CheckArgsInferType<float, double, double>();
}
TEST_F(RandomDistributionsTest, UniformExamples) {
// Examples.
absl::InsecureBitGen gen;
EXPECT_NE(1, absl::Uniform(gen, static_cast<uint16_t>(0), 1.0f));
@ -307,6 +221,58 @@ TEST_F(RandomDistributionsTest, UniformNoBounds) {
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.
TEST_F(RandomDistributionsTest, UniformReal) {
std::vector<double> values(kSize);

@ -716,3 +716,15 @@ cc_test(
"@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<
std::is_same<Tag, IntervalOpenOpenTag>>>::value,
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>
@ -136,7 +136,7 @@ typename absl::enable_if_t<
std::is_same<Tag, IntervalOpenOpenTag>>>::value,
IntType>
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>
@ -172,6 +172,40 @@ 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.
//
// 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
// or absl::uniform_real_distribution depending on the NumType parameter.
template <typename NumType>

@ -0,0 +1,279 @@
// 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/uniform_helper.h"
#include <cmath>
#include <cstdint>
#include <random>
#include "gtest/gtest.h"
namespace {
using absl::IntervalClosedClosedTag;
using absl::IntervalClosedOpenTag;
using absl::IntervalOpenClosedTag;
using absl::IntervalOpenOpenTag;
using absl::random_internal::uniform_inferred_return_t;
using absl::random_internal::uniform_lower_bound;
using absl::random_internal::uniform_upper_bound;
class UniformHelperTest : public testing::Test {};
TEST_F(UniformHelperTest, UniformBoundFunctionsGeneral) {
constexpr IntervalClosedClosedTag IntervalClosedClosed;
constexpr IntervalClosedOpenTag IntervalClosedOpen;
constexpr IntervalOpenClosedTag IntervalOpenClosed;
constexpr IntervalOpenOpenTag IntervalOpenOpen;
// 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);
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);
}
TEST_F(UniformHelperTest, UniformBoundFunctionsIntBounds) {
// Verifies the saturating nature of uniform_lower_bound and
// uniform_upper_bound
constexpr IntervalOpenOpenTag IntervalOpenOpen;
// uint max.
constexpr auto m = (std::numeric_limits<uint64_t>::max)();
EXPECT_EQ(1, uniform_lower_bound(IntervalOpenOpen, 0u, 0u));
EXPECT_EQ(m, uniform_lower_bound(IntervalOpenOpen, m, m));
EXPECT_EQ(m, uniform_lower_bound(IntervalOpenOpen, m - 1, m - 1));
EXPECT_EQ(0, uniform_upper_bound(IntervalOpenOpen, 0u, 0u));
EXPECT_EQ(m - 1, uniform_upper_bound(IntervalOpenOpen, m, m));
// int min/max
constexpr auto l = (std::numeric_limits<int64_t>::min)();
constexpr auto r = (std::numeric_limits<int64_t>::max)();
EXPECT_EQ(1, uniform_lower_bound(IntervalOpenOpen, 0, 0));
EXPECT_EQ(l + 1, uniform_lower_bound(IntervalOpenOpen, l, l));
EXPECT_EQ(r, uniform_lower_bound(IntervalOpenOpen, r - 1, r - 1));
EXPECT_EQ(r, uniform_lower_bound(IntervalOpenOpen, r, r));
EXPECT_EQ(-1, uniform_upper_bound(IntervalOpenOpen, 0, 0));
EXPECT_EQ(l, uniform_upper_bound(IntervalOpenOpen, l, l));
EXPECT_EQ(r - 1, uniform_upper_bound(IntervalOpenOpen, r, r));
}
TEST_F(UniformHelperTest, UniformBoundFunctionsRealBounds) {
// absl::uniform_real_distribution natively assumes IntervalClosedOpen;
// use the inverse here so each bound has to change.
constexpr IntervalOpenClosedTag IntervalOpenClosed;
// Edge cases: the next value toward itself is itself.
EXPECT_EQ(1.0, uniform_lower_bound(IntervalOpenClosed, 1.0, 1.0));
EXPECT_EQ(1.0f, uniform_lower_bound(IntervalOpenClosed, 1.0f, 1.0f));
// rightmost and leftmost finite values.
constexpr auto r = (std::numeric_limits<double>::max)();
const auto re = std::nexttoward(r, 0.0);
constexpr auto l = -r;
const auto le = std::nexttoward(l, 0.0);
EXPECT_EQ(l, uniform_lower_bound(IntervalOpenClosed, l, l)); // (l,l)
EXPECT_EQ(r, uniform_lower_bound(IntervalOpenClosed, r, r)); // (r,r)
EXPECT_EQ(le, uniform_lower_bound(IntervalOpenClosed, l, r)); // (l,r)
EXPECT_EQ(le, uniform_lower_bound(IntervalOpenClosed, l, 0.0)); // (l, 0)
EXPECT_EQ(le, uniform_lower_bound(IntervalOpenClosed, l, le)); // (l, le)
EXPECT_EQ(r, uniform_lower_bound(IntervalOpenClosed, re, r)); // (re, r)
EXPECT_EQ(le, uniform_upper_bound(IntervalOpenClosed, l, l)); // (l,l)
EXPECT_EQ(r, uniform_upper_bound(IntervalOpenClosed, r, r)); // (r,r)
EXPECT_EQ(r, uniform_upper_bound(IntervalOpenClosed, l, r)); // (l,r)
EXPECT_EQ(r, uniform_upper_bound(IntervalOpenClosed, l, re)); // (l,re)
EXPECT_EQ(r, uniform_upper_bound(IntervalOpenClosed, 0.0, r)); // (0, r)
EXPECT_EQ(r, uniform_upper_bound(IntervalOpenClosed, re, r)); // (re, r)
EXPECT_EQ(r, uniform_upper_bound(IntervalOpenClosed, le, re)); // (le, re)
const double e = std::nextafter(1.0, 2.0); // 1 + epsilon
const double f = std::nextafter(1.0, 0.0); // 1 - epsilon
// (1.0, 1.0 + epsilon)
EXPECT_EQ(e, uniform_lower_bound(IntervalOpenClosed, 1.0, e));
EXPECT_EQ(std::nextafter(e, 2.0),
uniform_upper_bound(IntervalOpenClosed, 1.0, e));
// (1.0-epsilon, 1.0)
EXPECT_EQ(1.0, uniform_lower_bound(IntervalOpenClosed, f, 1.0));
EXPECT_EQ(e, uniform_upper_bound(IntervalOpenClosed, f, 1.0));
// denorm cases.
const double g = std::numeric_limits<double>::denorm_min();
const double h = std::nextafter(g, 1.0);
// (0, denorm_min)
EXPECT_EQ(g, uniform_lower_bound(IntervalOpenClosed, 0.0, g));
EXPECT_EQ(h, uniform_upper_bound(IntervalOpenClosed, 0.0, g));
// (denorm_min, 1.0)
EXPECT_EQ(h, uniform_lower_bound(IntervalOpenClosed, g, 1.0));
EXPECT_EQ(e, uniform_upper_bound(IntervalOpenClosed, g, 1.0));
// Edge cases: invalid bounds.
EXPECT_EQ(f, uniform_lower_bound(IntervalOpenClosed, 1.0, -1.0));
}
struct Invalid {};
template <typename A, typename B>
auto InferredUniformReturnT(int) -> uniform_inferred_return_t<A, B>;
template <typename, typename>
Invalid InferredUniformReturnT(...);
// Given types <A, B, Expect>, CheckArgsInferType() verifies that
//
// uniform_inferred_return_t<A, B> and
// uniform_inferred_return_t<B, A>
//
// returns the type "Expect".
//
// This interface can also be used to assert that a given inferred return types
// are invalid. Writing:
//
// CheckArgsInferType<float, int, Invalid>()
//
// will assert that this overload does not exist.
template <typename A, typename B, typename Expect>
void CheckArgsInferType() {
static_assert(
absl::conjunction<
std::is_same<Expect, decltype(InferredUniformReturnT<A, B>(0))>,
std::is_same<Expect,
decltype(InferredUniformReturnT<B, A>(0))>>::value,
"");
}
TEST_F(UniformHelperTest, UniformTypeInference) {
// Infers common types.
CheckArgsInferType<uint16_t, uint16_t, uint16_t>();
CheckArgsInferType<uint32_t, uint32_t, uint32_t>();
CheckArgsInferType<uint64_t, uint64_t, uint64_t>();
CheckArgsInferType<int16_t, int16_t, int16_t>();
CheckArgsInferType<int32_t, int32_t, int32_t>();
CheckArgsInferType<int64_t, int64_t, int64_t>();
CheckArgsInferType<float, float, float>();
CheckArgsInferType<double, double, double>();
// Properly promotes uint16_t.
CheckArgsInferType<uint16_t, uint32_t, uint32_t>();
CheckArgsInferType<uint16_t, uint64_t, uint64_t>();
CheckArgsInferType<uint16_t, int32_t, int32_t>();
CheckArgsInferType<uint16_t, int64_t, int64_t>();
CheckArgsInferType<uint16_t, float, float>();
CheckArgsInferType<uint16_t, double, double>();
// Properly promotes int16_t.
CheckArgsInferType<int16_t, int32_t, int32_t>();
CheckArgsInferType<int16_t, int64_t, int64_t>();
CheckArgsInferType<int16_t, float, float>();
CheckArgsInferType<int16_t, double, double>();
// Invalid (u)int16_t-pairings do not compile.
// See "CheckArgsInferType" comments above, for how this is achieved.
CheckArgsInferType<uint16_t, int16_t, Invalid>();
CheckArgsInferType<int16_t, uint32_t, Invalid>();
CheckArgsInferType<int16_t, uint64_t, Invalid>();
// Properly promotes uint32_t.
CheckArgsInferType<uint32_t, uint64_t, uint64_t>();
CheckArgsInferType<uint32_t, int64_t, int64_t>();
CheckArgsInferType<uint32_t, double, double>();
// Properly promotes int32_t.
CheckArgsInferType<int32_t, int64_t, int64_t>();
CheckArgsInferType<int32_t, double, double>();
// Invalid (u)int32_t-pairings do not compile.
CheckArgsInferType<uint32_t, int32_t, Invalid>();
CheckArgsInferType<int32_t, uint64_t, Invalid>();
CheckArgsInferType<int32_t, float, Invalid>();
CheckArgsInferType<uint32_t, float, Invalid>();
// Invalid (u)int64_t-pairings do not compile.
CheckArgsInferType<uint64_t, int64_t, Invalid>();
CheckArgsInferType<int64_t, float, Invalid>();
CheckArgsInferType<int64_t, double, Invalid>();
// Properly promotes float.
CheckArgsInferType<float, double, double>();
}
} // namespace

@ -125,9 +125,9 @@ class Cord {
absl::enable_if_t<std::is_same<T, std::string>::value, int>;
public:
// Cord::Cord() Constructors
// Cord::Cord() Constructors.
// Creates an empty Cord
// Creates an empty Cord.
constexpr Cord() noexcept;
// Creates a Cord from an existing Cord. Cord is copyable and efficiently
@ -153,7 +153,7 @@ class Cord {
// Cord::~Cord()
//
// Destructs the Cord
// Destructs the Cord.
~Cord() {
if (contents_.is_tree()) DestroyCordSlow();
}
@ -587,7 +587,7 @@ class Cord {
// 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().
//
// NOTE: This routine is reasonably efficient. It is roughly
@ -599,8 +599,8 @@ class Cord {
// Cord::TryFlat()
//
// If this cord's representation is a single flat array, return a
// string_view referencing that array. Otherwise return nullopt.
// If this cord's representation is a single flat array, returns a
// string_view referencing that array. Otherwise returns nullopt.
absl::optional<absl::string_view> TryFlat() const;
// Cord::Flatten()
@ -610,7 +610,7 @@ class Cord {
// If the cord was already flat, the contents are not modified.
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) {
cord->Append(part);
}
@ -629,7 +629,7 @@ class Cord {
friend bool operator==(const Cord& lhs, const Cord& 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.
void ForEachChunk(absl::FunctionRef<void(absl::string_view)>) const;
@ -673,7 +673,7 @@ class Cord {
void replace_tree(absl::cord_internal::CordRep* rep);
// Returns non-null iff was holding a pointer
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);
void reduce_size(size_t n); // REQUIRES: holding data
void remove_prefix(size_t n); // REQUIRES: holding data
@ -731,14 +731,14 @@ class Cord {
};
InlineRep contents_;
// Helper for MemoryUsage()
// Helper for MemoryUsage().
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,
absl::string_view* fragment);
// Helper for ForEachChunk()
// Helper for ForEachChunk().
static void ForEachChunkAux(
absl::cord_internal::CordRep* rep,
absl::FunctionRef<void(absl::string_view)> callback);
@ -767,11 +767,11 @@ class Cord {
absl::cord_internal::CordRep* TakeRep() const&;
absl::cord_internal::CordRep* TakeRep() &&;
// Helper for Append()
// Helper for Append().
template <typename C>
void AppendImpl(C&& src);
// Helper for AbslHashValue()
// Helper for AbslHashValue().
template <typename H>
H HashFragmented(H hash_state) const {
typename H::AbslInternalPiecewiseCombiner combiner;

@ -47,9 +47,9 @@
// this abstraction, make sure that you should not instead be rewriting your
// code to be more specific.
//
// Abseil expects to release an `absl::variant` type shortly (a C++11 compatible
// version of the C++17 `std::variant), which is generally preferred for use
// over `absl::any`.
// Abseil has also released an `absl::variant` type (a C++11 compatible version
// of the C++17 `std::variant`), which is generally preferred for use over
// `absl::any`.
#ifndef ABSL_TYPES_ANY_H_
#define ABSL_TYPES_ANY_H_

Loading…
Cancel
Save