libstdc++: Fix tr1::variate_generator::engine_value_type

The tr1/5_numerical_facilities/random/variate_generator/37986.cc test
fails for strict -std=c++98 mode because _Adaptor(const _Engine&) is
ill-formed in C++98 when _Engine is a reference type.

Rather than attempt to make the _Adaptor handle references and pointers,
just strip references and pointers from the _Engine type before we adapt
it. That removes the need for the _Adaptor<_Engine*> partial
specialization and avoids the reference-to-reference problem for c++98
mode.

While looking into this I noticed that the TR1 spec requires the
variate_generator<E,D>::engine_value_type to be the underlying engine
type, whereas we make it the _Adaptor<E> type that wraps the engine.

libstdc++-v3/ChangeLog:

	* include/tr1/random.h (__detail::_Adaptor::_BEngine): Remove.
	(__detail::_Adaptor::_M_g): Make public.
	(__detail::_Adaptor<_Engine*, _Dist>): Remove partial
	specialization.
	(variate_generate::_Value): New helper to simplify handling of
	_Engine* and _Engine& template arguments.
	(variate_generate::engine_value_type): Define to underlying
	engine type, not adapted type.
	(variate_generate::engine()): Return underlying engine instead
	of adaptor.
	* testsuite/tr1/5_numerical_facilities/random/variate_generator/37986.cc:
	Fix comment.
	* testsuite/tr1/5_numerical_facilities/random/variate_generator/requirements/typedefs.cc:
	Check member typedefs have the correct types.
This commit is contained in:
Jonathan Wakely 2022-09-16 15:40:06 +01:00
parent 5ad435f2a0
commit b6adc6255f
3 changed files with 84 additions and 84 deletions

View file

@ -81,9 +81,8 @@ namespace tr1
template<typename _Engine, typename _Distribution>
struct _Adaptor
{
typedef typename remove_reference<_Engine>::type _BEngine;
typedef typename _BEngine::result_type _Engine_result_type;
typedef typename _Distribution::input_type result_type;
typedef typename _Engine::result_type _Engine_result_type;
typedef typename _Distribution::input_type result_type;
public:
_Adaptor(const _Engine& __g)
@ -146,72 +145,8 @@ namespace tr1
return __return_value;
}
private:
_Engine _M_g;
};
// Specialization for _Engine*.
template<typename _Engine, typename _Distribution>
struct _Adaptor<_Engine*, _Distribution>
{
typedef typename _Engine::result_type _Engine_result_type;
typedef typename _Distribution::input_type result_type;
public:
_Adaptor(_Engine* __g)
: _M_g(__g) { }
result_type
min() const
{
result_type __return_value;
if (is_integral<_Engine_result_type>::value
&& is_integral<result_type>::value)
__return_value = _M_g->min();
else
__return_value = result_type(0);
return __return_value;
}
result_type
max() const
{
result_type __return_value;
if (is_integral<_Engine_result_type>::value
&& is_integral<result_type>::value)
__return_value = _M_g->max();
else if (!is_integral<result_type>::value)
__return_value = result_type(1);
else
__return_value = std::numeric_limits<result_type>::max() - 1;
return __return_value;
}
result_type
operator()()
{
result_type __return_value;
if (is_integral<_Engine_result_type>::value
&& is_integral<result_type>::value)
__return_value = (*_M_g)();
else if (!is_integral<_Engine_result_type>::value
&& !is_integral<result_type>::value)
__return_value = result_type((*_M_g)() - _M_g->min())
/ result_type(_M_g->max() - _M_g->min());
else if (is_integral<_Engine_result_type>::value
&& !is_integral<result_type>::value)
__return_value = result_type((*_M_g)() - _M_g->min())
/ result_type(_M_g->max() - _M_g->min() + result_type(1));
else
__return_value = ((((*_M_g)() - _M_g->min())
/ (_M_g->max() - _M_g->min()))
* std::numeric_limits<result_type>::max());
return __return_value;
}
private:
_Engine* _M_g;
};
} // namespace __detail
/**
@ -223,17 +158,45 @@ namespace tr1
template<typename _Engine, typename _Dist>
class variate_generator
{
// Concept requirements.
__glibcxx_class_requires(_Engine, _CopyConstructibleConcept)
// __glibcxx_class_requires(_Engine, _EngineConcept)
// __glibcxx_class_requires(_Dist, _EngineConcept)
template<typename _Eng>
struct _Value
{
typedef _Eng type;
static const _Eng&
_S_ref(const _Eng& __e) { return __e; }
};
template<typename _Eng>
struct _Value<_Eng*>
{
typedef _Eng type;
__attribute__((__nonnull__))
static const _Eng&
_S_ref(const _Eng* __e) { return *__e; }
};
template<typename _Eng>
struct _Value<_Eng&>
{
typedef _Eng type;
static const _Eng&
_S_ref(const _Eng& __e) { return __e; }
};
public:
typedef _Engine engine_type;
typedef __detail::_Adaptor<_Engine, _Dist> engine_value_type;
typedef typename _Value<_Engine>::type engine_value_type;
typedef _Dist distribution_type;
typedef typename _Dist::result_type result_type;
// Concept requirements.
__glibcxx_class_requires(engine_value_type, _CopyConstructibleConcept)
// __glibcxx_class_requires(_Engine, _EngineConcept)
// __glibcxx_class_requires(_Dist, _EngineConcept)
// tr1:5.1.1 table 5.1 requirement
typedef typename __gnu_cxx::__enable_if<
is_arithmetic<result_type>::value, result_type>::__type _IsValidType;
@ -246,7 +209,7 @@ namespace tr1
* the @p _Engine or @p _Dist objects.
*/
variate_generator(engine_type __eng, distribution_type __dist)
: _M_engine(__eng), _M_dist(__dist) { }
: _M_engine(_Value<_Engine>::_S_ref(__eng)), _M_dist(__dist) { }
/**
* Gets the next generated value on the distribution.
@ -269,7 +232,7 @@ namespace tr1
*/
engine_value_type&
engine()
{ return _M_engine; }
{ return _M_engine._M_g; }
/**
* Gets a const reference to the underlying uniform random number
@ -277,7 +240,7 @@ namespace tr1
*/
const engine_value_type&
engine() const
{ return _M_engine; }
{ return _M_engine._M_g; }
/**
* Gets a reference to the underlying random distribution.
@ -308,7 +271,7 @@ namespace tr1
{ return this->distribution().max(); }
private:
engine_value_type _M_engine;
__detail::_Adaptor<engine_value_type, _Dist> _M_engine;
distribution_type _M_dist;
};

View file

@ -21,7 +21,7 @@
#include <tr1/random>
// libtsdc++/37986
// libstdc++/37986
void test01()
{
std::tr1::mt19937 mt;

View file

@ -23,19 +23,56 @@
#include <tr1/random>
template<typename T, typename U> struct require_same; // not defined
template<typename T> struct require_same<T, T> { };
typedef std::tr1::linear_congruential<unsigned long, 16807, 0, 2147483647> E;
typedef std::tr1::uniform_int<int> D;
void
test01()
{
using namespace std::tr1;
typedef variate_generator
<
linear_congruential<unsigned long, 16807 , 0 , 2147483647>,
uniform_int<int>
> test_type;
typedef std::tr1::variate_generator<E, D> test_type;
typedef test_type::engine_type engine_type;
typedef test_type::engine_value_type engine_value_type;
typedef test_type::distribution_type distribution_type;
typedef test_type::result_type result_type;
require_same<engine_type, E> check_e;
require_same<engine_value_type, E> check_ev;
require_same<distribution_type, D> check_d;
require_same<result_type, typename D::result_type> check_r;
}
void
test02()
{
typedef std::tr1::variate_generator<E&, D> test_type;
typedef test_type::engine_type engine_type;
typedef test_type::engine_value_type engine_value_type;
typedef test_type::distribution_type distribution_type;
typedef test_type::result_type result_type;
require_same<engine_type, E&> check_e;
require_same<engine_value_type, E> check_ev;
require_same<distribution_type, D> check_d;
require_same<result_type, typename D::result_type> check_r;
}
void
test03()
{
typedef std::tr1::variate_generator<E*, D> test_type;
typedef test_type::engine_type engine_type;
typedef test_type::engine_value_type engine_value_type;
typedef test_type::distribution_type distribution_type;
typedef test_type::result_type result_type;
require_same<engine_type, E*> check_e;
require_same<engine_value_type, E> check_ev;
require_same<distribution_type, D> check_d;
require_same<result_type, typename D::result_type> check_r;
}