In D125283, we ensured that integer distributions would not compile when used with arbitrary unsupported types. This effectively enforced what the Standard mentions here: http://eel.is/c++draft/rand#req.genl-1.5. However, this also had the effect of breaking some users that were using integer distributions with unsupported types like int8_t. Since we already support using __int128_t in those distributions, it is reasonable to also support smaller types like int8_t and its unsigned variant. This commit implements that, adds tests and documents the extension. Note that we voluntarily don't add support for instantiating these distributions with bool and char, since those are not integer types. However, it is trivial to replace uses of these random distributions on char using int8_t. It is also interesting to note that in the process of adding tests for smaller types, I discovered that our distributions sometimes don't provide as faithful a distribution when instantiated with smaller types, so I had to relax a couple of tests. In particular, we do a really bad job at implementing the negative binomial, geometric and poisson distributions for small types. I think this all boils down to the algorithm we use in std::poisson_distribution, however I am running out of time to investigate that and changing the algorithm would be an ABI break (which might be reasonable). As part of this patch, I also added a mitigation for a very likely integer overflow bug we were hitting in our tests in negative_binomial_distribution. I also filed http://llvm.org/PR56656 to track fixing the problematic distributions with int8_t and uint8_t. Supersedes D125283. Differential Revision: https://reviews.llvm.org/D126823
62 lines
2.8 KiB
C++
62 lines
2.8 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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 _LIBCPP___RANDOM_IS_VALID_H
|
|
#define _LIBCPP___RANDOM_IS_VALID_H
|
|
|
|
#include <__config>
|
|
#include <cstdint>
|
|
#include <type_traits>
|
|
|
|
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
|
# pragma GCC system_header
|
|
#endif
|
|
|
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
|
|
|
// [rand.req.genl]/1.5:
|
|
// The effect of instantiating a template that has a template type parameter
|
|
// named IntType is undefined unless the corresponding template argument is
|
|
// cv-unqualified and is one of short, int, long, long long, unsigned short,
|
|
// unsigned int, unsigned long, or unsigned long long.
|
|
|
|
template<class> struct __libcpp_random_is_valid_inttype : false_type {};
|
|
template<> struct __libcpp_random_is_valid_inttype<int8_t> : true_type {}; // extension
|
|
template<> struct __libcpp_random_is_valid_inttype<short> : true_type {};
|
|
template<> struct __libcpp_random_is_valid_inttype<int> : true_type {};
|
|
template<> struct __libcpp_random_is_valid_inttype<long> : true_type {};
|
|
template<> struct __libcpp_random_is_valid_inttype<long long> : true_type {};
|
|
template<> struct __libcpp_random_is_valid_inttype<uint8_t> : true_type {}; // extension
|
|
template<> struct __libcpp_random_is_valid_inttype<unsigned short> : true_type {};
|
|
template<> struct __libcpp_random_is_valid_inttype<unsigned int> : true_type {};
|
|
template<> struct __libcpp_random_is_valid_inttype<unsigned long> : true_type {};
|
|
template<> struct __libcpp_random_is_valid_inttype<unsigned long long> : true_type {};
|
|
|
|
#ifndef _LIBCPP_HAS_NO_INT128
|
|
template<> struct __libcpp_random_is_valid_inttype<__int128_t> : true_type {}; // extension
|
|
template<> struct __libcpp_random_is_valid_inttype<__uint128_t> : true_type {}; // extension
|
|
#endif // _LIBCPP_HAS_NO_INT128
|
|
|
|
// [rand.req.urng]/3:
|
|
// A class G meets the uniform random bit generator requirements if G models
|
|
// uniform_random_bit_generator, invoke_result_t<G&> is an unsigned integer type,
|
|
// and G provides a nested typedef-name result_type that denotes the same type
|
|
// as invoke_result_t<G&>.
|
|
// (In particular, reject URNGs with signed result_types; our distributions cannot
|
|
// handle such generator types.)
|
|
|
|
template<class, class = void> struct __libcpp_random_is_valid_urng : false_type {};
|
|
template<class _Gp> struct __libcpp_random_is_valid_urng<_Gp, __enable_if_t<
|
|
is_unsigned<typename _Gp::result_type>::value &&
|
|
_IsSame<decltype(declval<_Gp&>()()), typename _Gp::result_type>::value
|
|
> > : true_type {};
|
|
|
|
_LIBCPP_END_NAMESPACE_STD
|
|
|
|
#endif // _LIBCPP___RANDOM_IS_VALID_H
|