diff options
author | Justin Bassett <jbassett@google.com> | 2024-05-24 11:33:05 -0700 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2024-05-24 11:33:58 -0700 |
commit | 4a7c2ec65afca528226fd4a8fd514dda78572bda (patch) | |
tree | 6b415e82992b2f3399f95a9e0cbe34e0ac838b01 /absl/random | |
parent | 0ef5bc614d9447350222ad52e140d81a4785da07 (diff) |
Forbid absl::Uniform<absl::int128>(gen)
std::is_signed can't be specialized, so this actually lets through non-unsigned types where the types are not language primitives (i.e. it lets absl::int128 through). However, std::numeric_limits can be specialized, and is indeed specialized, so we can use that instead.
PiperOrigin-RevId: 636983590
Change-Id: Ic993518e9cac7c453b08deaf3784b6fba49f15d0
Diffstat (limited to 'absl/random')
-rw-r--r-- | absl/random/BUILD.bazel | 2 | ||||
-rw-r--r-- | absl/random/CMakeLists.txt | 2 | ||||
-rw-r--r-- | absl/random/distributions.h | 16 | ||||
-rw-r--r-- | absl/random/distributions_test.cc | 60 |
4 files changed, 64 insertions, 16 deletions
diff --git a/absl/random/BUILD.bazel b/absl/random/BUILD.bazel index fa1200d5..f276cc08 100644 --- a/absl/random/BUILD.bazel +++ b/absl/random/BUILD.bazel @@ -221,6 +221,8 @@ cc_test( deps = [ ":distributions", ":random", + "//absl/meta:type_traits", + "//absl/numeric:int128", "//absl/random/internal:distribution_test_util", "@com_google_googletest//:gtest", "@com_google_googletest//:gtest_main", diff --git a/absl/random/CMakeLists.txt b/absl/random/CMakeLists.txt index 56bbfd81..af91d1a4 100644 --- a/absl/random/CMakeLists.txt +++ b/absl/random/CMakeLists.txt @@ -288,6 +288,8 @@ absl_cc_test( DEPS absl::random_distributions absl::random_random + absl::type_traits + absl::int128 absl::random_internal_distribution_test_util GTest::gmock GTest::gtest_main diff --git a/absl/random/distributions.h b/absl/random/distributions.h index d62f7f3b..b6ade685 100644 --- a/absl/random/distributions.h +++ b/absl/random/distributions.h @@ -46,23 +46,23 @@ #ifndef ABSL_RANDOM_DISTRIBUTIONS_H_ #define ABSL_RANDOM_DISTRIBUTIONS_H_ -#include <algorithm> -#include <cmath> #include <limits> -#include <random> #include <type_traits> +#include "absl/base/config.h" #include "absl/base/internal/inline_variable.h" +#include "absl/meta/type_traits.h" #include "absl/random/bernoulli_distribution.h" #include "absl/random/beta_distribution.h" #include "absl/random/exponential_distribution.h" #include "absl/random/gaussian_distribution.h" #include "absl/random/internal/distribution_caller.h" // IWYU pragma: export +#include "absl/random/internal/traits.h" #include "absl/random/internal/uniform_helper.h" // IWYU pragma: export #include "absl/random/log_uniform_int_distribution.h" #include "absl/random/poisson_distribution.h" -#include "absl/random/uniform_int_distribution.h" -#include "absl/random/uniform_real_distribution.h" +#include "absl/random/uniform_int_distribution.h" // IWYU pragma: export +#include "absl/random/uniform_real_distribution.h" // IWYU pragma: export #include "absl/random/zipf_distribution.h" namespace absl { @@ -176,7 +176,7 @@ Uniform(TagType tag, return random_internal::DistributionCaller<gen_t>::template Call< distribution_t>(&urbg, tag, static_cast<return_t>(lo), - static_cast<return_t>(hi)); + static_cast<return_t>(hi)); } // absl::Uniform(bitgen, lo, hi) @@ -200,7 +200,7 @@ Uniform(URBG&& urbg, // NOLINT(runtime/references) return random_internal::DistributionCaller<gen_t>::template Call< distribution_t>(&urbg, static_cast<return_t>(lo), - static_cast<return_t>(hi)); + static_cast<return_t>(hi)); } // absl::Uniform<unsigned T>(bitgen) @@ -208,7 +208,7 @@ Uniform(URBG&& urbg, // NOLINT(runtime/references) // Overload of Uniform() using the minimum and maximum values of a given type // `T` (which must be unsigned), returning a value of type `unsigned T` template <typename R, typename URBG> -typename absl::enable_if_t<!std::is_signed<R>::value, R> // +typename absl::enable_if_t<!std::numeric_limits<R>::is_signed, R> // Uniform(URBG&& urbg) { // NOLINT(runtime/references) using gen_t = absl::decay_t<URBG>; using distribution_t = random_internal::UniformDistributionWrapper<R>; diff --git a/absl/random/distributions_test.cc b/absl/random/distributions_test.cc index 5321a11c..ea321839 100644 --- a/absl/random/distributions_test.cc +++ b/absl/random/distributions_test.cc @@ -17,10 +17,14 @@ #include <cfloat> #include <cmath> #include <cstdint> -#include <random> +#include <limits> +#include <type_traits> +#include <utility> #include <vector> #include "gtest/gtest.h" +#include "absl/meta/type_traits.h" +#include "absl/numeric/int128.h" #include "absl/random/internal/distribution_test_util.h" #include "absl/random/random.h" @@ -30,7 +34,6 @@ constexpr int kSize = 400000; class RandomDistributionsTest : public testing::Test {}; - struct Invalid {}; template <typename A, typename B> @@ -93,17 +96,18 @@ void CheckArgsInferType() { } template <typename A, typename B, typename ExplicitRet> -auto ExplicitUniformReturnT(int) -> decltype( - absl::Uniform<ExplicitRet>(*std::declval<absl::InsecureBitGen*>(), - std::declval<A>(), std::declval<B>())); +auto ExplicitUniformReturnT(int) -> decltype(absl::Uniform<ExplicitRet>( + std::declval<absl::InsecureBitGen&>(), + std::declval<A>(), std::declval<B>())); template <typename, typename, typename ExplicitRet> Invalid ExplicitUniformReturnT(...); template <typename TagType, typename A, typename B, typename ExplicitRet> -auto ExplicitTaggedUniformReturnT(int) -> decltype(absl::Uniform<ExplicitRet>( - std::declval<TagType>(), *std::declval<absl::InsecureBitGen*>(), - std::declval<A>(), std::declval<B>())); +auto ExplicitTaggedUniformReturnT(int) + -> decltype(absl::Uniform<ExplicitRet>( + std::declval<TagType>(), std::declval<absl::InsecureBitGen&>(), + std::declval<A>(), std::declval<B>())); template <typename, typename, typename, typename ExplicitRet> Invalid ExplicitTaggedUniformReturnT(...); @@ -135,6 +139,14 @@ void CheckArgsReturnExpectedType() { ""); } +// Takes the type of `absl::Uniform<R>(gen)` if valid or `Invalid` otherwise. +template <typename R> +auto UniformNoBoundsReturnT(int) + -> decltype(absl::Uniform<R>(std::declval<absl::InsecureBitGen&>())); + +template <typename> +Invalid UniformNoBoundsReturnT(...); + TEST_F(RandomDistributionsTest, UniformTypeInference) { // Infers common types. CheckArgsInferType<uint16_t, uint16_t, uint16_t>(); @@ -221,6 +233,38 @@ TEST_F(RandomDistributionsTest, UniformNoBounds) { absl::Uniform<uint32_t>(gen); absl::Uniform<uint64_t>(gen); absl::Uniform<absl::uint128>(gen); + + // Compile-time validity tests. + + // Allows unsigned ints. + testing::StaticAssertTypeEq<uint8_t, + decltype(UniformNoBoundsReturnT<uint8_t>(0))>(); + testing::StaticAssertTypeEq<uint16_t, + decltype(UniformNoBoundsReturnT<uint16_t>(0))>(); + testing::StaticAssertTypeEq<uint32_t, + decltype(UniformNoBoundsReturnT<uint32_t>(0))>(); + testing::StaticAssertTypeEq<uint64_t, + decltype(UniformNoBoundsReturnT<uint64_t>(0))>(); + testing::StaticAssertTypeEq< + absl::uint128, decltype(UniformNoBoundsReturnT<absl::uint128>(0))>(); + + // Disallows signed ints. + testing::StaticAssertTypeEq<Invalid, + decltype(UniformNoBoundsReturnT<int8_t>(0))>(); + testing::StaticAssertTypeEq<Invalid, + decltype(UniformNoBoundsReturnT<int16_t>(0))>(); + testing::StaticAssertTypeEq<Invalid, + decltype(UniformNoBoundsReturnT<int32_t>(0))>(); + testing::StaticAssertTypeEq<Invalid, + decltype(UniformNoBoundsReturnT<int64_t>(0))>(); + testing::StaticAssertTypeEq< + Invalid, decltype(UniformNoBoundsReturnT<absl::int128>(0))>(); + + // Disallows float types. + testing::StaticAssertTypeEq<Invalid, + decltype(UniformNoBoundsReturnT<float>(0))>(); + testing::StaticAssertTypeEq<Invalid, + decltype(UniformNoBoundsReturnT<double>(0))>(); } TEST_F(RandomDistributionsTest, UniformNonsenseRanges) { |