128 changes: 23 additions & 105 deletions libcxx/docs/TestingLibcxx.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Usage
After building libc++, you can run parts of the libc++ test suite by simply
running ``llvm-lit`` on a specified test or directory. If you're unsure
whether the required libraries have been built, you can use the
`cxx-test-depends` target. For example:
``cxx-test-depends`` target. For example:

.. code-block:: bash
Expand All @@ -37,45 +37,41 @@ whether the required libraries have been built, you can use the
$ <build>/bin/llvm-lit -sv libcxx/test/std/depr/depr.c.headers/stdlib_h.pass.cpp # Run a single test
$ <build>/bin/llvm-lit -sv libcxx/test/std/atomics libcxx/test/std/threads # Test std::thread and std::atomic
.. note::
If you used the Bootstrapping build instead of the default runtimes build, the
``cxx-test-depends`` target is instead named ``runtimes-test-depends``, and
you will need to prefix ``<build>/runtimes/runtimes-<target>-bins/`` to the
paths of all tests.

In the default configuration, the tests are built against headers that form a
fake installation root of libc++. This installation root has to be updated when
changes are made to the headers, so you should re-run the `cxx-test-depends`
target before running the tests manually with `lit` when you make any sort of
changes are made to the headers, so you should re-run the ``cxx-test-depends``
target before running the tests manually with ``lit`` when you make any sort of
change, including to the headers.

Sometimes you'll want to change the way LIT is running the tests. Custom options
can be specified using the `--param=<name>=<val>` flag. The most common option
you'll want to change is the standard dialect (ie -std=c++XX). By default the
can be specified using the ``--param <name>=<val>`` flag. The most common option
you'll want to change is the standard dialect (ie ``-std=c++XX``). By default the
test suite will select the newest C++ dialect supported by the compiler and use
that. However if you want to manually specify the option like so:
that. However, you can manually specify the option like so if you want:

.. code-block:: bash
$ <build>/bin/llvm-lit -sv libcxx/test/std/containers # Run the tests with the newest -std
$ <build>/bin/llvm-lit -sv libcxx/test/std/containers --param=std=c++03 # Run the tests in C++03
Occasionally you'll want to add extra compile or link flags when testing.
You can do this as follows:

.. code-block:: bash
$ <build>/bin/llvm-lit -sv libcxx/test --param=compile_flags='-Wcustom-warning'
$ <build>/bin/llvm-lit -sv libcxx/test --param=link_flags='-L/custom/library/path'
$ <build>/bin/llvm-lit -sv libcxx/test/std/containers --param std=c++03 # Run the tests in C++03
Some other common examples include:
Other parameters are supported by the test suite. Those are defined in ``libcxx/utils/libcxx/test/params.py``.
If you want to customize how to run the libc++ test suite beyond what is available
in ``params.py``, you most likely want to use a custom site configuration instead.

.. code-block:: bash
The libc++ test suite works by loading a site configuration that defines various
"base" parameters (via Lit substitutions). These base parameters represent things
like the compiler to use for running the tests, which default compiler and linker
flags to use, and how to run an executable. This system is meant to be easily
extended for custom needs, in particular when porting the libc++ test suite to
new platforms.

# Specify a custom compiler.
$ <build>/bin/llvm-lit -sv libcxx/test/std --param=cxx_under_test=/opt/bin/g++
# Disable warnings in the test suite
$ <build>/bin/llvm-lit -sv libcxx/test --param=enable_warnings=False
# Use UBSAN when running the tests.
$ <build>/bin/llvm-lit -sv libcxx/test --param=use_sanitizer=Undefined
Using a custom site configuration
Using a Custom Site Configuration
---------------------------------

By default, the libc++ test suite will use a site configuration that matches
Expand All @@ -96,84 +92,6 @@ configuration easier.
$ make -C <build> cxx-test-depends
$ <build>/bin/llvm-lit -sv libcxx/test # will use your custom config file
LIT Options
===========

:program:`lit` [*options*...] [*filenames*...]

Command Line Options
--------------------

To use these options you pass them on the LIT command line as ``--param NAME``
or ``--param NAME=VALUE``. Some options have default values specified during
CMake's configuration. Passing the option on the command line will override the
default.

.. program:: lit

.. option:: cxx_under_test=<path/to/compiler>

Specify the compiler used to build the tests.

.. option:: stdlib=<stdlib name>

**Values**: libc++, libstdc++, msvc

Specify the C++ standard library being tested. The default is libc++ if this
option is not provided. This option is intended to allow running the libc++
test suite against other standard library implementations.

.. option:: std=<standard version>

**Values**: c++03, c++11, c++14, c++17, c++20, c++2b

Change the standard version used when building the tests.

.. option:: cxx_headers=<path/to/headers>

Specify the c++ standard library headers that are tested. By default the
headers in the source tree are used.

.. option:: cxx_library_root=<path/to/lib/>

Specify the directory of the libc++ library to be tested. By default the
library folder of the build directory is used.


.. option:: cxx_runtime_root=<path/to/lib/>

Specify the directory of the libc++ library to use at runtime. This directory
is not added to the linkers search path. This can be used to compile tests
against one version of libc++ and run them using another. The default value
for this option is `cxx_library_root`.

.. option:: use_system_cxx_lib=<bool>

**Default**: False

Enable or disable testing against the installed version of libc++ library.
This impacts whether the ``use_system_cxx_lib`` Lit feature is defined or
not. The ``cxx_library_root`` and ``cxx_runtime_root`` parameters should
still be used to specify the path of the library to link to and run against,
respectively.

.. option:: use_sanitizer=<sanitizer name>

**Values**: Memory, MemoryWithOrigins, Address, Undefined

Run the tests using the given sanitizer. If LLVM_USE_SANITIZER was given when
building libc++ then that sanitizer will be used by default.

.. option:: llvm_unwinder

Enable the use of LLVM unwinder instead of libgcc.

.. option:: builtins_library

Path to the builtins library to use instead of libgcc.


Writing Tests
-------------

