Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adapt parallel algorithms to C++20 #4822

36 of 50 tasks
hkaiser opened this issue Jul 11, 2020 · 1 comment
36 of 50 tasks

Adapt parallel algorithms to C++20 #4822

hkaiser opened this issue Jul 11, 2020 · 1 comment


Copy link
Task lists! Give feedback

@hkaiser hkaiser commented Jul 11, 2020

Adapt our parallel algorithms to C++20 (

Here is the list of algorithms mandated by the standard:

  • adjacent_difference (@kmoham6 works on this)
  • adjacent_find (#4996)
  • all_of any_of none_of (#4859)
  • copy copy_if copy_n (#4821)
  • move (#4870)
  • count count_if (#4865)
  • equal (#4883) mismatch (#4884)
  • exclusive_scan (#5436)
  • inclusive_scan (#5439)
  • reduce (#4836)
  • transform (#5051)
  • fill fill_n (#4860)
  • find find_end find_first_of find_if find_if_not (#4885)
  • for_each for_each_n (#4867)
  • for_loop for_loop_n for_loop_strided for_loop_strided_n (#4911)
  • generate generate_n (#4896)
  • is_heap is_heap_until (#4965)
  • is_partitioned (#5006)
  • is_sorted is_sorted_until (#5025)
  • lexicographical_compare (#5350)
  • max_element min_element minmax_element (#5241)
  • make_heap (#4964)
  • partial_sort partial_sort_copy nth_element
  • sort
  • stable_sort
  • partition
  • partition_copy
  • stable_partition
  • remove remove_if (#5125)
  • remove_copy remove_copy_if (#5150)
  • replace replace_copy replace_copy_if replace_if (#5192)
  • reverse reverse_copy (#5225)
  • rotate (Chuanqui He works on this)
  • rotate_copy
  • search search_n (#5066)
  • set_difference set_intersection set_symmetric_difference set_union includes (#4970)
  • inplace_merge (#4970)
  • merge (#4970)
  • swap_ranges (#5449)
  • uninitialized_copy uninitialized_copy_n (#5371)
  • uninitialized_fill uninitialized_fill_n (#5402)
  • uninitialized_default_construct uninitialized_default_construct_n (#5415)
  • uninitialized_value_construct uninitialized_value_construct_n (#5416)
  • uninitialized_move uninitialized_move_n (#5389)
  • destroy destroy_n (#4869)
  • unique (#5458)
  • unique_copy (#5458)
  • transform_reduce (#4925)
  • transform_exclusive_scan (#5440) transform_inclusive_scan (#5444)
  • shift_left shift_right
@hkaiser hkaiser added this to Open Tickets in Standard Algorithms Jul 12, 2020
@hkaiser hkaiser added this to the 1.6.0 milestone Jul 26, 2020
@hkaiser hkaiser moved this from Open Tickets to Work in progress in Standard Algorithms Aug 4, 2020
@msimberg msimberg mentioned this issue Sep 4, 2020
@msimberg msimberg removed this from the 1.6.0 milestone Jan 5, 2021
Copy link

@gonidelis gonidelis commented Mar 6, 2021

How to adapt a parallel algorithm to C++20

  1. Render the old overload under namespace parallel deprecated (e.g. hpx::parallel::for_each), according to the hpx deprecation headers. Be careful on referring to the pending HPX release version.

  2. Change the base implementations (usually found as function objects under namespace hpx::parallel::v1::detail) in order to support iterator/sentinel pairs according to 3646 (just differenciate the type of last from the type of first).

  3. Change the result type (if needed) on the base implementations. Mind not to create conflicts with the deprecated overloads. If there is no other way, change the result type on the deprecated overloads, too.

  4. Add the C++20 overloads according to the C++20 Standard, using the tag_fallback/tag_fallback_invoke Customization Point Object (CPO) mechanism.

    1. If the algorithm has a segmented counterpart (under /libs/full/segmented_algorithms), provide the segmented overloads using tag_invoke instead of tag_fallback_invoke under namespace hpx::segmented and delete the dispatch functions (the ones with the underscore: e.g. for_each_).
  5. Adapt the unit tests so they use the overloads under hpx and hpx::ranges namespaces.

    1. Mind to add tests for the overloads without an ExPolicy, in every test category (test_<algorithm>, test_<algorithm>_exception, test_<algorithm>_bad_alloc).
    2. Add tests that check the newly introduced iterator-sentinel_value overloads (test_<algorithm>_sent).
  6. Provide docs for every given overload using the #if defined(DOXYGEN) - #else - #endif directives.

    1. Mind to pack the docs under namespace hpx or namespace hpx::ranges accordingly.
    2. Pay attention to the (possibly) altered result type.
    3. Be careful on documenting the overloads that do not have an ExPolicy. No parallelization is happening there.

Nitpicks and Tips

  • For a given algorithm, the adaptation takes place both under /libs/parallelism/algorithms/include/hpx/parallel/algorithms/<algorithm>.hpp (non ranges overloads) and under /libs/parallelism/algorithms/include/hpx/parallel/container_algorithms/<algorithm>.hpp (ranges overloads).
  • When documenting the adapted algorithms, cppreference is a good place to read about the effect of the algorithm.
  • When documenting an algorithm under hpx::ranges namespace, that takes a Rng as an input source, there are no inherent first and last values. Mind to declare at the top that first is equivalent to parallel::util::begin(rng) and last is equivalent to parallel::util::end(rng).
  • Disable clang-format for all the template parameters sections that include an HPX_CONCEPT_REQUIRES_ (// clang-format off/on) macro.
  • Check our result types header for the newly introduced C++20 result types.
  • We do not need any additional unit tests (overloads without an ExPolicy) for any of the _async tests.
  • Provide static_assertions that check the validity of the iterators for every given overload: the ones with no ExPolicy usually use input iterators while the parallel ones use forward/bidirectional/random-access iterators.
  • The previous bullet should be taken into consideration even for the Rng overloads. Here are some HPX custom facilities that provide an iterator-based interface for the Rng type.
  • std::pair usually changes to hpx::parallel::util::in_out_result and std::tuple changes to hpx::parallel::util::in_in_out_result. std::distance, occasionally used on the base implementations, changes to detail::distance in order to support iterator/sentinel pairs.
  • In order to test the iterator/sentinel-value case, you will need to include in the testing file, the iter_sent header like #include <hpx/iterator_support/tests/iter_sent.hpp>, which implements a custom sentinel facility.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Standard Algorithms
Work in progress
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants