From 92b7277b5a32b9762b70b853aeb233b82beeaad0 Mon Sep 17 00:00:00 2001 From: Adam Lugowski Date: Wed, 15 Nov 2023 20:14:06 -0800 Subject: [PATCH] Add std::copy_n --- README.md | 16 ++++++++-------- include/poolstl/algorithm | 15 +++++++++++++++ tests/poolstl_test.cpp | 19 +++++++++++++++++++ 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 24bc12e..3601c3a 100644 --- a/README.md +++ b/README.md @@ -16,12 +16,12 @@ It is not meant as a full implementation, only the basics are expected to be cov Supports C++11 and higher, C++17 preferred. Tested in CI on GCC 7+, Clang/LLVM 5+, Apple Clang, MSVC. -## Implemented algorithms +## Implemented Algorithms Algorithms are added on an as-needed basis. If you need one [open an issue](https://github.com/alugowski/poolSTL/issues) or contribute a PR. ### `` * [all_of](https://en.cppreference.com/w/cpp/algorithm/all_of), [any_of](https://en.cppreference.com/w/cpp/algorithm/any_of), [none_of](https://en.cppreference.com/w/cpp/algorithm/none_of) -* [copy](https://en.cppreference.com/w/cpp/algorithm/copy) +* [copy](https://en.cppreference.com/w/cpp/algorithm/copy), [copy_n](https://en.cppreference.com/w/cpp/algorithm/copy_n) * [fill](https://en.cppreference.com/w/cpp/algorithm/fill), [fill_n](https://en.cppreference.com/w/cpp/algorithm/fill_n) * [find](https://en.cppreference.com/w/cpp/algorithm/find), [find_if](https://en.cppreference.com/w/cpp/algorithm/find_if), [find_if_not](https://en.cppreference.com/w/cpp/algorithm/find_if_not) * [for_each](https://en.cppreference.com/w/cpp/algorithm/for_each), [for_each_n](https://en.cppreference.com/w/cpp/algorithm/for_each_n) @@ -49,21 +49,21 @@ int main() { std::vector v = {0, 1, 2, 3, 4, 5}; auto sum = std::reduce(poolstl::par, v.cbegin(), v.cend()); // ^^^^^^^^^^^^ - // Just add this to make your code parallel. + // Add this to make your code parallel. std::cout << "Sum=" << sum << std::endl; return 0; } ``` -### Pool control +### Controlling Thread Pool Size The thread pool used by `poolstl::par` is managed internally by poolSTL. It is started on first use. -Full control over thread count, startup/shutdown, etc. with your own [thread pool](https://github.com/alugowski/task-thread-pool) -and `poolstl::par_pool`: +Use your own [thread pool](https://github.com/alugowski/task-thread-pool) +with `poolstl::par_pool` for full control over thread count, startup/shutdown, etc.: ```c++ -task_thread_pool::task_thread_pool pool; +task_thread_pool::task_thread_pool pool{4}; // 4 threads std::reduce(poolstl::par_pool(pool), v.cbegin(), v.cbegin()); ``` @@ -127,7 +127,7 @@ reduce(poolstl::par)/real_time 4.21 ms reduce(std::execution::par)/real_time 3.55 ms 3.09 ms 199 ``` -# poolSTL as `std::execution::par` substitute +# poolSTL as `std::execution::par` Substitute **USE AT YOUR OWN RISK!** Two-line hack for missing compiler support. A no-op on compilers with support. diff --git a/include/poolstl/algorithm b/include/poolstl/algorithm index 9973eb8..48ac082 100644 --- a/include/poolstl/algorithm +++ b/include/poolstl/algorithm @@ -25,6 +25,21 @@ namespace std { poolstl::internal::get_futures(futures); } + /** + * NOTE: Iterators are expected to be random access. + * See std::copy_n https://en.cppreference.com/w/cpp/algorithm/copy_n + */ + template + poolstl::internal::enable_if_poolstl_execution_policy + copy_n(ExecPolicy &&policy, RandIt1 first, Size n, RandIt2 dest) { + if (n <= 0) { + return dest; + } + RandIt1 last = poolstl::internal::advanced(first, n); + std::copy(std::forward(policy), first, last, dest); + return poolstl::internal::advanced(dest, n); + } + /** * NOTE: Iterators are expected to be random access. * See std::fill https://en.cppreference.com/w/cpp/algorithm/fill diff --git a/tests/poolstl_test.cpp b/tests/poolstl_test.cpp index e28acee..5642326 100644 --- a/tests/poolstl_test.cpp +++ b/tests/poolstl_test.cpp @@ -72,6 +72,25 @@ TEST_CASE("copy", "[alg][algorithm]") { } } +TEST_CASE("copy_n", "[alg][algorithm]") { + for (auto num_threads : test_thread_counts) { + ttp::task_thread_pool pool(num_threads); + + auto vec_size = *std::max_element(test_arr_sizes.cbegin(), test_arr_sizes.cend()); + for (auto num_iters : test_arr_sizes) { + auto source = iota_vector(num_iters); + std::vector dest1(vec_size); + std::vector dest2(vec_size); + + std::copy_n(source.cbegin(), num_iters, dest1.begin()); + std::copy_n(poolstl::par_pool(pool), source.cbegin(), num_iters, dest2.begin()); + + REQUIRE(dest1 == dest2); + } + } +} + + TEST_CASE("fill", "[alg][algorithm]") { for (auto num_threads : test_thread_counts) { ttp::task_thread_pool pool(num_threads);