| //===----------------------------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef TEST_SUPPORT_CONSTEXPR_RANDOM_H |
| #define TEST_SUPPORT_CONSTEXPR_RANDOM_H |
| |
| #include <climits> |
| #include <cstddef> |
| #include <cstdint> |
| #include <iterator> |
| #include <limits> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "test_macros.h" |
| |
| namespace support { |
| |
| namespace detail { |
| |
| template <class> |
| struct is_valid_integer_type_for_random : std::false_type {}; |
| template <> |
| struct is_valid_integer_type_for_random<std::int8_t> : std::true_type {}; |
| template <> |
| struct is_valid_integer_type_for_random<short> : std::true_type {}; |
| template <> |
| struct is_valid_integer_type_for_random<int> : std::true_type {}; |
| template <> |
| struct is_valid_integer_type_for_random<long> : std::true_type {}; |
| template <> |
| struct is_valid_integer_type_for_random<long long> : std::true_type {}; |
| template <> |
| struct is_valid_integer_type_for_random<std::uint8_t> : std::true_type {}; |
| template <> |
| struct is_valid_integer_type_for_random<unsigned short> : std::true_type {}; |
| template <> |
| struct is_valid_integer_type_for_random<unsigned int> : std::true_type {}; |
| template <> |
| struct is_valid_integer_type_for_random<unsigned long> : std::true_type {}; |
| template <> |
| struct is_valid_integer_type_for_random<unsigned long long> : std::true_type {}; |
| |
| #ifndef TEST_HAS_NO_INT128 |
| template <> |
| struct is_valid_integer_type_for_random<__int128_t> : std::true_type {}; |
| template <> |
| struct is_valid_integer_type_for_random<__uint128_t> : std::true_type {}; |
| #endif // TEST_HAS_NO_INT128 |
| |
| template <class, class = void> |
| struct is_valid_urng : std::false_type {}; |
| template <class Gen> |
| struct is_valid_urng< |
| Gen, |
| typename std::enable_if<std::is_unsigned<typename Gen::result_type>::value && |
| std::is_same<decltype(std::declval<Gen&>()()), typename Gen::result_type>::value>::type> |
| : std::true_type {}; |
| |
| template <class UIntType, UIntType N, std::size_t R> |
| struct meta_log2_imp; |
| |
| template <unsigned long long N, std::size_t R> |
| struct meta_log2_imp<unsigned long long, N, R> { |
| static const std::size_t value = |
| N & ((unsigned long long)(1) << R) ? R : meta_log2_imp<unsigned long long, N, R - 1>::value; |
| }; |
| |
| template <unsigned long long N> |
| struct meta_log2_imp<unsigned long long, N, 0> { |
| static const std::size_t value = 0; |
| }; |
| |
| template <size_t R> |
| struct meta_log2_imp<unsigned long long, 0, R> { |
| static const std::size_t value = R + 1; |
| }; |
| |
| #ifndef TEST_HAS_NO_INT128 |
| template <__uint128_t N, std::size_t R> |
| struct meta_log2_imp<__uint128_t, N, R> { |
| static const size_t value = |
| (N >> 64) ? (64 + meta_log2_imp<unsigned long long, (N >> 64), 63>::value) |
| : meta_log2_imp<unsigned long long, N, 63>::value; |
| }; |
| #endif // TEST_HAS_NO_INT128 |
| |
| template <class UIntType, UIntType N> |
| struct meta_log2 { |
| static const size_t value = meta_log2_imp< |
| #ifndef TEST_HAS_NO_INT128 |
| typename std::conditional<sizeof(UIntType) <= sizeof(unsigned long long), unsigned long long, __uint128_t>::type, |
| #else |
| unsigned long long, |
| #endif // TEST_HAS_NO_INT128 |
| N, |
| sizeof(UIntType) * CHAR_BIT - 1 >::value; |
| }; |
| |
| #ifdef TEST_COMPILER_MSVC |
| template <int Width, class T, typename std::enable_if<(Width <= 1), int>::type = 0> |
| TEST_CONSTEXPR int countl_zero_div_conq(T n) TEST_NOEXCEPT { |
| return static_cast<int>(~n) & 1; |
| } |
| |
| template <int Width, class T, typename std::enable_if<(Width > 1), int>::type = 0> |
| TEST_CONSTEXPR int countl_zero_div_conq(T n) TEST_NOEXCEPT { |
| return n >= (static_cast<T>(1) << (Width / 2)) |
| ? detail::countl_zero_div_conq<Width / 2>(n >> (Width / 2)) |
| : detail::countl_zero_div_conq<Width / 2>(n) + Width / 2; |
| } |
| #endif |
| |
| template <class T, typename std::enable_if<std::is_same<T, unsigned int>::value, int>::type = 0> |
| TEST_CONSTEXPR int countl_zero(T n) TEST_NOEXCEPT { |
| #ifdef TEST_COMPILER_MSVC |
| return detail::countl_zero_div_conq<std::numeric_limits<T>::digits>(n); |
| #else |
| return __builtin_clz(n); |
| #endif |
| } |
| |
| template <class T, typename std::enable_if<std::is_same<T, unsigned long>::value, int>::type = 0> |
| TEST_CONSTEXPR_CXX14 int countl_zero(T n) TEST_NOEXCEPT { |
| #ifdef TEST_COMPILER_MSVC |
| return detail::countl_zero_div_conq<std::numeric_limits<T>::digits>(n); |
| #else |
| return __builtin_clzl(n); |
| #endif |
| } |
| |
| template <class T, typename std::enable_if<std::is_same<T, unsigned long long>::value, int>::type = 0> |
| TEST_CONSTEXPR int countl_zero(T n) TEST_NOEXCEPT { |
| #ifdef TEST_COMPILER_MSVC |
| return detail::countl_zero_div_conq<std::numeric_limits<T>::digits>(n); |
| #else |
| return __builtin_clzll(n); |
| #endif |
| } |
| |
| #ifndef TEST_HAS_NO_INT128 |
| template <class T, typename std::enable_if<std::is_same<T, __uint128_t>::value, int>::type = 0> |
| TEST_CONSTEXPR int countl_zero(T n) TEST_NOEXCEPT { |
| return n > std::numeric_limits<std::uint64_t>::max() |
| ? detail::countl_zero(static_cast<std::uint64_t>(n >> 64)) |
| : detail::countl_zero(static_cast<std::uint64_t>(n)) + 64; |
| } |
| #endif // TEST_HAS_NO_INT128 |
| |
| template <class T, |
| typename std::enable_if<std::is_same<T, unsigned char>::value || std::is_same<T, unsigned short>::value, |
| int>::type = 0> |
| TEST_CONSTEXPR int countl_zero(T n) TEST_NOEXCEPT { |
| return detail::countl_zero(static_cast<unsigned int>(n)) - |
| (std::numeric_limits<unsigned int>::digits - std::numeric_limits<T>::digits); |
| } |
| |
| template <class Engine, class UIntType> |
| class independent_bits_engine { |
| public: |
| typedef UIntType result_type; |
| |
| private: |
| typedef typename Engine::result_type engine_result_type; |
| typedef |
| typename std::conditional<sizeof(engine_result_type) <= sizeof(result_type), result_type, engine_result_type>:: |
| type working_result_type; |
| |
| Engine& eng_; |
| std::size_t width_; |
| std::size_t wid0_; |
| std::size_t round_count_all_; |
| std::size_t round_count_regular_; |
| working_result_type y0_; |
| working_result_type y1_; |
| engine_result_type mask0_; |
| engine_result_type mask1_; |
| |
| #if TEST_STD_VER >= 11 |
| static constexpr working_result_type rp = Engine::max() - Engine::min() + working_result_type(1); |
| #else |
| static const working_result_type rp = Engine::max_value - Engine::min_value + working_result_type(1); |
| #endif |
| static TEST_CONSTEXPR const std::size_t rp_log2 = meta_log2<working_result_type, rp>::value; |
| static TEST_CONSTEXPR const std::size_t w_digits = std::numeric_limits<working_result_type>::digits; |
| static TEST_CONSTEXPR const std::size_t e_digits = std::numeric_limits<engine_result_type>::digits; |
| |
| public: |
| // constructors and seeding functions |
| TEST_CONSTEXPR_CXX14 independent_bits_engine(Engine& eng, std::size_t width) |
| : eng_(eng), |
| width_(width), |
| wid0_(), |
| round_count_all_(), |
| round_count_regular_(), |
| y0_(), |
| y1_(), |
| mask0_(), |
| mask1_() { |
| round_count_all_ = width_ / rp_log2 + (width_ % rp_log2 != 0); |
| wid0_ = width_ / round_count_all_; |
| if TEST_CONSTEXPR_CXX17 (rp == 0) { |
| y0_ = rp; |
| } else { |
| if (wid0_ < w_digits) |
| y0_ = (rp >> wid0_) << wid0_; |
| else |
| y0_ = 0; |
| } |
| if (rp - y0_ > y0_ / round_count_all_) { |
| ++round_count_all_; |
| wid0_ = width_ / round_count_all_; |
| if (wid0_ < w_digits) |
| y0_ = (rp >> wid0_) << wid0_; |
| else |
| y0_ = 0; |
| } |
| round_count_regular_ = round_count_all_ - width_ % round_count_all_; |
| if (wid0_ < w_digits - 1) |
| y1_ = (rp >> (wid0_ + 1)) << (wid0_ + 1); |
| else |
| y1_ = 0; |
| mask0_ = wid0_ > 0 ? static_cast<engine_result_type>(engine_result_type(~0) >> (e_digits - wid0_)) |
| : engine_result_type(0); |
| mask1_ = wid0_ < e_digits - 1 ? static_cast<engine_result_type>(engine_result_type(~0) >> (e_digits - (wid0_ + 1))) |
| : engine_result_type(~0); |
| } |
| |
| // generating functions |
| TEST_CONSTEXPR_CXX14 result_type operator()() { return generate(std::integral_constant<bool, (rp != 0)>()); } |
| |
| private: |
| TEST_CONSTEXPR_CXX14 result_type generate(std::false_type) { return static_cast<result_type>(eng_() & mask0_); } |
| |
| TEST_CONSTEXPR_CXX14 result_type generate(std::true_type) { |
| const std::size_t r_digits = std::numeric_limits<result_type>::digits; |
| result_type result = 0; |
| for (std::size_t k = 0; k < round_count_regular_; ++k) { |
| engine_result_type eng_result = 0; |
| do { |
| eng_result = static_cast<engine_result_type>(eng_() - Engine::min()); |
| } while (eng_result >= y0_); |
| if (wid0_ < r_digits) |
| result <<= wid0_; |
| else |
| result = 0; |
| result += eng_result & mask0_; |
| } |
| for (std::size_t k = round_count_regular_; k < round_count_all_; ++k) { |
| engine_result_type eng_result = 0; |
| do { |
| eng_result = static_cast<engine_result_type>(eng_() - Engine::min()); |
| } while (eng_result >= y1_); |
| if (wid0_ < r_digits - 1) |
| result <<= wid0_ + 1; |
| else |
| result = 0; |
| result += eng_result & mask1_; |
| } |
| return result; |
| } |
| }; |
| |
| } // namespace detail |
| |
| template <class IntType = int> |
| class uniform_int_distribution { |
| static_assert(detail::is_valid_integer_type_for_random<IntType>::value, "IntType must be a supported integer type"); |
| |
| public: |
| // types |
| typedef IntType result_type; |
| |
| class param_type { |
| result_type a_; |
| result_type b_; |
| |
| public: |
| typedef uniform_int_distribution distribution_type; |
| |
| #if TEST_STD_VER >= 11 |
| constexpr param_type() : param_type(0) {} |
| #else |
| param_type() : a_(0), b_(std::numeric_limits<result_type>::max()) {} |
| #endif |
| TEST_CONSTEXPR explicit param_type(result_type ax, result_type bx = std::numeric_limits<result_type>::max()) |
| : a_(ax), b_(bx) {} |
| |
| TEST_CONSTEXPR result_type a() const { return a_; } |
| TEST_CONSTEXPR result_type b() const { return b_; } |
| |
| #if TEST_STD_VER >= 20 |
| friend bool operator==(const param_type&, const param_type&) = default; |
| #else |
| TEST_CONSTEXPR friend bool operator==(const param_type& lhs, const param_type& rhs) { |
| return lhs.a_ == rhs.a_ && lhs.b_ == rhs.b_; |
| } |
| TEST_CONSTEXPR friend bool operator!=(const param_type& lhs, const param_type& rhs) { return !(lhs == rhs); } |
| #endif |
| }; |
| |
| private: |
| param_type param_; |
| |
| public: |
| // constructors and reset functions |
| #if TEST_STD_VER >= 11 |
| uniform_int_distribution() = default; |
| #else |
| uniform_int_distribution() {} |
| #endif |
| TEST_CONSTEXPR explicit uniform_int_distribution(result_type ax, |
| result_type bx = std::numeric_limits<result_type>::max()) |
| : param_(ax, bx) {} |
| TEST_CONSTEXPR explicit uniform_int_distribution(const param_type& param) : param_(param) {} |
| TEST_CONSTEXPR_CXX14 void reset() {} |
| |
| // generating functions |
| template <class URNG> |
| TEST_CONSTEXPR_CXX14 result_type operator()(URNG& gen) { |
| return (*this)(gen, param_); |
| } |
| |
| #if TEST_HAS_FEATURE(no_sanitize) && !defined(TEST_COMPILER_GCC) |
| # define TEST_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK __attribute__((__no_sanitize__("unsigned-integer-overflow"))) |
| #else |
| # define TEST_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK |
| #endif |
| template <class URNG> |
| TEST_CONSTEXPR_CXX14 result_type operator()(URNG& gen, const param_type& param) |
| TEST_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK { |
| static_assert(detail::is_valid_urng<URNG>::value, "invalid uniform random bit generator used"); |
| typedef typename std::conditional<sizeof(result_type) <= sizeof(std::uint32_t), |
| std::uint32_t, |
| typename std::make_unsigned<result_type>::type>::type UIntType; |
| const UIntType rp = UIntType(param.b()) - UIntType(param.a()) + UIntType(1); |
| if (rp == 1) |
| return param.a(); |
| const std::size_t ur_digits = std::numeric_limits<UIntType>::digits; |
| typedef detail::independent_bits_engine<URNG, UIntType> Eng; |
| if (rp == 0) |
| return static_cast<result_type>(Eng(gen, ur_digits)()); |
| std::size_t width = ur_digits - detail::countl_zero(rp) - 1; |
| if ((rp & (std::numeric_limits<UIntType>::max() >> (ur_digits - width))) != 0) |
| ++width; |
| Eng eng(gen, width); |
| UIntType eng_result = 0; |
| do { |
| eng_result = eng(); |
| } while (eng_result >= rp); |
| return static_cast<result_type>(eng_result + param.a()); |
| } |
| #undef TEST_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK |
| |
| // property functions |
| TEST_CONSTEXPR result_type a() const { return param_.a(); } |
| TEST_CONSTEXPR result_type b() const { return param_.b(); } |
| |
| TEST_CONSTEXPR param_type param() const { return param_; } |
| TEST_CONSTEXPR_CXX14 void param(const param_type& param) { param_ = param; } |
| |
| TEST_CONSTEXPR result_type min() const { return a(); } |
| TEST_CONSTEXPR result_type max() const { return b(); } |
| |
| #if TEST_STD_VER >= 20 |
| friend bool operator==(const uniform_int_distribution&, const uniform_int_distribution&) = default; |
| #else |
| TEST_CONSTEXPR friend bool operator==(const uniform_int_distribution& lhs, const uniform_int_distribution& rhs) { |
| return lhs.param_ == rhs.param_; |
| } |
| TEST_CONSTEXPR friend bool operator!=(const uniform_int_distribution& lhs, const uniform_int_distribution& rhs) { |
| return !(lhs == rhs); |
| } |
| #endif |
| }; |
| |
| class simple_random_generator { // A linear congruential generator, using the constants used by MS UCRT. |
| private: |
| std::uint32_t status_; |
| |
| public: |
| typedef std::uint16_t result_type; |
| |
| static TEST_CONSTEXPR result_type min() TEST_NOEXCEPT { return 0; } |
| static TEST_CONSTEXPR result_type max() TEST_NOEXCEPT { return static_cast<result_type>(-1); } |
| #if TEST_STD_VER < 11 |
| static const result_type min_value = 0; |
| static const result_type max_value = static_cast<result_type>(-1); |
| #endif |
| static TEST_CONSTEXPR const result_type default_seed = 19937; |
| |
| #if TEST_STD_VER >= 11 |
| constexpr simple_random_generator() noexcept : simple_random_generator(default_seed) {} |
| #else |
| simple_random_generator() throw() : status_(default_seed) {} |
| #endif |
| TEST_CONSTEXPR explicit simple_random_generator(std::uint16_t s) TEST_NOEXCEPT : status_(s) {} |
| |
| TEST_CONSTEXPR_CXX14 result_type operator()() TEST_NOEXCEPT { |
| status_ = status_ * 214013u + 2531011u; |
| return static_cast<result_type>(status_ >> 16); |
| } |
| }; |
| |
| template <class RandomAccessIterator, class UniformRandomNumberGenerator> |
| TEST_CONSTEXPR_CXX14 void |
| #if TEST_STD_VER >= 11 |
| shuffle(RandomAccessIterator first, RandomAccessIterator last, UniformRandomNumberGenerator&& gen) |
| #else |
| shuffle(RandomAccessIterator first, RandomAccessIterator last, UniformRandomNumberGenerator& gen) |
| #endif |
| { |
| typedef typename std::iterator_traits<RandomAccessIterator>::difference_type difference_type; |
| typedef uniform_int_distribution<ptrdiff_t> dist; |
| typedef typename dist::param_type param_type; |
| |
| RandomAccessIterator last_iter = last; |
| difference_type diff = last_iter - first; |
| if (diff > 1) { |
| dist uid; |
| for (--last_iter, (void)--diff; first < last; ++first, (void)--diff) { |
| difference_type index = uid(gen, param_type(0, diff)); |
| if (index != difference_type(0)) { |
| using std::swap; |
| swap(*first, *(first + index)); |
| } |
| } |
| } |
| } |
| |
| } // namespace support |
| |
| #endif // TEST_SUPPORT_CONSTEXPR_RANDOM_H |