aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/include/experimental/algorithm
blob: 0ba6311e952f6cd31fea9b07838d608afc9683f4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// <experimental/algorithm> -*- C++ -*-

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

// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.

// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>.

/** @file experimental/algorithm
 *  This is a TS C++ Library header.
 */

#ifndef _GLIBCXX_EXPERIMENTAL_ALGORITHM
#define _GLIBCXX_EXPERIMENTAL_ALGORITHM 1

#pragma GCC system_header

#if __cplusplus <= 201103L
# include <bits/c++14_warning.h>
#else

#include <algorithm>
#include <random>
#include <experimental/bits/lfts_config.h>

namespace std _GLIBCXX_VISIBILITY(default)
{
namespace experimental
{
inline namespace fundamentals_v1
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION

  template<typename _ForwardIterator, typename _Searcher>
    inline _ForwardIterator
    search(_ForwardIterator __first, _ForwardIterator __last,
	   const _Searcher& __searcher)
    { return __searcher(__first, __last); }

#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>
    _SampleIterator
    sample(_PopulationIterator __first, _PopulationIterator __last,
	   _SampleIterator __out, _Distance __n,
	   _UniformRandomNumberGenerator&& __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::experimental::__sample(
	  __first, __last, __pop_cat{}, __out, __samp_cat{},
	  __n, std::forward<_UniformRandomNumberGenerator>(__g));
    }

_GLIBCXX_END_NAMESPACE_VERSION
} // namespace fundamentals_v1
} // namespace experimental
} // namespace std

#endif // C++14

#endif // _GLIBCXX_EXPERIMENTAL_ALGORITHM