Skip to content

Commit b049fc0

Browse files
committed
[libc++][PSTL] Implement std::copy{,_n}
Reviewed By: ldionne, #libc Spies: jloser, libcxx-commits Differential Revision: https://reviews.llvm.org/D149706
1 parent f986987 commit b049fc0

File tree

7 files changed

+265
-44
lines changed

7 files changed

+265
-44
lines changed

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ set(files
7979
__algorithm/pstl_backends/cpu_backends/for_each.h
8080
__algorithm/pstl_backends/cpu_backends/serial.h
8181
__algorithm/pstl_backends/cpu_backends/transform.h
82+
__algorithm/pstl_copy.h
8283
__algorithm/pstl_fill.h
8384
__algorithm/pstl_find.h
8485
__algorithm/pstl_for_each.h
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef _LIBCPP___ALGORITHM_PSTL_COPY_H
10+
#define _LIBCPP___ALGORITHM_PSTL_COPY_H
11+
12+
#include <__algorithm/copy_n.h>
13+
#include <__algorithm/pstl_transform.h>
14+
#include <__config>
15+
#include <__functional/identity.h>
16+
#include <__iterator/iterator_traits.h>
17+
#include <__type_traits/is_constant_evaluated.h>
18+
#include <__type_traits/is_execution_policy.h>
19+
#include <__type_traits/is_trivially_copyable.h>
20+
21+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
22+
# pragma GCC system_header
23+
#endif
24+
25+
#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17
26+
27+
_LIBCPP_BEGIN_NAMESPACE_STD
28+
29+
// TODO: Use the std::copy/move shenanigans to forward to std::memmove
30+
31+
template <class _ExecutionPolicy,
32+
class _ForwardIterator,
33+
class _ForwardOutIterator,
34+
enable_if_t<is_execution_policy_v<__remove_cvref_t<_ExecutionPolicy>>, int> = 0>
35+
_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator
36+
copy(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _ForwardOutIterator __result) {
37+
return std::transform(__policy, __first, __last, __result, __identity());
38+
}
39+
40+
template <class _ExecutionPolicy,
41+
class _ForwardIterator,
42+
class _ForwardOutIterator,
43+
class _Size,
44+
enable_if_t<is_execution_policy_v<__remove_cvref_t<_ExecutionPolicy>>, int> = 0>
45+
_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator
46+
copy_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __n, _ForwardOutIterator __result) {
47+
if constexpr (__is_cpp17_random_access_iterator<_ForwardIterator>::value)
48+
return std::copy(__policy, __first, __first + __n, __result);
49+
else
50+
return std::copy_n(__first, __n, __result);
51+
}
52+
53+
_LIBCPP_END_NAMESPACE_STD
54+
55+
#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17
56+
57+
#endif // _LIBCPP___ALGORITHM_PSTL_COPY_H

libcxx/include/__pstl/internal/glue_algorithm_defs.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -112,14 +112,6 @@ __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardItera
112112

113113
// [alg.copy]
114114

