// Copyright (C) 2019 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once #include #include #include #include namespace Utils { template class function_output_iterator { public: typedef std::output_iterator_tag iterator_category; typedef void value_type; typedef std::ptrdiff_t difference_type; typedef void pointer; typedef void reference; explicit function_output_iterator() {} explicit function_output_iterator(const Callable &callable) : m_callable(&callable) {} struct helper { helper(const Callable *callable) : m_callable(callable) {} template helper &operator=(T &&value) { (*m_callable)(std::forward(value)); return *this; } const Callable *m_callable; }; helper operator*() { return helper(m_callable); } function_output_iterator &operator++() { return *this; } function_output_iterator &operator++(int) { return *this; } private: const Callable *m_callable; }; template function_output_iterator make_iterator(const Callable &callable) { return function_output_iterator(callable); } template concept callmergeable = std::indirect_strict_weak_order, std::projected>; template using set_intersection_result = std::ranges::set_intersection_result; struct set_greedy_intersection_functor { template Sentinel1, std::input_iterator Iterator2, std::sentinel_for Sentinel2, std::invocable &> Callable, typename Comp = std::ranges::less, typename Projection1 = std::identity, typename Projection2 = std::identity> requires callmergeable constexpr void operator()(Iterator1 first1, Sentinel1 last1, Iterator2 first2, Sentinel2 last2, Callable &&callable, Comp comp = {}, Projection1 proj1 = {}, Projection2 proj2 = {}) const { while (first1 != last1 && first2 != last2) if (std::invoke(comp, std::invoke(proj1, *first1), std::invoke(proj2, *first2))) ++first1; else if (std::invoke(comp, std::invoke(proj2, *first2), std::invoke(proj1, *first1))) ++first2; else { std::invoke(callable, *first1); ++first1; } } template &> Callable, typename Comp = std::ranges::less, typename Projection1 = std::identity, typename Projection2 = std::identity> requires callmergeable, std::ranges::iterator_t, Comp, Projection1, Projection2> constexpr void operator()(Range1 &&range1, Range2 &&range2, Callable callable, Comp comp = {}, Projection1 proj1 = {}, Projection2 proj2 = {}) const { (*this)(std::ranges::begin(range1), std::ranges::end(range1), std::ranges::begin(range2), std::ranges::end(range2), std::forward(callable), std::move(comp), std::move(proj1), std::move(proj2)); } template Sentinel1, std::input_iterator Iterator2, std::sentinel_for Sentinel2, std::invocable &, std::iter_value_t &> Callable, typename Comp = std::ranges::less, typename Projection1 = std::identity, typename Projection2 = std::identity> requires callmergeable constexpr void operator()(Iterator1 first1, Sentinel1 last1, Iterator2 first2, Sentinel2 last2, Callable &&callable, Comp comp = {}, Projection1 proj1 = {}, Projection2 proj2 = {}) const { while (first1 != last1 && first2 != last2) if (std::invoke(comp, std::invoke(proj1, *first1), std::invoke(proj2, *first2))) ++first1; else if (std::invoke(comp, std::invoke(proj2, *first2), std::invoke(proj1, *first1))) ++first2; else { std::invoke(callable, *first1, *first2); ++first1; } } template &, std::iter_value_t &> Callable, typename Comp = std::ranges::less, typename Projection1 = std::identity, typename Projection2 = std::identity> requires callmergeable, std::ranges::iterator_t, Comp, Projection1, Projection2> constexpr void operator()(Range1 &&range1, Range2 &&range2, Callable &&callable, Comp comp = {}, Projection1 proj1 = {}, Projection2 proj2 = {}) const { (*this)(std::ranges::begin(range1), std::ranges::end(range1), std::ranges::begin(range2), std::ranges::end(range2), std::forward(callable), std::move(comp), std::move(proj1), std::move(proj2)); } }; inline constexpr set_greedy_intersection_functor set_greedy_intersection{}; struct set_greedy_difference_functor { template Sentinel1, std::input_iterator Iterator2, std::sentinel_for Sentinel2, std::invocable &> Callable, typename Comp = std::ranges::less, typename Projection1 = std::identity, typename Projection2 = std::identity> requires callmergeable constexpr void operator()(Iterator1 first1, Sentinel1 last1, Iterator2 first2, Sentinel2 last2, Callable &&callable, Comp comp = {}, Projection1 proj1 = {}, Projection2 proj2 = {}) const { while (first1 != last1 && first2 != last2) { if (std::invoke(comp, std::invoke(proj1, *first1), std::invoke(proj2, *first2))) { std::invoke(callable, *first1); ++first1; } else if (std::invoke(comp, std::invoke(proj2, *first2), std::invoke(proj1, *first1))) { ++first2; } else { ++first1; } } while (first1 != last1) { std::invoke(callable, *first1); ++first1; } } template &> Callable, typename Comp = std::ranges::less, typename Projection1 = std::identity, typename Projection2 = std::identity> requires callmergeable, std::ranges::iterator_t, Comp, Projection1, Projection2> constexpr void operator()(Range1 &&range1, Range2 &&range2, Callable &&callable, Comp comp = {}, Projection1 proj1 = {}, Projection2 proj2 = {}) const { (*this)(std::ranges::begin(range1), std::ranges::end(range1), std::ranges::begin(range2), std::ranges::end(range2), std::forward(callable), std::move(comp), std::move(proj1), std::move(proj2)); } }; inline constexpr set_greedy_difference_functor set_greedy_difference{}; struct set_difference_functor { template Sentinel1, std::input_iterator Iterator2, std::sentinel_for Sentinel2, std::invocable &> Callable, typename Comp = std::ranges::less, typename Projection1 = std::identity, typename Projection2 = std::identity> requires callmergeable constexpr void operator()(Iterator1 first1, Sentinel1 last1, Iterator2 first2, Sentinel2 last2, Callable &&callable, Comp comp = {}, Projection1 proj1 = {}, Projection2 proj2 = {}) const { while (first1 != last1 && first2 != last2) { if (std::invoke(comp, std::invoke(proj1, *first1), std::invoke(proj2, *first2))) { std::invoke(callable, *first1); ++first1; } else if (std::invoke(comp, std::invoke(proj2, *first2), std::invoke(proj1, *first1))) { ++first2; } else { ++first1; ++first2; } } while (first1 != last1) { std::invoke(callable, *first1); ++first1; } } template &> Callable, typename Comp = std::ranges::less, typename Projection1 = std::identity, typename Projection2 = std::identity> requires callmergeable, std::ranges::iterator_t, Comp, Projection1, Projection2> constexpr void operator()(Range1 &&range1, Range2 &&range2, Callable &&callable, Comp comp = {}, Projection1 proj1 = {}, Projection2 proj2 = {}) const { (*this)(std::ranges::begin(range1), std::ranges::end(range1), std::ranges::begin(range2), std::ranges::end(range2), std::forward(callable), std::move(comp), std::move(proj1), std::move(proj2)); } }; inline constexpr set_difference_functor set_difference{}; struct set_has_common_element_functor { template Sentinel1, std::input_iterator Iterator2, std::sentinel_for Sentinel2, typename Comp = std::ranges::less, typename Projection1 = std::identity, typename Projection2 = std::identity> requires callmergeable constexpr bool operator()(Iterator1 first1, Sentinel1 last1, Iterator2 first2, Sentinel2 last2, Comp comp = {}, Projection1 proj1 = {}, Projection2 proj2 = {}) const { while (first1 != last1 && first2 != last2) if (std::invoke(comp, std::invoke(proj1, *first1), std::invoke(proj2, *first2))) ++first1; else if (std::invoke(comp, std::invoke(proj2, *first2), std::invoke(proj1, *first1))) ++first2; else return true; return false; } template requires callmergeable, std::ranges::iterator_t, Comp, Projection1, Projection2> constexpr bool operator()(Range1 &&range1, Range2 &&range2, Comp comp = {}, Projection1 proj1 = {}, Projection2 proj2 = {}) const { return (*this)(std::ranges::begin(range1), std::ranges::end(range1), std::ranges::begin(range2), std::ranges::end(range2), std::move(comp), std::move(proj1), std::move(proj2)); } }; inline constexpr set_has_common_element_functor set_has_common_element{}; } // namespace Utils