Path: blob/main/contrib/llvm-project/libcxx/include/__pstl/backends/default.h
35266 views
//===----------------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#ifndef _LIBCPP___PSTL_BACKENDS_DEFAULT_H9#define _LIBCPP___PSTL_BACKENDS_DEFAULT_H1011#include <__algorithm/copy_n.h>12#include <__algorithm/equal.h>13#include <__algorithm/fill_n.h>14#include <__algorithm/for_each_n.h>15#include <__config>16#include <__functional/identity.h>17#include <__functional/not_fn.h>18#include <__functional/operations.h>19#include <__iterator/concepts.h>20#include <__iterator/iterator_traits.h>21#include <__pstl/backend_fwd.h>22#include <__pstl/dispatch.h>23#include <__utility/empty.h>24#include <__utility/forward.h>25#include <__utility/move.h>26#include <optional>2728#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)29# pragma GCC system_header30#endif3132_LIBCPP_PUSH_MACROS33#include <__undef_macros>3435_LIBCPP_BEGIN_NAMESPACE_STD36namespace __pstl {3738//39// This file provides an incomplete PSTL backend that implements all of the PSTL algorithms40// based on a smaller set of basis operations.41//42// It is intended as a building block for other PSTL backends that implement some operations more43// efficiently but may not want to define the full set of PSTL algorithms.44//45// This backend implements all the PSTL algorithms based on the following basis operations:46//47// find_if family48// --------------49// - find50// - find_if_not51// - any_of52// - all_of53// - none_of54// - is_partitioned55//56// for_each family57// ---------------58// - for_each_n59// - fill60// - fill_n61// - replace62// - replace_if63// - generate64// - generate_n65//66// merge family67// ------------68// No other algorithms based on merge69//70// stable_sort family71// ------------------72// - sort73//74// transform_reduce and transform_reduce_binary family75// ---------------------------------------------------76// - count_if77// - count78// - equal(3 legs)79// - equal80// - reduce81//82// transform and transform_binary family83// -------------------------------------84// - replace_copy_if85// - replace_copy86// - move87// - copy88// - copy_n89// - rotate_copy90//9192//////////////////////////////////////////////////////////////93// find_if family94//////////////////////////////////////////////////////////////95template <class _ExecutionPolicy>96struct __find<__default_backend_tag, _ExecutionPolicy> {97template <class _Policy, class _ForwardIterator, class _Tp>98[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator>99operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) const noexcept {100using _FindIf = __dispatch<__find_if, __current_configuration, _ExecutionPolicy>;101return _FindIf()(102__policy, std::move(__first), std::move(__last), [&](__iter_reference<_ForwardIterator> __element) {103return __element == __value;104});105}106};107108template <class _ExecutionPolicy>109struct __find_if_not<__default_backend_tag, _ExecutionPolicy> {110template <class _Policy, class _ForwardIterator, class _Pred>111[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator>112operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred&& __pred) const noexcept {113using _FindIf = __dispatch<__find_if, __current_configuration, _ExecutionPolicy>;114return _FindIf()(__policy, __first, __last, std::not_fn(std::forward<_Pred>(__pred)));115}116};117118template <class _ExecutionPolicy>119struct __any_of<__default_backend_tag, _ExecutionPolicy> {120template <class _Policy, class _ForwardIterator, class _Pred>121[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool>122operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred&& __pred) const noexcept {123using _FindIf = __dispatch<__find_if, __current_configuration, _ExecutionPolicy>;124auto __res = _FindIf()(__policy, __first, __last, std::forward<_Pred>(__pred));125if (!__res)126return nullopt;127return *__res != __last;128}129};130131template <class _ExecutionPolicy>132struct __all_of<__default_backend_tag, _ExecutionPolicy> {133template <class _Policy, class _ForwardIterator, class _Pred>134[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool>135operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred&& __pred) const noexcept {136using _AnyOf = __dispatch<__any_of, __current_configuration, _ExecutionPolicy>;137auto __res = _AnyOf()(__policy, __first, __last, [&](__iter_reference<_ForwardIterator> __value) {138return !__pred(__value);139});140if (!__res)141return nullopt;142return !*__res;143}144};145146template <class _ExecutionPolicy>147struct __none_of<__default_backend_tag, _ExecutionPolicy> {148template <class _Policy, class _ForwardIterator, class _Pred>149[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool>150operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred&& __pred) const noexcept {151using _AnyOf = __dispatch<__any_of, __current_configuration, _ExecutionPolicy>;152auto __res = _AnyOf()(__policy, __first, __last, std::forward<_Pred>(__pred));153if (!__res)154return nullopt;155return !*__res;156}157};158159template <class _ExecutionPolicy>160struct __is_partitioned<__default_backend_tag, _ExecutionPolicy> {161template <class _Policy, class _ForwardIterator, class _Pred>162[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool>163operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred&& __pred) const noexcept {164using _FindIfNot = __dispatch<__find_if_not, __current_configuration, _ExecutionPolicy>;165auto __maybe_first = _FindIfNot()(__policy, std::move(__first), std::move(__last), __pred);166if (__maybe_first == nullopt)167return nullopt;168169__first = *__maybe_first;170if (__first == __last)171return true;172++__first;173using _NoneOf = __dispatch<__none_of, __current_configuration, _ExecutionPolicy>;174return _NoneOf()(__policy, std::move(__first), std::move(__last), __pred);175}176};177178//////////////////////////////////////////////////////////////179// for_each family180//////////////////////////////////////////////////////////////181template <class _ExecutionPolicy>182struct __for_each_n<__default_backend_tag, _ExecutionPolicy> {183template <class _Policy, class _ForwardIterator, class _Size, class _Function>184[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>185operator()(_Policy&& __policy, _ForwardIterator __first, _Size __size, _Function __func) const noexcept {186if constexpr (__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {187using _ForEach = __dispatch<__for_each, __current_configuration, _ExecutionPolicy>;188_ForwardIterator __last = __first + __size;189return _ForEach()(__policy, std::move(__first), std::move(__last), std::move(__func));190} else {191// Otherwise, use the serial algorithm to avoid doing two passes over the input192std::for_each_n(std::move(__first), __size, std::move(__func));193return __empty{};194}195}196};197198template <class _ExecutionPolicy>199struct __fill<__default_backend_tag, _ExecutionPolicy> {200template <class _Policy, class _ForwardIterator, class _Tp>201[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>202operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Tp const& __value) const noexcept {203using _ForEach = __dispatch<__for_each, __current_configuration, _ExecutionPolicy>;204using _Ref = __iter_reference<_ForwardIterator>;205return _ForEach()(__policy, std::move(__first), std::move(__last), [&](_Ref __element) { __element = __value; });206}207};208209template <class _ExecutionPolicy>210struct __fill_n<__default_backend_tag, _ExecutionPolicy> {211template <class _Policy, class _ForwardIterator, class _Size, class _Tp>212[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>213operator()(_Policy&& __policy, _ForwardIterator __first, _Size __n, _Tp const& __value) const noexcept {214if constexpr (__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {215using _Fill = __dispatch<__fill, __current_configuration, _ExecutionPolicy>;216_ForwardIterator __last = __first + __n;217return _Fill()(__policy, std::move(__first), std::move(__last), __value);218} else {219// Otherwise, use the serial algorithm to avoid doing two passes over the input220std::fill_n(std::move(__first), __n, __value);221return optional<__empty>{__empty{}};222}223}224};225226template <class _ExecutionPolicy>227struct __replace<__default_backend_tag, _ExecutionPolicy> {228template <class _Policy, class _ForwardIterator, class _Tp>229[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>230operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Tp const& __old, _Tp const& __new)231const noexcept {232using _ReplaceIf = __dispatch<__replace_if, __current_configuration, _ExecutionPolicy>;233using _Ref = __iter_reference<_ForwardIterator>;234return _ReplaceIf()(235__policy, std::move(__first), std::move(__last), [&](_Ref __element) { return __element == __old; }, __new);236}237};238239template <class _ExecutionPolicy>240struct __replace_if<__default_backend_tag, _ExecutionPolicy> {241template <class _Policy, class _ForwardIterator, class _Pred, class _Tp>242[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> operator()(243_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred&& __pred, _Tp const& __new_value)244const noexcept {245using _ForEach = __dispatch<__for_each, __current_configuration, _ExecutionPolicy>;246using _Ref = __iter_reference<_ForwardIterator>;247return _ForEach()(__policy, std::move(__first), std::move(__last), [&](_Ref __element) {248if (__pred(__element))249__element = __new_value;250});251}252};253254template <class _ExecutionPolicy>255struct __generate<__default_backend_tag, _ExecutionPolicy> {256template <class _Policy, class _ForwardIterator, class _Generator>257[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>258operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Generator&& __gen) const noexcept {259using _ForEach = __dispatch<__for_each, __current_configuration, _ExecutionPolicy>;260using _Ref = __iter_reference<_ForwardIterator>;261return _ForEach()(__policy, std::move(__first), std::move(__last), [&](_Ref __element) { __element = __gen(); });262}263};264265template <class _ExecutionPolicy>266struct __generate_n<__default_backend_tag, _ExecutionPolicy> {267template <class _Policy, class _ForwardIterator, class _Size, class _Generator>268[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>269operator()(_Policy&& __policy, _ForwardIterator __first, _Size __n, _Generator&& __gen) const noexcept {270using _ForEachN = __dispatch<__for_each_n, __current_configuration, _ExecutionPolicy>;271using _Ref = __iter_reference<_ForwardIterator>;272return _ForEachN()(__policy, std::move(__first), __n, [&](_Ref __element) { __element = __gen(); });273}274};275276//////////////////////////////////////////////////////////////277// stable_sort family278//////////////////////////////////////////////////////////////279template <class _ExecutionPolicy>280struct __sort<__default_backend_tag, _ExecutionPolicy> {281template <class _Policy, class _RandomAccessIterator, class _Comp>282_LIBCPP_HIDE_FROM_ABI optional<__empty> operator()(283_Policy&& __policy, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp&& __comp) const noexcept {284using _StableSort = __dispatch<__stable_sort, __current_configuration, _ExecutionPolicy>;285return _StableSort()(__policy, std::move(__first), std::move(__last), std::forward<_Comp>(__comp));286}287};288289//////////////////////////////////////////////////////////////290// transform_reduce family291//////////////////////////////////////////////////////////////292template <class _ExecutionPolicy>293struct __count_if<__default_backend_tag, _ExecutionPolicy> {294template <class _Policy, class _ForwardIterator, class _Predicate>295[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__iter_diff_t<_ForwardIterator>> operator()(296_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate&& __pred) const noexcept {297using _TransformReduce = __dispatch<__transform_reduce, __current_configuration, _ExecutionPolicy>;298using _DiffT = __iter_diff_t<_ForwardIterator>;299using _Ref = __iter_reference<_ForwardIterator>;300return _TransformReduce()(301__policy, std::move(__first), std::move(__last), _DiffT{}, std::plus{}, [&](_Ref __element) -> _DiffT {302return __pred(__element) ? _DiffT(1) : _DiffT(0);303});304}305};306307template <class _ExecutionPolicy>308struct __count<__default_backend_tag, _ExecutionPolicy> {309template <class _Policy, class _ForwardIterator, class _Tp>310[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__iter_diff_t<_ForwardIterator>>311operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Tp const& __value) const noexcept {312using _CountIf = __dispatch<__count_if, __current_configuration, _ExecutionPolicy>;313using _Ref = __iter_reference<_ForwardIterator>;314return _CountIf()(__policy, std::move(__first), std::move(__last), [&](_Ref __element) -> bool {315return __element == __value;316});317}318};319320template <class _ExecutionPolicy>321struct __equal_3leg<__default_backend_tag, _ExecutionPolicy> {322template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Predicate>323[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool>324operator()(_Policy&& __policy,325_ForwardIterator1 __first1,326_ForwardIterator1 __last1,327_ForwardIterator2 __first2,328_Predicate&& __pred) const noexcept {329using _TransformReduce = __dispatch<__transform_reduce_binary, __current_configuration, _ExecutionPolicy>;330return _TransformReduce()(331__policy,332std::move(__first1),333std::move(__last1),334std::move(__first2),335true,336std::logical_and{},337std::forward<_Predicate>(__pred));338}339};340341template <class _ExecutionPolicy>342struct __equal<__default_backend_tag, _ExecutionPolicy> {343template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Predicate>344[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool>345operator()(_Policy&& __policy,346_ForwardIterator1 __first1,347_ForwardIterator1 __last1,348_ForwardIterator2 __first2,349_ForwardIterator2 __last2,350_Predicate&& __pred) const noexcept {351if constexpr (__has_random_access_iterator_category<_ForwardIterator1>::value &&352__has_random_access_iterator_category<_ForwardIterator2>::value) {353if (__last1 - __first1 != __last2 - __first2)354return false;355// Fall back to the 3 legged algorithm356using _Equal3Leg = __dispatch<__equal_3leg, __current_configuration, _ExecutionPolicy>;357return _Equal3Leg()(358__policy, std::move(__first1), std::move(__last1), std::move(__first2), std::forward<_Predicate>(__pred));359} else {360// If we don't have random access, fall back to the serial algorithm cause we can't do much361return std::equal(362std::move(__first1),363std::move(__last1),364std::move(__first2),365std::move(__last2),366std::forward<_Predicate>(__pred));367}368}369};370371template <class _ExecutionPolicy>372struct __reduce<__default_backend_tag, _ExecutionPolicy> {373template <class _Policy, class _ForwardIterator, class _Tp, class _BinaryOperation>374[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_Tp>375operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Tp __init, _BinaryOperation&& __op)376const noexcept {377using _TransformReduce = __dispatch<__transform_reduce, __current_configuration, _ExecutionPolicy>;378return _TransformReduce()(379__policy,380std::move(__first),381std::move(__last),382std::move(__init),383std::forward<_BinaryOperation>(__op),384__identity{});385}386};387388//////////////////////////////////////////////////////////////389// transform family390//////////////////////////////////////////////////////////////391template <class _ExecutionPolicy>392struct __replace_copy_if<__default_backend_tag, _ExecutionPolicy> {393template <class _Policy, class _ForwardIterator, class _ForwardOutIterator, class _Pred, class _Tp>394[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>395operator()(_Policy&& __policy,396_ForwardIterator __first,397_ForwardIterator __last,398_ForwardOutIterator __out_it,399_Pred&& __pred,400_Tp const& __new_value) const noexcept {401using _Transform = __dispatch<__transform, __current_configuration, _ExecutionPolicy>;402using _Ref = __iter_reference<_ForwardIterator>;403auto __res =404_Transform()(__policy, std::move(__first), std::move(__last), std::move(__out_it), [&](_Ref __element) {405return __pred(__element) ? __new_value : __element;406});407if (__res == nullopt)408return nullopt;409return __empty{};410}411};412413template <class _ExecutionPolicy>414struct __replace_copy<__default_backend_tag, _ExecutionPolicy> {415template <class _Policy, class _ForwardIterator, class _ForwardOutIterator, class _Tp>416[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>417operator()(_Policy&& __policy,418_ForwardIterator __first,419_ForwardIterator __last,420_ForwardOutIterator __out_it,421_Tp const& __old_value,422_Tp const& __new_value) const noexcept {423using _ReplaceCopyIf = __dispatch<__replace_copy_if, __current_configuration, _ExecutionPolicy>;424using _Ref = __iter_reference<_ForwardIterator>;425return _ReplaceCopyIf()(426__policy,427std::move(__first),428std::move(__last),429std::move(__out_it),430[&](_Ref __element) { return __element == __old_value; },431__new_value);432}433};434435// TODO: Use the std::copy/move shenanigans to forward to std::memmove436// Investigate whether we want to still forward to std::transform(policy)437// in that case for the execution::par part, or whether we actually want438// to run everything serially in that case.439template <class _ExecutionPolicy>440struct __move<__default_backend_tag, _ExecutionPolicy> {441template <class _Policy, class _ForwardIterator, class _ForwardOutIterator>442[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator>443operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _ForwardOutIterator __out_it)444const noexcept {445using _Transform = __dispatch<__transform, __current_configuration, _ExecutionPolicy>;446return _Transform()(__policy, std::move(__first), std::move(__last), std::move(__out_it), [&](auto&& __element) {447return std::move(__element);448});449}450};451452// TODO: Use the std::copy/move shenanigans to forward to std::memmove453template <class _ExecutionPolicy>454struct __copy<__default_backend_tag, _ExecutionPolicy> {455template <class _Policy, class _ForwardIterator, class _ForwardOutIterator>456[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator>457operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _ForwardOutIterator __out_it)458const noexcept {459using _Transform = __dispatch<__transform, __current_configuration, _ExecutionPolicy>;460return _Transform()(__policy, std::move(__first), std::move(__last), std::move(__out_it), __identity());461}462};463464template <class _ExecutionPolicy>465struct __copy_n<__default_backend_tag, _ExecutionPolicy> {466template <class _Policy, class _ForwardIterator, class _Size, class _ForwardOutIterator>467[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator>468operator()(_Policy&& __policy, _ForwardIterator __first, _Size __n, _ForwardOutIterator __out_it) const noexcept {469if constexpr (__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {470using _Copy = __dispatch<__copy, __current_configuration, _ExecutionPolicy>;471_ForwardIterator __last = __first + __n;472return _Copy()(__policy, std::move(__first), std::move(__last), std::move(__out_it));473} else {474// Otherwise, use the serial algorithm to avoid doing two passes over the input475return std::copy_n(std::move(__first), __n, std::move(__out_it));476}477}478};479480template <class _ExecutionPolicy>481struct __rotate_copy<__default_backend_tag, _ExecutionPolicy> {482template <class _Policy, class _ForwardIterator, class _ForwardOutIterator>483[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator>484operator()(_Policy&& __policy,485_ForwardIterator __first,486_ForwardIterator __middle,487_ForwardIterator __last,488_ForwardOutIterator __out_it) const noexcept {489using _Copy = __dispatch<__copy, __current_configuration, _ExecutionPolicy>;490auto __result_mid = _Copy()(__policy, __middle, std::move(__last), std::move(__out_it));491if (__result_mid == nullopt)492return nullopt;493return _Copy()(__policy, std::move(__first), std::move(__middle), *std::move(__result_mid));494}495};496497} // namespace __pstl498_LIBCPP_END_NAMESPACE_STD499500_LIBCPP_POP_MACROS501502#endif // _LIBCPP___PSTL_BACKENDS_DEFAULT_H503504505