[committed] libstdc++: Fix tr1::variate_generator::engine_value_type

Message ID 20220916161857.510663-1-jwakely@redhat.com
State New, archived
Headers
Series [committed] libstdc++: Fix tr1::variate_generator::engine_value_type |

Commit Message

Jonathan Wakely Sept. 16, 2022, 4:18 p.m. UTC
  Tested x86_64-linux, pushed to trunk.

-- >8 --

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.
---
 libstdc++-v3/include/tr1/random.h             | 115 ++++++------------
 .../random/variate_generator/37986.cc         |   2 +-
 .../requirements/typedefs.cc                  |  51 ++++++--
 3 files changed, 84 insertions(+), 84 deletions(-)
  

Patch

diff --git a/libstdc++-v3/include/tr1/random.h b/libstdc++-v3/include/tr1/random.h
index 535f142a004..6061649c5a4 100644
--- a/libstdc++-v3/include/tr1/random.h
+++ b/libstdc++-v3/include/tr1/random.h
@@ -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;
     };
 
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/variate_generator/37986.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/variate_generator/37986.cc
index 5eeccf04771..a13094740e7 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/variate_generator/37986.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/variate_generator/37986.cc
@@ -21,7 +21,7 @@ 
 
 #include <tr1/random>
 
-// libtsdc++/37986
+// libstdc++/37986
 void test01()
 {
   std::tr1::mt19937 mt;
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/variate_generator/requirements/typedefs.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/variate_generator/requirements/typedefs.cc
index 0bdb610e31b..a71c8ddfd81 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/variate_generator/requirements/typedefs.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/variate_generator/requirements/typedefs.cc
@@ -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;
 }