diff --git a/libs/algorithms/CMakeLists.txt b/libs/algorithms/CMakeLists.txt index 28cbc40257c4..e87bec1421d9 100644 --- a/libs/algorithms/CMakeLists.txt +++ b/libs/algorithms/CMakeLists.txt @@ -90,6 +90,7 @@ set(algorithms_headers hpx/parallel/container_algorithms/is_heap.hpp hpx/parallel/container_algorithms/merge.hpp hpx/parallel/container_algorithms/minmax.hpp + hpx/parallel/container_algorithms/mismatch.hpp hpx/parallel/container_algorithms/move.hpp hpx/parallel/container_algorithms/partition.hpp hpx/parallel/container_algorithms/reduce.hpp diff --git a/libs/algorithms/include/hpx/parallel/algorithms/mismatch.hpp b/libs/algorithms/include/hpx/parallel/algorithms/mismatch.hpp index 91600808a50b..7e962cad30c3 100644 --- a/libs/algorithms/include/hpx/parallel/algorithms/mismatch.hpp +++ b/libs/algorithms/include/hpx/parallel/algorithms/mismatch.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2017 Hartmut Kaiser +// Copyright (c) 2007-2020 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -8,6 +8,171 @@ #pragma once +#if defined(DOXYGEN) +namespace hpx { + // clang-format off + + /// Returns true if the range [first1, last1) is mismatch to the range + /// [first2, last2), and false otherwise. + /// + /// \note Complexity: At most min(last1 - first1, last2 - first2) + /// applications of the predicate \a f. If \a FwdIter1 + /// and \a FwdIter2 meet the requirements of \a RandomAccessIterator + /// and (last1 - first1) != (last2 - first2) then no applications + /// of the predicate \a f are made. + /// + /// \tparam ExPolicy The type of the execution policy to use (deduced). + /// It describes the manner in which the execution + /// of the algorithm may be parallelized and the manner + /// in which it executes the assignments. + /// \tparam FwdIter1 The type of the source iterators used for the + /// first range (deduced). + /// This iterator type must meet the requirements of an + /// forward iterator. + /// \tparam FwdIter2 The type of the source iterators used for the + /// second range (deduced). + /// This iterator type must meet the requirements of an + /// forward iterator. + /// \tparam Pred The type of an optional function/function object to use. + /// Unlike its sequential form, the parallel + /// overload of \a mismatch requires \a Pred to meet the + /// requirements of \a CopyConstructible. This defaults + /// to std::equal_to<> + /// + /// \param policy The execution policy to use for the scheduling of + /// the iterations. + /// \param first1 Refers to the beginning of the sequence of elements + /// of the first range the algorithm will be applied to. + /// \param last1 Refers to the end of the sequence of elements of + /// the first range the algorithm will be applied to. + /// \param first2 Refers to the beginning of the sequence of elements + /// of the second range the algorithm will be applied to. + /// \param last2 Refers to the end of the sequence of elements of + /// the second range the algorithm will be applied to. + /// \param op The binary predicate which returns true if the + /// elements should be treated as mismatch. The signature + /// of the predicate function should be equivalent to + /// the following: + /// \code + /// bool pred(const Type1 &a, const Type2 &b); + /// \endcode \n + /// The signature does not need to have const &, but + /// the function must not modify the objects passed to + /// it. The types \a Type1 and \a Type2 must be such + /// that objects of types \a FwdIter1 and \a FwdIter2 can + /// be dereferenced and then implicitly converted to + /// \a Type1 and \a Type2 respectively + /// + /// The comparison operations in the parallel \a mismatch algorithm invoked + /// with an execution policy object of type \a sequenced_policy + /// execute in sequential order in the calling thread. + /// + /// The comparison operations in the parallel \a mismatch algorithm invoked + /// with an execution policy object of type \a parallel_policy + /// or \a parallel_task_policy are permitted to execute in an unordered + /// fashion in unspecified threads, and indeterminately sequenced + /// within each thread. + /// + /// \note The two ranges are considered mismatch if, for every iterator + /// i in the range [first1,last1), *i mismatchs *(first2 + (i - first1)). + /// This overload of mismatch uses operator== to determine if two + /// elements are mismatch. + /// + /// \returns The \a mismatch algorithm returns a \a hpx::future if the + /// execution policy is of type + /// \a sequenced_task_policy or + /// \a parallel_task_policy and + /// returns \a bool otherwise. + /// The \a mismatch algorithm returns true if the elements in the + /// two ranges are mismatch, otherwise it returns false. + /// If the length of the range [first1, last1) does not mismatch + /// the length of the range [first2, last2), it returns false. + /// + template + typename util::detail::algorithm_result< + ExPolicy, std::pair>::type + mismatch(ExPolicy&& policy, FwdIter1 first1, FwdIter1 last1, + FwdIter2 first2, FwdIter2 last2, Pred&& op = Pred()); + + /// Returns std::pair with iterators to the first two non-equivalent + /// elements. + /// + /// \note Complexity: At most \a last1 - \a first1 applications of the + /// predicate \a f. + /// + /// \tparam ExPolicy The type of the execution policy to use (deduced). + /// It describes the manner in which the execution + /// of the algorithm may be parallelized and the manner + /// in which it executes the assignments. + /// \tparam FwdIter1 The type of the source iterators used for the + /// first range (deduced). + /// This iterator type must meet the requirements of an + /// forward iterator. + /// \tparam FwdIter2 The type of the source iterators used for the + /// second range (deduced). + /// This iterator type must meet the requirements of an + /// forward iterator. + /// \tparam Pred The type of an optional function/function object to use. + /// Unlike its sequential form, the parallel + /// overload of \a mismatch requires \a Pred to meet the + /// requirements of \a CopyConstructible. This defaults + /// to std::equal_to<> + /// + /// \param policy The execution policy to use for the scheduling of + /// the iterations. + /// \param first1 Refers to the beginning of the sequence of elements + /// of the first range the algorithm will be applied to. + /// \param last1 Refers to the end of the sequence of elements of + /// the first range the algorithm will be applied to. + /// \param first2 Refers to the beginning of the sequence of elements + /// of the second range the algorithm will be applied to. + /// \param op The binary predicate which returns true if the + /// elements should be treated as mismatch. The signature + /// of the predicate function should be equivalent to + /// the following: + /// \code + /// bool pred(const Type1 &a, const Type2 &b); + /// \endcode \n + /// The signature does not need to have const &, but + /// the function must not modify the objects passed to + /// it. The types \a Type1 and \a Type2 must be such + /// that objects of types \a FwdIter1 and \a FwdIter2 can + /// be dereferenced and then implicitly converted to + /// \a Type1 and \a Type2 respectively + /// + /// The comparison operations in the parallel \a mismatch algorithm invoked + /// with an execution policy object of type \a sequenced_policy + /// execute in sequential order in the calling thread. + /// + /// The comparison operations in the parallel \a mismatch algorithm invoked + /// with an execution policy object of type \a parallel_policy + /// or \a parallel_task_policy are permitted to execute in an unordered + /// fashion in unspecified threads, and indeterminately sequenced + /// within each thread. + /// + /// \returns The \a mismatch algorithm returns a + /// \a hpx::future > if the + /// execution policy is of type + /// \a sequenced_task_policy or + /// \a parallel_task_policy and + /// returns \a std::pair otherwise. + /// The \a mismatch algorithm returns the first mismatching pair + /// of elements from two ranges: one defined by [first1, last1) + /// and another defined by [first2, last2). + /// + template + typename util::detail::algorithm_result< + ExPolicy, std::pair>::type + mismatch(ExPolicy&& policy, FwdIter1 first1, FwdIter1 last1, FwdIter2 first2, + Pred&& op = Pred()); + + // clang-format on +} // namespace hpx + +#else // DOXYGEN + #include #include #include @@ -15,9 +180,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -31,51 +198,62 @@ namespace hpx { namespace parallel { inline namespace v1 { /////////////////////////////////////////////////////////////////////////// // mismatch (binary) namespace detail { - /// \cond NOINTERNAL - template - std::pair sequential_mismatch_binary( - InIter1 first1, InIter1 last1, InIter2 first2, InIter2 last2, F&& f) + + /////////////////////////////////////////////////////////////////////// + template + util::in_in_result sequential_mismatch_binary( + Iter1 first1, Sent1 last1, Iter2 first2, Sent2 last2, F&& f, + Proj1&& proj1, Proj2&& proj2) { while (first1 != last1 && first2 != last2 && - hpx::util::invoke(f, *first1, *first2)) + hpx::util::invoke(f, hpx::util::invoke(proj1, *first1), + hpx::util::invoke(proj2, *first2))) { ++first1, ++first2; } - return std::make_pair(first1, first2); + return {first1, first2}; } - template - struct mismatch_binary : public detail::algorithm, T> + template + struct mismatch_binary + : public detail::algorithm, IterPair> { mismatch_binary() : mismatch_binary::algorithm("mismatch_binary") { } - template - static T sequential(ExPolicy, InIter1 first1, InIter1 last1, - InIter2 first2, InIter2 last2, F&& f) + template + static util::in_in_result sequential(ExPolicy, + Iter1 first1, Sent1 last1, Iter2 first2, Sent2 last2, F&& f, + Proj1&& proj1, Proj2&& proj2) { - return sequential_mismatch_binary( - first1, last1, first2, last2, std::forward(f)); + return sequential_mismatch_binary(first1, last1, first2, last2, + std::forward(f), std::forward(proj1), + std::forward(proj2)); } - template - static typename util::detail::algorithm_result::type - parallel(ExPolicy&& policy, FwdIter1 first1, FwdIter1 last1, - FwdIter2 first2, FwdIter2 last2, F&& f) + template + static typename util::detail::algorithm_result>::type + parallel(ExPolicy&& policy, Iter1 first1, Sent1 last1, Iter2 first2, + Sent2 last2, F&& f, Proj1&& proj1, Proj2&& proj2) { if (first1 == last1 || first2 == last2) { - return util::detail::algorithm_result::get( - std::make_pair(first1, first2)); + return util::detail::algorithm_result>:: + get(util::in_in_result{first1, first2}); } - typedef typename std::iterator_traits::difference_type + typedef typename std::iterator_traits::difference_type difference_type1; - difference_type1 count1 = std::distance(first1, last1); + difference_type1 count1 = detail::distance(first1, last1); // The specification of std::mismatch(_binary) states that if FwdIter1 // and FwdIter2 meet the requirements of RandomAccessIterator and @@ -84,28 +262,33 @@ namespace hpx { namespace parallel { inline namespace v1 { // // We perform this check for any iterator type better than input // iterators. This could turn into a QoI issue. - typedef typename std::iterator_traits::difference_type + typedef typename std::iterator_traits::difference_type difference_type2; - difference_type2 count2 = std::distance(first2, last2); + difference_type2 count2 = detail::distance(first2, last2); if (count1 != count2) { - return util::detail::algorithm_result::get( - std::make_pair(first1, first2)); + return util::detail::algorithm_result>:: + get(util::in_in_result{first1, first2}); } - typedef hpx::util::zip_iterator - zip_iterator; + typedef hpx::util::zip_iterator zip_iterator; typedef typename zip_iterator::reference reference; util::cancellation_token tok(count1); - auto f1 = [tok, f = std::forward(f)](zip_iterator it, - std::size_t part_count, + auto f1 = [tok, f = std::forward(f), + proj1 = std::forward(proj1), + proj2 = std::forward(proj2)]( + zip_iterator it, std::size_t part_count, std::size_t base_idx) mutable -> void { util::loop_idx_n(base_idx, it, part_count, tok, - [&f, &tok](reference t, std::size_t i) { - if (!hpx::util::invoke(f, hpx::util::get<0>(t), - hpx::util::get<1>(t))) + [&f, &proj1, &proj2, &tok](reference t, std::size_t i) { + if (!hpx::util::invoke(f, + hpx::util::invoke( + proj1, hpx::util::get<0>(t)), + hpx::util::invoke( + proj2, hpx::util::get<1>(t)))) { tok.cancel(i); } @@ -113,7 +296,7 @@ namespace hpx { namespace parallel { inline namespace v1 { }; auto f2 = [=](std::vector>&&) mutable - -> std::pair { + -> util::in_in_result { difference_type1 mismatched = static_cast(tok.get_data()); if (mismatched != count1) @@ -126,99 +309,52 @@ namespace hpx { namespace parallel { inline namespace v1 { first1 = last1; first2 = last2; } - return std::make_pair(first1, first2); + return {first1, first2}; }; - return util::partitioner::call_with_index( - std::forward(policy), + return util::partitioner, + void>::call_with_index(std::forward(policy), hpx::util::make_zip_iterator(first1, first2), count1, 1, std::move(f1), std::move(f2)); } }; - /// \endcond + + /////////////////////////////////////////////////////////////////////// + template + std::pair get_pair(util::in_in_result&& p) + { + return {p.in1, p.in2}; + } + + template + hpx::future> get_pair( + hpx::future>&& f) + { + return lcos::make_future>(std::move(f), + [](util::in_in_result&& p) -> std::pair { + return {std::move(p.in1), std::move(p.in2)}; + }); + } } // namespace detail - /// Returns true if the range [first1, last1) is mismatch to the range - /// [first2, last2), and false otherwise. - /// - /// \note Complexity: At most min(last1 - first1, last2 - first2) - /// applications of the predicate \a f. If \a FwdIter1 - /// and \a FwdIter2 meet the requirements of \a RandomAccessIterator - /// and (last1 - first1) != (last2 - first2) then no applications - /// of the predicate \a f are made. - /// - /// \tparam ExPolicy The type of the execution policy to use (deduced). - /// It describes the manner in which the execution - /// of the algorithm may be parallelized and the manner - /// in which it executes the assignments. - /// \tparam FwdIter1 The type of the source iterators used for the - /// first range (deduced). - /// This iterator type must meet the requirements of an - /// forward iterator. - /// \tparam FwdIter2 The type of the source iterators used for the - /// second range (deduced). - /// This iterator type must meet the requirements of an - /// forward iterator. - /// \tparam Pred The type of an optional function/function object to use. - /// Unlike its sequential form, the parallel - /// overload of \a mismatch requires \a Pred to meet the - /// requirements of \a CopyConstructible. This defaults - /// to std::equal_to<> - /// - /// \param policy The execution policy to use for the scheduling of - /// the iterations. - /// \param first1 Refers to the beginning of the sequence of elements - /// of the first range the algorithm will be applied to. - /// \param last1 Refers to the end of the sequence of elements of - /// the first range the algorithm will be applied to. - /// \param first2 Refers to the beginning of the sequence of elements - /// of the second range the algorithm will be applied to. - /// \param last2 Refers to the end of the sequence of elements of - /// the second range the algorithm will be applied to. - /// \param op The binary predicate which returns true if the - /// elements should be treated as mismatch. The signature - /// of the predicate function should be equivalent to - /// the following: - /// \code - /// bool pred(const Type1 &a, const Type2 &b); - /// \endcode \n - /// The signature does not need to have const &, but - /// the function must not modify the objects passed to - /// it. The types \a Type1 and \a Type2 must be such - /// that objects of types \a FwdIter1 and \a FwdIter2 can - /// be dereferenced and then implicitly converted to - /// \a Type1 and \a Type2 respectively - /// - /// The comparison operations in the parallel \a mismatch algorithm invoked - /// with an execution policy object of type \a sequenced_policy - /// execute in sequential order in the calling thread. - /// - /// The comparison operations in the parallel \a mismatch algorithm invoked - /// with an execution policy object of type \a parallel_policy - /// or \a parallel_task_policy are permitted to execute in an unordered - /// fashion in unspecified threads, and indeterminately sequenced - /// within each thread. - /// - /// \note The two ranges are considered mismatch if, for every iterator - /// i in the range [first1,last1), *i mismatchs *(first2 + (i - first1)). - /// This overload of mismatch uses operator== to determine if two - /// elements are mismatch. - /// - /// \returns The \a mismatch algorithm returns a \a hpx::future if the - /// execution policy is of type - /// \a sequenced_task_policy or - /// \a parallel_task_policy and - /// returns \a bool otherwise. - /// The \a mismatch algorithm returns true if the elements in the - /// two ranges are mismatch, otherwise it returns false. - /// If the length of the range [first1, last1) does not mismatch - /// the length of the range [first2, last2), it returns false. + // clang-format off template - inline - typename std::enable_if::value, - typename util::detail::algorithm_result>::type>::type + typename Pred = detail::equal_to, + HPX_CONCEPT_REQUIRES_( + execution::is_execution_policy::value && + hpx::traits::is_iterator::value && + hpx::traits::is_iterator::value && + hpx::traits::is_invocable::value_type, + typename std::iterator_traits::value_type + >::value + )> + // clang-format on + HPX_DEPRECATED_V(1, 6, + "hpx::parallel::mismatch is deprecated, use hpx::mismatch instead") + typename util::detail::algorithm_result>::type mismatch(ExPolicy&& policy, FwdIter1 first1, FwdIter1 last1, FwdIter2 first2, FwdIter2 last2, Pred&& op = Pred()) { @@ -227,20 +363,20 @@ namespace hpx { namespace parallel { inline namespace v1 { static_assert((hpx::traits::is_forward_iterator::value), "Requires at least forward iterator."); - typedef execution::is_sequenced_execution_policy is_seq; + using is_seq = execution::is_sequenced_execution_policy; - typedef std::pair result_type; - return detail::mismatch_binary().call( - std::forward(policy), is_seq(), first1, last1, first2, - last2, std::forward(op)); + return detail::get_pair( + detail::mismatch_binary>() + .call(std::forward(policy), is_seq{}, first1, last1, + first2, last2, std::forward(op))); } /////////////////////////////////////////////////////////////////////////// // mismatch namespace detail { - /// \cond NOINTERNAL - template - struct mismatch : public detail::algorithm, T> + + template + struct mismatch : public detail::algorithm, IterPair> { mismatch() : mismatch::algorithm("mismatch") @@ -249,7 +385,7 @@ namespace hpx { namespace parallel { inline namespace v1 { template - static T sequential( + static IterPair sequential( ExPolicy, InIter1 first1, InIter1 last1, InIter2 first2, F&& f) { return std::mismatch(first1, last1, first2, std::forward(f)); @@ -257,14 +393,15 @@ namespace hpx { namespace parallel { inline namespace v1 { template - static typename util::detail::algorithm_result::type + static typename util::detail::algorithm_result::type parallel(ExPolicy&& policy, FwdIter1 first1, FwdIter1 last1, FwdIter2 first2, F&& f) { if (first1 == last1) { - return util::detail::algorithm_result::get( - std::make_pair(first1, first2)); + return util::detail::algorithm_result::get(std::make_pair(first1, first2)); } typedef typename std::iterator_traits::difference_type @@ -302,87 +439,31 @@ namespace hpx { namespace parallel { inline namespace v1 { return std::make_pair(first1, first2); }; - return util::partitioner::call_with_index( - std::forward(policy), + return util::partitioner::call_with_index(std::forward(policy), hpx::util::make_zip_iterator(first1, first2), count, 1, std::move(f1), std::move(f2)); } }; - /// \endcond } // namespace detail - /// Returns std::pair with iterators to the first two non-equivalent - /// elements. - /// - /// \note Complexity: At most \a last1 - \a first1 applications of the - /// predicate \a f. - /// - /// \tparam ExPolicy The type of the execution policy to use (deduced). - /// It describes the manner in which the execution - /// of the algorithm may be parallelized and the manner - /// in which it executes the assignments. - /// \tparam FwdIter1 The type of the source iterators used for the - /// first range (deduced). - /// This iterator type must meet the requirements of an - /// forward iterator. - /// \tparam FwdIter2 The type of the source iterators used for the - /// second range (deduced). - /// This iterator type must meet the requirements of an - /// forward iterator. - /// \tparam Pred The type of an optional function/function object to use. - /// Unlike its sequential form, the parallel - /// overload of \a mismatch requires \a Pred to meet the - /// requirements of \a CopyConstructible. This defaults - /// to std::equal_to<> - /// - /// \param policy The execution policy to use for the scheduling of - /// the iterations. - /// \param first1 Refers to the beginning of the sequence of elements - /// of the first range the algorithm will be applied to. - /// \param last1 Refers to the end of the sequence of elements of - /// the first range the algorithm will be applied to. - /// \param first2 Refers to the beginning of the sequence of elements - /// of the second range the algorithm will be applied to. - /// \param op The binary predicate which returns true if the - /// elements should be treated as mismatch. The signature - /// of the predicate function should be equivalent to - /// the following: - /// \code - /// bool pred(const Type1 &a, const Type2 &b); - /// \endcode \n - /// The signature does not need to have const &, but - /// the function must not modify the objects passed to - /// it. The types \a Type1 and \a Type2 must be such - /// that objects of types \a FwdIter1 and \a FwdIter2 can - /// be dereferenced and then implicitly converted to - /// \a Type1 and \a Type2 respectively - /// - /// The comparison operations in the parallel \a mismatch algorithm invoked - /// with an execution policy object of type \a sequenced_policy - /// execute in sequential order in the calling thread. - /// - /// The comparison operations in the parallel \a mismatch algorithm invoked - /// with an execution policy object of type \a parallel_policy - /// or \a parallel_task_policy are permitted to execute in an unordered - /// fashion in unspecified threads, and indeterminately sequenced - /// within each thread. - /// - /// \returns The \a mismatch algorithm returns a - /// \a hpx::future > if the - /// execution policy is of type - /// \a sequenced_task_policy or - /// \a parallel_task_policy and - /// returns \a std::pair otherwise. - /// The \a mismatch algorithm returns the first mismatching pair - /// of elements from two ranges: one defined by [first1, last1) - /// and another defined by [first2, last2). - /// + // clang-format off template - inline - typename std::enable_if::value, - typename util::detail::algorithm_result>::type>::type + typename Pred = detail::equal_to, + HPX_CONCEPT_REQUIRES_( + execution::is_execution_policy::value && + hpx::traits::is_iterator::value && + hpx::traits::is_iterator::value && + hpx::traits::is_invocable::value_type, + typename std::iterator_traits::value_type + >::value + )> + // clang-format on + HPX_DEPRECATED_V(1, 6, + "hpx::parallel::mismatch is deprecated, use hpx::mismatch instead") + typename util::detail::algorithm_result>::type mismatch(ExPolicy&& policy, FwdIter1 first1, FwdIter1 last1, FwdIter2 first2, Pred&& op = Pred()) { @@ -395,7 +476,252 @@ namespace hpx { namespace parallel { inline namespace v1 { typedef std::pair result_type; return detail::mismatch().call( - std::forward(policy), is_seq(), first1, last1, first2, + std::forward(policy), is_seq{}, first1, last1, first2, std::forward(op)); } + }}} // namespace hpx::parallel::v1 + +namespace hpx { + + /////////////////////////////////////////////////////////////////////////// + // CPO for hpx::mismatch + HPX_INLINE_CONSTEXPR_VARIABLE struct mismatch_t final + : hpx::functional::tag + { + private: + // clang-format off + template ::value && + hpx::traits::is_iterator::value && + hpx::traits::is_iterator::value && + hpx::traits::is_invocable::value_type, + typename std::iterator_traits::value_type + >::value + )> + // clang-format on + friend typename hpx::parallel::util::detail::algorithm_result>::type + tag_invoke(mismatch_t, ExPolicy&& policy, FwdIter1 first1, + FwdIter1 last1, FwdIter2 first2, FwdIter2 last2, Pred&& op) + { + static_assert((hpx::traits::is_forward_iterator::value), + "Requires at least forward iterator."); + static_assert((hpx::traits::is_forward_iterator::value), + "Requires at least forward iterator."); + + using is_seq = + hpx::parallel::execution::is_sequenced_execution_policy< + ExPolicy>; + + return hpx::parallel::v1::detail::get_pair( + hpx::parallel::v1::detail::mismatch_binary< + hpx::parallel::util::in_in_result>() + .call(std::forward(policy), is_seq{}, first1, + last1, first2, last2, std::forward(op), + hpx::parallel::util::projection_identity{}, + hpx::parallel::util::projection_identity{})); + } + + // clang-format off + template ::value && + hpx::traits::is_iterator::value && + hpx::traits::is_iterator::value + )> + // clang-format on + friend typename hpx::parallel::util::detail::algorithm_result>::type + tag_invoke(mismatch_t, ExPolicy&& policy, FwdIter1 first1, + FwdIter1 last1, FwdIter2 first2, FwdIter2 last2) + { + static_assert((hpx::traits::is_forward_iterator::value), + "Requires at least forward iterator."); + static_assert((hpx::traits::is_forward_iterator::value), + "Requires at least forward iterator."); + + using is_seq = + hpx::parallel::execution::is_sequenced_execution_policy< + ExPolicy>; + + return hpx::parallel::v1::detail::get_pair( + hpx::parallel::v1::detail::mismatch_binary< + hpx::parallel::util::in_in_result>() + .call(std::forward(policy), is_seq{}, first1, + last1, first2, last2, + hpx::parallel::v1::detail::equal_to{}, + hpx::parallel::util::projection_identity{}, + hpx::parallel::util::projection_identity{})); + } + + // clang-format off + template ::value && + hpx::traits::is_iterator::value && + hpx::traits::is_iterator::value && + hpx::traits::is_invocable::value_type, + typename std::iterator_traits::value_type + >::value + )> + // clang-format on + friend typename hpx::parallel::util::detail::algorithm_result>::type + tag_invoke(mismatch_t, ExPolicy&& policy, FwdIter1 first1, + FwdIter1 last1, FwdIter2 first2, Pred&& op) + { + static_assert((hpx::traits::is_forward_iterator::value), + "Requires at least forward iterator."); + static_assert((hpx::traits::is_forward_iterator::value), + "Requires at least forward iterator."); + + using is_seq = + hpx::parallel::execution::is_sequenced_execution_policy< + ExPolicy>; + + return hpx::parallel::v1::detail::mismatch< + std::pair>() + .call(std::forward(policy), is_seq{}, first1, last1, + first2, std::forward(op)); + } + + // clang-format off + template ::value && + hpx::traits::is_iterator::value && + hpx::traits::is_iterator::value + )> + // clang-format on + friend typename hpx::parallel::util::detail::algorithm_result>::type + tag_invoke(mismatch_t, ExPolicy&& policy, FwdIter1 first1, + FwdIter1 last1, FwdIter2 first2) + { + static_assert((hpx::traits::is_forward_iterator::value), + "Requires at least forward iterator."); + static_assert((hpx::traits::is_forward_iterator::value), + "Requires at least forward iterator."); + + using is_seq = + hpx::parallel::execution::is_sequenced_execution_policy< + ExPolicy>; + + return hpx::parallel::v1::detail::mismatch< + std::pair>() + .call(std::forward(policy), is_seq{}, first1, last1, + first2, hpx::parallel::v1::detail::equal_to{}); + } + + // clang-format off + template ::value && + hpx::traits::is_iterator::value && + hpx::traits::is_invocable::value_type, + typename std::iterator_traits::value_type + >::value + )> + // clang-format on + friend std::pair tag_invoke(mismatch_t, + FwdIter1 first1, FwdIter1 last1, FwdIter2 first2, FwdIter2 last2, + Pred&& op) + { + static_assert((hpx::traits::is_forward_iterator::value), + "Requires at least forward iterator."); + static_assert((hpx::traits::is_forward_iterator::value), + "Requires at least forward iterator."); + + return hpx::parallel::v1::detail::get_pair( + hpx::parallel::v1::detail::mismatch_binary< + hpx::parallel::util::in_in_result>() + .call(hpx::parallel::execution::seq, std::true_type{}, + first1, last1, first2, last2, std::forward(op), + hpx::parallel::util::projection_identity{}, + hpx::parallel::util::projection_identity{})); + } + + // clang-format off + template ::value && + hpx::traits::is_iterator::value + )> + // clang-format on + friend std::pair tag_invoke(mismatch_t, + FwdIter1 first1, FwdIter1 last1, FwdIter2 first2, FwdIter2 last2) + { + static_assert((hpx::traits::is_forward_iterator::value), + "Requires at least forward iterator."); + static_assert((hpx::traits::is_forward_iterator::value), + "Requires at least forward iterator."); + + return hpx::parallel::v1::detail::get_pair( + hpx::parallel::v1::detail::mismatch_binary< + hpx::parallel::util::in_in_result>() + .call(hpx::parallel::execution::seq, std::true_type{}, + first1, last1, first2, last2, + hpx::parallel::v1::detail::equal_to{}, + hpx::parallel::util::projection_identity{}, + hpx::parallel::util::projection_identity{})); + } + + // clang-format off + template ::value && + hpx::traits::is_iterator::value && + hpx::traits::is_invocable::value_type, + typename std::iterator_traits::value_type + >::value + )> + // clang-format on + friend std::pair tag_invoke(mismatch_t, + FwdIter1 first1, FwdIter1 last1, FwdIter2 first2, Pred&& op) + { + static_assert((hpx::traits::is_forward_iterator::value), + "Requires at least forward iterator."); + static_assert((hpx::traits::is_forward_iterator::value), + "Requires at least forward iterator."); + + return hpx::parallel::v1::detail::mismatch< + std::pair>() + .call(hpx::parallel::execution::seq, std::true_type{}, first1, + last1, first2, std::forward(op)); + } + + // clang-format off + template ::value && + hpx::traits::is_iterator::value + )> + // clang-format on + friend std::pair tag_invoke( + mismatch_t, FwdIter1 first1, FwdIter1 last1, FwdIter2 first2) + { + static_assert((hpx::traits::is_forward_iterator::value), + "Requires at least forward iterator."); + static_assert((hpx::traits::is_forward_iterator::value), + "Requires at least forward iterator."); + + return hpx::parallel::v1::detail::mismatch< + std::pair>() + .call(hpx::parallel::execution::seq, std::true_type{}, first1, + last1, first2, hpx::parallel::v1::detail::equal_to{}); + } + + } mismatch; +} // namespace hpx + +#endif // DOXYGEN diff --git a/libs/algorithms/include/hpx/parallel/container_algorithms.hpp b/libs/algorithms/include/hpx/parallel/container_algorithms.hpp index 770309df3bc9..31e16bcbf964 100644 --- a/libs/algorithms/include/hpx/parallel/container_algorithms.hpp +++ b/libs/algorithms/include/hpx/parallel/container_algorithms.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/libs/algorithms/include/hpx/parallel/container_algorithms/equal.hpp b/libs/algorithms/include/hpx/parallel/container_algorithms/equal.hpp index d981af448685..077b3ead2dfe 100644 --- a/libs/algorithms/include/hpx/parallel/container_algorithms/equal.hpp +++ b/libs/algorithms/include/hpx/parallel/container_algorithms/equal.hpp @@ -215,6 +215,7 @@ namespace hpx { namespace ranges { #include #include +#include #include #include #include @@ -224,8 +225,6 @@ namespace hpx { namespace ranges { namespace hpx { namespace ranges { - using equal_to = hpx::parallel::v1::detail::equal_to; - /////////////////////////////////////////////////////////////////////////// // CPO for hpx::equal HPX_INLINE_CONSTEXPR_VARIABLE struct equal_t final diff --git a/libs/algorithms/include/hpx/parallel/container_algorithms/mismatch.hpp b/libs/algorithms/include/hpx/parallel/container_algorithms/mismatch.hpp new file mode 100644 index 000000000000..c1a8cebb0eff --- /dev/null +++ b/libs/algorithms/include/hpx/parallel/container_algorithms/mismatch.hpp @@ -0,0 +1,405 @@ +// Copyright (c) 2007-2020 Hartmut Kaiser +// +// SPDX-License-Identifier: BSL-1.0 +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/// \file parallel/container_algorithms/mismatch.hpp + +#pragma once + +#if defined(DOXYGEN) +namespace hpx { namespace ranges { + // clang-format off + + /// Returns true if the range [first1, last1) is mismatch to the range + /// [first2, last2), and false otherwise. + /// + /// \note Complexity: At most min(last1 - first1, last2 - first2) + /// applications of the predicate \a f. If \a FwdIter1 + /// and \a FwdIter2 meet the requirements of \a RandomAccessIterator + /// and (last1 - first1) != (last2 - first2) then no applications + /// of the predicate \a f are made. + /// + /// \tparam ExPolicy The type of the execution policy to use (deduced). + /// It describes the manner in which the execution + /// of the algorithm may be parallelized and the manner + /// in which it executes the assignments. + /// \tparam Iter1 The type of the source iterators used for the + /// first range (deduced). + /// This iterator type must meet the requirements of an + /// forward iterator. + /// \tparam Sent1 The type of the source iterators used for the end of + /// the first range (deduced). + /// \tparam Iter2 The type of the source iterators used for the + /// second range (deduced). + /// This iterator type must meet the requirements of an + /// forward iterator. + /// \tparam Sent2 The type of the source iterators used for the end of + /// the second range (deduced). + /// \tparam Pred The type of an optional function/function object to use. + /// Unlike its sequential form, the parallel + /// overload of \a mismatch requires \a Pred to meet the + /// requirements of \a CopyConstructible. This defaults + /// to std::equal_to<> + /// \tparam Proj1 The type of an optional projection function applied + /// to the first range. This + /// defaults to \a util::projection_identity + /// \tparam Proj2 The type of an optional projection function applied + /// to the second range. This + /// defaults to \a util::projection_identity + /// + /// \param policy The execution policy to use for the scheduling of + /// the iterations. + /// \param first1 Refers to the beginning of the sequence of elements + /// of the first range the algorithm will be applied to. + /// \param last1 Refers to the end of the sequence of elements of + /// the first range the algorithm will be applied to. + /// \param first2 Refers to the beginning of the sequence of elements + /// of the second range the algorithm will be applied to. + /// \param last2 Refers to the end of the sequence of elements of + /// the second range the algorithm will be applied to. + /// \param op The binary predicate which returns true if the + /// elements should be treated as mismatch. The signature + /// of the predicate function should be equivalent to + /// the following: + /// \code + /// bool pred(const Type1 &a, const Type2 &b); + /// \endcode \n + /// The signature does not need to have const &, but + /// the function must not modify the objects passed to + /// it. The types \a Type1 and \a Type2 must be such + /// that objects of types \a FwdIter1 and \a FwdIter2 can + /// be dereferenced and then implicitly converted to + /// \a Type1 and \a Type2 respectively + /// \param proj1 Specifies the function (or function object) which + /// will be invoked for each of the elements of the + /// first range as a + /// projection operation before the actual predicate + /// \a is invoked. + /// \param proj2 Specifies the function (or function object) which + /// will be invoked for each of the elements of the + /// second range as a + /// projection operation before the actual predicate + /// \a is invoked. + /// + /// The comparison operations in the parallel \a mismatch algorithm invoked + /// with an execution policy object of type \a sequenced_policy + /// execute in sequential order in the calling thread. + /// + /// The comparison operations in the parallel \a mismatch algorithm invoked + /// with an execution policy object of type \a parallel_policy + /// or \a parallel_task_policy are permitted to execute in an unordered + /// fashion in unspecified threads, and indeterminately sequenced + /// within each thread. + /// + /// \note The two ranges are considered mismatch if, for every iterator + /// i in the range [first1,last1), *i mismatchs *(first2 + (i - first1)). + /// This overload of mismatch uses operator== to determine if two + /// elements are mismatch. + /// + /// \returns The \a mismatch algorithm returns a \a hpx::future if the + /// execution policy is of type + /// \a sequenced_task_policy or + /// \a parallel_task_policy and + /// returns \a bool otherwise. + /// The \a mismatch algorithm returns true if the elements in the + /// two ranges are mismatch, otherwise it returns false. + /// If the length of the range [first1, last1) does not mismatch + /// the length of the range [first2, last2), it returns false. + /// + template + typename util::detail::algorithm_result< + ExPolicy, ranges::mismatch_result>::type + mismatch(ExPolicy&& policy, FwdIter1 first1, FwdIter1 last1, + FwdIter2 first2, FwdIter2 last2, Pred&& op = Pred(), + Proj1&& proj1 = Proj1(), Proj2&& proj2 = Proj2()); + + /// Returns std::pair with iterators to the first two non-equivalent + /// elements. + /// + /// \note Complexity: At most \a last1 - \a first1 applications of the + /// predicate \a f. + /// + /// \tparam ExPolicy The type of the execution policy to use (deduced). + /// It describes the manner in which the execution + /// of the algorithm may be parallelized and the manner + /// in which it executes the assignments. + /// \tparam Rng1 The type of the first source range used (deduced). + /// The iterators extracted from this range type must + /// meet the requirements of an forward iterator. + /// \tparam Rng2 The type of the second source range used (deduced). + /// The iterators extracted from this range type must + /// meet the requirements of an forward iterator. + /// \tparam Pred The type of an optional function/function object to use. + /// Unlike its sequential form, the parallel + /// overload of \a mismatch requires \a Pred to meet the + /// requirements of \a CopyConstructible. This defaults + /// to std::equal_to<> + /// \tparam Proj1 The type of an optional projection function applied + /// to the first range. This + /// defaults to \a util::projection_identity + /// \tparam Proj2 The type of an optional projection function applied + /// to the second range. This + /// defaults to \a util::projection_identity + /// + /// \param policy The execution policy to use for the scheduling of + /// the iterations. + /// \param rng1 Refers to the first sequence of elements the + /// algorithm will be applied to. + /// \param rng2 Refers to the second sequence of elements the + /// algorithm will be applied to. + /// \param op The binary predicate which returns true if the + /// elements should be treated as mismatch. The signature + /// of the predicate function should be equivalent to + /// the following: + /// \code + /// bool pred(const Type1 &a, const Type2 &b); + /// \endcode \n + /// The signature does not need to have const &, but + /// the function must not modify the objects passed to + /// it. The types \a Type1 and \a Type2 must be such + /// that objects of types \a FwdIter1 and \a FwdIter2 can + /// be dereferenced and then implicitly converted to + /// \a Type1 and \a Type2 respectively + /// \param proj1 Specifies the function (or function object) which + /// will be invoked for each of the elements of the + /// first range as a + /// projection operation before the actual predicate + /// \a is invoked. + /// \param proj2 Specifies the function (or function object) which + /// will be invoked for each of the elements of the + /// second range as a + /// projection operation before the actual predicate + /// \a is invoked. + /// + /// The comparison operations in the parallel \a mismatch algorithm invoked + /// with an execution policy object of type \a sequenced_policy + /// execute in sequential order in the calling thread. + /// + /// The comparison operations in the parallel \a mismatch algorithm invoked + /// with an execution policy object of type \a parallel_policy + /// or \a parallel_task_policy are permitted to execute in an unordered + /// fashion in unspecified threads, and indeterminately sequenced + /// within each thread. + /// + /// \returns The \a mismatch algorithm returns a + /// \a hpx::future > if the + /// execution policy is of type + /// \a sequenced_task_policy or + /// \a parallel_task_policy and + /// returns \a std::pair otherwise. + /// The \a mismatch algorithm returns the first mismatching pair + /// of elements from two ranges: one defined by [first1, last1) + /// and another defined by [first2, last2). + /// + template + typename util::detail::algorithm_result< + ExPolicy, ranges::mimatch_result>::type + mismatch(ExPolicy&& policy, Rng1&& rng1, Rng2&& rng2, Pred&& op = Pred(), + Proj1&& proj1 = Proj1(), Proj2&& proj2 = Proj2()); + + // clang-format on +}} // namespace hpx::ranges + +#else // DOXYGEN + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace hpx { namespace ranges { + + /////////////////////////////////////////////////////////////////////////// + template + using mismatch_result = hpx::parallel::util::in_in_result; + + /////////////////////////////////////////////////////////////////////////// + // CPO for hpx::ranges::mismatch + HPX_INLINE_CONSTEXPR_VARIABLE struct mismatch_t final + : hpx::functional::tag + { + private: + // clang-format off + template ::value && + hpx::traits::is_sentinel_for::value && + hpx::traits::is_sentinel_for::value && + hpx::parallel::traits::is_indirect_callable, + hpx::parallel::traits::projected + >::value + )> + // clang-format on + friend typename hpx::parallel::util::detail::algorithm_result>::type + tag_invoke(mismatch_t, ExPolicy&& policy, Iter1 first1, Sent1 last1, + Iter2 first2, Sent2 last2, Pred&& op = Pred(), + Proj1&& proj1 = Proj1(), Proj2&& proj2 = Proj2()) + { + static_assert((hpx::traits::is_forward_iterator::value), + "Requires at least forward iterator."); + static_assert((hpx::traits::is_forward_iterator::value), + "Requires at least forward iterator."); + + using is_seq = + hpx::parallel::execution::is_sequenced_execution_policy< + ExPolicy>; + + return hpx::parallel::v1::detail::mismatch_binary< + mismatch_result>() + .call(std::forward(policy), is_seq{}, first1, last1, + first2, last2, std::forward(op), + std::forward(proj1), std::forward(proj2)); + } + + // clang-format off + template ::value && + hpx::parallel::traits::is_projected_range::value && + hpx::parallel::traits::is_projected_range::value && + hpx::parallel::traits::is_indirect_callable::iterator_type>, + hpx::parallel::traits::projected::iterator_type> + >::value + )> + // clang-format on + friend typename hpx::parallel::util::detail::algorithm_result::iterator_type, + typename hpx::traits::range_traits::iterator_type>>::type + tag_invoke(mismatch_t, ExPolicy&& policy, Rng1&& rng1, Rng2&& rng2, + Pred&& op = Pred(), Proj1&& proj1 = Proj1(), + Proj2&& proj2 = Proj2()) + { + static_assert( + (hpx::traits::is_forward_iterator::iterator_type>::value), + "Requires at least forward iterator."); + static_assert( + (hpx::traits::is_forward_iterator::iterator_type>::value), + "Requires at least forward iterator."); + + using is_seq = + hpx::parallel::execution::is_sequenced_execution_policy< + ExPolicy>; + using result_type = mismatch_result< + typename hpx::traits::range_traits::iterator_type, + typename hpx::traits::range_traits::iterator_type>; + + return hpx::parallel::v1::detail::mismatch_binary() + .call(std::forward(policy), is_seq{}, + hpx::util::begin(rng1), hpx::util::end(rng1), + hpx::util::begin(rng2), hpx::util::end(rng2), + std::forward(op), std::forward(proj1), + std::forward(proj2)); + } + + // clang-format off + template ::value && + hpx::traits::is_sentinel_for::value && + hpx::parallel::traits::is_indirect_callable< + hpx::parallel::execution::sequenced_policy, Pred, + hpx::parallel::traits::projected, + hpx::parallel::traits::projected + >::value + )> + // clang-format on + friend mismatch_result tag_invoke(mismatch_t, + Iter1 first1, Sent1 last1, Iter2 first2, Sent2 last2, + Pred&& op = Pred(), Proj1&& proj1 = Proj1(), + Proj2&& proj2 = Proj2()) + { + static_assert((hpx::traits::is_forward_iterator::value), + "Requires at least forward iterator."); + static_assert((hpx::traits::is_forward_iterator::value), + "Requires at least forward iterator."); + + return hpx::parallel::v1::detail::mismatch_binary< + mismatch_result>() + .call(hpx::parallel::execution::seq, std::true_type{}, first1, + last1, first2, last2, std::forward(op), + std::forward(proj1), std::forward(proj2)); + } + + // clang-format off + template ::value && + hpx::parallel::traits::is_projected_range::value && + hpx::parallel::traits::is_indirect_callable< + hpx::parallel::execution::sequenced_policy, Pred, + hpx::parallel::traits::projected::iterator_type>, + hpx::parallel::traits::projected::iterator_type> + >::value + )> + // clang-format on + friend mismatch_result< + typename hpx::traits::range_traits::iterator_type, + typename hpx::traits::range_traits::iterator_type> + tag_invoke(mismatch_t, Rng1&& rng1, Rng2&& rng2, Pred&& op = Pred(), + Proj1&& proj1 = Proj1(), Proj2&& proj2 = Proj2()) + { + static_assert( + (hpx::traits::is_forward_iterator::iterator_type>::value), + "Requires at least forward iterator."); + static_assert( + (hpx::traits::is_forward_iterator::iterator_type>::value), + "Requires at least forward iterator."); + + using result_type = mismatch_result< + typename hpx::traits::range_traits::iterator_type, + typename hpx::traits::range_traits::iterator_type>; + + return hpx::parallel::v1::detail::mismatch_binary() + .call(hpx::parallel::execution::seq, std::true_type{}, + hpx::util::begin(rng1), hpx::util::end(rng1), + hpx::util::begin(rng2), hpx::util::end(rng2), + std::forward(op), std::forward(proj1), + std::forward(proj2)); + } + + } mismatch; +}} // namespace hpx::ranges + +#endif // DOXYGEN diff --git a/libs/algorithms/include/hpx/parallel/util/compare_projected.hpp b/libs/algorithms/include/hpx/parallel/util/compare_projected.hpp index d066992c77c6..5fba6385a7b5 100644 --- a/libs/algorithms/include/hpx/parallel/util/compare_projected.hpp +++ b/libs/algorithms/include/hpx/parallel/util/compare_projected.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017 Hartmut Kaiser +// Copyright (c) 2016-2020 Hartmut Kaiser // Copyright (c) 2018 Christopher Ogle // // SPDX-License-Identifier: BSL-1.0 @@ -10,13 +10,17 @@ #include #include +#include + #include namespace hpx { namespace parallel { namespace util { + /////////////////////////////////////////////////////////////////////////// template struct compare_projected; + /////////////////////////////////////////////////////////////////////////// template struct compare_projected { @@ -28,7 +32,7 @@ namespace hpx { namespace parallel { namespace util { } template - inline bool operator()(T1&& t1, T2&& t2) const + inline constexpr bool operator()(T1&& t1, T2&& t2) const { return hpx::util::invoke(comp_, hpx::util::invoke(proj_, std::forward(t1)), @@ -39,6 +43,26 @@ namespace hpx { namespace parallel { namespace util { Proj proj_; }; + template + struct compare_projected + { + template + compare_projected(Compare_&& comp, util::projection_identity) + : comp_(std::forward(comp)) + { + } + + template + inline constexpr bool operator()(T1&& t1, T2&& t2) const + { + return hpx::util::invoke( + comp_, std::forward(t1), std::forward(t2)); + } + + Compare comp_; + }; + + /////////////////////////////////////////////////////////////////////////// template struct compare_projected { @@ -51,7 +75,7 @@ namespace hpx { namespace parallel { namespace util { } template - inline bool operator()(T1&& t1, T2&& t2) const + inline constexpr bool operator()(T1&& t1, T2&& t2) const { return hpx::util::invoke(comp_, hpx::util::invoke(proj1_, std::forward(t1)), @@ -62,4 +86,70 @@ namespace hpx { namespace parallel { namespace util { Proj1 proj1_; Proj2 proj2_; }; + + template + struct compare_projected + { + template + compare_projected( + Compare_&& comp, util::projection_identity, Proj2_&& proj2) + : comp_(std::forward(comp)) + , proj2_(std::forward(proj2)) + { + } + + template + inline constexpr bool operator()(T1&& t1, T2&& t2) const + { + return hpx::util::invoke(comp_, std::forward(t1), + hpx::util::invoke(proj2_, std::forward(t2))); + } + + Compare comp_; + Proj2 proj2_; + }; + + template + struct compare_projected + { + template + compare_projected( + Compare_&& comp, Proj1_&& proj1, util::projection_identity) + : comp_(std::forward(comp)) + , proj1_(std::forward(proj1)) + { + } + + template + inline constexpr bool operator()(T1&& t1, T2&& t2) const + { + return hpx::util::invoke(comp_, + hpx::util::invoke(proj1_, std::forward(t1)), + std::forward(t2)); + } + + Compare comp_; + Proj1 proj1_; + }; + + template + struct compare_projected + { + template + compare_projected(Compare_&& comp, util::projection_identity, + util::projection_identity) + : comp_(std::forward(comp)) + { + } + + template + inline constexpr bool operator()(T1&& t1, T2&& t2) const + { + return hpx::util::invoke( + comp_, std::forward(t1), std::forward(t2)); + } + + Compare comp_; + }; }}} // namespace hpx::parallel::util diff --git a/libs/algorithms/include/hpx/parallel/util/projection_identity.hpp b/libs/algorithms/include/hpx/parallel/util/projection_identity.hpp index 89e1acb1e594..d74be1aa0f16 100644 --- a/libs/algorithms/include/hpx/parallel/util/projection_identity.hpp +++ b/libs/algorithms/include/hpx/parallel/util/projection_identity.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2016 Hartmut Kaiser +// Copyright (c) 2015-2020 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -15,7 +15,7 @@ namespace hpx { namespace parallel { namespace util { struct projection_identity { template - HPX_HOST_DEVICE HPX_FORCEINLINE T&& operator()(T&& val) const + HPX_HOST_DEVICE HPX_FORCEINLINE constexpr T&& operator()(T&& val) const { return std::forward(val); } diff --git a/libs/algorithms/include/hpx/parallel/util/result_types.hpp b/libs/algorithms/include/hpx/parallel/util/result_types.hpp index 7d136b7f6d47..17b0bc5ca5f0 100644 --- a/libs/algorithms/include/hpx/parallel/util/result_types.hpp +++ b/libs/algorithms/include/hpx/parallel/util/result_types.hpp @@ -17,6 +17,40 @@ namespace hpx { namespace parallel { namespace util { + /////////////////////////////////////////////////////////////////////////// + template + struct in_in_result + { + HPX_NO_UNIQUE_ADDRESS I1 in1; + HPX_NO_UNIQUE_ADDRESS I2 in2; + + template ::value && + std::is_convertible::value>::type> + constexpr operator in_in_result() const& + { + return {in1, in2}; + } + + template ::value && + std::is_convertible::value>::type> + constexpr operator in_in_result() && + { + return {std::move(in1), std::move(in2)}; + } + + template + void serialize(Archive& ar, unsigned) + { + // clang-format off + ar & in1 & in2; + // clang-format on + } + }; + /////////////////////////////////////////////////////////////////////////// template struct in_out_result diff --git a/libs/algorithms/tests/performance/benchmark_unique.cpp b/libs/algorithms/tests/performance/benchmark_unique.cpp index 470d528e063d..97a42305d1cd 100644 --- a/libs/algorithms/tests/performance/benchmark_unique.cpp +++ b/libs/algorithms/tests/performance/benchmark_unique.cpp @@ -64,6 +64,11 @@ struct vector_type return vec_ == t.vec_; } + bool operator!=(vector_type const& t) const + { + return vec_ != t.vec_; + } + std::vector vec_; static const std::size_t vec_size_{30}; }; @@ -82,6 +87,11 @@ struct array_type return arr_ == t.arr_; } + bool operator!=(array_type const& t) const + { + return arr_ != t.arr_; + } + static const std::size_t arr_size_{30}; std::array arr_; }; diff --git a/libs/algorithms/tests/unit/algorithms/mismatch.cpp b/libs/algorithms/tests/unit/algorithms/mismatch.cpp index b824db011e5e..804a19d5b316 100644 --- a/libs/algorithms/tests/unit/algorithms/mismatch.cpp +++ b/libs/algorithms/tests/unit/algorithms/mismatch.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017 Hartmut Kaiser +// Copyright (c) 2014-2020 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -25,8 +25,48 @@ int seed = std::random_device{}(); std::mt19937 gen(seed); std::uniform_int_distribution<> dis(0, 10006); +template +void test_mismatch1(IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + iterator begin1 = iterator(std::begin(c1)); + iterator end1 = iterator(std::end(c1)); + + { + auto result = hpx::mismatch(begin1, end1, std::begin(c2)); + + // verify values + HPX_TEST_EQ( + std::size_t(std::distance(begin1, result.first)), c1.size()); + HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.second)), + c2.size()); + } + + { + std::size_t changed_idx = dis(gen); //-V104 + ++c1[changed_idx]; + + auto result = hpx::mismatch(begin1, end1, std::begin(c2)); + + // verify values + HPX_TEST_EQ( + std::size_t(std::distance(begin1, result.first)), changed_idx); + HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.second)), + changed_idx); + } +} + template -void test_mismatch1(ExPolicy policy, IteratorTag) +void test_mismatch1(ExPolicy&& policy, IteratorTag) { static_assert( hpx::parallel::execution::is_execution_policy::value, @@ -35,9 +75,6 @@ void test_mismatch1(ExPolicy policy, IteratorTag) typedef std::vector::iterator base_iterator; typedef test::test_iterator iterator; - typedef std::pair base_return_type; - typedef std::pair return_type; - std::vector c1(10007); std::vector c2(c1.size()); @@ -49,8 +86,7 @@ void test_mismatch1(ExPolicy policy, IteratorTag) iterator end1 = iterator(std::end(c1)); { - return_type result = - hpx::parallel::mismatch(policy, begin1, end1, std::begin(c2)); + auto result = hpx::mismatch(policy, begin1, end1, std::begin(c2)); // verify values HPX_TEST_EQ( @@ -63,8 +99,7 @@ void test_mismatch1(ExPolicy policy, IteratorTag) std::size_t changed_idx = dis(gen); //-V104 ++c1[changed_idx]; - return_type result = - hpx::parallel::mismatch(policy, begin1, end1, std::begin(c2)); + auto result = hpx::mismatch(policy, begin1, end1, std::begin(c2)); // verify values HPX_TEST_EQ( @@ -75,14 +110,11 @@ void test_mismatch1(ExPolicy policy, IteratorTag) } template -void test_mismatch1_async(ExPolicy p, IteratorTag) +void test_mismatch1_async(ExPolicy&& p, IteratorTag) { typedef std::vector::iterator base_iterator; typedef test::test_iterator iterator; - typedef std::pair base_return_type; - typedef std::pair return_type; - std::vector c1(10007); std::vector c2(c1.size()); @@ -94,12 +126,11 @@ void test_mismatch1_async(ExPolicy p, IteratorTag) iterator end1 = iterator(std::end(c1)); { - hpx::future f = - hpx::parallel::mismatch(p, begin1, end1, std::begin(c2)); + auto f = hpx::mismatch(p, begin1, end1, std::begin(c2)); f.wait(); // verify values - return_type result = f.get(); + auto result = f.get(); HPX_TEST_EQ( std::size_t(std::distance(begin1, result.first)), c1.size()); HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.second)), @@ -110,12 +141,11 @@ void test_mismatch1_async(ExPolicy p, IteratorTag) std::size_t changed_idx = dis(gen); //-V104 ++c1[changed_idx]; - hpx::future f = - hpx::parallel::mismatch(p, begin1, end1, std::begin(c2)); + auto f = hpx::mismatch(p, begin1, end1, std::begin(c2)); f.wait(); // verify values - return_type result = f.get(); + auto result = f.get(); HPX_TEST_EQ( std::size_t(std::distance(begin1, result.first)), changed_idx); HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.second)), @@ -128,6 +158,8 @@ void test_mismatch1() { using namespace hpx::parallel; + test_mismatch1(IteratorTag()); + test_mismatch1(execution::seq, IteratorTag()); test_mismatch1(execution::par, IteratorTag()); test_mismatch1(execution::par_unseq, IteratorTag()); @@ -143,8 +175,50 @@ void mismatch_test1() } /////////////////////////////////////////////////////////////////////////////// +template +void test_mismatch2(IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + iterator begin1 = iterator(std::begin(c1)); + iterator end1 = iterator(std::end(c1)); + + { + auto result = hpx::mismatch( + begin1, end1, std::begin(c2), std::equal_to()); + + // verify values + HPX_TEST_EQ( + std::size_t(std::distance(begin1, result.first)), c1.size()); + HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.second)), + c2.size()); + } + + { + std::size_t changed_idx = dis(gen); //-V104 + ++c1[changed_idx]; + + auto result = hpx::mismatch( + begin1, end1, std::begin(c2), std::equal_to()); + + // verify values + HPX_TEST_EQ( + std::size_t(std::distance(begin1, result.first)), changed_idx); + HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.second)), + changed_idx); + } +} + template -void test_mismatch2(ExPolicy policy, IteratorTag) +void test_mismatch2(ExPolicy&& policy, IteratorTag) { static_assert( hpx::parallel::execution::is_execution_policy::value, @@ -153,9 +227,6 @@ void test_mismatch2(ExPolicy policy, IteratorTag) typedef std::vector::iterator base_iterator; typedef test::test_iterator iterator; - typedef std::pair base_return_type; - typedef std::pair return_type; - std::vector c1(10007); std::vector c2(c1.size()); @@ -167,7 +238,7 @@ void test_mismatch2(ExPolicy policy, IteratorTag) iterator end1 = iterator(std::end(c1)); { - return_type result = hpx::parallel::mismatch( + auto result = hpx::mismatch( policy, begin1, end1, std::begin(c2), std::equal_to()); // verify values @@ -181,7 +252,7 @@ void test_mismatch2(ExPolicy policy, IteratorTag) std::size_t changed_idx = dis(gen); //-V104 ++c1[changed_idx]; - return_type result = hpx::parallel::mismatch( + auto result = hpx::mismatch( policy, begin1, end1, std::begin(c2), std::equal_to()); // verify values @@ -193,14 +264,11 @@ void test_mismatch2(ExPolicy policy, IteratorTag) } template -void test_mismatch2_async(ExPolicy p, IteratorTag) +void test_mismatch2_async(ExPolicy&& p, IteratorTag) { typedef std::vector::iterator base_iterator; typedef test::test_iterator iterator; - typedef std::pair base_return_type; - typedef std::pair return_type; - std::vector c1(10007); std::vector c2(c1.size()); @@ -212,12 +280,12 @@ void test_mismatch2_async(ExPolicy p, IteratorTag) iterator end1 = iterator(std::end(c1)); { - hpx::future f = hpx::parallel::mismatch( + auto f = hpx::mismatch( p, begin1, end1, std::begin(c2), std::equal_to()); f.wait(); // verify values - return_type result = f.get(); + auto result = f.get(); HPX_TEST_EQ( std::size_t(std::distance(begin1, result.first)), c1.size()); HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.second)), @@ -228,12 +296,12 @@ void test_mismatch2_async(ExPolicy p, IteratorTag) std::size_t changed_idx = dis(gen); //-V104 ++c1[changed_idx]; - hpx::future f = hpx::parallel::mismatch( + auto f = hpx::mismatch( p, begin1, end1, std::begin(c2), std::equal_to()); f.wait(); // verify values - return_type result = f.get(); + auto result = f.get(); HPX_TEST_EQ( std::size_t(std::distance(begin1, result.first)), changed_idx); HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.second)), @@ -246,6 +314,8 @@ void test_mismatch2() { using namespace hpx::parallel; + test_mismatch2(IteratorTag()); + test_mismatch2(execution::seq, IteratorTag()); test_mismatch2(execution::par, IteratorTag()); test_mismatch2(execution::par_unseq, IteratorTag()); @@ -261,8 +331,45 @@ void mismatch_test2() } /////////////////////////////////////////////////////////////////////////////// +template +void test_mismatch_exception(IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + bool caught_exception = false; + try + { + hpx::mismatch(iterator(std::begin(c1)), iterator(std::end(c1)), + std::begin(c2), [](std::size_t v1, std::size_t v2) { + return throw std::runtime_error("test"), true; + }); + + HPX_TEST(false); + } + catch (hpx::exception_list const& e) + { + caught_exception = true; + test::test_num_exceptions::call(hpx::parallel::execution::seq, e); + } + catch (...) + { + HPX_TEST(false); + } + + HPX_TEST(caught_exception); +} + template -void test_mismatch_exception(ExPolicy policy, IteratorTag) +void test_mismatch_exception(ExPolicy&& policy, IteratorTag) { static_assert( hpx::parallel::execution::is_execution_policy::value, @@ -271,9 +378,6 @@ void test_mismatch_exception(ExPolicy policy, IteratorTag) typedef std::vector::iterator base_iterator; typedef test::test_iterator iterator; - typedef std::pair base_return_type; - typedef std::pair return_type; - std::vector c1(10007); std::vector c2(c1.size()); @@ -284,9 +388,8 @@ void test_mismatch_exception(ExPolicy policy, IteratorTag) bool caught_exception = false; try { - hpx::parallel::mismatch(policy, iterator(std::begin(c1)), - iterator(std::end(c1)), std::begin(c2), - [](std::size_t v1, std::size_t v2) { + hpx::mismatch(policy, iterator(std::begin(c1)), iterator(std::end(c1)), + std::begin(c2), [](std::size_t v1, std::size_t v2) { return throw std::runtime_error("test"), true; }); @@ -306,14 +409,11 @@ void test_mismatch_exception(ExPolicy policy, IteratorTag) } template -void test_mismatch_exception_async(ExPolicy p, IteratorTag) +void test_mismatch_exception_async(ExPolicy&& p, IteratorTag) { typedef std::vector::iterator base_iterator; typedef test::test_iterator iterator; - typedef std::pair base_return_type; - typedef std::pair return_type; - std::vector c1(10007); std::vector c2(c1.size()); @@ -325,11 +425,11 @@ void test_mismatch_exception_async(ExPolicy p, IteratorTag) bool returned_from_algorithm = false; try { - hpx::future f = hpx::parallel::mismatch(p, - iterator(std::begin(c1)), iterator(std::end(c1)), std::begin(c2), - [](std::size_t v1, std::size_t v2) { - return throw std::runtime_error("test"), true; - }); + auto f = + hpx::mismatch(p, iterator(std::begin(c1)), iterator(std::end(c1)), + std::begin(c2), [](std::size_t v1, std::size_t v2) { + return throw std::runtime_error("test"), true; + }); returned_from_algorithm = true; f.get(); @@ -374,7 +474,7 @@ void mismatch_exception_test() ///////////////////////////////////////////////////////////////////////////// template -void test_mismatch_bad_alloc(ExPolicy policy, IteratorTag) +void test_mismatch_bad_alloc(ExPolicy&& policy, IteratorTag) { static_assert( hpx::parallel::execution::is_execution_policy::value, @@ -383,9 +483,6 @@ void test_mismatch_bad_alloc(ExPolicy policy, IteratorTag) typedef std::vector::iterator base_iterator; typedef test::test_iterator iterator; - typedef std::pair base_return_type; - typedef std::pair return_type; - std::vector c1(10007); std::vector c2(c1.size()); @@ -396,9 +493,8 @@ void test_mismatch_bad_alloc(ExPolicy policy, IteratorTag) bool caught_bad_alloc = false; try { - hpx::parallel::mismatch(policy, iterator(std::begin(c1)), - iterator(std::end(c1)), std::begin(c2), - [](std::size_t v1, std::size_t v2) { + hpx::mismatch(policy, iterator(std::begin(c1)), iterator(std::end(c1)), + std::begin(c2), [](std::size_t v1, std::size_t v2) { return throw std::bad_alloc(), true; }); @@ -417,14 +513,11 @@ void test_mismatch_bad_alloc(ExPolicy policy, IteratorTag) } template -void test_mismatch_bad_alloc_async(ExPolicy p, IteratorTag) +void test_mismatch_bad_alloc_async(ExPolicy&& p, IteratorTag) { typedef std::vector::iterator base_iterator; typedef test::test_iterator iterator; - typedef std::pair base_return_type; - typedef std::pair return_type; - std::vector c1(10007); std::vector c2(c1.size()); @@ -436,11 +529,11 @@ void test_mismatch_bad_alloc_async(ExPolicy p, IteratorTag) bool returned_from_algorithm = false; try { - hpx::future f = hpx::parallel::mismatch(p, - iterator(std::begin(c1)), iterator(std::end(c1)), std::begin(c2), - [](std::size_t v1, std::size_t v2) { - return throw std::bad_alloc(), true; - }); + auto f = + hpx::mismatch(p, iterator(std::begin(c1)), iterator(std::end(c1)), + std::begin(c2), [](std::size_t v1, std::size_t v2) { + return throw std::bad_alloc(), true; + }); returned_from_algorithm = true; f.get(); diff --git a/libs/algorithms/tests/unit/algorithms/mismatch_binary.cpp b/libs/algorithms/tests/unit/algorithms/mismatch_binary.cpp index 99f5bed284be..d51fba9026f0 100644 --- a/libs/algorithms/tests/unit/algorithms/mismatch_binary.cpp +++ b/libs/algorithms/tests/unit/algorithms/mismatch_binary.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2017 Hartmut Kaiser +// Copyright (c) 2014-2020 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -25,8 +25,48 @@ int seed = std::random_device{}(); std::mt19937 gen(seed); std::uniform_int_distribution<> dis(0, 10006); +template +void test_mismatch_binary1(IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + iterator begin1 = iterator(std::begin(c1)); + iterator end1 = iterator(std::end(c1)); + + { + auto result = hpx::mismatch(begin1, end1, std::begin(c2), std::end(c2)); + + // verify values + HPX_TEST_EQ( + std::size_t(std::distance(begin1, result.first)), c1.size()); + HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.second)), + c2.size()); + } + + { + std::size_t changed_idx = dis(gen); //-V104 + ++c1[changed_idx]; + + auto result = hpx::mismatch(begin1, end1, std::begin(c2), std::end(c2)); + + // verify values + HPX_TEST_EQ( + std::size_t(std::distance(begin1, result.first)), changed_idx); + HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.second)), + changed_idx); + } +} + template -void test_mismatch_binary1(ExPolicy policy, IteratorTag) +void test_mismatch_binary1(ExPolicy&& policy, IteratorTag) { static_assert( hpx::parallel::execution::is_execution_policy::value, @@ -35,9 +75,6 @@ void test_mismatch_binary1(ExPolicy policy, IteratorTag) typedef std::vector::iterator base_iterator; typedef test::test_iterator iterator; - typedef std::pair base_return_type; - typedef std::pair return_type; - std::vector c1(10007); std::vector c2(c1.size()); @@ -49,8 +86,8 @@ void test_mismatch_binary1(ExPolicy policy, IteratorTag) iterator end1 = iterator(std::end(c1)); { - return_type result = hpx::parallel::mismatch( - policy, begin1, end1, std::begin(c2), std::end(c2)); + auto result = + hpx::mismatch(policy, begin1, end1, std::begin(c2), std::end(c2)); // verify values HPX_TEST_EQ( @@ -63,8 +100,8 @@ void test_mismatch_binary1(ExPolicy policy, IteratorTag) std::size_t changed_idx = dis(gen); //-V104 ++c1[changed_idx]; - return_type result = hpx::parallel::mismatch( - policy, begin1, end1, std::begin(c2), std::end(c2)); + auto result = + hpx::mismatch(policy, begin1, end1, std::begin(c2), std::end(c2)); // verify values HPX_TEST_EQ( @@ -75,14 +112,11 @@ void test_mismatch_binary1(ExPolicy policy, IteratorTag) } template -void test_mismatch_binary1_async(ExPolicy p, IteratorTag) +void test_mismatch_binary1_async(ExPolicy&& p, IteratorTag) { typedef std::vector::iterator base_iterator; typedef test::test_iterator iterator; - typedef std::pair base_return_type; - typedef std::pair return_type; - std::vector c1(10007); std::vector c2(c1.size()); @@ -94,12 +128,11 @@ void test_mismatch_binary1_async(ExPolicy p, IteratorTag) iterator end1 = iterator(std::end(c1)); { - hpx::future f = hpx::parallel::mismatch( - p, begin1, end1, std::begin(c2), std::end(c2)); + auto f = hpx::mismatch(p, begin1, end1, std::begin(c2), std::end(c2)); f.wait(); // verify values - return_type result = f.get(); + auto result = f.get(); HPX_TEST_EQ( std::size_t(std::distance(begin1, result.first)), c1.size()); HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.second)), @@ -110,12 +143,11 @@ void test_mismatch_binary1_async(ExPolicy p, IteratorTag) std::size_t changed_idx = dis(gen); //-V104 ++c1[changed_idx]; - hpx::future f = hpx::parallel::mismatch( - p, begin1, end1, std::begin(c2), std::end(c2)); + auto f = hpx::mismatch(p, begin1, end1, std::begin(c2), std::end(c2)); f.wait(); // verify values - return_type result = f.get(); + auto result = f.get(); HPX_TEST_EQ( std::size_t(std::distance(begin1, result.first)), changed_idx); HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.second)), @@ -128,6 +160,8 @@ void test_mismatch_binary1() { using namespace hpx::parallel; + test_mismatch_binary1(IteratorTag()); + test_mismatch_binary1(execution::seq, IteratorTag()); test_mismatch_binary1(execution::par, IteratorTag()); test_mismatch_binary1(execution::par_unseq, IteratorTag()); @@ -143,8 +177,50 @@ void mismatch_binary_test1() } /////////////////////////////////////////////////////////////////////////////// +template +void test_mismatch_binary2(IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + iterator begin1 = iterator(std::begin(c1)); + iterator end1 = iterator(std::end(c1)); + + { + auto result = hpx::mismatch(begin1, end1, std::begin(c2), std::end(c2), + std::equal_to()); + + // verify values + HPX_TEST_EQ( + std::size_t(std::distance(begin1, result.first)), c1.size()); + HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.second)), + c2.size()); + } + + { + std::size_t changed_idx = dis(gen); //-V104 + ++c1[changed_idx]; + + auto result = hpx::mismatch(begin1, end1, std::begin(c2), std::end(c2), + std::equal_to()); + + // verify values + HPX_TEST_EQ( + std::size_t(std::distance(begin1, result.first)), changed_idx); + HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.second)), + changed_idx); + } +} + template -void test_mismatch_binary2(ExPolicy policy, IteratorTag) +void test_mismatch_binary2(ExPolicy&& policy, IteratorTag) { static_assert( hpx::parallel::execution::is_execution_policy::value, @@ -153,9 +229,6 @@ void test_mismatch_binary2(ExPolicy policy, IteratorTag) typedef std::vector::iterator base_iterator; typedef test::test_iterator iterator; - typedef std::pair base_return_type; - typedef std::pair return_type; - std::vector c1(10007); std::vector c2(c1.size()); @@ -167,8 +240,8 @@ void test_mismatch_binary2(ExPolicy policy, IteratorTag) iterator end1 = iterator(std::end(c1)); { - return_type result = hpx::parallel::mismatch(policy, begin1, end1, - std::begin(c2), std::end(c2), std::equal_to()); + auto result = hpx::mismatch(policy, begin1, end1, std::begin(c2), + std::end(c2), std::equal_to()); // verify values HPX_TEST_EQ( @@ -181,8 +254,8 @@ void test_mismatch_binary2(ExPolicy policy, IteratorTag) std::size_t changed_idx = dis(gen); //-V104 ++c1[changed_idx]; - return_type result = hpx::parallel::mismatch(policy, begin1, end1, - std::begin(c2), std::end(c2), std::equal_to()); + auto result = hpx::mismatch(policy, begin1, end1, std::begin(c2), + std::end(c2), std::equal_to()); // verify values HPX_TEST_EQ( @@ -193,14 +266,11 @@ void test_mismatch_binary2(ExPolicy policy, IteratorTag) } template -void test_mismatch_binary2_async(ExPolicy p, IteratorTag) +void test_mismatch_binary2_async(ExPolicy&& p, IteratorTag) { typedef std::vector::iterator base_iterator; typedef test::test_iterator iterator; - typedef std::pair base_return_type; - typedef std::pair return_type; - std::vector c1(10007); std::vector c2(c1.size()); @@ -212,12 +282,12 @@ void test_mismatch_binary2_async(ExPolicy p, IteratorTag) iterator end1 = iterator(std::end(c1)); { - hpx::future f = hpx::parallel::mismatch(p, begin1, end1, - std::begin(c2), std::end(c2), std::equal_to()); + auto f = hpx::mismatch(p, begin1, end1, std::begin(c2), std::end(c2), + std::equal_to()); f.wait(); // verify values - return_type result = f.get(); + auto result = f.get(); HPX_TEST_EQ( std::size_t(std::distance(begin1, result.first)), c1.size()); HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.second)), @@ -228,12 +298,12 @@ void test_mismatch_binary2_async(ExPolicy p, IteratorTag) std::size_t changed_idx = dis(gen); //-V104 ++c1[changed_idx]; - hpx::future f = hpx::parallel::mismatch(p, begin1, end1, - std::begin(c2), std::end(c2), std::equal_to()); + auto f = hpx::mismatch(p, begin1, end1, std::begin(c2), std::end(c2), + std::equal_to()); f.wait(); // verify values - return_type result = f.get(); + auto result = f.get(); HPX_TEST_EQ( std::size_t(std::distance(begin1, result.first)), changed_idx); HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.second)), @@ -246,6 +316,8 @@ void test_mismatch_binary2() { using namespace hpx::parallel; + test_mismatch_binary2(IteratorTag()); + test_mismatch_binary2(execution::seq, IteratorTag()); test_mismatch_binary2(execution::par, IteratorTag()); test_mismatch_binary2(execution::par_unseq, IteratorTag()); @@ -261,8 +333,45 @@ void mismatch_binary_test2() } /////////////////////////////////////////////////////////////////////////////// +template +void test_mismatch_binary_exception(IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + bool caught_exception = false; + try + { + hpx::mismatch(iterator(std::begin(c1)), iterator(std::end(c1)), + std::begin(c2), std::end(c2), [](std::size_t v1, std::size_t v2) { + return throw std::runtime_error("test"), true; + }); + + HPX_TEST(false); + } + catch (hpx::exception_list const& e) + { + caught_exception = true; + test::test_num_exceptions::call(hpx::parallel::execution::seq, e); + } + catch (...) + { + HPX_TEST(false); + } + + HPX_TEST(caught_exception); +} + template -void test_mismatch_binary_exception(ExPolicy policy, IteratorTag) +void test_mismatch_binary_exception(ExPolicy&& policy, IteratorTag) { static_assert( hpx::parallel::execution::is_execution_policy::value, @@ -271,9 +380,6 @@ void test_mismatch_binary_exception(ExPolicy policy, IteratorTag) typedef std::vector::iterator base_iterator; typedef test::test_iterator iterator; - typedef std::pair base_return_type; - typedef std::pair return_type; - std::vector c1(10007); std::vector c2(c1.size()); @@ -284,9 +390,8 @@ void test_mismatch_binary_exception(ExPolicy policy, IteratorTag) bool caught_exception = false; try { - hpx::parallel::mismatch(policy, iterator(std::begin(c1)), - iterator(std::end(c1)), std::begin(c2), std::end(c2), - [](std::size_t v1, std::size_t v2) { + hpx::mismatch(policy, iterator(std::begin(c1)), iterator(std::end(c1)), + std::begin(c2), std::end(c2), [](std::size_t v1, std::size_t v2) { return throw std::runtime_error("test"), true; }); @@ -306,14 +411,11 @@ void test_mismatch_binary_exception(ExPolicy policy, IteratorTag) } template -void test_mismatch_binary_exception_async(ExPolicy p, IteratorTag) +void test_mismatch_binary_exception_async(ExPolicy&& p, IteratorTag) { typedef std::vector::iterator base_iterator; typedef test::test_iterator iterator; - typedef std::pair base_return_type; - typedef std::pair return_type; - std::vector c1(10007); std::vector c2(c1.size()); @@ -325,9 +427,9 @@ void test_mismatch_binary_exception_async(ExPolicy p, IteratorTag) bool returned_from_algorithm = false; try { - hpx::future f = hpx::parallel::mismatch(p, - iterator(std::begin(c1)), iterator(std::end(c1)), std::begin(c2), - std::end(c2), [](std::size_t v1, std::size_t v2) { + auto f = hpx::mismatch(p, iterator(std::begin(c1)), + iterator(std::end(c1)), std::begin(c2), std::end(c2), + [](std::size_t v1, std::size_t v2) { return throw std::runtime_error("test"), true; }); returned_from_algorithm = true; @@ -354,6 +456,8 @@ void test_mismatch_binary_exception() { using namespace hpx::parallel; + test_mismatch_binary_exception(IteratorTag()); + // If the execution policy object is of type vector_execution_policy, // std::terminate shall be called. therefore we do not test exceptions // with a vector execution policy @@ -374,7 +478,7 @@ void mismatch_binary_exception_test() ///////////////////////////////////////////////////////////////////////////// template -void test_mismatch_binary_bad_alloc(ExPolicy policy, IteratorTag) +void test_mismatch_binary_bad_alloc(ExPolicy&& policy, IteratorTag) { static_assert( hpx::parallel::execution::is_execution_policy::value, @@ -383,9 +487,6 @@ void test_mismatch_binary_bad_alloc(ExPolicy policy, IteratorTag) typedef std::vector::iterator base_iterator; typedef test::test_iterator iterator; - typedef std::pair base_return_type; - typedef std::pair return_type; - std::vector c1(10007); std::vector c2(c1.size()); @@ -396,9 +497,8 @@ void test_mismatch_binary_bad_alloc(ExPolicy policy, IteratorTag) bool caught_bad_alloc = false; try { - hpx::parallel::mismatch(policy, iterator(std::begin(c1)), - iterator(std::end(c1)), std::begin(c2), std::end(c2), - [](std::size_t v1, std::size_t v2) { + hpx::mismatch(policy, iterator(std::begin(c1)), iterator(std::end(c1)), + std::begin(c2), std::end(c2), [](std::size_t v1, std::size_t v2) { return throw std::bad_alloc(), true; }); @@ -417,14 +517,11 @@ void test_mismatch_binary_bad_alloc(ExPolicy policy, IteratorTag) } template -void test_mismatch_binary_bad_alloc_async(ExPolicy p, IteratorTag) +void test_mismatch_binary_bad_alloc_async(ExPolicy&& p, IteratorTag) { typedef std::vector::iterator base_iterator; typedef test::test_iterator iterator; - typedef std::pair base_return_type; - typedef std::pair return_type; - std::vector c1(10007); std::vector c2(c1.size()); @@ -436,9 +533,9 @@ void test_mismatch_binary_bad_alloc_async(ExPolicy p, IteratorTag) bool returned_from_algorithm = false; try { - hpx::future f = hpx::parallel::mismatch(p, - iterator(std::begin(c1)), iterator(std::end(c1)), std::begin(c2), - std::end(c2), [](std::size_t v1, std::size_t v2) { + auto f = hpx::mismatch(p, iterator(std::begin(c1)), + iterator(std::end(c1)), std::begin(c2), std::end(c2), + [](std::size_t v1, std::size_t v2) { return throw std::bad_alloc(), true; }); returned_from_algorithm = true; diff --git a/libs/algorithms/tests/unit/algorithms/unique_copy_tests.hpp b/libs/algorithms/tests/unit/algorithms/unique_copy_tests.hpp index 7755cfc9dd18..bf0a857db062 100644 --- a/libs/algorithms/tests/unit/algorithms/unique_copy_tests.hpp +++ b/libs/algorithms/tests/unit/algorithms/unique_copy_tests.hpp @@ -75,11 +75,21 @@ struct user_defined_type return this->name == t.name && this->val == t.val; } + bool operator!=(user_defined_type const& t) const + { + return this->name != t.name || this->val != t.val; + } + bool operator==(int rand_no) const { return this->val == rand_no; } + bool operator!=(int rand_no) const + { + return this->val != rand_no; + } + static const std::vector name_list; int val; diff --git a/libs/algorithms/tests/unit/algorithms/unique_tests.hpp b/libs/algorithms/tests/unit/algorithms/unique_tests.hpp index 596b5a17d459..6d108e107693 100644 --- a/libs/algorithms/tests/unit/algorithms/unique_tests.hpp +++ b/libs/algorithms/tests/unit/algorithms/unique_tests.hpp @@ -75,11 +75,21 @@ struct user_defined_type return this->name == t.name && this->val == t.val; } + bool operator!=(user_defined_type const& t) const + { + return this->name != t.name || this->val != t.val; + } + bool operator==(int rand_no) const { return this->val == rand_no; } + bool operator!=(int rand_no) const + { + return this->val != rand_no; + } + static const std::vector name_list; int val; diff --git a/libs/algorithms/tests/unit/container_algorithms/CMakeLists.txt b/libs/algorithms/tests/unit/container_algorithms/CMakeLists.txt index 56220003425d..2bedbd85305a 100644 --- a/libs/algorithms/tests/unit/container_algorithms/CMakeLists.txt +++ b/libs/algorithms/tests/unit/container_algorithms/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2014-2015 Hartmut Kaiser +# Copyright (c) 2014-2020 Hartmut Kaiser # # SPDX-License-Identifier: BSL-1.0 # Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -31,6 +31,8 @@ set(tests merge_range min_element_range minmax_element_range + mismatch_binary_range + mismatch_range move_range none_of_range partition_range diff --git a/libs/algorithms/tests/unit/container_algorithms/mismatch_binary_range.cpp b/libs/algorithms/tests/unit/container_algorithms/mismatch_binary_range.cpp new file mode 100644 index 000000000000..c1e7d938f46e --- /dev/null +++ b/libs/algorithms/tests/unit/container_algorithms/mismatch_binary_range.cpp @@ -0,0 +1,663 @@ +// Copyright (c) 2014-2020 Hartmut Kaiser +// +// SPDX-License-Identifier: BSL-1.0 +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_utils.hpp" + +/////////////////////////////////////////////////////////////////////////////// +int seed = std::random_device{}(); +std::mt19937 gen(seed); +std::uniform_int_distribution<> dis(0, 10006); + +template +void test_mismatch_binary1(IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef hpx::util::iterator_range base_range; + typedef test::test_iterator iterator; + typedef hpx::util::iterator_range range; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + iterator begin1 = iterator(std::begin(c1)); + iterator end1 = iterator(std::end(c1)); + + { + auto result = + hpx::ranges::mismatch(range(iterator(begin1), iterator(end1)), + base_range(std::begin(c2), std::end(c2))); + + // verify values + HPX_TEST_EQ(std::size_t(std::distance(begin1, result.in1)), c1.size()); + HPX_TEST_EQ( + std::size_t(std::distance(std::begin(c2), result.in2)), c2.size()); + } + + { + std::size_t changed_idx = dis(gen); //-V104 + ++c1[changed_idx]; + + auto result = + hpx::ranges::mismatch(range(iterator(begin1), iterator(end1)), + base_range(std::begin(c2), std::end(c2))); + + // verify values + HPX_TEST_EQ( + std::size_t(std::distance(begin1, result.in1)), changed_idx); + HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.in2)), + changed_idx); + } +} + +template +void test_mismatch_binary1(ExPolicy&& policy, IteratorTag) +{ + static_assert( + hpx::parallel::execution::is_execution_policy::value, + "hpx::parallel::execution::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef hpx::util::iterator_range base_range; + typedef test::test_iterator iterator; + typedef hpx::util::iterator_range range; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + iterator begin1 = iterator(std::begin(c1)); + iterator end1 = iterator(std::end(c1)); + + { + auto result = hpx::ranges::mismatch(policy, + range(iterator(begin1), iterator(end1)), + base_range(std::begin(c2), std::end(c2))); + + // verify values + HPX_TEST_EQ(std::size_t(std::distance(begin1, result.in1)), c1.size()); + HPX_TEST_EQ( + std::size_t(std::distance(std::begin(c2), result.in2)), c2.size()); + } + + { + std::size_t changed_idx = dis(gen); //-V104 + ++c1[changed_idx]; + + auto result = hpx::ranges::mismatch(policy, + range(iterator(begin1), iterator(end1)), + base_range(std::begin(c2), std::end(c2))); + + // verify values + HPX_TEST_EQ( + std::size_t(std::distance(begin1, result.in1)), changed_idx); + HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.in2)), + changed_idx); + } +} + +template +void test_mismatch_binary1_async(ExPolicy&& p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef hpx::util::iterator_range base_range; + typedef test::test_iterator iterator; + typedef hpx::util::iterator_range range; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + iterator begin1 = iterator(std::begin(c1)); + iterator end1 = iterator(std::end(c1)); + + { + auto f = + hpx::ranges::mismatch(p, range(iterator(begin1), iterator(end1)), + base_range(std::begin(c2), std::end(c2))); + f.wait(); + + // verify values + auto result = f.get(); + HPX_TEST_EQ(std::size_t(std::distance(begin1, result.in1)), c1.size()); + HPX_TEST_EQ( + std::size_t(std::distance(std::begin(c2), result.in2)), c2.size()); + } + + { + std::size_t changed_idx = dis(gen); //-V104 + ++c1[changed_idx]; + + auto f = + hpx::ranges::mismatch(p, range(iterator(begin1), iterator(end1)), + base_range(std::begin(c2), std::end(c2))); + f.wait(); + + // verify values + auto result = f.get(); + HPX_TEST_EQ( + std::size_t(std::distance(begin1, result.in1)), changed_idx); + HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.in2)), + changed_idx); + } +} + +template +void test_mismatch_binary1() +{ + using namespace hpx::parallel; + + test_mismatch_binary1(IteratorTag()); + + test_mismatch_binary1(execution::seq, IteratorTag()); + test_mismatch_binary1(execution::par, IteratorTag()); + test_mismatch_binary1(execution::par_unseq, IteratorTag()); + + test_mismatch_binary1_async(execution::seq(execution::task), IteratorTag()); + test_mismatch_binary1_async(execution::par(execution::task), IteratorTag()); +} + +void mismatch_binary_test1() +{ + test_mismatch_binary1(); + test_mismatch_binary1(); +} + +/////////////////////////////////////////////////////////////////////////////// +template +void test_mismatch_binary2(IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef hpx::util::iterator_range base_range; + typedef test::test_iterator iterator; + typedef hpx::util::iterator_range range; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + iterator begin1 = iterator(std::begin(c1)); + iterator end1 = iterator(std::end(c1)); + + { + auto result = + hpx::ranges::mismatch(range(iterator(begin1), iterator(end1)), + base_range(std::begin(c2), std::end(c2)), + std::equal_to()); + + // verify values + HPX_TEST_EQ(std::size_t(std::distance(begin1, result.in1)), c1.size()); + HPX_TEST_EQ( + std::size_t(std::distance(std::begin(c2), result.in2)), c2.size()); + } + + { + std::size_t changed_idx = dis(gen); //-V104 + ++c1[changed_idx]; + + auto result = + hpx::ranges::mismatch(range(iterator(begin1), iterator(end1)), + base_range(std::begin(c2), std::end(c2)), + std::equal_to()); + + // verify values + HPX_TEST_EQ( + std::size_t(std::distance(begin1, result.in1)), changed_idx); + HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.in2)), + changed_idx); + } +} + +template +void test_mismatch_binary2(ExPolicy&& policy, IteratorTag) +{ + static_assert( + hpx::parallel::execution::is_execution_policy::value, + "hpx::parallel::execution::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef hpx::util::iterator_range base_range; + typedef test::test_iterator iterator; + typedef hpx::util::iterator_range range; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + iterator begin1 = iterator(std::begin(c1)); + iterator end1 = iterator(std::end(c1)); + + { + auto result = hpx::ranges::mismatch(policy, + range(iterator(begin1), iterator(end1)), + base_range(std::begin(c2), std::end(c2)), + std::equal_to()); + + // verify values + HPX_TEST_EQ(std::size_t(std::distance(begin1, result.in1)), c1.size()); + HPX_TEST_EQ( + std::size_t(std::distance(std::begin(c2), result.in2)), c2.size()); + } + + { + std::size_t changed_idx = dis(gen); //-V104 + ++c1[changed_idx]; + + auto result = hpx::ranges::mismatch(policy, + range(iterator(begin1), iterator(end1)), + base_range(std::begin(c2), std::end(c2)), + std::equal_to()); + + // verify values + HPX_TEST_EQ( + std::size_t(std::distance(begin1, result.in1)), changed_idx); + HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.in2)), + changed_idx); + } +} + +template +void test_mismatch_binary2_async(ExPolicy&& p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef hpx::util::iterator_range base_range; + typedef test::test_iterator iterator; + typedef hpx::util::iterator_range range; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + iterator begin1 = iterator(std::begin(c1)); + iterator end1 = iterator(std::end(c1)); + + { + auto f = + hpx::ranges::mismatch(p, range(iterator(begin1), iterator(end1)), + base_range(std::begin(c2), std::end(c2)), + std::equal_to()); + f.wait(); + + // verify values + auto result = f.get(); + HPX_TEST_EQ(std::size_t(std::distance(begin1, result.in1)), c1.size()); + HPX_TEST_EQ( + std::size_t(std::distance(std::begin(c2), result.in2)), c2.size()); + } + + { + std::size_t changed_idx = dis(gen); //-V104 + ++c1[changed_idx]; + + auto f = + hpx::ranges::mismatch(p, range(iterator(begin1), iterator(end1)), + base_range(std::begin(c2), std::end(c2)), + std::equal_to()); + f.wait(); + + // verify values + auto result = f.get(); + HPX_TEST_EQ( + std::size_t(std::distance(begin1, result.in1)), changed_idx); + HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.in2)), + changed_idx); + } +} + +template +void test_mismatch_binary2() +{ + using namespace hpx::parallel; + + test_mismatch_binary2(IteratorTag()); + + test_mismatch_binary2(execution::seq, IteratorTag()); + test_mismatch_binary2(execution::par, IteratorTag()); + test_mismatch_binary2(execution::par_unseq, IteratorTag()); + + test_mismatch_binary2_async(execution::seq(execution::task), IteratorTag()); + test_mismatch_binary2_async(execution::par(execution::task), IteratorTag()); +} + +void mismatch_binary_test2() +{ + test_mismatch_binary2(); + test_mismatch_binary2(); +} + +/////////////////////////////////////////////////////////////////////////////// +template +void test_mismatch_binary_exception(IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef hpx::util::iterator_range base_range; + typedef test::test_iterator iterator; + typedef hpx::util::iterator_range range; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + bool caught_exception = false; + try + { + hpx::ranges::mismatch( + range(iterator(std::begin(c1)), iterator(std::end(c1))), + base_range(std::begin(c2), std::end(c2)), + [](std::size_t v1, std::size_t v2) { + return throw std::runtime_error("test"), true; + }); + + HPX_TEST(false); + } + catch (hpx::exception_list const& e) + { + caught_exception = true; + test::test_num_exceptions::call(hpx::parallel::execution::seq, e); + } + catch (...) + { + HPX_TEST(false); + } + + HPX_TEST(caught_exception); +} + +template +void test_mismatch_binary_exception(ExPolicy&& policy, IteratorTag) +{ + static_assert( + hpx::parallel::execution::is_execution_policy::value, + "hpx::parallel::execution::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef hpx::util::iterator_range base_range; + typedef test::test_iterator iterator; + typedef hpx::util::iterator_range range; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + bool caught_exception = false; + try + { + hpx::ranges::mismatch(policy, + range(iterator(std::begin(c1)), iterator(std::end(c1))), + base_range(std::begin(c2), std::end(c2)), + [](std::size_t v1, std::size_t v2) { + return throw std::runtime_error("test"), true; + }); + + HPX_TEST(false); + } + catch (hpx::exception_list const& e) + { + caught_exception = true; + test::test_num_exceptions::call(policy, e); + } + catch (...) + { + HPX_TEST(false); + } + + HPX_TEST(caught_exception); +} + +template +void test_mismatch_binary_exception_async(ExPolicy&& p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef hpx::util::iterator_range base_range; + typedef test::test_iterator iterator; + typedef hpx::util::iterator_range range; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + bool caught_exception = false; + bool returned_from_algorithm = false; + try + { + auto f = hpx::ranges::mismatch(p, + range(iterator(std::begin(c1)), iterator(std::end(c1))), + base_range(std::begin(c2), std::end(c2)), + [](std::size_t v1, std::size_t v2) { + return throw std::runtime_error("test"), true; + }); + returned_from_algorithm = true; + f.get(); + + HPX_TEST(false); + } + catch (hpx::exception_list const& e) + { + caught_exception = true; + test::test_num_exceptions::call(p, e); + } + catch (...) + { + HPX_TEST(false); + } + + HPX_TEST(caught_exception); + HPX_TEST(returned_from_algorithm); +} + +template +void test_mismatch_binary_exception() +{ + using namespace hpx::parallel; + + test_mismatch_binary_exception(IteratorTag()); + + // If the execution policy object is of type vector_execution_policy, + // std::terminate shall be called. therefore we do not test exceptions + // with a vector execution policy + test_mismatch_binary_exception(execution::seq, IteratorTag()); + test_mismatch_binary_exception(execution::par, IteratorTag()); + + test_mismatch_binary_exception_async( + execution::seq(execution::task), IteratorTag()); + test_mismatch_binary_exception_async( + execution::par(execution::task), IteratorTag()); +} + +void mismatch_binary_exception_test() +{ + test_mismatch_binary_exception(); + test_mismatch_binary_exception(); +} + +///////////////////////////////////////////////////////////////////////////// +template +void test_mismatch_binary_bad_alloc(ExPolicy&& policy, IteratorTag) +{ + static_assert( + hpx::parallel::execution::is_execution_policy::value, + "hpx::parallel::execution::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef hpx::util::iterator_range base_range; + typedef test::test_iterator iterator; + typedef hpx::util::iterator_range range; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + bool caught_bad_alloc = false; + try + { + hpx::ranges::mismatch(policy, + range(iterator(std::begin(c1)), iterator(std::end(c1))), + base_range(std::begin(c2), std::end(c2)), + [](std::size_t v1, std::size_t v2) { + return throw std::bad_alloc(), true; + }); + + HPX_TEST(false); + } + catch (std::bad_alloc const&) + { + caught_bad_alloc = true; + } + catch (...) + { + HPX_TEST(false); + } + + HPX_TEST(caught_bad_alloc); +} + +template +void test_mismatch_binary_bad_alloc_async(ExPolicy&& p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef hpx::util::iterator_range base_range; + typedef test::test_iterator iterator; + typedef hpx::util::iterator_range range; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + bool caught_bad_alloc = false; + bool returned_from_algorithm = false; + try + { + auto f = hpx::ranges::mismatch(p, + range(iterator(std::begin(c1)), iterator(std::end(c1))), + base_range(std::begin(c2), std::end(c2)), + [](std::size_t v1, std::size_t v2) { + return throw std::bad_alloc(), true; + }); + returned_from_algorithm = true; + f.get(); + + HPX_TEST(false); + } + catch (std::bad_alloc const&) + { + caught_bad_alloc = true; + } + catch (...) + { + HPX_TEST(false); + } + + HPX_TEST(caught_bad_alloc); + HPX_TEST(returned_from_algorithm); +} + +template +void test_mismatch_binary_bad_alloc() +{ + using namespace hpx::parallel; + + // If the execution policy object is of type vector_execution_policy, + // std::terminate shall be called. therefore we do not test exceptions + // with a vector execution policy + test_mismatch_binary_bad_alloc(execution::seq, IteratorTag()); + test_mismatch_binary_bad_alloc(execution::par, IteratorTag()); + + test_mismatch_binary_bad_alloc_async( + execution::seq(execution::task), IteratorTag()); + test_mismatch_binary_bad_alloc_async( + execution::par(execution::task), IteratorTag()); +} + +void mismatch_binary_bad_alloc_test() +{ + test_mismatch_binary_bad_alloc(); + test_mismatch_binary_bad_alloc(); +} + +/////////////////////////////////////////////////////////////////////////////// +int hpx_main(hpx::program_options::variables_map& vm) +{ + unsigned int seed = (unsigned int) std::time(nullptr); + if (vm.count("seed")) + seed = vm["seed"].as(); + + std::cout << "using seed: " << seed << std::endl; + gen.seed(seed); + + mismatch_binary_test1(); + mismatch_binary_test2(); + mismatch_binary_exception_test(); + mismatch_binary_bad_alloc_test(); + return hpx::finalize(); +} + +int main(int argc, char* argv[]) +{ + // add command line option which controls the random number generator seed + using namespace hpx::program_options; + options_description desc_commandline( + "Usage: " HPX_APPLICATION_STRING " [options]"); + + desc_commandline.add_options()("seed,s", value(), + "the random number generator seed to use for this run"); + + // By default this test should run on all available cores + std::vector const cfg = {"hpx.os_threads=all"}; + + // Initialize and run HPX + HPX_TEST_EQ_MSG(hpx::init(desc_commandline, argc, argv, cfg), 0, + "HPX main exited with non-zero status"); + + return hpx::util::report_errors(); +} diff --git a/libs/algorithms/tests/unit/container_algorithms/mismatch_range.cpp b/libs/algorithms/tests/unit/container_algorithms/mismatch_range.cpp new file mode 100644 index 000000000000..92c636aa5c11 --- /dev/null +++ b/libs/algorithms/tests/unit/container_algorithms/mismatch_range.cpp @@ -0,0 +1,636 @@ +// Copyright (c) 2014-2020 Hartmut Kaiser +// +// SPDX-License-Identifier: BSL-1.0 +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_utils.hpp" + +/////////////////////////////////////////////////////////////////////////////// +int seed = std::random_device{}(); +std::mt19937 gen(seed); +std::uniform_int_distribution<> dis(0, 10006); + +template +void test_mismatch1(IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef hpx::util::iterator_range base_range; + typedef test::test_iterator iterator; + typedef hpx::util::iterator_range range; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + iterator begin1 = iterator(std::begin(c1)); + iterator end1 = iterator(std::end(c1)); + + { + auto result = + hpx::ranges::mismatch(begin1, end1, std::begin(c2), std::end(c2)); + + // verify values + HPX_TEST_EQ(std::size_t(std::distance(begin1, result.in1)), c1.size()); + HPX_TEST_EQ( + std::size_t(std::distance(std::begin(c2), result.in2)), c2.size()); + } + + { + std::size_t changed_idx = dis(gen); //-V104 + ++c1[changed_idx]; + + auto result = + hpx::ranges::mismatch(begin1, end1, std::begin(c2), std::end(c2)); + + // verify values + HPX_TEST_EQ( + std::size_t(std::distance(begin1, result.in1)), changed_idx); + HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.in2)), + changed_idx); + } +} + +template +void test_mismatch1(ExPolicy&& policy, IteratorTag) +{ + static_assert( + hpx::parallel::execution::is_execution_policy::value, + "hpx::parallel::execution::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef hpx::util::iterator_range base_range; + typedef test::test_iterator iterator; + typedef hpx::util::iterator_range range; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + iterator begin1 = iterator(std::begin(c1)); + iterator end1 = iterator(std::end(c1)); + + { + auto result = hpx::ranges::mismatch( + policy, begin1, end1, std::begin(c2), std::end(c2)); + + // verify values + HPX_TEST_EQ(std::size_t(std::distance(begin1, result.in1)), c1.size()); + HPX_TEST_EQ( + std::size_t(std::distance(std::begin(c2), result.in2)), c2.size()); + } + + { + std::size_t changed_idx = dis(gen); //-V104 + ++c1[changed_idx]; + + auto result = hpx::ranges::mismatch( + policy, begin1, end1, std::begin(c2), std::end(c2)); + + // verify values + HPX_TEST_EQ( + std::size_t(std::distance(begin1, result.in1)), changed_idx); + HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.in2)), + changed_idx); + } +} + +template +void test_mismatch1_async(ExPolicy&& p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef hpx::util::iterator_range base_range; + typedef test::test_iterator iterator; + typedef hpx::util::iterator_range range; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + iterator begin1 = iterator(std::begin(c1)); + iterator end1 = iterator(std::end(c1)); + + { + auto f = hpx::ranges::mismatch( + p, begin1, end1, std::begin(c2), std::end(c2)); + f.wait(); + + // verify values + auto result = f.get(); + HPX_TEST_EQ(std::size_t(std::distance(begin1, result.in1)), c1.size()); + HPX_TEST_EQ( + std::size_t(std::distance(std::begin(c2), result.in2)), c2.size()); + } + + { + std::size_t changed_idx = dis(gen); //-V104 + ++c1[changed_idx]; + + auto f = hpx::ranges::mismatch( + p, begin1, end1, std::begin(c2), std::end(c2)); + f.wait(); + + // verify values + auto result = f.get(); + HPX_TEST_EQ( + std::size_t(std::distance(begin1, result.in1)), changed_idx); + HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.in2)), + changed_idx); + } +} + +template +void test_mismatch1() +{ + using namespace hpx::parallel; + + test_mismatch1(IteratorTag()); + + test_mismatch1(execution::seq, IteratorTag()); + test_mismatch1(execution::par, IteratorTag()); + test_mismatch1(execution::par_unseq, IteratorTag()); + + test_mismatch1_async(execution::seq(execution::task), IteratorTag()); + test_mismatch1_async(execution::par(execution::task), IteratorTag()); +} + +void mismatch_test1() +{ + test_mismatch1(); + test_mismatch1(); +} + +/////////////////////////////////////////////////////////////////////////////// +template +void test_mismatch2(IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef hpx::util::iterator_range base_range; + typedef test::test_iterator iterator; + typedef hpx::util::iterator_range range; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + iterator begin1 = iterator(std::begin(c1)); + iterator end1 = iterator(std::end(c1)); + + { + auto result = hpx::ranges::mismatch(begin1, end1, std::begin(c2), + std::end(c2), std::equal_to()); + + // verify values + HPX_TEST_EQ(std::size_t(std::distance(begin1, result.in1)), c1.size()); + HPX_TEST_EQ( + std::size_t(std::distance(std::begin(c2), result.in2)), c2.size()); + } + + { + std::size_t changed_idx = dis(gen); //-V104 + ++c1[changed_idx]; + + auto result = hpx::ranges::mismatch(begin1, end1, std::begin(c2), + std::end(c2), std::equal_to()); + + // verify values + HPX_TEST_EQ( + std::size_t(std::distance(begin1, result.in1)), changed_idx); + HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.in2)), + changed_idx); + } +} + +template +void test_mismatch2(ExPolicy&& policy, IteratorTag) +{ + static_assert( + hpx::parallel::execution::is_execution_policy::value, + "hpx::parallel::execution::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef hpx::util::iterator_range base_range; + typedef test::test_iterator iterator; + typedef hpx::util::iterator_range range; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + iterator begin1 = iterator(std::begin(c1)); + iterator end1 = iterator(std::end(c1)); + + { + auto result = hpx::ranges::mismatch(policy, begin1, end1, + std::begin(c2), std::end(c2), std::equal_to()); + + // verify values + HPX_TEST_EQ(std::size_t(std::distance(begin1, result.in1)), c1.size()); + HPX_TEST_EQ( + std::size_t(std::distance(std::begin(c2), result.in2)), c2.size()); + } + + { + std::size_t changed_idx = dis(gen); //-V104 + ++c1[changed_idx]; + + auto result = hpx::ranges::mismatch(policy, begin1, end1, + std::begin(c2), std::end(c2), std::equal_to()); + + // verify values + HPX_TEST_EQ( + std::size_t(std::distance(begin1, result.in1)), changed_idx); + HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.in2)), + changed_idx); + } +} + +template +void test_mismatch2_async(ExPolicy&& p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef hpx::util::iterator_range base_range; + typedef test::test_iterator iterator; + typedef hpx::util::iterator_range range; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + iterator begin1 = iterator(std::begin(c1)); + iterator end1 = iterator(std::end(c1)); + + { + auto f = hpx::ranges::mismatch(p, begin1, end1, std::begin(c2), + std::end(c2), std::equal_to()); + f.wait(); + + // verify values + auto result = f.get(); + HPX_TEST_EQ(std::size_t(std::distance(begin1, result.in1)), c1.size()); + HPX_TEST_EQ( + std::size_t(std::distance(std::begin(c2), result.in2)), c2.size()); + } + + { + std::size_t changed_idx = dis(gen); //-V104 + ++c1[changed_idx]; + + auto f = hpx::ranges::mismatch(p, begin1, end1, std::begin(c2), + std::end(c2), std::equal_to()); + f.wait(); + + // verify values + auto result = f.get(); + HPX_TEST_EQ( + std::size_t(std::distance(begin1, result.in1)), changed_idx); + HPX_TEST_EQ(std::size_t(std::distance(std::begin(c2), result.in2)), + changed_idx); + } +} + +template +void test_mismatch2() +{ + using namespace hpx::parallel; + + test_mismatch2(IteratorTag()); + + test_mismatch2(execution::seq, IteratorTag()); + test_mismatch2(execution::par, IteratorTag()); + test_mismatch2(execution::par_unseq, IteratorTag()); + + test_mismatch2_async(execution::seq(execution::task), IteratorTag()); + test_mismatch2_async(execution::par(execution::task), IteratorTag()); +} + +void mismatch_test2() +{ + test_mismatch2(); + test_mismatch2(); +} + +/////////////////////////////////////////////////////////////////////////////// +template +void test_mismatch_exception(IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef hpx::util::iterator_range base_range; + typedef test::test_iterator iterator; + typedef hpx::util::iterator_range range; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + bool caught_exception = false; + try + { + hpx::ranges::mismatch(iterator(std::begin(c1)), iterator(std::end(c1)), + std::begin(c2), std::end(c2), [](std::size_t v1, std::size_t v2) { + return throw std::runtime_error("test"), true; + }); + + HPX_TEST(false); + } + catch (hpx::exception_list const& e) + { + caught_exception = true; + test::test_num_exceptions::call(hpx::parallel::execution::seq, e); + } + catch (...) + { + HPX_TEST(false); + } + + HPX_TEST(caught_exception); +} + +template +void test_mismatch_exception(ExPolicy&& policy, IteratorTag) +{ + static_assert( + hpx::parallel::execution::is_execution_policy::value, + "hpx::parallel::execution::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef hpx::util::iterator_range base_range; + typedef test::test_iterator iterator; + typedef hpx::util::iterator_range range; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + bool caught_exception = false; + try + { + hpx::ranges::mismatch(policy, iterator(std::begin(c1)), + iterator(std::end(c1)), std::begin(c2), std::end(c2), + [](std::size_t v1, std::size_t v2) { + return throw std::runtime_error("test"), true; + }); + + HPX_TEST(false); + } + catch (hpx::exception_list const& e) + { + caught_exception = true; + test::test_num_exceptions::call(policy, e); + } + catch (...) + { + HPX_TEST(false); + } + + HPX_TEST(caught_exception); +} + +template +void test_mismatch_exception_async(ExPolicy&& p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef hpx::util::iterator_range base_range; + typedef test::test_iterator iterator; + typedef hpx::util::iterator_range range; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + bool caught_exception = false; + bool returned_from_algorithm = false; + try + { + auto f = hpx::ranges::mismatch(p, iterator(std::begin(c1)), + iterator(std::end(c1)), std::begin(c2), std::end(c2), + [](std::size_t v1, std::size_t v2) { + return throw std::runtime_error("test"), true; + }); + returned_from_algorithm = true; + f.get(); + + HPX_TEST(false); + } + catch (hpx::exception_list const& e) + { + caught_exception = true; + test::test_num_exceptions::call(p, e); + } + catch (...) + { + HPX_TEST(false); + } + + HPX_TEST(caught_exception); + HPX_TEST(returned_from_algorithm); +} + +template +void test_mismatch_exception() +{ + using namespace hpx::parallel; + + // If the execution policy object is of type vector_execution_policy, + // std::terminate shall be called. therefore we do not test exceptions + // with a vector execution policy + test_mismatch_exception(execution::seq, IteratorTag()); + test_mismatch_exception(execution::par, IteratorTag()); + + test_mismatch_exception_async( + execution::seq(execution::task), IteratorTag()); + test_mismatch_exception_async( + execution::par(execution::task), IteratorTag()); +} + +void mismatch_exception_test() +{ + test_mismatch_exception(); + test_mismatch_exception(); +} + +///////////////////////////////////////////////////////////////////////////// +template +void test_mismatch_bad_alloc(ExPolicy&& policy, IteratorTag) +{ + static_assert( + hpx::parallel::execution::is_execution_policy::value, + "hpx::parallel::execution::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef hpx::util::iterator_range base_range; + typedef test::test_iterator iterator; + typedef hpx::util::iterator_range range; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + bool caught_bad_alloc = false; + try + { + hpx::ranges::mismatch(policy, iterator(std::begin(c1)), + iterator(std::end(c1)), std::begin(c2), std::end(c2), + [](std::size_t v1, std::size_t v2) { + return throw std::bad_alloc(), true; + }); + + HPX_TEST(false); + } + catch (std::bad_alloc const&) + { + caught_bad_alloc = true; + } + catch (...) + { + HPX_TEST(false); + } + + HPX_TEST(caught_bad_alloc); +} + +template +void test_mismatch_bad_alloc_async(ExPolicy&& p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef hpx::util::iterator_range base_range; + typedef test::test_iterator iterator; + typedef hpx::util::iterator_range range; + + std::vector c1(10007); + std::vector c2(c1.size()); + + std::size_t first_value = gen(); //-V101 + std::iota(std::begin(c1), std::end(c1), first_value); + std::iota(std::begin(c2), std::end(c2), first_value); + + bool caught_bad_alloc = false; + bool returned_from_algorithm = false; + try + { + auto f = hpx::ranges::mismatch(p, iterator(std::begin(c1)), + iterator(std::end(c1)), std::begin(c2), std::end(c2), + [](std::size_t v1, std::size_t v2) { + return throw std::bad_alloc(), true; + }); + returned_from_algorithm = true; + f.get(); + + HPX_TEST(false); + } + catch (std::bad_alloc const&) + { + caught_bad_alloc = true; + } + catch (...) + { + HPX_TEST(false); + } + + HPX_TEST(caught_bad_alloc); + HPX_TEST(returned_from_algorithm); +} + +template +void test_mismatch_bad_alloc() +{ + using namespace hpx::parallel; + + // If the execution policy object is of type vector_execution_policy, + // std::terminate shall be called. therefore we do not test exceptions + // with a vector execution policy + test_mismatch_bad_alloc(execution::seq, IteratorTag()); + test_mismatch_bad_alloc(execution::par, IteratorTag()); + + test_mismatch_bad_alloc_async( + execution::seq(execution::task), IteratorTag()); + test_mismatch_bad_alloc_async( + execution::par(execution::task), IteratorTag()); +} + +void mismatch_bad_alloc_test() +{ + test_mismatch_bad_alloc(); + test_mismatch_bad_alloc(); +} + +/////////////////////////////////////////////////////////////////////////////// +int hpx_main(hpx::program_options::variables_map& vm) +{ + unsigned int seed = (unsigned int) std::time(nullptr); + if (vm.count("seed")) + seed = vm["seed"].as(); + + std::cout << "using seed: " << seed << std::endl; + gen.seed(seed); + + mismatch_test1(); + mismatch_test2(); + mismatch_exception_test(); + mismatch_bad_alloc_test(); + return hpx::finalize(); +} + +int main(int argc, char* argv[]) +{ + // add command line option which controls the random number generator seed + using namespace hpx::program_options; + options_description desc_commandline( + "Usage: " HPX_APPLICATION_STRING " [options]"); + + desc_commandline.add_options()("seed,s", value(), + "the random number generator seed to use for this run"); + // By default this test should run on all available cores + std::vector const cfg = {"hpx.os_threads=all"}; + + // Initialize and run HPX + HPX_TEST_EQ_MSG(hpx::init(desc_commandline, argc, argv, cfg), 0, + "HPX main exited with non-zero status"); + + return hpx::util::report_errors(); +} diff --git a/libs/algorithms/tests/unit/container_algorithms/unique_copy_range.cpp b/libs/algorithms/tests/unit/container_algorithms/unique_copy_range.cpp index 2064f5abd47a..2a89c0a35fc7 100644 --- a/libs/algorithms/tests/unit/container_algorithms/unique_copy_range.cpp +++ b/libs/algorithms/tests/unit/container_algorithms/unique_copy_range.cpp @@ -35,6 +35,11 @@ struct user_defined_type return this->name == t.name && this->val == t.val; } + bool operator!=(user_defined_type const& t) const + { + return this->name != t.name || this->val != t.val; + } + static const std::vector name_list; int val; diff --git a/libs/algorithms/tests/unit/container_algorithms/unique_range.cpp b/libs/algorithms/tests/unit/container_algorithms/unique_range.cpp index 05d40a9b7576..9c8bf2fe443a 100644 --- a/libs/algorithms/tests/unit/container_algorithms/unique_range.cpp +++ b/libs/algorithms/tests/unit/container_algorithms/unique_range.cpp @@ -35,6 +35,11 @@ struct user_defined_type return this->name == t.name && this->val == t.val; } + bool operator!=(user_defined_type const& t) const + { + return this->name != t.name || this->val != t.val; + } + static const std::vector name_list; int val; diff --git a/libs/execution/include/hpx/execution/algorithms/detail/predicates.hpp b/libs/execution/include/hpx/execution/algorithms/detail/predicates.hpp index 26298610df88..25b510c6d2eb 100644 --- a/libs/execution/include/hpx/execution/algorithms/detail/predicates.hpp +++ b/libs/execution/include/hpx/execution/algorithms/detail/predicates.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -268,14 +269,28 @@ namespace hpx { namespace parallel { inline namespace v1 { namespace detail { /////////////////////////////////////////////////////////////////////////// struct equal_to { - template - HPX_HOST_DEVICE HPX_FORCEINLINE constexpr auto operator()( - T1 const& t1, T2 const& t2) const -> decltype(t1 == t2) + template ::value>::type> + HPX_HOST_DEVICE HPX_FORCEINLINE constexpr bool operator()( + T1&& t1, T2&& t2) const { return t1 == t2; } }; + struct not_equal_to + { + template ::value>::type> + HPX_HOST_DEVICE HPX_FORCEINLINE constexpr bool operator()( + T1&& t1, T2&& t2) const + { + return t1 != t2; + } + }; + template struct compare_to { @@ -302,10 +317,40 @@ namespace hpx { namespace parallel { inline namespace v1 { namespace detail { struct less { template - constexpr auto operator()(T1 const& t1, T2 const& t2) const - -> decltype(t1 < t2) + HPX_HOST_DEVICE HPX_FORCEINLINE constexpr bool operator()( + T1&& t1, T2&& t2) const { - return t1 < t2; + return std::forward(t1) < std::forward(t2); + } + }; + + struct greater + { + template + HPX_HOST_DEVICE HPX_FORCEINLINE constexpr bool operator()( + T1&& t1, T2&& t2) const + { + return std::forward(t1) > std::forward(t2); + } + }; + + struct greater_equal + { + template + HPX_HOST_DEVICE HPX_FORCEINLINE constexpr bool operator()( + T1&& t1, T2&& t2) const + { + return std::forward(t1) >= std::forward(t2); + } + }; + + struct less_equal + { + template + HPX_HOST_DEVICE HPX_FORCEINLINE constexpr bool operator()( + T1&& t1, T2&& t2) const + { + return std::forward(t1) <= std::forward(t2); } }; @@ -370,3 +415,14 @@ namespace hpx { namespace parallel { inline namespace v1 { namespace detail { } }; }}}} // namespace hpx::parallel::v1::detail + +namespace hpx { namespace ranges { + + /////////////////////////////////////////////////////////////////////////// + using equal_to = hpx::parallel::v1::detail::equal_to; + using not_equal_to = hpx::parallel::v1::detail::not_equal_to; + using less = hpx::parallel::v1::detail::less; + using greater = hpx::parallel::v1::detail::greater; + using greater_equal = hpx::parallel::v1::detail::greater_equal; + using less_equal = hpx::parallel::v1::detail::less_equal; +}} // namespace hpx::ranges diff --git a/libs/include/include/hpx/algorithm.hpp b/libs/include/include/hpx/algorithm.hpp index a7072d73510c..2212d989ed6f 100644 --- a/libs/include/include/hpx/algorithm.hpp +++ b/libs/include/include/hpx/algorithm.hpp @@ -36,7 +36,6 @@ namespace hpx { using hpx::parallel::merge; using hpx::parallel::min_element; using hpx::parallel::minmax_element; - using hpx::parallel::mismatch; using hpx::parallel::partition; using hpx::parallel::partition_copy; using hpx::parallel::remove; diff --git a/libs/include/include/hpx/include/parallel_mismatch.hpp b/libs/include/include/hpx/include/parallel_mismatch.hpp index c19618f81b1d..82bc79a8f4da 100644 --- a/libs/include/include/hpx/include/parallel_mismatch.hpp +++ b/libs/include/include/hpx/include/parallel_mismatch.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2014 Hartmut Kaiser +// Copyright (c) 2007-2020 Hartmut Kaiser // Copyright (c) 2014 Grant Mercer // // SPDX-License-Identifier: BSL-1.0 @@ -8,3 +8,4 @@ #pragma once #include +#include diff --git a/libs/iterator_support/include/hpx/iterator_support/traits/is_iterator.hpp b/libs/iterator_support/include/hpx/iterator_support/traits/is_iterator.hpp index fec5f5f8aef6..1201dcdf4e59 100644 --- a/libs/iterator_support/include/hpx/iterator_support/traits/is_iterator.hpp +++ b/libs/iterator_support/include/hpx/iterator_support/traits/is_iterator.hpp @@ -9,6 +9,7 @@ #include #include +#include #include @@ -71,34 +72,6 @@ namespace hpx { namespace traits { using type = decltype(*(std::declval())); }; - template - struct equality_result - { - }; - - template - struct equality_result() == std::declval())>::type> - { - using type = - decltype(std::declval() == std::declval()); - }; - - template - struct inequality_result - { - }; - - template - struct inequality_result() != std::declval())>::type> - { - using type = - decltype(std::declval() != std::declval()); - }; - template struct inplace_addition_result { diff --git a/libs/iterator_support/include/hpx/iterator_support/traits/is_sentinel_for.hpp b/libs/iterator_support/include/hpx/iterator_support/traits/is_sentinel_for.hpp index b54ee80f72c1..4538dbc800d5 100644 --- a/libs/iterator_support/include/hpx/iterator_support/traits/is_sentinel_for.hpp +++ b/libs/iterator_support/include/hpx/iterator_support/traits/is_sentinel_for.hpp @@ -12,13 +12,13 @@ #include #include -// The trait checks whether sentinel Sent is proper for iterator I. -// There are two requirements for this: -// 1. iterator I should be an input or output iterator -// 2. I and S should oblige with the weakly-equality-comparable concept - namespace hpx { namespace traits { + /////////////////////////////////////////////////////////////////////////// + // The trait checks whether sentinel Sent is proper for iterator I. + // There are two requirements for this: + // 1. iterator I should be an input or output iterator + // 2. I and S should oblige with the weakly-equality-comparable concept template struct is_sentinel_for : std::false_type { @@ -26,16 +26,13 @@ namespace hpx { namespace traits { template struct is_sentinel_for::value>::type, - typename detail::equality_result::type, - typename detail::equality_result::type, - typename detail::inequality_result::type, - typename detail::inequality_result::type>::type> + typename std::enable_if::value && + is_weakly_equality_comparable_with::value>::type> : std::true_type { }; + /////////////////////////////////////////////////////////////////////////// #if defined(HPX_HAVE_CXX20_STD_DISABLE_SIZED_SENTINEL_FOR) template inline constexpr bool disable_sized_sentinel_for = diff --git a/libs/type_support/CMakeLists.txt b/libs/type_support/CMakeLists.txt index d42b116a2c6b..86e2946773c1 100644 --- a/libs/type_support/CMakeLists.txt +++ b/libs/type_support/CMakeLists.txt @@ -11,6 +11,7 @@ set(type_support_headers hpx/type_support/always_void.hpp hpx/type_support/decay.hpp hpx/type_support/detected.hpp + hpx/type_support/equality.hpp hpx/type_support/identity.hpp hpx/type_support/lazy_conditional.hpp hpx/type_support/lazy_enable_if.hpp diff --git a/libs/type_support/include/hpx/type_support/equality.hpp b/libs/type_support/include/hpx/type_support/equality.hpp new file mode 100644 index 000000000000..351a7a5b38e2 --- /dev/null +++ b/libs/type_support/include/hpx/type_support/equality.hpp @@ -0,0 +1,82 @@ +// Copyright (c) 2007-2020 Hartmut Kaiser +// Copyright (c) 2019 Austin McCartney +// +// SPDX-License-Identifier: BSL-1.0 +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#pragma once + +#include +#include + +#include +#include + +namespace hpx { namespace traits { + namespace detail { + + /////////////////////////////////////////////////////////////////////// + template + struct equality_result + { + }; + + template + struct equality_result() == std::declval())>::type> + { + using type = + decltype(std::declval() == std::declval()); + }; + + /////////////////////////////////////////////////////////////////////// + template + struct inequality_result + { + }; + + template + struct inequality_result() != std::declval())>::type> + { + using type = + decltype(std::declval() != std::declval()); + }; + + /////////////////////////////////////////////////////////////////////// + template + struct is_weakly_equality_comparable_with : std::false_type + { + }; + + template + struct is_weakly_equality_comparable_with::type, + typename detail::equality_result::type, + typename detail::inequality_result::type, + typename detail::inequality_result::type>::type> + : std::true_type + { + }; + + } // namespace detail + + template + struct is_weakly_equality_comparable_with + : detail::is_weakly_equality_comparable_with::type, + typename std::decay::type> + { + }; + + // for now is_equality_comparable is equivalent to its weak version + template + struct is_equality_comparable_with + : detail::is_weakly_equality_comparable_with::type, + typename std::decay::type> + { + }; +}} // namespace hpx::traits