Define std::sample for C++17
authorJonathan Wakely <jwakely@redhat.com>
Wed, 12 Oct 2016 15:26:48 +0000 (16:26 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Wed, 12 Oct 2016 15:26:48 +0000 (16:26 +0100)
* doc/xml/manual/status_cxx2017.xml: Add std::sample status.
* doc/html/*: Regenerate.
* include/experimental/algorithm (__sample): Move to bits/stl_algo.h
and into namespace std.
* include/bits/stl_algo.h (__sample): Define here. Fix invalid use
of input iterator. Defend against overloaded comma operator.
(sample): Define for C++17.
* testsuite/25_algorithms/sample/1.cc: New test.

From-SVN: r241062

libstdc++-v3/ChangeLog
libstdc++-v3/doc/html/manual/bugs.html
libstdc++-v3/doc/html/manual/status.html
libstdc++-v3/doc/xml/manual/status_cxx2017.xml
libstdc++-v3/include/bits/stl_algo.h
libstdc++-v3/include/experimental/algorithm
libstdc++-v3/testsuite/25_algorithms/sample/1.cc [new file with mode: 0644]

index 633f4f1ad42f58752d1f132dd32078e3e2af2e01..efbcd2dec19d53147ba0e50babf97a4de1edee5f 100644 (file)
@@ -1,5 +1,14 @@
 2016-10-12  Jonathan Wakely  <jwakely@redhat.com>
 
+       * doc/xml/manual/status_cxx2017.xml: Add std::sample status.
+       * doc/html/*: Regenerate.
+       * include/experimental/algorithm (__sample): Move to bits/stl_algo.h
+       and into namespace std.
+       * include/bits/stl_algo.h (__sample): Define here. Fix invalid use
+       of input iterator. Defend against overloaded comma operator.
+       (sample): Define for C++17.
+       * testsuite/25_algorithms/sample/1.cc: New test.
+
        * testsuite/util/testsuite_common_types.h
        (bitwise_assignment_operators): Use direct-initialization for C++11
        and later, to avoid CopyConstructible requirement.
index 31600a49bd6db45ebc802c86621c7bc066590c76..122bf8f7b9fe0f25006b64801a2606c19068240a 100644 (file)
     </p></dd><dt><span class="term"><a class="link" href="../ext/lwg-defects.html#2441" target="_top">2441</a>:
        <span class="emphasis"><em>Exact-width atomic typedefs should be provided</em></span>
     </span></dt><dd><p>Define the typedefs.
+    </p></dd><dt><span class="term"><a class="link" href="../ext/lwg-defects.html#2442" target="_top">2442</a>:
+       <span class="emphasis"><em><code class="code">call_once()</code> shouldn't <code class="code">DECAY_COPY()</code></em></span>
+    </span></dt><dd><p>Remove indirection through call wrapper that made copies
+    of arguments and forward arguments straight to <code class="code">std::invoke</code>.
     </p></dd><dt><span class="term"><a class="link" href="../ext/lwg-defects.html#2454" target="_top">2454</a>:
        <span class="emphasis"><em>Add <code class="code">raw_storage_iterator::base()</code> member
        </em></span>
        <span class="emphasis"><em><code class="code">allocator_traits::max_size()</code> default behavior is incorrect
        </em></span>
     </span></dt><dd><p>Divide by the object type.
+    </p></dd><dt><span class="term"><a class="link" href="../ext/lwg-defects.html#2484" target="_top">2484</a>:
+       <span class="emphasis"><em><code class="code">rethrow_if_nested()</code>  is doubly unimplementable
+       </em></span>
+    </span></dt><dd><p>Avoid using <code class="code">dynamic_cast</code> when it would be
+    ill-formed.
     </p></dd><dt><span class="term"><a class="link" href="../ext/lwg-defects.html#2583" target="_top">2583</a>:
        <span class="emphasis"><em>There is no way to supply an allocator for <code class="code"> basic_string(str, pos)</code>
        </em></span>
index 1808122f5075f3be0cf6ee0910978b82f29e6fc6..5ef66daa49469da13b05d948440c615c080e8223 100644 (file)
@@ -573,7 +573,11 @@ Feature-testing recommendations for C++</a>.
        <a class="link" href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0220r1.html" target="_top">
        P0220R1
        </a>
-      </td><td align="center"> 7 </td><td align="left"> <code class="code">__cpp_lib_boyer_moore_searcher &gt;= 201603</code> </td></tr><tr><td align="left"> Constant View: A proposal for a <code class="code">std::as_const</code> helper function template </td><td align="left">
+      </td><td align="center"> 7 </td><td align="left"> <code class="code">__cpp_lib_boyer_moore_searcher &gt;= 201603</code> </td></tr><tr><td align="left"> Library Fundamentals V1 TS Components: Sampling </td><td align="left">
+       <a class="link" href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0220r1.html" target="_top">
+       P0220R1
+       </a>
+      </td><td align="center"> 7 </td><td align="left"> <code class="code">__cpp_lib_sample &gt;= 201603</code> </td></tr><tr><td align="left"> Constant View: A proposal for a <code class="code">std::as_const</code> helper function template       </td><td align="left">
        <a class="link" href="" target="_top">
        P0007R1
        </a>
index c6b84409f68277fa73b6d25d00d96afb5c39b464..ae8dfa9529be332f6b2edde69b48c760a5d755cd 100644 (file)
@@ -181,6 +181,17 @@ Feature-testing recommendations for C++</link>.
       <entry> <code>__cpp_lib_boyer_moore_searcher >= 201603</code> </entry>
     </row>
 
+    <row>
+      <entry> Library Fundamentals V1 TS Components: Sampling </entry>
+      <entry>
+       <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0220r1.html">
+       P0220R1
+       </link>
+      </entry>
+      <entry align="center"> 7 </entry>
+      <entry> <code>__cpp_lib_sample >= 201603</code> </entry>
+    </row>
+
     <row>
       <entry> Constant View: A proposal for a <code>std::as_const</code> helper function template      </entry>
       <entry>
index ea0b56ca43fe52081ec0e7ae3b4df61b1ca1fc95..0538a79a3514776433845d1cd4c934124a85591f 100644 (file)
@@ -5615,6 +5615,86 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO
                                __gnu_cxx::__ops::__iter_comp_iter(__comp));
     }
 
+#if __cplusplus >= 201402L
+  /// Reservoir sampling algorithm.
+  template<typename _InputIterator, typename _RandomAccessIterator,
+           typename _Size, typename _UniformRandomBitGenerator>
+    _RandomAccessIterator
+    __sample(_InputIterator __first, _InputIterator __last, input_iterator_tag,
+            _RandomAccessIterator __out, random_access_iterator_tag,
+            _Size __n, _UniformRandomBitGenerator&& __g)
+    {
+      using __distrib_type = uniform_int_distribution<_Size>;
+      using __param_type = typename __distrib_type::param_type;
+      __distrib_type __d{};
+      _Size __sample_sz = 0;
+      while (__first != __last && __sample_sz != __n)
+       {
+         __out[__sample_sz++] = *__first;
+         ++__first;
+       }
+      for (auto __pop_sz = __sample_sz; __first != __last;
+         ++__first, (void) ++__pop_sz)
+       {
+         const auto __k = __d(__g, __param_type{0, __pop_sz});
+         if (__k < __n)
+           __out[__k] = *__first;
+       }
+      return __out + __sample_sz;
+    }
+
+  /// Selection sampling algorithm.
+  template<typename _ForwardIterator, typename _OutputIterator, typename _Cat,
+           typename _Size, typename _UniformRandomBitGenerator>
+    _OutputIterator
+    __sample(_ForwardIterator __first, _ForwardIterator __last,
+            forward_iterator_tag,
+            _OutputIterator __out, _Cat,
+            _Size __n, _UniformRandomBitGenerator&& __g)
+    {
+      using __distrib_type = uniform_int_distribution<_Size>;
+      using __param_type = typename __distrib_type::param_type;
+      __distrib_type __d{};
+      _Size __unsampled_sz = std::distance(__first, __last);
+      for (__n = std::min(__n, __unsampled_sz); __n != 0; ++__first)
+       if (__d(__g, __param_type{0, --__unsampled_sz}) < __n)
+         {
+           *__out++ = *__first;
+           --__n;
+         }
+      return __out;
+    }
+
+#if __cplusplus > 201402L
+#define __cpp_lib_sample 201603
+  /// Take a random sample from a population.
+  template<typename _PopulationIterator, typename _SampleIterator,
+           typename _Distance, typename _UniformRandomBitGenerator>
+    _SampleIterator
+    sample(_PopulationIterator __first, _PopulationIterator __last,
+          _SampleIterator __out, _Distance __n,
+          _UniformRandomBitGenerator&& __g)
+    {
+      using __pop_cat = typename
+       std::iterator_traits<_PopulationIterator>::iterator_category;
+      using __samp_cat = typename
+       std::iterator_traits<_SampleIterator>::iterator_category;
+
+      static_assert(
+         __or_<is_convertible<__pop_cat, forward_iterator_tag>,
+               is_convertible<__samp_cat, random_access_iterator_tag>>::value,
+         "output range must use a RandomAccessIterator when input range"
+         " does not meet the ForwardIterator requirements");
+
+      static_assert(is_integral<_Distance>::value,
+                   "sample size must be an integer type");
+
+      return std::__sample(__first, __last, __pop_cat{}, __out, __samp_cat{},
+                          __n, std::forward<_UniformRandomBitGenerator>(__g));
+    }
+#endif // C++17
+#endif // C++14
+
 _GLIBCXX_END_NAMESPACE_ALGO
 } // namespace std
 
index 0ba6311e952f6cd31fea9b07838d608afc9683f4..eb18dde198ee88e52dc03591570452bde59defb3 100644 (file)
@@ -36,7 +36,6 @@
 #else
 
 #include <algorithm>
-#include <random>
 #include <experimental/bits/lfts_config.h>
 
 namespace std _GLIBCXX_VISIBILITY(default)
@@ -55,52 +54,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 #define __cpp_lib_experimental_sample 201402
 
-  /// Reservoir sampling algorithm.
-  template<typename _InputIterator, typename _RandomAccessIterator,
-           typename _Size, typename _UniformRandomNumberGenerator>
-    _RandomAccessIterator
-    __sample(_InputIterator __first, _InputIterator __last, input_iterator_tag,
-            _RandomAccessIterator __out, random_access_iterator_tag,
-            _Size __n, _UniformRandomNumberGenerator&& __g)
-    {
-      using __distrib_type = std::uniform_int_distribution<_Size>;
-      using __param_type = typename __distrib_type::param_type;
-      __distrib_type __d{};
-      _Size __sample_sz = 0;
-      while (__first != __last && __sample_sz != __n)
-       __out[__sample_sz++] = *__first++;
-      for (auto __pop_sz = __sample_sz; __first != __last;
-         ++__first, ++__pop_sz)
-       {
-         const auto __k = __d(__g, __param_type{0, __pop_sz});
-         if (__k < __n)
-           __out[__k] = *__first;
-       }
-      return __out + __sample_sz;
-    }
-
-  /// Selection sampling algorithm.
-  template<typename _ForwardIterator, typename _OutputIterator, typename _Cat,
-           typename _Size, typename _UniformRandomNumberGenerator>
-    _OutputIterator
-    __sample(_ForwardIterator __first, _ForwardIterator __last,
-            forward_iterator_tag,
-            _OutputIterator __out, _Cat,
-            _Size __n, _UniformRandomNumberGenerator&& __g)
-    {
-      using __distrib_type = std::uniform_int_distribution<_Size>;
-      using __param_type = typename __distrib_type::param_type;
-      __distrib_type __d{};
-      _Size __unsampled_sz = std::distance(__first, __last);
-      for (__n = std::min(__n, __unsampled_sz); __n != 0; ++__first)
-       if (__d(__g, __param_type{0, --__unsampled_sz}) < __n)
-         {
-           *__out++ = *__first;
-           --__n;
-         }
-      return __out;
-    }
-
   /// Take a random sample from a population.
   template<typename _PopulationIterator, typename _SampleIterator,
            typename _Distance, typename _UniformRandomNumberGenerator>
@@ -123,9 +76,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       static_assert(is_integral<_Distance>::value,
                    "sample size must be an integer type");
 
-      return std::experimental::__sample(
-         __first, __last, __pop_cat{}, __out, __samp_cat{},
-         __n, std::forward<_UniformRandomNumberGenerator>(__g));
+      return std::__sample(__first, __last, __pop_cat{}, __out, __samp_cat{},
+                          __n,
+                          std::forward<_UniformRandomNumberGenerator>(__g));
     }
 
 _GLIBCXX_END_NAMESPACE_VERSION
diff --git a/libstdc++-v3/testsuite/25_algorithms/sample/1.cc b/libstdc++-v3/testsuite/25_algorithms/sample/1.cc
new file mode 100644 (file)
index 0000000..10376e2
--- /dev/null
@@ -0,0 +1,110 @@
+// Copyright (C) 2014-2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++1z } }
+
+#include <algorithm>
+#include <random>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+std::mt19937 rng;
+
+using std::sample;
+using __gnu_test::test_container;
+using __gnu_test::input_iterator_wrapper;
+using __gnu_test::output_iterator_wrapper;
+using __gnu_test::forward_iterator_wrapper;
+using __gnu_test::random_access_iterator_wrapper;
+
+void
+test01()
+{
+  const int in[] = { 1, 2 };
+  test_container<const int, random_access_iterator_wrapper> pop(in);
+  const int sample_size = 10;
+  int samp[sample_size] = { };
+
+  // population smaller than desired sample size
+  auto it = sample(pop.begin(), pop.end(), samp, sample_size, rng);
+  VERIFY( it == samp + std::distance(pop.begin(), pop.end()) );
+  const auto sum = std::accumulate(pop.begin(), pop.end(), 0);
+  VERIFY( std::accumulate(samp, samp + sample_size, 0) == sum );
+}
+
+void
+test02()
+{
+  const int in[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
+  test_container<const int, random_access_iterator_wrapper> pop(in);
+  const int sample_size = 10;
+  int samp[sample_size] = { };
+
+  auto it = sample(pop.begin(), pop.end(), samp, sample_size, rng);
+  VERIFY( it == samp + sample_size );
+
+  // verify no duplicates
+  std::sort(samp, it);
+  auto it2 = std::unique(samp, it);
+  VERIFY( it2 == it );
+}
+
+void
+test03()
+{
+  const int in[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+  test_container<const int, input_iterator_wrapper> pop(in);
+  const int sample_size = 5;
+  int samp[sample_size] = { };
+
+  // input iterator for population
+  auto it = sample(pop.begin(), pop.end(), samp, sample_size, rng);
+  VERIFY( it == samp + sample_size );
+
+  // verify no duplicates
+  std::sort(samp, it);
+  auto it2 = std::unique(samp, it);
+  VERIFY( it2 == it );
+}
+
+void
+test04()
+{
+  const int in[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+  test_container<const int, forward_iterator_wrapper> pop(in);
+  const int sample_size = 5;
+  int out[sample_size];
+  test_container<int, output_iterator_wrapper> samp(out);
+
+  // forward iterator for population and output iterator for result
+  auto res = sample(pop.begin(), pop.end(), samp.begin(), sample_size, rng);
+
+  // verify no duplicates
+  std::sort(std::begin(out), std::end(out));
+  auto it = std::unique(std::begin(out), std::end(out));
+  VERIFY( it == std::end(out) );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+  test04();
+}