[libc++] [ABI BREAK] Conform lognormal_distribution::param_type.
authorArthur O'Dwyer <arthur.j.odwyer@gmail.com>
Tue, 28 Dec 2021 22:51:55 +0000 (17:51 -0500)
committerArthur O'Dwyer <arthur.j.odwyer@gmail.com>
Mon, 17 Jan 2022 15:22:41 +0000 (10:22 -0500)
Fixes #52906.

Differential Revision: https://reviews.llvm.org/D116344

libcxx/docs/ReleaseNotes.rst
libcxx/include/__random/lognormal_distribution.h
libcxx/test/std/numerics/rand/rand.dis/rand.dist.norm/rand.dist.norm.lognormal/eval_param.PR52906.pass.cpp [new file with mode: 0644]

index 1a8c007..4a18312 100644 (file)
@@ -119,6 +119,15 @@ ABI Changes
   constructing a ``std::random_device`` will now be ignored instead of interpreted as a
   file to read entropy from.
 
+- ``std::lognormal_distribution::param_type`` used to store a data member of type
+  ``std::normal_distribution``; now this member is stored in the ``lognormal_distribution``
+  class itself, and the ``param_type`` stores only the mean and standard deviation,
+  as required by the Standard. This changes ``sizeof(std::lognormal_distribution::param_type)``.
+  You can define the ``_LIBCPP_ABI_OLD_LOGNORMAL_DISTRIBUTION`` macro to return to the
+  previous behavior. That macro will be removed in LLVM 15. Please comment
+  `here <https://llvm.org/PR52906>`_ if you are broken by this change and need to
+  define the macro.
+
 Build System Changes
 --------------------
 