115-
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2>
116-
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
117-
copy(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __result);
118-
119-
template <class _ExecutionPolicy, class _ForwardIterator1, class _Size, class _ForwardIterator2>
120-
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
121-
copy_n(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _Size __n, _ForwardIterator2 __result);
122-
123115
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Predicate>
124116
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
125117
copy_if(_ExecutionPolicy&& __exec,

libcxx/include/__pstl/internal/glue_algorithm_impl.h

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -178,42 +178,6 @@ __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardItera
178178

179179
// [alg.copy]
180180

181-
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2>
182-
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
183-
copy(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __result) {
184-
auto __dispatch_tag = __pstl::__internal::__select_backend(__exec, __first, __result);
185-
186-
using __is_vector = typename decltype(__dispatch_tag)::__is_vector;
187-
188-
return __pstl::__internal::__pattern_walk2_brick(
189-
__dispatch_tag,
190-
std::forward<_ExecutionPolicy>(__exec),
191-
__first,
192-
__last,
193-
__result,
194-
[](_ForwardIterator1 __begin, _ForwardIterator1 __end, _ForwardIterator2 __res) {
195-
return __pstl::__internal::__brick_copy(__begin, __end, __res, __is_vector{});
196-
});
197-
}
198-
199-
template <class _ExecutionPolicy, class _ForwardIterator1, class _Size, class _ForwardIterator2>
200-
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
201-
copy_n(_ExecutionPolicy&& __exec, _ForwardIterator1 __first, _Size __n, _ForwardIterator2 __result) {
202-
auto __dispatch_tag = __pstl::__internal::__select_backend(__exec, __first, __result);
203-
204-
using __is_vector = typename decltype(__dispatch_tag)::__is_vector;
205-
206-
return __pstl::__internal::__pattern_walk2_brick_n(
207-
__dispatch_tag,
208-
std::forward<_ExecutionPolicy>(__exec),
209-
__first,
210-
__n,
211-
__result,
212-
[](_ForwardIterator1 __begin, _Size __sz, _ForwardIterator2 __res) {
213-
return __pstl::__internal::__brick_copy_n(__begin, __sz, __res, __is_vector{});
214-
});
215-
}
216-
217181
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _Predicate>
218182
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
219183
copy_if(_ExecutionPolicy&& __exec,

libcxx/include/algorithm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1789,6 +1789,7 @@ template <class BidirectionalIterator, class Compare>
17891789
#include <__algorithm/pop_heap.h>
17901790
#include <__algorithm/prev_permutation.h>
17911791
#include <__algorithm/pstl_any_all_none_of.h>
1792+
#include <__algorithm/pstl_copy.h>
17921793
#include <__algorithm/pstl_fill.h>
17931794
#include <__algorithm/pstl_find.h>
17941795
#include <__algorithm/pstl_for_each.h>
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03, c++11, c++14
10+
11+
// REQUIRES: with-pstl
12+
13+
// <algorithm>
14+
15+
// template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2>
16+
// ForwardIterator2 copy(ExecutionPolicy&& policy,
17+
// ForwardIterator1 first, ForwardIterator1 last,
18+
// ForwardIterator2 result);
19+
20+
#include <algorithm>
21+
#include <vector>
22+
23+
#include "test_macros.h"
24+
#include "test_execution_policies.h"
25+
#include "test_iterators.h"
26+
27+
EXECUTION_POLICY_SFINAE_TEST(copy);
28+
29+
static_assert(sfinae_test_copy<int, int*, int*, bool (*)(int)>);
30+
static_assert(!sfinae_test_copy<std::execution::parallel_policy, int*, int*, int>);
31+
32+
template <class Iter1, class Iter2>
33+
struct TestInt {
34+
template <class Policy>
35+
void operator()(Policy&& policy) {
36+
// simple test
37+
for (const int size : {0, 1, 2, 100, 350}) {
38+
std::vector<int> a(size);
39+
for (int i = 0; i != size; ++i)
40+
a[i] = i + 1;
41+
42+
std::vector<int> out(std::size(a));
43+
decltype(auto) ret =
44+
std::copy(policy, Iter1(std::data(a)), Iter1(std::data(a) + std::size(a)), Iter2(std::data(out)));
45+
static_assert(std::is_same_v<decltype(ret), Iter2>);
46+
assert(base(ret) == std::data(out) + std::size(out));
47+
for (int i = 0; i != size; ++i)
48+
assert(out[i] == i + 1);
49+
}
50+
}
51+
};
52+
53+
struct CopiedToTester {
54+
bool copied_to = false;
55+
CopiedToTester() = default;
56+
CopiedToTester(const CopiedToTester&) {}
57+
CopiedToTester& operator=(const CopiedToTester&) {
58+
assert(!copied_to);
59+
copied_to = true;
60+
return *this;
61+
}
62+
~CopiedToTester() = default;
63+
};
64+
65+
template <class Iter1, class Iter2>
66+
struct TestNonTrivial {
67+
template <class Policy>
68+
void operator()(Policy&& policy) {
69+
// simple test
70+
for (const int size : {0, 1, 2, 100, 350}) {
71+
std::vector<CopiedToTester> a(size);
72+
73+
std::vector<CopiedToTester> out(std::size(a));
74+
auto ret = std::copy(policy, Iter1(std::data(a)), Iter1(std::data(a) + std::size(a)), Iter2(std::data(out)));
75+
assert(base(ret) == std::data(out) + std::size(out));
76+
assert(std::all_of(std::begin(out), std::end(out), [](CopiedToTester& t) { return t.copied_to; }));
77+
assert(std::none_of(std::begin(a), std::end(a), [](CopiedToTester& t) { return t.copied_to; }));
78+
}
79+
}
80+
};
81+
82+
struct TestIteratorsNonTrivial {
83+
template <class Iter2>
84+
void operator()() {}
85+
};
86+
87+
int main(int, char**) {
88+
types::for_each(types::forward_iterator_list<int*>{}, types::apply_type_identity{[](auto v) {
89+
using Iter = typename decltype(v)::type;
90+
types::for_each(
91+
types::forward_iterator_list<int*>{},
92+
TestIteratorWithPolicies< types::partial_instantiation<TestInt, Iter>::template apply>{});
93+
}});
94+
95+
types::for_each(
96+
types::forward_iterator_list<CopiedToTester*>{}, types::apply_type_identity{[](auto v) {
97+
using Iter = typename decltype(v)::type;
98+
types::for_each(
99+
types::forward_iterator_list<CopiedToTester*>{},
100+
TestIteratorWithPolicies< types::partial_instantiation<TestNonTrivial, Iter>::template apply>{});
101+
}});
102+
103+
return 0;
104+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03, c++11, c++14
10+
11+
// REQUIRES: with-pstl
12+
13+
// <algorithm>
14+
15+
// template<class ExecutionPolicy, class ForwardIterator1, class Size, class ForwardIterator2>
16+
// ForwardIterator2 copy_n(ExecutionPolicy&& exec,
17+
// ForwardIterator1 first, Size n,
18+
// ForwardIterator2 result);
19+
20+
#include <algorithm>
21+
#include <vector>
22+
23+
#include "test_macros.h"
24+
#include "test_execution_policies.h"
25+
#include "test_iterators.h"
26+
27+
EXECUTION_POLICY_SFINAE_TEST(copy_n);
28+
29+
static_assert(sfinae_test_copy_n<int, int*, int*, bool (*)(int)>);
30+
static_assert(!sfinae_test_copy_n<std::execution::parallel_policy, int*, int*, int>);
31+
32+
template <class Iter1, class Iter2>
33+
struct TestInt {
34+
template <class Policy>
35+
void operator()(Policy&& policy) {
36+
// simple test
37+
for (const int size : {0, 1, 2, 100, 350}) {
38+
std::vector<int> a(size);
39+
for (int i = 0; i != size; ++i)
40+
a[i] = i + 1;
41+
42+
std::vector<int> out(std::size(a));
43+
decltype(auto) ret = std::copy_n(policy, Iter1(std::data(a)), std::size(a), Iter2(std::data(out)));
44+
static_assert(std::is_same_v<decltype(ret), Iter2>);
45+
assert(base(ret) == std::data(out) + std::size(out));
46+
for (int i = 0; i != size; ++i)
47+
assert(out[i] == i + 1);
48+
}
49+
}
50+
};
51+
52+
struct TestIteratorsInt {
53+
template <class Iter2>
54+
void operator()() {
55+
types::for_each(types::forward_iterator_list<int*>{},
56+
TestIteratorWithPolicies<types::partial_instantiation<TestInt, Iter2>::template apply>{});
57+
}
58+
};
59+
60+
struct CopiedToTester {
61+
bool copied_to = false;
62+
CopiedToTester() = default;
63+
CopiedToTester(const CopiedToTester&) {}
64+
CopiedToTester& operator=(const CopiedToTester&) {
65+
assert(!copied_to);
66+
copied_to = true;
67+
return *this;
68+
}
69+
~CopiedToTester() = default;
70+
};
71+
72+
template <class Iter1, class Iter2>
73+
struct TestNonTrivial {
74+
template <class Policy>
75+
void operator()(Policy&& policy) {
76+
// simple test
77+
for (const int size : {0, 1, 2, 100, 350}) {
78+
std::vector<CopiedToTester> a(size);
79+
80+
std::vector<CopiedToTester> out(std::size(a));
81+
auto ret = std::copy_n(policy, Iter1(std::data(a)), std::size(a), Iter2(std::data(out)));
82+
assert(base(ret) == std::data(out) + std::size(out));
83+
assert(std::all_of(std::begin(out), std::end(out), [](CopiedToTester& t) { return t.copied_to; }));
84+
assert(std::none_of(std::begin(a), std::end(a), [](CopiedToTester& t) { return t.copied_to; }));
85+
}
86+
}
87+
};
88+
89+
struct TestIteratorsNonTrivial {
90+
template <class Iter2>
91+
void operator()() {
92+
types::for_each(types::forward_iterator_list<CopiedToTester*>{},
93+
TestIteratorWithPolicies<types::partial_instantiation<TestNonTrivial, Iter2>::template apply>{});
94+
}
95+
};
96+
97+
int main(int, char**) {
98+
types::for_each(types::forward_iterator_list<int*>{}, TestIteratorsInt{});
99+
types::for_each(types::forward_iterator_list<CopiedToTester*>{}, TestIteratorsNonTrivial{});
100+
101+
return 0;
102+
}

0 commit comments

Comments
 (0)