Expand Down
4 changes: 4 additions & 0 deletions libcxx/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ set(files
__algorithm/ranges_mismatch.h
__algorithm/ranges_move.h
__algorithm/ranges_move_backward.h
__algorithm/ranges_next_permutation.h
__algorithm/ranges_none_of.h
__algorithm/ranges_nth_element.h
__algorithm/ranges_partial_sort.h
Expand All @@ -121,6 +122,7 @@ set(files
__algorithm/ranges_partition_copy.h
__algorithm/ranges_partition_point.h
__algorithm/ranges_pop_heap.h
__algorithm/ranges_prev_permutation.h
__algorithm/ranges_push_heap.h
__algorithm/ranges_remove.h
__algorithm/ranges_remove_copy.h
Expand All @@ -133,6 +135,7 @@ set(files
__algorithm/ranges_reverse.h
__algorithm/ranges_reverse_copy.h
__algorithm/ranges_rotate_copy.h
__algorithm/ranges_sample.h
__algorithm/ranges_search.h
__algorithm/ranges_search_n.h
__algorithm/ranges_set_difference.h
Expand Down Expand Up @@ -178,6 +181,7 @@ set(files
__algorithm/stable_sort.h
__algorithm/swap_ranges.h
__algorithm/transform.h
__algorithm/uniform_random_bit_generator_adaptor.h
__algorithm/unique.h
__algorithm/unique_copy.h
__algorithm/unwrap_iter.h
Expand Down
6 changes: 3 additions & 3 deletions libcxx/include/__algorithm/copy_backward.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
#include <__ranges/subrange.h>
#include <__utility/move.h>
#include <__utility/pair.h>
#include <cstring>
#include <type_traits>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
Expand All @@ -44,9 +43,10 @@ __copy_backward(_InputIterator __first, _InputIterator __last, _OutputIterator _
template <class _AlgPolicy, class _Iter1, class _Sent1, class _Iter2,
__enable_if_t<is_same<_AlgPolicy, _RangeAlgPolicy>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr pair<_Iter1, _Iter2> __copy_backward(_Iter1 __first, _Sent1 __last, _Iter2 __result) {
auto __reverse_range = std::__reverse_range(std::ranges::subrange(std::move(__first), std::move(__last)));
auto __last_iter = _IterOps<_AlgPolicy>::next(__first, std::move(__last));
auto __reverse_range = std::__reverse_range(std::ranges::subrange(std::move(__first), __last_iter));
auto __ret = ranges::copy(std::move(__reverse_range), std::make_reverse_iterator(__result));
return std::make_pair(__ret.in.base(), __ret.out.base());
return std::make_pair(__last_iter, __ret.out.base());
}
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)

Expand Down
14 changes: 14 additions & 0 deletions libcxx/include/__algorithm/iterator_operations.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
#define _LIBCPP___ALGORITHM_ITERATOR_OPERATIONS_H

#include <__algorithm/iter_swap.h>
#include <__algorithm/ranges_iterator_concept.h>
#include <__config>
#include <__iterator/advance.h>
#include <__iterator/distance.h>
#include <__iterator/incrementable_traits.h>
#include <__iterator/iter_move.h>
#include <__iterator/iter_swap.h>
#include <__iterator/iterator_traits.h>
Expand Down Expand Up @@ -40,6 +42,12 @@ struct _IterOps<_RangeAlgPolicy> {
template <class _Iter>
using __value_type = iter_value_t<_Iter>;

template <class _Iter>
using __iterator_category = ranges::__iterator_concept<_Iter>;

template <class _Iter>
using __difference_type = iter_difference_t<_Iter>;

static constexpr auto advance = ranges::advance;
static constexpr auto distance = ranges::distance;
static constexpr auto __iter_move = ranges::iter_move;
Expand All @@ -58,6 +66,12 @@ struct _IterOps<_ClassicAlgPolicy> {
template <class _Iter>
using __value_type = typename iterator_traits<_Iter>::value_type;

template <class _Iter>
using __iterator_category = typename iterator_traits<_Iter>::iterator_category;

template <class _Iter>
using __difference_type = typename iterator_traits<_Iter>::difference_type;

// advance
template <class _Iter, class _Distance>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
Expand Down
36 changes: 22 additions & 14 deletions libcxx/include/__algorithm/next_permutation.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,40 +11,47 @@

#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
#include <__algorithm/iterator_operations.h>
#include <__algorithm/reverse.h>
#include <__config>
#include <__iterator/iterator_traits.h>
#include <__utility/swap.h>
#include <__utility/move.h>
#include <__utility/pair.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

template <class _Compare, class _BidirectionalIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 bool
__next_permutation(_BidirectionalIterator __first, _BidirectionalIterator __last, _Compare __comp)
template <class _AlgPolicy, class _Compare, class _BidirectionalIterator, class _Sentinel>
_LIBCPP_CONSTEXPR_AFTER_CXX17
pair<_BidirectionalIterator, bool>
__next_permutation(_BidirectionalIterator __first, _Sentinel __last, _Compare&& __comp)
{
_BidirectionalIterator __i = __last;
using _Result = pair<_BidirectionalIterator, bool>;

_BidirectionalIterator __last_iter = _IterOps<_AlgPolicy>::next(__first, __last);
_BidirectionalIterator __i = __last_iter;
if (__first == __last || __first == --__i)
return false;
return _Result(std::move(__last_iter), false);

while (true)
{
_BidirectionalIterator __ip1 = __i;
if (__comp(*--__i, *__ip1))
{
_BidirectionalIterator __j = __last;
_BidirectionalIterator __j = __last_iter;
while (!__comp(*__i, *--__j))
;
swap(*__i, *__j);
_VSTD::reverse(__ip1, __last);
return true;
_IterOps<_AlgPolicy>::iter_swap(__i, __j);
std::__reverse<_AlgPolicy>(__ip1, __last_iter);
return _Result(std::move(__last_iter), true);
}
if (__i == __first)
{
_VSTD::reverse(__first, __last);
return false;
std::__reverse<_AlgPolicy>(__first, __last_iter);
return _Result(std::move(__last_iter), false);
}
}
}
Expand All @@ -54,8 +61,9 @@ inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
bool
next_permutation(_BidirectionalIterator __first, _BidirectionalIterator __last, _Compare __comp)
{
typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
return _VSTD::__next_permutation<_Comp_ref>(__first, __last, __comp);
using _Comp_ref = typename __comp_ref_type<_Compare>::type;
return std::__next_permutation<_ClassicAlgPolicy>(
std::move(__first), std::move(__last), static_cast<_Comp_ref>(__comp)).second;
}

template <class _BidirectionalIterator>
Expand Down
36 changes: 22 additions & 14 deletions libcxx/include/__algorithm/prev_permutation.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,40 +11,47 @@

#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
#include <__algorithm/iterator_operations.h>
#include <__algorithm/reverse.h>
#include <__config>
#include <__iterator/iterator_traits.h>
#include <__utility/swap.h>
#include <__utility/move.h>
#include <__utility/pair.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

template <class _Compare, class _BidirectionalIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 bool
__prev_permutation(_BidirectionalIterator __first, _BidirectionalIterator __last, _Compare __comp)
template <class _AlgPolicy, class _Compare, class _BidirectionalIterator, class _Sentinel>
_LIBCPP_CONSTEXPR_AFTER_CXX17
pair<_BidirectionalIterator, bool>
__prev_permutation(_BidirectionalIterator __first, _Sentinel __last, _Compare&& __comp)
{
_BidirectionalIterator __i = __last;
using _Result = pair<_BidirectionalIterator, bool>;

_BidirectionalIterator __last_iter = _IterOps<_AlgPolicy>::next(__first, __last);
_BidirectionalIterator __i = __last_iter;
if (__first == __last || __first == --__i)
return false;
return _Result(std::move(__last_iter), false);

while (true)
{
_BidirectionalIterator __ip1 = __i;
if (__comp(*__ip1, *--__i))
{
_BidirectionalIterator __j = __last;
_BidirectionalIterator __j = __last_iter;
while (!__comp(*--__j, *__i))
;
swap(*__i, *__j);
_VSTD::reverse(__ip1, __last);
return true;
_IterOps<_AlgPolicy>::iter_swap(__i, __j);
std::__reverse<_AlgPolicy>(__ip1, __last_iter);
return _Result(std::move(__last_iter), true);
}
if (__i == __first)
{
_VSTD::reverse(__first, __last);
return false;
std::__reverse<_AlgPolicy>(__first, __last_iter);
return _Result(std::move(__last_iter), false);
}
}
}
Expand All @@ -54,8 +61,9 @@ inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
bool
prev_permutation(_BidirectionalIterator __first, _BidirectionalIterator __last, _Compare __comp)
{
typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
return _VSTD::__prev_permutation<_Comp_ref>(__first, __last, __comp);
using _Comp_ref = typename __comp_ref_type<_Compare>::type;
return std::__prev_permutation<_ClassicAlgPolicy>(
std::move(__first), std::move(__last), static_cast<_Comp_ref>(__comp)).second;
}

template <class _BidirectionalIterator>
Expand Down
5 changes: 3 additions & 2 deletions libcxx/include/__algorithm/ranges_move_backward.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,11 @@ struct __fn {
template <class _InIter, class _Sent, class _OutIter>
_LIBCPP_HIDE_FROM_ABI constexpr static
move_backward_result<_InIter, _OutIter> __move_backward_impl(_InIter __first, _Sent __last, _OutIter __result) {
auto __ret = ranges::move(std::make_reverse_iterator(ranges::next(__first, __last)),
auto __last_iter = ranges::next(__first, std::move(__last));
auto __ret = ranges::move(std::make_reverse_iterator(__last_iter),
std::make_reverse_iterator(__first),
std::make_reverse_iterator(__result));
return {std::move(__ret.in.base()), std::move(__ret.out.base())};
return {std::move(__last_iter), std::move(__ret.out.base())};
}

template <bidirectional_iterator _InIter, sentinel_for<_InIter> _Sent, bidirectional_iterator _OutIter>
Expand Down
72 changes: 72 additions & 0 deletions libcxx/include/__algorithm/ranges_next_permutation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP___ALGORITHM_RANGES_NEXT_PERMUTATION_H
#define _LIBCPP___ALGORITHM_RANGES_NEXT_PERMUTATION_H

#include <__algorithm/in_found_result.h>
#include <__algorithm/iterator_operations.h>
#include <__algorithm/make_projected.h>
#include <__algorithm/next_permutation.h>
#include <__config>
#include <__functional/identity.h>
#include <__functional/ranges_operations.h>
#include <__iterator/concepts.h>
#include <__iterator/sortable.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__ranges/dangling.h>
#include <__utility/move.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)

_LIBCPP_BEGIN_NAMESPACE_STD

namespace ranges {

template <class _InIter>
using next_permutation_result = in_found_result<_InIter>;

namespace __next_permutation {

struct __fn {
template <bidirectional_iterator _Iter, sentinel_for<_Iter> _Sent, class _Comp = ranges::less, class _Proj = identity>
requires sortable<_Iter, _Comp, _Proj>
_LIBCPP_HIDE_FROM_ABI constexpr next_permutation_result<_Iter>
operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const {
auto __result = std::__next_permutation<_RangeAlgPolicy>(
std::move(__first), std::move(__last), std::__make_projected(__comp, __proj));
return {std::move(__result.first), std::move(__result.second)};
}

template <bidirectional_range _Range, class _Comp = ranges::less, class _Proj = identity>
requires sortable<iterator_t<_Range>, _Comp, _Proj>
_LIBCPP_HIDE_FROM_ABI constexpr next_permutation_result<borrowed_iterator_t<_Range>>
operator()(_Range&& __range, _Comp __comp = {}, _Proj __proj = {}) const {
auto __result = std::__next_permutation<_RangeAlgPolicy>(
ranges::begin(__range), ranges::end(__range), std::__make_projected(__comp, __proj));
return {std::move(__result.first), std::move(__result.second)};
}
};

} // namespace __next_permutation

inline namespace __cpo {
constexpr inline auto next_permutation = __next_permutation::__fn{};
} // namespace __cpo
} // namespace ranges

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)

#endif // _LIBCPP___ALGORITHM_RANGES_NEXT_PERMUTATION_H
76 changes: 76 additions & 0 deletions libcxx/include/__algorithm/ranges_prev_permutation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP___ALGORITHM_RANGES_PREV_PERMUTATION_H
#define _LIBCPP___ALGORITHM_RANGES_PREV_PERMUTATION_H

#include <__algorithm/in_found_result.h>
#include <__algorithm/iterator_operations.h>
#include <__algorithm/make_projected.h>
#include <__algorithm/prev_permutation.h>
#include <__config>
#include <__functional/identity.h>
#include <__functional/ranges_operations.h>
#include <__iterator/concepts.h>
#include <__iterator/sortable.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__ranges/dangling.h>
#include <__utility/move.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)

_LIBCPP_BEGIN_NAMESPACE_STD

namespace ranges {

template <class _InIter>
using prev_permutation_result = in_found_result<_InIter>;

namespace __prev_permutation {

struct __fn {

template <bidirectional_iterator _Iter, sentinel_for<_Iter> _Sent,
class _Comp = ranges::less, class _Proj = identity>
requires sortable<_Iter, _Comp, _Proj>
_LIBCPP_HIDE_FROM_ABI constexpr prev_permutation_result<_Iter>
operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const {
auto __result = std::__prev_permutation<_RangeAlgPolicy>(
std::move(__first), std::move(__last), std::__make_projected(__comp, __proj));
return {std::move(__result.first), std::move(__result.second)};
}

template <bidirectional_range _Range,
class _Comp = ranges::less, class _Proj = identity>
requires sortable<iterator_t<_Range>, _Comp, _Proj>
_LIBCPP_HIDE_FROM_ABI constexpr prev_permutation_result<borrowed_iterator_t<_Range>>
operator()(_Range&& __range, _Comp __comp = {}, _Proj __proj = {}) const {
auto __result = std::__prev_permutation<_RangeAlgPolicy>(
ranges::begin(__range), ranges::end(__range), std::__make_projected(__comp, __proj));
return {std::move(__result.first), std::move(__result.second)};
}

};

} // namespace __prev_permutation

inline namespace __cpo {
constexpr inline auto prev_permutation = __prev_permutation::__fn{};
} // namespace __cpo
} // namespace ranges

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)

#endif // _LIBCPP___ALGORITHM_RANGES_PREV_PERMUTATION_H
55 changes: 25 additions & 30 deletions libcxx/include/__algorithm/ranges_remove_copy.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,16 @@
#define _LIBCPP___ALGORITHM_RANGES_REMOVE_COPY_H

#include <__algorithm/in_out_result.h>
#include <__algorithm/make_projected.h>
#include <__algorithm/remove_copy.h>
#include <__algorithm/ranges_remove_copy_if.h>
#include <__config>
#include <__functional/identity.h>
#include <__functional/invoke.h>
#include <__functional/ranges_operations.h>
#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
#include <__iterator/projected.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__ranges/dangling.h>
#include <__utility/forward.h>
#include <__utility/move.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
Expand All @@ -40,32 +37,30 @@ using remove_copy_result = in_out_result<_InIter, _OutIter>;

namespace __remove_copy {

struct __fn {

template <input_iterator _InIter, sentinel_for<_InIter> _Sent, weakly_incrementable _OutIter, class _Type,
class _Proj = identity>
requires indirectly_copyable<_InIter, _OutIter> &&
indirect_binary_predicate<ranges::equal_to, projected<_InIter, _Proj>, const _Type*>
_LIBCPP_HIDE_FROM_ABI constexpr
remove_copy_result<_InIter, _OutIter>
operator()(_InIter __first, _Sent __last, _OutIter __result, const _Type& __value, _Proj __proj = {}) const {
// TODO: implement
(void)__first; (void)__last; (void)__result; (void)__value; (void)__proj;
return {};
}

template <input_range _Range, weakly_incrementable _OutIter, class _Type, class _Proj = identity>
requires indirectly_copyable<iterator_t<_Range>, _OutIter> &&
indirect_binary_predicate<ranges::equal_to, projected<iterator_t<_Range>, _Proj>, const _Type*>
_LIBCPP_HIDE_FROM_ABI constexpr
remove_copy_result<borrowed_iterator_t<_Range>, _OutIter>
operator()(_Range&& __range, _OutIter __result, const _Type& __value, _Proj __proj = {}) const {
// TODO: implement
(void)__range; (void)__result; (void)__value; (void)__proj;
return {};
}

};
struct __fn {
template <input_iterator _InIter,
sentinel_for<_InIter> _Sent,
weakly_incrementable _OutIter,
class _Type,
class _Proj = identity>
requires indirectly_copyable<_InIter, _OutIter> &&
indirect_binary_predicate<ranges::equal_to, projected<_InIter, _Proj>, const _Type*>
_LIBCPP_HIDE_FROM_ABI constexpr remove_copy_result<_InIter, _OutIter>
operator()(_InIter __first, _Sent __last, _OutIter __result, const _Type& __value, _Proj __proj = {}) const {
auto __pred = [&](auto&& __val) { return __value == __val; };
return ranges::__remove_copy_if_impl(std::move(__first), std::move(__last), std::move(__result), __pred, __proj);
}

template <input_range _Range, weakly_incrementable _OutIter, class _Type, class _Proj = identity>
requires indirectly_copyable<iterator_t<_Range>, _OutIter> &&
indirect_binary_predicate<ranges::equal_to, projected<iterator_t<_Range>, _Proj>, const _Type*>
_LIBCPP_HIDE_FROM_ABI constexpr remove_copy_result<borrowed_iterator_t<_Range>, _OutIter>
operator()(_Range&& __range, _OutIter __result, const _Type& __value, _Proj __proj = {}) const {
auto __pred = [&](auto&& __val) { return __value == __val; };
return ranges::__remove_copy_if_impl(
ranges::begin(__range), ranges::end(__range), std::move(__result), __pred, __proj);
}
};

} // namespace __remove_copy

Expand Down
58 changes: 34 additions & 24 deletions libcxx/include/__algorithm/ranges_remove_copy_if.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,33 +38,43 @@ namespace ranges {
template <class _InIter, class _OutIter>
using remove_copy_if_result = in_out_result<_InIter, _OutIter>;

namespace __remove_copy_if {

struct __fn {

template <input_iterator _InIter, sentinel_for<_InIter> _Sent, weakly_incrementable _OutIter,
class _Proj = identity, indirect_unary_predicate<projected<_InIter, _Proj>> _Pred>
requires indirectly_copyable<_InIter, _OutIter>
_LIBCPP_HIDE_FROM_ABI constexpr
remove_copy_if_result<_InIter, _OutIter>
operator()(_InIter __first, _Sent __last, _OutIter __result, _Pred __pred, _Proj __proj = {}) const {
// TODO: implement
(void)__first; (void)__last; (void)__result; (void)__pred; (void)__proj;
return {};
template <class _InIter, class _Sent, class _OutIter, class _Proj, class _Pred>
_LIBCPP_HIDE_FROM_ABI constexpr in_out_result<_InIter, _OutIter>
__remove_copy_if_impl(_InIter __first, _Sent __last, _OutIter __result, _Pred& __pred, _Proj& __proj) {
for (; __first != __last; ++__first) {
if (!std::invoke(__pred, std::invoke(__proj, *__first))) {
*__result = *__first;
++__result;
}
}
return {std::move(__first), std::move(__result)};
}

template <input_range _Range, weakly_incrementable _OutIter, class _Proj = identity,
indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred>
requires indirectly_copyable<iterator_t<_Range>, _OutIter>
_LIBCPP_HIDE_FROM_ABI constexpr
remove_copy_if_result<borrowed_iterator_t<_Range>, _OutIter>
operator()(_Range&& __range, _OutIter __result, _Pred __pred, _Proj __proj = {}) const {
// TODO: implement
(void)__range; (void)__result; (void)__pred; (void)__proj;
return {};
}
namespace __remove_copy_if {

};
struct __fn {
template <input_iterator _InIter,
sentinel_for<_InIter> _Sent,
weakly_incrementable _OutIter,
class _Proj = identity,
indirect_unary_predicate<projected<_InIter, _Proj>> _Pred>
requires indirectly_copyable<_InIter, _OutIter>
_LIBCPP_HIDE_FROM_ABI constexpr remove_copy_if_result<_InIter, _OutIter>
operator()(_InIter __first, _Sent __last, _OutIter __result, _Pred __pred, _Proj __proj = {}) const {
return ranges::__remove_copy_if_impl(std::move(__first), std::move(__last), std::move(__result), __pred, __proj);
}

template <input_range _Range,
weakly_incrementable _OutIter,
class _Proj = identity,
indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred>
requires indirectly_copyable<iterator_t<_Range>, _OutIter>
_LIBCPP_HIDE_FROM_ABI constexpr remove_copy_if_result<borrowed_iterator_t<_Range>, _OutIter>
operator()(_Range&& __range, _OutIter __result, _Pred __pred, _Proj __proj = {}) const {
return ranges::__remove_copy_if_impl(
ranges::begin(__range), ranges::end(__range), std::move(__result), __pred, __proj);
}
};

} // namespace __remove_copy_if

Expand Down
69 changes: 38 additions & 31 deletions libcxx/include/__algorithm/ranges_replace_copy.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,16 @@
#define _LIBCPP___ALGORITHM_RANGES_REPLACE_COPY_H

#include <__algorithm/in_out_result.h>
#include <__algorithm/make_projected.h>
#include <__algorithm/replace_copy.h>
#include <__algorithm/ranges_replace_copy_if.h>
#include <__config>
#include <__functional/identity.h>
#include <__functional/invoke.h>
#include <__functional/ranges_operations.h>
#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
#include <__iterator/projected.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__ranges/dangling.h>
#include <__utility/forward.h>
#include <__utility/move.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
Expand All @@ -40,35 +37,45 @@ using replace_copy_result = in_out_result<_InIter, _OutIter>;

namespace __replace_copy {

struct __fn {

template <input_iterator _InIter, sentinel_for<_InIter> _Sent, class _Type1, class _Type2,
output_iterator<const _Type2&> _OutIter, class _Proj = identity>
requires indirectly_copyable<_InIter, _OutIter> &&
indirect_binary_predicate<ranges::equal_to, projected<_InIter, _Proj>, const _Type1*>
_LIBCPP_HIDE_FROM_ABI constexpr
replace_copy_result<_InIter, _OutIter>
operator()(_InIter __first, _Sent __last, _OutIter __result, const _Type1& __old_value, const _Type2& __new_value,
struct __fn {
template <input_iterator _InIter,
sentinel_for<_InIter> _Sent,
class _OldType,
class _NewType,
output_iterator<const _NewType&> _OutIter,
class _Proj = identity>
requires indirectly_copyable<_InIter, _OutIter> &&
indirect_binary_predicate<ranges::equal_to, projected<_InIter, _Proj>, const _OldType*>
_LIBCPP_HIDE_FROM_ABI constexpr replace_copy_result<_InIter, _OutIter>
operator()(_InIter __first,
_Sent __last,
_OutIter __result,
const _OldType& __old_value,
const _NewType& __new_value,
_Proj __proj = {}) const {
// TODO: implement
(void)__first; (void)__last; (void)__result; (void)__old_value; (void)__new_value; (void)__proj;
return {};
}

template <input_range _Range, class _Type1, class _Type2, output_iterator<const _Type2&> _OutIter,
class _Proj = identity>
requires indirectly_copyable<iterator_t<_Range>, _OutIter> &&
indirect_binary_predicate<ranges::equal_to, projected<iterator_t<_Range>, _Proj>, const _Type1*>
_LIBCPP_HIDE_FROM_ABI constexpr
replace_copy_result<borrowed_iterator_t<_Range>, _OutIter>
operator()(_Range&& __range, _OutIter __result, const _Type1& __old_value, const _Type2& __new_value,
auto __pred = [&](const auto& __value) { return __value == __old_value; };
return ranges::__replace_copy_if_impl(
std::move(__first), std::move(__last), std::move(__result), __pred, __new_value, __proj);
}

template <input_range _Range,
class _OldType,
class _NewType,
output_iterator<const _NewType&> _OutIter,
class _Proj = identity>
requires indirectly_copyable<iterator_t<_Range>, _OutIter> &&
indirect_binary_predicate<ranges::equal_to, projected<iterator_t<_Range>, _Proj>, const _OldType*>
_LIBCPP_HIDE_FROM_ABI constexpr replace_copy_result<borrowed_iterator_t<_Range>, _OutIter>
operator()(_Range&& __range,
_OutIter __result,
const _OldType& __old_value,
const _NewType& __new_value,
_Proj __proj = {}) const {
// TODO: implement
(void)__range; (void)__result; (void)__old_value; (void)__new_value; (void)__proj;
return {};
}

};
auto __pred = [&](const auto& __value) { return __value == __old_value; };
return ranges::__replace_copy_if_impl(
ranges::begin(__range), ranges::end(__range), std::move(__result), __pred, __new_value, __proj);
}
};

} // namespace __replace_copy

Expand Down
72 changes: 42 additions & 30 deletions libcxx/include/__algorithm/ranges_replace_copy_if.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,14 @@
#define _LIBCPP___ALGORITHM_RANGES_REPLACE_COPY_IF_H

#include <__algorithm/in_out_result.h>
#include <__algorithm/make_projected.h>
#include <__algorithm/replace_copy_if.h>
#include <__config>
#include <__functional/identity.h>
#include <__functional/invoke.h>
#include <__functional/ranges_operations.h>
#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
#include <__iterator/projected.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__ranges/dangling.h>
#include <__utility/forward.h>
#include <__utility/move.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
Expand All @@ -38,34 +33,51 @@ namespace ranges {
template <class _InIter, class _OutIter>
using replace_copy_if_result = in_out_result<_InIter, _OutIter>;

namespace __replace_copy_if {

struct __fn {

template <input_iterator _InIter, sentinel_for<_InIter> _Sent, class _Type, output_iterator<const _Type&> _OutIter,
class _Proj = identity, indirect_unary_predicate<projected<_InIter, _Proj>> _Pred>
requires indirectly_copyable<_InIter, _OutIter>
_LIBCPP_HIDE_FROM_ABI constexpr
replace_copy_if_result<_InIter, _OutIter>
operator()(_InIter __first, _Sent __last, _OutIter __result, _Pred __pred, const _Type& __new_value,
_Proj __proj = {}) const {
// TODO: implement
(void)__first; (void)__last; (void)__result; (void)__pred; (void)__new_value; (void)__proj;
return {};
template <class _InIter, class _Sent, class _OutIter, class _Pred, class _Type, class _Proj>
_LIBCPP_HIDE_FROM_ABI constexpr replace_copy_if_result<_InIter, _OutIter> __replace_copy_if_impl(
_InIter __first, _Sent __last, _OutIter __result, _Pred& __pred, const _Type& __new_value, _Proj& __proj) {
while (__first != __last) {
if (std::invoke(__pred, std::invoke(__proj, *__first)))
*__result = __new_value;
else
*__result = *__first;

++__first;
++__result;
}

template <input_range _Range, class _Type, output_iterator<const _Type&> _OutIter, class _Proj = identity,
indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred>
requires indirectly_copyable<iterator_t<_Range>, _OutIter>
_LIBCPP_HIDE_FROM_ABI constexpr
replace_copy_if_result<borrowed_iterator_t<_Range>, _OutIter>
operator()(_Range&& __range, _OutIter __result, _Pred __pred, const _Type& __new_value, _Proj __proj = {}) const {
// TODO: implement
(void)__range; (void)__result; (void)__pred; (void)__new_value; (void)__proj;
return {};
}
return {std::move(__first), std::move(__result)};
}

namespace __replace_copy_if {

};
struct __fn {
template <input_iterator _InIter,
sentinel_for<_InIter> _Sent,
class _Type,
output_iterator<const _Type&> _OutIter,
class _Proj = identity,
indirect_unary_predicate<projected<_InIter, _Proj>> _Pred>
requires indirectly_copyable<_InIter, _OutIter>
_LIBCPP_HIDE_FROM_ABI constexpr replace_copy_if_result<_InIter, _OutIter> operator()(
_InIter __first, _Sent __last, _OutIter __result, _Pred __pred, const _Type& __new_value, _Proj __proj = {})
const {
return ranges::__replace_copy_if_impl(
std::move(__first), std::move(__last), std::move(__result), __pred, __new_value, __proj);
}

template <input_range _Range,
class _Type,
output_iterator<const _Type&> _OutIter,
class _Proj = identity,
indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred>
requires indirectly_copyable<iterator_t<_Range>, _OutIter>
_LIBCPP_HIDE_FROM_ABI constexpr replace_copy_if_result<borrowed_iterator_t<_Range>, _OutIter>
operator()(_Range&& __range, _OutIter __result, _Pred __pred, const _Type& __new_value, _Proj __proj = {}) const {
return ranges::__replace_copy_if_impl(
ranges::begin(__range), ranges::end(__range), std::move(__result), __pred, __new_value, __proj);
}
};

} // namespace __replace_copy_if

Expand Down
74 changes: 74 additions & 0 deletions libcxx/include/__algorithm/ranges_sample.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP___ALGORITHM_RANGES_SAMPLE_H
#define _LIBCPP___ALGORITHM_RANGES_SAMPLE_H

#include <__algorithm/iterator_operations.h>
#include <__algorithm/sample.h>
#include <__algorithm/uniform_random_bit_generator_adaptor.h>
#include <__config>
#include <__iterator/concepts.h>
#include <__iterator/incrementable_traits.h>
#include <__iterator/iterator_traits.h>
#include <__random/uniform_random_bit_generator.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__utility/forward.h>
#include <__utility/move.h>
#include <type_traits>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)

_LIBCPP_BEGIN_NAMESPACE_STD

namespace ranges {
namespace __sample {

struct __fn {

template <input_iterator _Iter, sentinel_for<_Iter> _Sent, weakly_incrementable _OutIter, class _Gen>
requires (forward_iterator<_Iter> || random_access_iterator<_OutIter>) &&
indirectly_copyable<_Iter, _OutIter> &&
uniform_random_bit_generator<remove_reference_t<_Gen>>
_LIBCPP_HIDE_FROM_ABI
_OutIter operator()(_Iter __first, _Sent __last,
_OutIter __out_first, iter_difference_t<_Iter> __n, _Gen&& __gen) const {
_ClassicGenAdaptor<_Gen> __adapted_gen(__gen);
return std::__sample<_RangeAlgPolicy>(
std::move(__first), std::move(__last), std::move(__out_first), __n, __adapted_gen);
}

template <input_range _Range, weakly_incrementable _OutIter, class _Gen>
requires (forward_range<_Range> || random_access_iterator<_OutIter>) &&
indirectly_copyable<iterator_t<_Range>, _OutIter> &&
uniform_random_bit_generator<remove_reference_t<_Gen>>
_LIBCPP_HIDE_FROM_ABI
_OutIter operator()(_Range&& __range, _OutIter __out_first, range_difference_t<_Range> __n, _Gen&& __gen) const {
return (*this)(ranges::begin(__range), ranges::end(__range),
std::move(__out_first), __n, std::forward<_Gen>(__gen));
}

};

} // namespace __sample

inline namespace __cpo {
inline constexpr auto sample = __sample::__fn{};
} // namespace __cpo
} // namespace ranges

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)

#endif // _LIBCPP___ALGORITHM_RANGES_SAMPLE_H
34 changes: 1 addition & 33 deletions libcxx/include/__algorithm/ranges_shuffle.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <__algorithm/iterator_operations.h>
#include <__algorithm/shuffle.h>
#include <__algorithm/uniform_random_bit_generator_adaptor.h>
#include <__config>
#include <__functional/invoke.h>
#include <__functional/ranges_operations.h>
Expand All @@ -32,43 +33,12 @@

#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)

_LIBCPP_PUSH_MACROS
#include <__undef_macros>

_LIBCPP_BEGIN_NAMESPACE_STD

namespace ranges {
namespace __shuffle {

struct __fn {
// `std::shuffle` is more constrained than `std::ranges::shuffle`. `std::ranges::shuffle` only requires the given
// generator to satisfy the `std::uniform_random_bit_generator` concept. `std::shuffle` requires the given
// generator to meet the uniform random bit generator requirements; these requirements include satisfying
// `std::uniform_random_bit_generator` and add a requirement for the generator to provide a nested `result_type`
// typedef (see `[rand.req.urng]`).
//
// To reuse the implementation from `std::shuffle`, make the given generator meet the classic requirements by wrapping
// it into an adaptor type that forwards all of its interface and adds the required typedef.
template <class _Gen>
class _ClassicGenAdaptor {
private:
// The generator is not required to be copyable or movable, so it has to be stored as a reference.
_Gen& __gen;

public:
using result_type = invoke_result_t<_Gen&>;

_LIBCPP_HIDE_FROM_ABI
static constexpr auto min() { return __uncvref_t<_Gen>::min(); }
_LIBCPP_HIDE_FROM_ABI
static constexpr auto max() { return __uncvref_t<_Gen>::max(); }

_LIBCPP_HIDE_FROM_ABI
constexpr explicit _ClassicGenAdaptor(_Gen& __g) : __gen(__g) {}

_LIBCPP_HIDE_FROM_ABI
constexpr auto operator()() const { return __gen(); }
};

template <random_access_iterator _Iter, sentinel_for<_Iter> _Sent, class _Gen>
requires permutable<_Iter> && uniform_random_bit_generator<remove_reference_t<_Gen>>
Expand Down Expand Up @@ -96,8 +66,6 @@ inline namespace __cpo {

_LIBCPP_END_NAMESPACE_STD

_LIBCPP_POP_MACROS

#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)

#endif // _LIBCPP___ALGORITHM_RANGES_SHUFFLE_H
23 changes: 16 additions & 7 deletions libcxx/include/__algorithm/reverse.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,45 +10,54 @@
#define _LIBCPP___ALGORITHM_REVERSE_H

#include <__algorithm/iter_swap.h>
#include <__algorithm/iterator_operations.h>
#include <__config>
#include <__iterator/iterator_traits.h>
#include <__utility/move.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

template <class _BidirectionalIterator>
template <class _AlgPolicy, class _BidirectionalIterator>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
void
__reverse(_BidirectionalIterator __first, _BidirectionalIterator __last, bidirectional_iterator_tag)
__reverse_impl(_BidirectionalIterator __first, _BidirectionalIterator __last, bidirectional_iterator_tag)
{
while (__first != __last)
{
if (__first == --__last)
break;
_VSTD::iter_swap(__first, __last);
_IterOps<_AlgPolicy>::iter_swap(__first, __last);
++__first;
}
}

template <class _RandomAccessIterator>
template <class _AlgPolicy, class _RandomAccessIterator>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
void
__reverse(_RandomAccessIterator __first, _RandomAccessIterator __last, random_access_iterator_tag)
__reverse_impl(_RandomAccessIterator __first, _RandomAccessIterator __last, random_access_iterator_tag)
{
if (__first != __last)
for (; __first < --__last; ++__first)
_VSTD::iter_swap(__first, __last);
_IterOps<_AlgPolicy>::iter_swap(__first, __last);
}

template <class _AlgPolicy, class _BidirectionalIterator, class _Sentinel>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
void __reverse(_BidirectionalIterator __first, _Sentinel __last) {
using _IterCategory = typename _IterOps<_AlgPolicy>::template __iterator_category<_BidirectionalIterator>;
std::__reverse_impl<_AlgPolicy>(std::move(__first), std::move(__last), _IterCategory());
}

template <class _BidirectionalIterator>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
void
reverse(_BidirectionalIterator __first, _BidirectionalIterator __last)
{
_VSTD::__reverse(__first, __last, typename iterator_traits<_BidirectionalIterator>::iterator_category());
std::__reverse<_ClassicAlgPolicy>(std::move(__first), std::move(__last));
}

_LIBCPP_END_NAMESPACE_STD
Expand Down
48 changes: 28 additions & 20 deletions libcxx/include/__algorithm/sample.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
#ifndef _LIBCPP___ALGORITHM_SAMPLE_H
#define _LIBCPP___ALGORITHM_SAMPLE_H

#include <__algorithm/iterator_operations.h>
#include <__algorithm/min.h>
#include <__assert>
#include <__config>
#include <__iterator/distance.h>
#include <__iterator/iterator_traits.h>
#include <__random/uniform_int_distribution.h>
#include <__utility/move.h>
#include <type_traits>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
Expand All @@ -26,13 +28,14 @@ _LIBCPP_PUSH_MACROS

_LIBCPP_BEGIN_NAMESPACE_STD

template <class _PopulationIterator, class _SampleIterator, class _Distance,
template <class _AlgPolicy,
class _PopulationIterator, class _PopulationSentinel, class _SampleIterator, class _Distance,
class _UniformRandomNumberGenerator>
_LIBCPP_INLINE_VISIBILITY
_SampleIterator __sample(_PopulationIterator __first,
_PopulationIterator __last, _SampleIterator __output_iter,
_PopulationSentinel __last, _SampleIterator __output_iter,
_Distance __n,
_UniformRandomNumberGenerator & __g,
_UniformRandomNumberGenerator& __g,
input_iterator_tag) {

_Distance __k = 0;
Expand All @@ -47,15 +50,16 @@ _SampleIterator __sample(_PopulationIterator __first,
return __output_iter + _VSTD::min(__n, __k);
}

template <class _PopulationIterator, class _SampleIterator, class _Distance,
template <class _AlgPolicy,
class _PopulationIterator, class _PopulationSentinel, class _SampleIterator, class _Distance,
class _UniformRandomNumberGenerator>
_LIBCPP_INLINE_VISIBILITY
_SampleIterator __sample(_PopulationIterator __first,
_PopulationIterator __last, _SampleIterator __output_iter,
_PopulationSentinel __last, _SampleIterator __output_iter,
_Distance __n,
_UniformRandomNumberGenerator& __g,
forward_iterator_tag) {
_Distance __unsampled_sz = _VSTD::distance(__first, __last);
_Distance __unsampled_sz = _IterOps<_AlgPolicy>::distance(__first, __last);
for (__n = _VSTD::min(__n, __unsampled_sz); __n != 0; ++__first) {
_Distance __r = uniform_int_distribution<_Distance>(0, --__unsampled_sz)(__g);
if (__r < __n) {
Expand All @@ -66,24 +70,22 @@ _SampleIterator __sample(_PopulationIterator __first,
return __output_iter;
}

template <class _PopulationIterator, class _SampleIterator, class _Distance,
template <class _AlgPolicy,
class _PopulationIterator, class _PopulationSentinel, class _SampleIterator, class _Distance,
class _UniformRandomNumberGenerator>
_LIBCPP_INLINE_VISIBILITY
_SampleIterator __sample(_PopulationIterator __first,
_PopulationIterator __last, _SampleIterator __output_iter,
_PopulationSentinel __last, _SampleIterator __output_iter,
_Distance __n, _UniformRandomNumberGenerator& __g) {
typedef typename iterator_traits<_PopulationIterator>::iterator_category
_PopCategory;
typedef typename iterator_traits<_PopulationIterator>::difference_type
_Difference;
static_assert(__is_cpp17_forward_iterator<_PopulationIterator>::value ||
__is_cpp17_random_access_iterator<_SampleIterator>::value,
"SampleIterator must meet the requirements of RandomAccessIterator");
typedef typename common_type<_Distance, _Difference>::type _CommonType;
_LIBCPP_ASSERT(__n >= 0, "N must be a positive number.");
return _VSTD::__sample(
__first, __last, __output_iter, _CommonType(__n),
__g, _PopCategory());

using _PopIterCategory = typename _IterOps<_AlgPolicy>::template __iterator_category<_PopulationIterator>;
using _Difference = typename _IterOps<_AlgPolicy>::template __difference_type<_PopulationIterator>;
using _CommonType = typename common_type<_Distance, _Difference>::type;

return std::__sample<_AlgPolicy>(
std::move(__first), std::move(__last), std::move(__output_iter), _CommonType(__n),
__g, _PopIterCategory());
}

#if _LIBCPP_STD_VER > 14
Expand All @@ -93,8 +95,14 @@ inline _LIBCPP_INLINE_VISIBILITY
_SampleIterator sample(_PopulationIterator __first,
_PopulationIterator __last, _SampleIterator __output_iter,
_Distance __n, _UniformRandomNumberGenerator&& __g) {
return _VSTD::__sample(__first, __last, __output_iter, __n, __g);
static_assert(__is_cpp17_forward_iterator<_PopulationIterator>::value ||
__is_cpp17_random_access_iterator<_SampleIterator>::value,
"SampleIterator must meet the requirements of RandomAccessIterator");

return std::__sample<_ClassicAlgPolicy>(
std::move(__first), std::move(__last), std::move(__output_iter), __n, __g);
}

#endif // _LIBCPP_STD_VER > 14

_LIBCPP_END_NAMESPACE_STD
Expand Down
62 changes: 62 additions & 0 deletions libcxx/include/__algorithm/uniform_random_bit_generator_adaptor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP___ALGORITHM_RANGES_UNIFORM_RANDOM_BIT_GENERATOR_ADAPTOR_H
#define _LIBCPP___ALGORITHM_RANGES_UNIFORM_RANDOM_BIT_GENERATOR_ADAPTOR_H

#include <__config>
#include <__functional/invoke.h>
#include <type_traits>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

#if _LIBCPP_STD_VER > 17

_LIBCPP_PUSH_MACROS
#include <__undef_macros>

_LIBCPP_BEGIN_NAMESPACE_STD

// Range versions of random algorithms (e.g. `std::shuffle`) are less constrained than their classic counterparts.
// Range algorithms only require the given generator to satisfy the `std::uniform_random_bit_generator` concept.
// Classic algorithms require the given generator to meet the uniform random bit generator requirements; these
// requirements include satisfying `std::uniform_random_bit_generator` and add a requirement for the generator to
// provide a nested `result_type` typedef (see `[rand.req.urng]`).
//
// To be able to reuse classic implementations, make the given generator meet the classic requirements by wrapping
// it into an adaptor type that forwards all of its interface and adds the required typedef.
template <class _Gen>
class _ClassicGenAdaptor {
private:
// The generator is not required to be copyable or movable, so it has to be stored as a reference.
_Gen& __gen;

public:
using result_type = invoke_result_t<_Gen&>;

_LIBCPP_HIDE_FROM_ABI
static constexpr auto min() { return __uncvref_t<_Gen>::min(); }
_LIBCPP_HIDE_FROM_ABI
static constexpr auto max() { return __uncvref_t<_Gen>::max(); }

_LIBCPP_HIDE_FROM_ABI
constexpr explicit _ClassicGenAdaptor(_Gen& __g) : __gen(__g) {}

_LIBCPP_HIDE_FROM_ABI
constexpr auto operator()() const { return __gen(); }
};

_LIBCPP_END_NAMESPACE_STD

_LIBCPP_POP_MACROS

#endif // _LIBCPP_STD_VER > 17

#endif // _LIBCPP___ALGORITHM_RANGES_UNIFORM_RANDOM_BIT_GENERATOR_ADAPTOR_H
119 changes: 119 additions & 0 deletions libcxx/include/algorithm
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,18 @@ namespace ranges {
constexpr ranges::rotate_copy_result<borrowed_iterator_t<R>, O>
ranges::rotate_copy(R&& r, iterator_t<R> middle, O result); // since C++20
template<input_iterator I, sentinel_for<I> S, weakly_incrementable O, class Gen>
requires (forward_iterator<I> || random_access_iterator<O>) &&
indirectly_copyable<I, O> &&
uniform_random_bit_generator<remove_reference_t<Gen>>
O sample(I first, S last, O out, iter_difference_t<I> n, Gen&& g); // Since C++20
template<input_range R, weakly_incrementable O, class Gen>
requires (forward_range<R> || random_access_iterator<O>) &&
indirectly_copyable<iterator_t<R>, O> &&
uniform_random_bit_generator<remove_reference_t<Gen>>
O sample(R&& r, O out, range_difference_t<R> n, Gen&& g); // Since C++20
template<random_access_iterator I, sentinel_for<I> S, class Gen>
requires permutable<I> &&
uniform_random_bit_generator<remove_reference_t<Gen>>
Expand Down Expand Up @@ -912,8 +924,108 @@ namespace ranges {
indirectly_copyable_storable<iterator_t<R>, O>)
constexpr unique_copy_result<borrowed_iterator_t<R>, O>
unique_copy(R&& r, O result, C comp = {}, Proj proj = {}); // Since C++20
template<class I, class O>
using remove_copy_result = in_out_result<I, O>; // Since C++20
template<input_iterator I, sentinel_for<I> S, weakly_incrementable O, class T,
class Proj = identity>
indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
constexpr remove_copy_result<I, O>
remove_copy(I first, S last, O result, const T& value, Proj proj = {}); // Since C++20
template<input_range R, weakly_incrementable O, class T, class Proj = identity>
requires indirectly_copyable<iterator_t<R>, O> &&
indirect_binary_predicate<ranges::equal_to,
projected<iterator_t<R>, Proj>, const T*>
constexpr remove_copy_result<borrowed_iterator_t<R>, O>
remove_copy(R&& r, O result, const T& value, Proj proj = {}); // Since C++20
template<class I, class O>
using remove_copy_if_result = in_out_result<I, O>; // Since C++20
template<input_iterator I, sentinel_for<I> S, weakly_incrementable O,
class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
requires indirectly_copyable<I, O>
constexpr remove_copy_if_result<I, O>
remove_copy_if(I first, S last, O result, Pred pred, Proj proj = {}); // Since C++20
template<input_range R, weakly_incrementable O, class Proj = identity,
indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
requires indirectly_copyable<iterator_t<R>, O>
constexpr remove_copy_if_result<borrowed_iterator_t<R>, O>
remove_copy_if(R&& r, O result, Pred pred, Proj proj = {}); // Since C++20
template<class I, class O>
using replace_copy_result = in_out_result<I, O>; // Since C++20
template<input_iterator I, sentinel_for<I> S, class T1, class T2,
output_iterator<const T2&> O, class Proj = identity>
requires indirectly_copyable<I, O> &&
indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T1*>
constexpr replace_copy_result<I, O>
replace_copy(I first, S last, O result, const T1& old_value, const T2& new_value,
Proj proj = {}); // Since C++20
template<input_range R, class T1, class T2, output_iterator<const T2&> O,
class Proj = identity>
requires indirectly_copyable<iterator_t<R>, O> &&
indirect_binary_predicate<ranges::equal_to,
projected<iterator_t<R>, Proj>, const T1*>
constexpr replace_copy_result<borrowed_iterator_t<R>, O>
replace_copy(R&& r, O result, const T1& old_value, const T2& new_value,
Proj proj = {}); // Since C++20
template<class I, class O>
using replace_copy_if_result = in_out_result<I, O>; // Since C++20
template<input_iterator I, sentinel_for<I> S, class T, output_iterator<const T&> O,
class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
requires indirectly_copyable<I, O>
constexpr replace_copy_if_result<I, O>
replace_copy_if(I first, S last, O result, Pred pred, const T& new_value,
Proj proj = {}); // Since C++20
template<input_range R, class T, output_iterator<const T&> O, class Proj = identity,
indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
requires indirectly_copyable<iterator_t<R>, O>
constexpr replace_copy_if_result<borrowed_iterator_t<R>, O>
replace_copy_if(R&& r, O result, Pred pred, const T& new_value,
Proj proj = {}); // Since C++20
template<class I>
using prev_permutation_result = in_found_result<I>; // Since C++20
template<bidirectional_iterator I, sentinel_for<I> S, class Comp = ranges::less,
class Proj = identity>
requires sortable<I, Comp, Proj>
constexpr ranges::prev_permutation_result<I>
ranges::prev_permutation(I first, S last, Comp comp = {}, Proj proj = {}); // Since C++20
template<bidirectional_range R, class Comp = ranges::less,
class Proj = identity>
requires sortable<iterator_t<R>, Comp, Proj>
constexpr ranges::prev_permutation_result<borrowed_iterator_t<R>>
ranges::prev_permutation(R&& r, Comp comp = {}, Proj proj = {}); // Since C++20
template<class I>
using next_permutation_result = in_found_result<I>; // Since C++20
template<bidirectional_iterator I, sentinel_for<I> S, class Comp = ranges::less,
class Proj = identity>
requires sortable<I, Comp, Proj>
constexpr ranges::next_permutation_result<I>
ranges::next_permutation(I first, S last, Comp comp = {}, Proj proj = {}); // Since C++20
template<bidirectional_range R, class Comp = ranges::less,
class Proj = identity>
requires sortable<iterator_t<R>, Comp, Proj>
constexpr ranges::next_permutation_result<borrowed_iterator_t<R>>
ranges::next_permutation(R&& r, Comp comp = {}, Proj proj = {}); // Since C++20
}
template <class InputIterator, class Predicate>
constexpr bool // constexpr in C++20
all_of(InputIterator first, InputIterator last, Predicate pred);
Expand Down Expand Up @@ -1684,6 +1796,7 @@ template <class BidirectionalIterator, class Compare>
#include <__algorithm/ranges_mismatch.h>
#include <__algorithm/ranges_move.h>
#include <__algorithm/ranges_move_backward.h>
#include <__algorithm/ranges_next_permutation.h>
#include <__algorithm/ranges_none_of.h>
#include <__algorithm/ranges_nth_element.h>
#include <__algorithm/ranges_partial_sort.h>
Expand All @@ -1692,14 +1805,20 @@ template <class BidirectionalIterator, class Compare>
#include <__algorithm/ranges_partition_copy.h>
#include <__algorithm/ranges_partition_point.h>
#include <__algorithm/ranges_pop_heap.h>
#include <__algorithm/ranges_prev_permutation.h>
#include <__algorithm/ranges_push_heap.h>
#include <__algorithm/ranges_remove.h>
#include <__algorithm/ranges_remove_copy.h>
#include <__algorithm/ranges_remove_copy_if.h>
#include <__algorithm/ranges_remove_if.h>
#include <__algorithm/ranges_replace.h>
#include <__algorithm/ranges_replace_copy.h>
#include <__algorithm/ranges_replace_copy_if.h>
#include <__algorithm/ranges_replace_if.h>
#include <__algorithm/ranges_reverse.h>
#include <__algorithm/ranges_reverse_copy.h>
#include <__algorithm/ranges_rotate_copy.h>
#include <__algorithm/ranges_sample.h>
#include <__algorithm/ranges_search.h>
#include <__algorithm/ranges_search_n.h>
#include <__algorithm/ranges_set_difference.h>
Expand Down
6 changes: 6 additions & 0 deletions libcxx/include/module.modulemap.in
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ module std [system] {
module ranges_mismatch { private header "__algorithm/ranges_mismatch.h" }
module ranges_move { private header "__algorithm/ranges_move.h" }
module ranges_move_backward { private header "__algorithm/ranges_move_backward.h" }
module ranges_next_permutation { private header "__algorithm/ranges_next_permutation.h" }
module ranges_none_of { private header "__algorithm/ranges_none_of.h" }
module ranges_nth_element { private header "__algorithm/ranges_nth_element.h" }
module ranges_partial_sort { private header "__algorithm/ranges_partial_sort.h" }
Expand All @@ -360,6 +361,7 @@ module std [system] {
module ranges_partition_copy { private header "__algorithm/ranges_partition_copy.h" }
module ranges_partition_point { private header "__algorithm/ranges_partition_point.h" }
module ranges_pop_heap { private header "__algorithm/ranges_pop_heap.h" }
module ranges_prev_permutation { private header "__algorithm/ranges_prev_permutation.h" }
module ranges_push_heap { private header "__algorithm/ranges_push_heap.h" }
module ranges_remove { private header "__algorithm/ranges_remove.h" }
module ranges_remove_copy { private header "__algorithm/ranges_remove_copy.h" }
Expand All @@ -372,6 +374,7 @@ module std [system] {
module ranges_reverse { private header "__algorithm/ranges_reverse.h" }
module ranges_reverse_copy { private header "__algorithm/ranges_reverse_copy.h" }
module ranges_rotate_copy { private header "__algorithm/ranges_rotate_copy.h" }
module ranges_sample { private header "__algorithm/ranges_sample.h" }
module ranges_search { private header "__algorithm/ranges_search.h" }
module ranges_search_n { private header "__algorithm/ranges_search_n.h" }
module ranges_set_difference { private header "__algorithm/ranges_set_difference.h" }
Expand All @@ -385,6 +388,9 @@ module std [system] {
module ranges_stable_sort { private header "__algorithm/ranges_stable_sort.h" }
module ranges_swap_ranges { private header "__algorithm/ranges_swap_ranges.h" }
module ranges_transform { private header "__algorithm/ranges_transform.h" }
module uniform_random_bit_generator_adaptor {
private header "__algorithm/uniform_random_bit_generator_adaptor.h"
}
module ranges_unique { private header "__algorithm/ranges_unique.h" }
module ranges_unique_copy { private header "__algorithm/ranges_unique_copy.h" }
module ranges_upper_bound { private header "__algorithm/ranges_upper_bound.h" }
Expand Down
4 changes: 2 additions & 2 deletions libcxx/include/version
Original file line number Diff line number Diff line change
Expand Up @@ -331,8 +331,8 @@ __cpp_lib_void_t 201411L <type_traits>
# define __cpp_lib_erase_if 202002L
# undef __cpp_lib_execution
// # define __cpp_lib_execution 201902L
# if !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_format)
// # define __cpp_lib_format 202106L
# if !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_format) && !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
# define __cpp_lib_format 202106L
# endif
# define __cpp_lib_generic_unordered_lookup 201811L
# define __cpp_lib_int_pow2 202002L
Expand Down
40 changes: 24 additions & 16 deletions libcxx/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -212,20 +212,6 @@ if (LIBCXX_ENABLE_SHARED)
cxx_add_common_build_flags(cxx_shared)
cxx_set_common_defines(cxx_shared)

# Link against LLVM libunwind
# Note that we do need to link against libunwind directly to ensure that the correct
# dependencies are recorded when creating a linker script.
# TODO: Look into modifying the linker script creation to recursively consider interface libraries
if (LIBCXXABI_USE_LLVM_UNWINDER)
if (LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_SHARED_LIBRARY)
# libunwind is already included in libc++abi
elseif (TARGET unwind_shared OR HAVE_LIBUNWIND)
target_link_libraries(cxx_shared PUBLIC unwind_shared)
else()
target_link_libraries(cxx_shared PUBLIC unwind)
endif()
endif()

# Link against libc++abi
if (LIBCXX_STATICALLY_LINK_ABI_IN_SHARED_LIBRARY)
target_link_libraries(cxx_shared PRIVATE libcxx-abi-shared-objects)
Expand Down Expand Up @@ -254,8 +240,30 @@ if (LIBCXX_ENABLE_SHARED)

# Generate a linker script in place of a libc++.so symlink.
if (LIBCXX_ENABLE_ABI_LINKER_SCRIPT)
include(DefineLinkerScript)
define_linker_script(cxx_shared)
set(link_libraries)

set(imported_libname "$<TARGET_PROPERTY:libcxx-abi-shared,IMPORTED_LIBNAME>")
set(output_name "$<TARGET_PROPERTY:libcxx-abi-shared,OUTPUT_NAME>")
string(APPEND link_libraries "${CMAKE_LINK_LIBRARY_FLAG}$<IF:$<BOOL:${imported_libname}>,${imported_libname},${output_name}>")

# TODO: Move to the same approach as above for the unwind library
if (LIBCXXABI_USE_LLVM_UNWINDER)
if (LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_SHARED_LIBRARY)
# libunwind is already included in libc++abi
elseif (TARGET unwind_shared OR HAVE_LIBUNWIND)
string(APPEND link_libraries " ${CMAKE_LINK_LIBRARY_FLAG}$<TARGET_PROPERTY:unwind_shared,OUTPUT_NAME>")
else()
string(APPEND link_libraries " ${CMAKE_LINK_LIBRARY_FLAG}unwind")
endif()
endif()

set(linker_script "INPUT($<TARGET_SONAME_FILE_NAME:cxx_shared> ${link_libraries})")
add_custom_command(TARGET cxx_shared POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E remove "$<TARGET_LINKER_FILE:cxx_shared>"
COMMAND "${CMAKE_COMMAND}" -E echo "${linker_script}" > "$<TARGET_LINKER_FILE:cxx_shared>"
COMMENT "Generating linker script: '${linker_script}' as file $<TARGET_LINKER_FILE:cxx_shared>"
VERBATIM
)
endif()

list(APPEND LIBCXX_BUILD_TARGETS "cxx_shared")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,8 @@ constexpr bool all_the_algorithms()
(void)std::ranges::minmax_element(a, Less(&copies)); assert(copies == 0);
(void)std::ranges::mismatch(first, last, first2, last2, Equal(&copies)); assert(copies == 0);
(void)std::ranges::mismatch(a, b, Equal(&copies)); assert(copies == 0);
//(void)std::ranges::next_permutation(first, last, Less(&copies)); assert(copies == 0);
//(void)std::ranges::next_permutation(a, Less(&copies)); assert(copies == 0);
(void)std::ranges::next_permutation(first, last, Less(&copies)); assert(copies == 0);
(void)std::ranges::next_permutation(a, Less(&copies)); assert(copies == 0);
(void)std::ranges::none_of(first, last, UnaryTrue(&copies)); assert(copies == 0);
(void)std::ranges::none_of(a, UnaryTrue(&copies)); assert(copies == 0);
(void)std::ranges::nth_element(first, mid, last, Less(&copies)); assert(copies == 0);
Expand All @@ -183,16 +183,16 @@ constexpr bool all_the_algorithms()
(void)std::ranges::partition_point(a, UnaryTrue(&copies)); assert(copies == 0);
(void)std::ranges::pop_heap(first, last, Less(&copies)); assert(copies == 0);
(void)std::ranges::pop_heap(a, Less(&copies)); assert(copies == 0);
//(void)std::ranges::prev_permutation(first, last, Less(&copies)); assert(copies == 0);
//(void)std::ranges::prev_permutation(a, Less(&copies)); assert(copies == 0);
(void)std::ranges::prev_permutation(first, last, Less(&copies)); assert(copies == 0);
(void)std::ranges::prev_permutation(a, Less(&copies)); assert(copies == 0);
(void)std::ranges::push_heap(first, last, Less(&copies)); assert(copies == 0);
(void)std::ranges::push_heap(a, Less(&copies)); assert(copies == 0);
//(void)std::ranges::remove_copy_if(first, last, first2, UnaryTrue(&copies)); assert(copies == 0);
//(void)std::ranges::remove_copy_if(a, first2, UnaryTrue(&copies)); assert(copies == 0);
(void)std::ranges::remove_copy_if(first, last, first2, UnaryTrue(&copies)); assert(copies == 0);
(void)std::ranges::remove_copy_if(a, first2, UnaryTrue(&copies)); assert(copies == 0);
(void)std::ranges::remove_if(first, last, UnaryTrue(&copies)); assert(copies == 0);
(void)std::ranges::remove_if(a, UnaryTrue(&copies)); assert(copies == 0);
//(void)std::ranges::replace_copy_if(first, last, first2, UnaryTrue(&copies), value); assert(copies == 0);
//(void)std::ranges::replace_copy_if(a, first2, UnaryTrue(&copies), value); assert(copies == 0);
(void)std::ranges::replace_copy_if(first, last, first2, UnaryTrue(&copies), value); assert(copies == 0);
(void)std::ranges::replace_copy_if(a, first2, UnaryTrue(&copies), value); assert(copies == 0);
(void)std::ranges::replace_if(first, last, UnaryTrue(&copies), value); assert(copies == 0);
(void)std::ranges::replace_if(a, UnaryTrue(&copies), value); assert(copies == 0);
(void)std::ranges::search(first, last, first2, mid2, Equal(&copies)); assert(copies == 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,8 @@ constexpr bool all_the_algorithms()
(void)std::ranges::minmax_element(a, Less(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::mismatch(first, last, first2, last2, Equal(), Proj(&copies), Proj(&copies)); assert(copies == 0);
(void)std::ranges::mismatch(a, b, Equal(), Proj(&copies), Proj(&copies)); assert(copies == 0);
//(void)std::ranges::next_permutation(first, last, Less(), Proj(&copies)); assert(copies == 0);
//(void)std::ranges::next_permutation(a, Less(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::next_permutation(first, last, Less(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::next_permutation(a, Less(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::none_of(first, last, UnaryTrue(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::none_of(a, UnaryTrue(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::nth_element(first, mid, last, Less(), Proj(&copies)); assert(copies == 0);
Expand All @@ -166,22 +166,22 @@ constexpr bool all_the_algorithms()
(void)std::ranges::partition_point(a, UnaryTrue(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::pop_heap(first, last, Less(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::pop_heap(a, Less(), Proj(&copies)); assert(copies == 0);
//(void)std::ranges::prev_permutation(first, last, Less(), Proj(&copies)); assert(copies == 0);
//(void)std::ranges::prev_permutation(a, Less(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::prev_permutation(first, last, Less(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::prev_permutation(a, Less(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::push_heap(first, last, Less(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::push_heap(a, Less(), Proj(&copies)); assert(copies == 0);
//(void)std::ranges::remove_copy(first, last, first2, value, Proj(&copies)); assert(copies == 0);
//(void)std::ranges::remove_copy(a, first2, value, Proj(&copies)); assert(copies == 0);
//(void)std::ranges::remove_copy_if(first, last, first2, UnaryTrue(), Proj(&copies)); assert(copies == 0);
//(void)std::ranges::remove_copy_if(a, first2, UnaryTrue(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::remove_copy(first, last, first2, value, Proj(&copies)); assert(copies == 0);
(void)std::ranges::remove_copy(a, first2, value, Proj(&copies)); assert(copies == 0);
(void)std::ranges::remove_copy_if(first, last, first2, UnaryTrue(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::remove_copy_if(a, first2, UnaryTrue(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::remove(first, last, value, Proj(&copies)); assert(copies == 0);
(void)std::ranges::remove(a, value, Proj(&copies)); assert(copies == 0);
(void)std::ranges::remove_if(first, last, UnaryTrue(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::remove_if(a, UnaryTrue(), Proj(&copies)); assert(copies == 0);
//(void)std::ranges::replace_copy(first, last, first2, value, T(), Proj(&copies)); assert(copies == 0);
//(void)std::ranges::replace_copy(a, first2, value, T(), Proj(&copies)); assert(copies == 0);
//(void)std::ranges::replace_copy_if(first, last, first2, UnaryTrue(), T(), Proj(&copies)); assert(copies == 0);
//(void)std::ranges::replace_copy_if(a, first2, UnaryTrue(), T(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::replace_copy(first, last, first2, value, T(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::replace_copy(a, first2, value, T(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::replace_copy_if(first, last, first2, UnaryTrue(), T(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::replace_copy_if(a, first2, UnaryTrue(), T(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::replace(first, last, value, T(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::replace(a, value, T(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::replace_if(first, last, UnaryTrue(), T(), Proj(&copies)); assert(copies == 0);
Expand Down
4 changes: 4 additions & 0 deletions libcxx/test/libcxx/private_headers.verify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ END-SCRIPT
#include <__algorithm/ranges_mismatch.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_mismatch.h'}}
#include <__algorithm/ranges_move.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_move.h'}}
#include <__algorithm/ranges_move_backward.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_move_backward.h'}}
#include <__algorithm/ranges_next_permutation.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_next_permutation.h'}}
#include <__algorithm/ranges_none_of.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_none_of.h'}}
#include <__algorithm/ranges_nth_element.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_nth_element.h'}}
#include <__algorithm/ranges_partial_sort.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_partial_sort.h'}}
Expand All @@ -158,6 +159,7 @@ END-SCRIPT
#include <__algorithm/ranges_partition_copy.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_partition_copy.h'}}
#include <__algorithm/ranges_partition_point.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_partition_point.h'}}
#include <__algorithm/ranges_pop_heap.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_pop_heap.h'}}
#include <__algorithm/ranges_prev_permutation.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_prev_permutation.h'}}
#include <__algorithm/ranges_push_heap.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_push_heap.h'}}
#include <__algorithm/ranges_remove.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_remove.h'}}
#include <__algorithm/ranges_remove_copy.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_remove_copy.h'}}
Expand All @@ -170,6 +172,7 @@ END-SCRIPT
#include <__algorithm/ranges_reverse.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_reverse.h'}}
#include <__algorithm/ranges_reverse_copy.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_reverse_copy.h'}}
#include <__algorithm/ranges_rotate_copy.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_rotate_copy.h'}}
#include <__algorithm/ranges_sample.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_sample.h'}}
#include <__algorithm/ranges_search.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_search.h'}}
#include <__algorithm/ranges_search_n.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_search_n.h'}}
#include <__algorithm/ranges_set_difference.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_set_difference.h'}}
Expand Down Expand Up @@ -215,6 +218,7 @@ END-SCRIPT
#include <__algorithm/stable_sort.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/stable_sort.h'}}
#include <__algorithm/swap_ranges.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/swap_ranges.h'}}
#include <__algorithm/transform.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/transform.h'}}
#include <__algorithm/uniform_random_bit_generator_adaptor.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/uniform_random_bit_generator_adaptor.h'}}
#include <__algorithm/unique.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/unique.h'}}
#include <__algorithm/unique_copy.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/unique_copy.h'}}
#include <__algorithm/unwrap_iter.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/unwrap_iter.h'}}
Expand Down
1 change: 1 addition & 0 deletions libcxx/test/libcxx/selftest/dsl/dsl.sh.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def setUp(self):
params={})

self.config = lit.TestingConfig.TestingConfig.fromdefaults(self.litConfig)
self.config.environment = dict(os.environ)
self.config.test_source_root = SOURCE_ROOT
self.config.test_exec_root = EXEC_PATH
self.config.recursiveExpansionLimit = 10
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ constexpr void test_iterators() {
std::same_as<std::ranges::in_out_result<In, Out>> auto ret =
std::ranges::copy_backward(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data() + out.size()));
assert(in == out);
assert(base(ret.in) == in.data());
assert(base(ret.in) == in.data() + in.size());
assert(base(ret.out) == out.data());
}
{
Expand All @@ -75,7 +75,7 @@ constexpr void test_iterators() {
std::same_as<std::ranges::in_out_result<In, Out>> auto ret =
std::ranges::copy_backward(range, Out(out.data() + out.size()));
assert(in == out);
assert(base(ret.in) == in.data());
assert(base(ret.in) == in.data() + in.size());
assert(base(ret.out) == out.data());
}
}
Expand All @@ -86,15 +86,15 @@ constexpr void test_iterators() {
std::array<int, 0> out;
auto ret =
std::ranges::copy_backward(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data() + out.size()));
assert(base(ret.in) == in.data());
assert(base(ret.in) == in.data() + in.size());
assert(base(ret.out) == out.data());
}
{
std::array<int, 0> in;
std::array<int, 0> out;
auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + in.size())));
auto ret = std::ranges::copy_backward(range, Out(out.data()));
assert(base(ret.in) == in.data());
assert(base(ret.in) == in.data() + in.size());
assert(base(ret.out) == out.data());
}
}
Expand Down Expand Up @@ -143,7 +143,7 @@ constexpr bool test() {
std::array<int, 4> out;
std::same_as<std::ranges::in_out_result<int*, int*>> auto ret =
std::ranges::copy_backward(std::views::all(in), out.data() + out.size());
assert(ret.in == in.data());
assert(ret.in == in.data() + in.size());
assert(ret.out == out.data());
assert(in == out);
}
Expand All @@ -163,15 +163,15 @@ constexpr bool test() {
std::array<CopyOnce, 4> in {};
std::array<CopyOnce, 4> out {};
auto ret = std::ranges::copy_backward(in.begin(), in.end(), out.end());
assert(ret.in == in.begin());
assert(ret.in == in.end());
assert(ret.out == out.begin());
assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.copied; }));
}
{
std::array<CopyOnce, 4> in {};
std::array<CopyOnce, 4> out {};
auto ret = std::ranges::copy_backward(in, out.end());
assert(ret.in == in.begin());
assert(ret.in == in.end());
assert(ret.out == out.begin());
assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.copied; }));
}
Expand All @@ -196,7 +196,7 @@ constexpr bool test() {
out[2].next = &out[1];
out[2].canCopy = true;
auto ret = std::ranges::copy_backward(in, out.end());
assert(ret.in == in.begin());
assert(ret.in == in.end());
assert(ret.out == out.begin());
assert(out[0].canCopy);
assert(out[1].canCopy);
Expand All @@ -209,7 +209,7 @@ constexpr bool test() {
out[2].next = &out[1];
out[2].canCopy = true;
auto ret = std::ranges::copy_backward(in.begin(), in.end(), out.end());
assert(ret.in == in.begin());
assert(ret.in == in.end());
assert(ret.out == out.begin());
assert(out[0].canCopy);
assert(out[1].canCopy);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ constexpr void test(std::array<int, N> in) {
std::same_as<std::ranges::in_out_result<In, Out>> decltype(auto) ret =
std::ranges::move_backward(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data() + out.size()));
assert(in == out);
assert(base(ret.in) == in.data());
assert(base(ret.in) == in.data() + in.size());
assert(base(ret.out) == out.data());
}
{
Expand All @@ -73,7 +73,7 @@ constexpr void test(std::array<int, N> in) {
std::same_as<std::ranges::in_out_result<In, Out>> decltype(auto) ret =
std::ranges::move_backward(range, Out(out.data() + out.size()));
assert(in == out);
assert(base(ret.in) == in.data());
assert(base(ret.in) == in.data() + in.size());
assert(base(ret.out) == out.data());
}
}
Expand Down Expand Up @@ -186,7 +186,7 @@ constexpr bool test() {
std::array<int, 4> out;
std::same_as<std::ranges::in_out_result<int*, int*>> auto ret =
std::ranges::move_backward(std::views::all(in), out.data() + out.size());
assert(ret.in == in.data());
assert(ret.in == in.data() + in.size());
assert(ret.out == out.data());
assert(in == out);
}
Expand All @@ -206,15 +206,15 @@ constexpr bool test() {
std::array<MoveOnce, 4> in {};
std::array<MoveOnce, 4> out {};
auto ret = std::ranges::move_backward(in.begin(), in.end(), out.end());
assert(ret.in == in.begin());
assert(ret.in == in.end());
assert(ret.out == out.begin());
assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.moved; }));
}
{
std::array<MoveOnce, 4> in {};
std::array<MoveOnce, 4> out {};
auto ret = std::ranges::move_backward(in, out.end());
assert(ret.in == in.begin());
assert(ret.in == in.end());
assert(ret.out == out.begin());
assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.moved; }));
}
Expand All @@ -239,7 +239,7 @@ constexpr bool test() {
out[2].next = &out[1];
out[2].canMove = true;
auto ret = std::ranges::move_backward(in, out.end());
assert(ret.in == in.begin());
assert(ret.in == in.end());
assert(ret.out == out.begin());
assert(out[0].canMove);
assert(out[1].canMove);
Expand All @@ -252,7 +252,7 @@ constexpr bool test() {
out[2].next = &out[1];
out[2].canMove = true;
auto ret = std::ranges::move_backward(in.begin(), in.end(), out.end());
assert(ret.in == in.begin());
assert(ret.in == in.end());
assert(ret.out == out.begin());
assert(out[0].canMove);
assert(out[1].canMove);
Expand All @@ -265,7 +265,7 @@ constexpr bool test() {
int a[] = {1, 2, 3, 4};
std::array<int, 4> b;
auto ret = std::ranges::move_backward(IteratorWithMoveIter(a), IteratorWithMoveIter(a + 4), b.data() + b.size());
assert(ret.in == a);
assert(ret.in == a + 4);
assert(ret.out == b.data());
assert((b == std::array {42, 42, 42, 42}));
}
Expand All @@ -274,7 +274,7 @@ constexpr bool test() {
std::array<int, 4> b;
auto range = std::ranges::subrange(IteratorWithMoveIter(a), IteratorWithMoveIter(a + 4));
auto ret = std::ranges::move_backward(range, b.data() + b.size());
assert(ret.in == a);
assert(ret.in == a + 4);
assert(ret.out == b.data());
assert((b == std::array {42, 42, 42, 42}));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,334 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-has-no-incomplete-ranges

// <algorithm>

// template<input_iterator I, sentinel_for<I> S, weakly_incrementable O, class Gen>
// requires (forward_iterator<I> || random_access_iterator<O>) &&
// indirectly_copyable<I, O> &&
// uniform_random_bit_generator<remove_reference_t<Gen>>
// O sample(I first, S last, O out, iter_difference_t<I> n, Gen&& g); // Since C++20
//
// template<input_range R, weakly_incrementable O, class Gen>
// requires (forward_range<R> || random_access_iterator<O>) &&
// indirectly_copyable<iterator_t<R>, O> &&
// uniform_random_bit_generator<remove_reference_t<Gen>>
// O sample(R&& r, O out, range_difference_t<R> n, Gen&& g); // Since C++20

#include <algorithm>
#include <array>
#include <concepts>
#include <functional>
#include <random>
#include <ranges>
#include <utility>

#include "almost_satisfies_types.h"
#include "test_iterators.h"
#include "test_macros.h"

class RandGen {
public:
constexpr static size_t min() { return 0; }
constexpr static size_t max() { return 255; }

constexpr size_t operator()() {
flip = !flip;
return flip;
}

private:
bool flip = false;
};

static_assert(std::uniform_random_bit_generator<RandGen>);
// `std::uniform_random_bit_generator` is a subset of requirements of `__libcpp_random_is_valid_urng`. Make sure that
// a type satisfying the required minimum is still accepted by `ranges::shuffle`.
LIBCPP_STATIC_ASSERT(!std::__libcpp_random_is_valid_urng<RandGen>::value);

struct BadGen {
constexpr static size_t min() { return 255; }
constexpr static size_t max() { return 0; }
constexpr size_t operator()() const;
};
static_assert(!std::uniform_random_bit_generator<BadGen>);

// Test constraints of the (iterator, sentinel) overload.
// ======================================================

template <class Iter = int*, class Sent = int*, class Out = int*, class Gen = RandGen>
concept HasSampleIter =
requires(Iter&& iter, Sent&& sent, Out&& out, std::iter_difference_t<Iter> n, Gen&& gen) {
std::ranges::sample(std::forward<Iter>(iter), std::forward<Sent>(sent),
std::forward<Out>(out), n, std::forward<Gen>(gen));
};

static_assert(HasSampleIter<int*, int*, int*, RandGen>);

// !input_iterator<I>
static_assert(!HasSampleIter<InputIteratorNotDerivedFrom>);
static_assert(!HasSampleIter<InputIteratorNotIndirectlyReadable>);
static_assert(!HasSampleIter<InputIteratorNotInputOrOutputIterator>);

// !sentinel_for<S, I>
static_assert(!HasSampleIter<int*, SentinelForNotSemiregular>);
static_assert(!HasSampleIter<int*, SentinelForNotWeaklyEqualityComparableWith>);

// !weakly_incrementable<O>
static_assert(!HasSampleIter<int*, int*, WeaklyIncrementableNotMovable>);

// (forward_iterator<I> || random_access_iterator<O>)
static_assert(HasSampleIter<
forward_iterator<int*>, forward_iterator<int*>,
cpp20_output_iterator<int*>
>);
static_assert(HasSampleIter<
cpp20_input_iterator<int*>, sentinel_wrapper<cpp20_input_iterator<int*>>,
random_access_iterator<int*>
>);
// !(forward_iterator<I> || random_access_iterator<O>)
static_assert(!HasSampleIter<
cpp20_input_iterator<int*>, sentinel_wrapper<cpp20_input_iterator<int*>>,
cpp20_output_iterator<int*>
>);

// !indirectly_copyable<I, O>
static_assert(!HasSampleIter<int*, int*, int**>);

// !uniform_random_bit_generator<remove_reference_t<Gen>>
static_assert(!HasSampleIter<int*, int*, int*, BadGen>);

// Test constraints of the (range) overload.
// =========================================

template <class Range, class Out = int*, class Gen = RandGen>
concept HasSampleRange =
requires(Range&& range, Out&& out, std::ranges::range_difference_t<Range> n, Gen&& gen) {
std::ranges::sample(std::forward<Range>(range), std::forward<Out>(out), n, std::forward<Gen>(gen));
};

template <class T>
using R = UncheckedRange<T>;

static_assert(HasSampleRange<R<int*>, int*, RandGen>);

// !input_range<R>
static_assert(!HasSampleRange<InputRangeNotDerivedFrom>);
static_assert(!HasSampleRange<InputRangeNotIndirectlyReadable>);
static_assert(!HasSampleRange<InputRangeNotInputOrOutputIterator>);

// !weakly_incrementable<O>
static_assert(!HasSampleRange<R<int*>, WeaklyIncrementableNotMovable>);

// (forward_range<R> || random_access_iterator<O>)
static_assert(HasSampleRange<
R<forward_iterator<int*>>,
cpp20_output_iterator<int*>
>);
static_assert(HasSampleRange<
R<cpp20_input_iterator<int*>>,
random_access_iterator<int*>
>);
// !(forward_range<R> || random_access_iterator<O>)
static_assert(!HasSampleRange<
R<cpp20_input_iterator<int*>>,
cpp20_output_iterator<int*>
>);

// !indirectly_copyable<I, O>
static_assert(!HasSampleRange<R<int*>, int**>);

// !uniform_random_bit_generator<remove_reference_t<Gen>>
static_assert(!HasSampleRange<R<int*>, int*, BadGen>);

template <class Iter, class Sent, class Out, size_t N, class Gen>
void test_one(std::array<int, N> in, size_t n, Gen gen) {
assert(n <= static_cast<size_t>(N));

auto verify_is_subsequence = [&] (auto output) {
auto sorted_input = in;
std::ranges::sort(sorted_input);
auto sorted_output = std::ranges::subrange(output.begin(), output.begin() + n);
std::ranges::sort(sorted_output);
assert(std::ranges::includes(sorted_input, sorted_output));
};

{ // (iterator, sentinel) overload.
auto begin = Iter(in.data());
auto end = Sent(Iter(in.data() + in.size()));
std::array<int, N> output;
auto out = Out(output.begin());

std::same_as<Out> decltype(auto) result = std::ranges::sample(
std::move(begin), std::move(end), std::move(out), n, gen);
assert(base(result) == output.data() + n);
verify_is_subsequence(output);
// The output of `sample` is implementation-specific.
}

{ // (range) overload.
auto begin = Iter(in.data());
auto end = Sent(Iter(in.data() + in.size()));
std::array<int, N> output;
auto out = Out(output.begin());

std::same_as<Out> decltype(auto) result = std::ranges::sample(std::ranges::subrange(
std::move(begin), std::move(end)), std::move(out), n, gen);
assert(base(result) == output.data() + n);
verify_is_subsequence(output);
// The output of `sample` is implementation-specific.
}
}

template <class Iter, class Sent, class Out>
void test_iterators_iter_sent_out() {
RandGen gen;

// Empty sequence.
test_one<Iter, Sent, Out, 0>({}, 0, gen);
// 1-element sequence.
test_one<Iter, Sent, Out, 1>({1}, 1, gen);
// 2-element sequence.
test_one<Iter, Sent, Out, 2>({1, 2}, 1, gen);
test_one<Iter, Sent, Out, 2>({1, 2}, 2, gen);
// n == 0.
test_one<Iter, Sent, Out, 3>({1, 2, 3}, 0, gen);

// Longer sequence.
{
std::array input = {1, 8, 2, 3, 4, 6, 5, 7};
for (int i = 0; i <= static_cast<int>(input.size()); ++i){
test_one<Iter, Sent, Out, input.size()>(input, i, gen);
}
}
}

template <class Iter, class Sent>
void test_iterators_iter_sent() {
if constexpr (std::forward_iterator<Iter>) {
test_iterators_iter_sent_out<Iter, Sent, cpp20_output_iterator<int*>>();
test_iterators_iter_sent_out<Iter, Sent, forward_iterator<int*>>();
}
test_iterators_iter_sent_out<Iter, Sent, random_access_iterator<int*>>();
test_iterators_iter_sent_out<Iter, Sent, contiguous_iterator<int*>>();
test_iterators_iter_sent_out<Iter, Sent, int*>();
}

template <class Iter>
void test_iterators_iter() {
if constexpr (std::sentinel_for<Iter, Iter>) {
test_iterators_iter_sent<Iter, Iter>();
}
test_iterators_iter_sent<Iter, sentinel_wrapper<Iter>>();
}

void test_iterators() {
test_iterators_iter<cpp20_input_iterator<int*>>();
test_iterators_iter<random_access_iterator<int*>>();
test_iterators_iter<contiguous_iterator<int*>>();
test_iterators_iter<int*>();
test_iterators_iter<const int*>();
}

// Checks the logic for wrapping the given iterator to make sure it works correctly regardless of the value category of
// the given generator object.
template <class Gen, bool CheckConst = true>
void test_generator() {
std::array in = {1, 2, 3, 4, 5, 6, 7, 8};
constexpr int N = 5;
std::array<int, N> output;
auto begin = in.begin();
auto end = in.end();
auto out = output.begin();

{ // Lvalue.
Gen g;
std::ranges::sample(begin, end, out, N, g);
std::ranges::sample(in, out, N, g);
}

if constexpr (CheckConst) { // Const lvalue.
const Gen g;
std::ranges::sample(begin, end, out, N, g);
std::ranges::sample(in, out, N, g);
}

{ // Prvalue.
std::ranges::sample(begin, end, out, N, Gen());
std::ranges::sample(in, out, N, Gen());
}

{ // Xvalue.
Gen g1, g2;
std::ranges::sample(begin, end, out, N, std::move(g1));
std::ranges::sample(in, out, N, std::move(g2));
}
}

// Checks the logic for wrapping the given iterator to make sure it works correctly regardless of whether the given
// generator class has a const or non-const invocation operator (or both).
void test_generators() {
struct GenBase {
constexpr static size_t min() { return 0; }
constexpr static size_t max() { return 255; }
};
struct NonconstGen : GenBase {
size_t operator()() { return 1; }
};
struct ConstGen : GenBase {
size_t operator()() const { return 1; }
};
struct ConstAndNonconstGen : GenBase {
size_t operator()() { return 1; }
size_t operator()() const { return 1; }
};

test_generator<ConstGen>();
test_generator<NonconstGen, /*CheckConst=*/false>();
test_generator<ConstAndNonconstGen>();
}

void test() {
test_iterators();
test_generators();

{ // Stable (if `I` models `forward_iterator`).
struct OrderedValue {
int value;
int original_order;
bool operator==(const OrderedValue&) const = default;
auto operator<=>(const OrderedValue& rhs) const { return value <=> rhs.value; }
};

const std::array<OrderedValue, 8> in = {{
{1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6}, {1, 7}, {1, 8}
}};

{ // (iterator, sentinel) overload.
std::array<OrderedValue, in.size()> out;
std::ranges::sample(in.begin(), in.end(), out.begin(), in.size(), RandGen());
assert(out == in);
}

{ // (range) overload.
std::array<OrderedValue, in.size()> out;
std::ranges::sample(in, out.begin(), in.size(), RandGen());
assert(out == in);
}
}
}

int main(int, char**) {
test();
// Note: `ranges::sample` is not `constexpr`.

return 0;
}
Loading