index 752861c..8fadb5a 100644 (file)
@@ -24,6 +24,8 @@ _LIBCPP_PUSH_MACROS
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+#ifdef _LIBCPP_ABI_OLD_LOGNORMAL_DISTRIBUTION
+
 template<class _RealType = double>
 class _LIBCPP_TEMPLATE_VIS lognormal_distribution
 {
@@ -156,6 +158,140 @@ operator>>(basic_istream<_CharT, _Traits>& __is,
     return __is >> __x.__p_.__nd_;
 }
 
+#else // _LIBCPP_ABI_OLD_LOGNORMAL_DISTRIBUTION
+
+template<class _RealType = double>
+class _LIBCPP_TEMPLATE_VIS lognormal_distribution
+{
+public:
+    // types
+    typedef _RealType result_type;
+
+    class _LIBCPP_TEMPLATE_VIS param_type
+    {
+        result_type __m_;
+        result_type __s_;
+    public:
+        typedef lognormal_distribution distribution_type;
+
+        _LIBCPP_INLINE_VISIBILITY
+        explicit param_type(result_type __m = 0, result_type __s = 1)
+            : __m_(__m), __s_(__s) {}
+
+        _LIBCPP_INLINE_VISIBILITY
+        result_type m() const {return __m_;}
+        _LIBCPP_INLINE_VISIBILITY
+        result_type s() const {return __s_;}
+
+        friend _LIBCPP_INLINE_VISIBILITY
+        bool operator==(const param_type& __x, const param_type& __y)
+            {return __x.__m_ == __y.__m_ && __x.__s_ == __y.__s_;}
+        friend _LIBCPP_INLINE_VISIBILITY
+        bool operator!=(const param_type& __x, const param_type& __y)
+            {return !(__x == __y);}
+    };
+
+private:
+    normal_distribution<result_type> __nd_;
+
+public:
+    // constructor and reset functions
+#ifndef _LIBCPP_CXX03_LANG
+    _LIBCPP_INLINE_VISIBILITY
+    lognormal_distribution() : lognormal_distribution(0) {}
+    _LIBCPP_INLINE_VISIBILITY
+    explicit lognormal_distribution(result_type __m, result_type __s = 1)
+        : __nd_(__m, __s) {}
+#else
+    _LIBCPP_INLINE_VISIBILITY
+    explicit lognormal_distribution(result_type __m = 0,
+                                    result_type __s = 1)
+        : __nd_(__m, __s) {}
+#endif
+    _LIBCPP_INLINE_VISIBILITY
+    explicit lognormal_distribution(const param_type& __p)
+        : __nd_(__p.m(), __p.s()) {}
+    _LIBCPP_INLINE_VISIBILITY
+    void reset() {__nd_.reset();}
+
+    // generating functions
+    template<class _URNG>
+    _LIBCPP_INLINE_VISIBILITY
+    result_type operator()(_URNG& __g)
+    {
+        return _VSTD::exp(__nd_(__g));
+    }
+
+    template<class _URNG>
+    _LIBCPP_INLINE_VISIBILITY
+    result_type operator()(_URNG& __g, const param_type& __p)
+    {
+        typename normal_distribution<result_type>::param_type __pn(__p.m(), __p.s());
+        return _VSTD::exp(__nd_(__g, __pn));
+    }
+
+    // property functions
+    _LIBCPP_INLINE_VISIBILITY
+    result_type m() const {return __nd_.mean();}
+    _LIBCPP_INLINE_VISIBILITY
+    result_type s() const {return __nd_.stddev();}
+
+    _LIBCPP_INLINE_VISIBILITY
+    param_type param() const {return param_type(__nd_.mean(), __nd_.stddev());}
+    _LIBCPP_INLINE_VISIBILITY
+    void param(const param_type& __p)
+    {
+        typename normal_distribution<result_type>::param_type __pn(__p.m(), __p.s());
+        __nd_.param(__pn);
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    result_type min() const {return 0;}
+    _LIBCPP_INLINE_VISIBILITY
+    result_type max() const {return numeric_limits<result_type>::infinity();}
+
+    friend _LIBCPP_INLINE_VISIBILITY
+        bool operator==(const lognormal_distribution& __x,
+                        const lognormal_distribution& __y)
+        {return __x.__nd_ == __y.__nd_;}
+    friend _LIBCPP_INLINE_VISIBILITY
+        bool operator!=(const lognormal_distribution& __x,
+                        const lognormal_distribution& __y)
+        {return !(__x == __y);}
+
+    template <class _CharT, class _Traits, class _RT>
+    friend
+    basic_ostream<_CharT, _Traits>&
+    operator<<(basic_ostream<_CharT, _Traits>& __os,
+               const lognormal_distribution<_RT>& __x);
+
+    template <class _CharT, class _Traits, class _RT>
+    friend
+    basic_istream<_CharT, _Traits>&
+    operator>>(basic_istream<_CharT, _Traits>& __is,
+               lognormal_distribution<_RT>& __x);
+};
+
+template <class _CharT, class _Traits, class _RT>
+inline _LIBCPP_INLINE_VISIBILITY
+basic_ostream<_CharT, _Traits>&
+operator<<(basic_ostream<_CharT, _Traits>& __os,
+           const lognormal_distribution<_RT>& __x)
+{
+    return __os << __x.__nd_;
+}
+
+template <class _CharT, class _Traits, class _RT>
+inline _LIBCPP_INLINE_VISIBILITY
+basic_istream<_CharT, _Traits>&
+operator>>(basic_istream<_CharT, _Traits>& __is,
+           lognormal_distribution<_RT>& __x)
+{
+    return __is >> __x.__nd_;
+}
+
+#endif // _LIBCPP_ABI_OLD_LOGNORMAL_DISTRIBUTION
+
 _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
diff --git a/libcxx/test/std/numerics/rand/rand.dis/rand.dist.norm/rand.dist.norm.lognormal/eval_param.PR52906.pass.cpp b/libcxx/test/std/numerics/rand/rand.dis/rand.dist.norm/rand.dist.norm.lognormal/eval_param.PR52906.pass.cpp
new file mode 100644 (file)
index 0000000..d360b11
--- /dev/null
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <random>
+
+// template<class RealType = double>
+// class lognormal_distribution
+
+// template<class _URNG> result_type operator()(_URNG& g, const param_type& parm);
+//   https://llvm.org/PR52906
+
+#include <random>
+#include <cassert>
+
+#include "test_macros.h"
+
+int main(int, char**)
+{
+    typedef std::lognormal_distribution<> D;
+    typedef D::param_type P;
+    typedef std::mt19937 G;
+    G g;
+    D d;
+
+    const P p1 = d.param();
+    const P p2 = d.param();
+    assert(p1 == p2);
+    (void) d(g, p1); // This line must not modify p1.
+    assert(p1 == p2);
+    LIBCPP_ASSERT(p1 == d.param());
+
+    return 0;
+}