Define std::sample for C++17

* 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
This commit is contained in:
Jonathan Wakely 2016-10-12 16:26:48 +01:00 committed by Jonathan Wakely
parent d73c92c9f2
commit e7722f1106
7 changed files with 227 additions and 51 deletions

View 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.

View file

@ -466,6 +466,10 @@
</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>
@ -486,6 +490,11 @@
<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>

View 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>

View 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>

View 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

View 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

View file

@ -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();
}