// Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 #pragma once #include "predicates.h" #include // for Q_REQUIRED_RESULT #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Utils { ///////////////////////// // anyOf ///////////////////////// template bool anyOf(const T &container, F predicate); template bool anyOf(const T &container, R (S::*predicate)() const); template bool anyOf(const T &container, R S::*member); ///////////////////////// // count ///////////////////////// template int count(const T &container, F predicate); ///////////////////////// // allOf ///////////////////////// template bool allOf(const T &container, F predicate); ///////////////////////// // erase ///////////////////////// template void erase(T &container, F predicate); template bool eraseOne(T &container, F predicate); ///////////////////////// // contains ///////////////////////// template bool contains(const T &container, F function); template bool contains(const T &container, R (S::*function)() const); template bool contains(const C &container, R S::*member); ///////////////////////// // findOr ///////////////////////// template Q_REQUIRED_RESULT typename C::value_type findOr(const C &container, typename C::value_type other, F function); template Q_REQUIRED_RESULT typename T::value_type findOr(const T &container, typename T::value_type other, R (S::*function)() const); template Q_REQUIRED_RESULT typename T::value_type findOr(const T &container, typename T::value_type other, R S::*member); ///////////////////////// // findOrDefault ///////////////////////// template Q_REQUIRED_RESULT typename std::enable_if_t::value, typename C::value_type> findOrDefault(const C &container, F function); template Q_REQUIRED_RESULT typename std::enable_if_t::value, typename C::value_type> findOrDefault(const C &container, R (S::*function)() const); template Q_REQUIRED_RESULT typename std::enable_if_t::value, typename C::value_type> findOrDefault(const C &container, R S::*member); ///////////////////////// // indexOf ///////////////////////// template Q_REQUIRED_RESULT int indexOf(const C &container, F function); ///////////////////////// // maxElementOr ///////////////////////// template typename T::value_type maxElementOr(const T &container, typename T::value_type other); ///////////////////////// // filtered ///////////////////////// template Q_REQUIRED_RESULT C filtered(const C &container, F predicate); template Q_REQUIRED_RESULT C filtered(const C &container, R (S::*predicate)() const); ///////////////////////// // partition ///////////////////////// // Recommended usage: // C hit; // C miss; // std::tie(hit, miss) = Utils::partition(container, predicate); template Q_REQUIRED_RESULT std::tuple partition(const C &container, F predicate); template Q_REQUIRED_RESULT std::tuple partition(const C &container, R (S::*predicate)() const); ///////////////////////// // filteredUnique ///////////////////////// template Q_REQUIRED_RESULT C filteredUnique(const C &container); ///////////////////////// // qobject_container_cast ///////////////////////// template class Container, typename Base> Container qobject_container_cast(const Container &container); ///////////////////////// // static_container_cast ///////////////////////// template class Container, typename Base> Container static_container_cast(const Container &container); ///////////////////////// // sort ///////////////////////// template inline void sort(Container &container); template inline void sort(Container &container, Predicate p); template inline void sort(Container &container, R S::*member); template inline void sort(Container &container, R (S::*function)() const); ///////////////////////// // reverseForeach ///////////////////////// template inline void reverseForeach(const Container &c, const Op &operation); ///////////////////////// // toReferences ///////////////////////// template class ResultContainer, typename SourceContainer> auto toReferences(SourceContainer &sources); template auto toReferences(SourceContainer &sources); ///////////////////////// // toConstReferences ///////////////////////// template class ResultContainer, typename SourceContainer> auto toConstReferences(const SourceContainer &sources); template auto toConstReferences(const SourceContainer &sources); ///////////////////////// // take ///////////////////////// template Q_REQUIRED_RESULT std::optional take(C &container, P predicate); template Q_REQUIRED_RESULT decltype(auto) take(C &container, R S::*member); template Q_REQUIRED_RESULT decltype(auto) take(C &container, R (S::*function)() const); ///////////////////////// // setUnionMerge ///////////////////////// // Works like std::set_union but provides a merge function for items that match // !(a > b) && !(b > a) which normally means that there is an "equal" match. // It uses iterators to support move_iterators. template OutputIt setUnionMerge(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first, Merge merge, Compare comp); template OutputIt setUnionMerge( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first, Merge merge); template OutputContainer setUnionMerge(InputContainer1 &&input1, InputContainer2 &&input2, Merge merge, Compare comp); template OutputContainer setUnionMerge(InputContainer1 &&input1, InputContainer2 &&input2, Merge merge); ///////////////////////// // usize / ssize ///////////////////////// template std::make_unsigned_t usize(Container container); template std::make_signed_t ssize(Container container); ///////////////////////// // setUnion ///////////////////////// template OutputIterator set_union(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp); template OutputIterator set_union(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result); ///////////////////////// // transform ///////////////////////// // function without result type deduction: template // function type Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, F function); // function with result type deduction: template class C, // result container type typename SC, // input container type typename F, // function type typename Value = typename std::decay_t::value_type, typename Result = std::decay_t>, typename ResultContainer = C> Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, F function); #ifdef Q_CC_CLANG // "Matching of template template-arguments excludes compatible templates" // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0522r0.html (P0522R0) // in C++17 makes the above match e.g. C=std::vector even though that takes two // template parameters. Unfortunately the following one matches too, and there is no additional // partial ordering rule, resulting in an ambiguous call for this previously valid code. // GCC and MSVC ignore that issue and follow the standard to the letter, but Clang only // enables the new behavior when given -frelaxed-template-template-args . // To avoid requiring everyone using this header to enable that feature, keep the old implementation // for Clang. template class C, // result container type typename SC, // input container type typename F, // function type typename Value = typename std::decay_t::value_type, typename Result = std::decay_t>, typename ResultContainer = C>> Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, F function); #endif // member function without result type deduction: template class C, // result container type typename SC, // input container type typename R, typename S> Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, R (S::*p)() const); // member function with result type deduction: template Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, R (S::*p)() const); // member without result type deduction: template Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, R S::*p); // member with result type deduction: template class C, // result container typename SC, // input container typename R, typename S> Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, R S::*p); // same container types for input and output, const input // function: template class C, // container type typename F, // function type typename... CArgs> // Arguments to SC Q_REQUIRED_RESULT decltype(auto) transform(const C &container, F function); // same container types for input and output, const input // member function: template class C, // container type typename R, typename S, typename... CArgs> // Arguments to SC Q_REQUIRED_RESULT decltype(auto) transform(const C &container, R (S::*p)() const); // same container types for input and output, const input // members: template class C, // container typename R, typename S, typename... CArgs> // Arguments to SC Q_REQUIRED_RESULT decltype(auto) transform(const C &container, R S::*p); // same container types for input and output, non-const input // function: template class C, // container type typename F, // function type typename... CArgs> // Arguments to SC Q_REQUIRED_RESULT decltype(auto) transform(C &container, F function); // same container types for input and output, non-const input // member function: template class C, // container type typename R, typename S, typename... CArgs> // Arguments to SC Q_REQUIRED_RESULT decltype(auto) transform(C &container, R (S::*p)() const); // same container types for input and output, non-const input // members: template class C, // container typename R, typename S, typename... CArgs> // Arguments to SC Q_REQUIRED_RESULT decltype(auto) transform(C &container, R S::*p); ///////////////////////////////////////////////////////////////////////////// //////// Implementations ////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ////////////////// // anyOf ///////////////// template bool anyOf(const T &container, F predicate) { return std::any_of(std::begin(container), std::end(container), predicate); } // anyOf taking a member function pointer template bool anyOf(const T &container, R (S::*predicate)() const) { return std::any_of(std::begin(container), std::end(container), std::mem_fn(predicate)); } // anyOf taking a member pointer template bool anyOf(const T &container, R S::*member) { return std::any_of(std::begin(container), std::end(container), std::mem_fn(member)); } ////////////////// // count ///////////////// template int count(const T &container, F predicate) { return std::count_if(std::begin(container), std::end(container), predicate); } ////////////////// // allOf ///////////////// template bool allOf(const T &container, F predicate) { return std::all_of(std::begin(container), std::end(container), predicate); } // allOf taking a member function pointer template bool allOf(const T &container, R (S::*predicate)() const) { return std::all_of(std::begin(container), std::end(container), std::mem_fn(predicate)); } // allOf taking a member pointer template bool allOf(const T &container, R S::*member) { return std::all_of(std::begin(container), std::end(container), std::mem_fn(member)); } ////////////////// // erase ///////////////// template void erase(T &container, F predicate) { container.erase(std::remove_if(std::begin(container), std::end(container), predicate), std::end(container)); } template bool eraseOne(T &container, F predicate) { const auto it = std::find_if(std::begin(container), std::end(container), predicate); if (it == std::end(container)) return false; container.erase(it); return true; } ////////////////// // contains ///////////////// template bool contains(const T &container, F function) { return anyOf(container, function); } template bool contains(const T &container, R (S::*function)() const) { return anyOf(container, function); } template bool contains(const C &container, R S::*member) { return anyOf(container, std::mem_fn(member)); } ////////////////// // findOr ///////////////// template Q_REQUIRED_RESULT typename C::value_type findOr(const C &container, typename C::value_type other, F function) { typename C::const_iterator begin = std::begin(container); typename C::const_iterator end = std::end(container); typename C::const_iterator it = std::find_if(begin, end, function); return it == end ? other : *it; } template Q_REQUIRED_RESULT typename T::value_type findOr(const T &container, typename T::value_type other, R (S::*function)() const) { return findOr(container, other, std::mem_fn(function)); } template Q_REQUIRED_RESULT typename T::value_type findOr(const T &container, typename T::value_type other, R S::*member) { return findOr(container, other, std::mem_fn(member)); } ////////////////// // findOrDefault ////////////////// // Default implementation: template Q_REQUIRED_RESULT typename std::enable_if_t::value, typename C::value_type> findOrDefault(const C &container, F function) { return findOr(container, typename C::value_type(), function); } template Q_REQUIRED_RESULT typename std::enable_if_t::value, typename C::value_type> findOrDefault(const C &container, R (S::*function)() const) { return findOr(container, typename C::value_type(), std::mem_fn(function)); } template Q_REQUIRED_RESULT typename std::enable_if_t::value, typename C::value_type> findOrDefault(const C &container, R S::*member) { return findOr(container, typename C::value_type(), std::mem_fn(member)); } ////////////////// // index of: ////////////////// template Q_REQUIRED_RESULT int indexOf(const C& container, F function) { typename C::const_iterator begin = std::begin(container); typename C::const_iterator end = std::end(container); typename C::const_iterator it = std::find_if(begin, end, function); return it == end ? -1 : std::distance(begin, it); } ////////////////// // max element ////////////////// template typename T::value_type maxElementOr(const T &container, typename T::value_type other) { typename T::const_iterator begin = std::begin(container); typename T::const_iterator end = std::end(container); typename T::const_iterator it = std::max_element(begin, end); if (it == end) return other; return *it; } ////////////////// // transform ///////////////// namespace { ///////////////// // helper code for transform to use back_inserter and thus push_back for everything // and insert for QSet<> // // SetInsertIterator, straight from the standard for insert_iterator // just without the additional parameter to insert template class SetInsertIterator { protected: Container *container; public: using iterator_category = std::output_iterator_tag; using container_type = Container; explicit SetInsertIterator(Container &x) : container(&x) {} SetInsertIterator &operator=(const typename Container::value_type &value) { container->insert(value); return *this; } SetInsertIterator &operator=(typename Container::value_type &&value) { container->insert(std::move(value)); return *this; } SetInsertIterator &operator*() { return *this; } SetInsertIterator &operator++() { return *this; } SetInsertIterator operator++(int) { return *this; } }; // for QMap / QHash, inserting a std::pair / QPair template class MapInsertIterator { protected: Container *container; public: using iterator_category = std::output_iterator_tag; using container_type = Container; explicit MapInsertIterator(Container &x) : container(&x) {} MapInsertIterator &operator=( const std::pair &value) { container->insert(value.first, value.second); return *this; } MapInsertIterator &operator=( const QPair &value) { container->insert(value.first, value.second); return *this; } MapInsertIterator &operator*() { return *this; } MapInsertIterator &operator++() { return *this; } MapInsertIterator operator++(int) { return *this; } }; // inserter helper function, returns a std::back_inserter for most containers // and is overloaded for QSet<> and other containers without push_back, returning custom inserters template inline std::back_insert_iterator inserter(C &container) { return std::back_inserter(container); } template inline SetInsertIterator> inserter(QSet &container) { return SetInsertIterator>(container); } template inline SetInsertIterator> inserter(std::set &container) { return SetInsertIterator>(container); } template inline SetInsertIterator> inserter(std::unordered_set &container) { return SetInsertIterator>(container); } template inline SetInsertIterator> inserter(std::map &container) { return SetInsertIterator>(container); } template inline SetInsertIterator> inserter(std::unordered_map &container) { return SetInsertIterator>(container); } template inline MapInsertIterator> inserter(QMap &container) { return MapInsertIterator>(container); } template inline MapInsertIterator> inserter(QHash &container) { return MapInsertIterator>(container); } // Helper code for container.reserve that makes it possible to effectively disable it for // specific cases // default: do reserve // Template arguments are more specific than the second version below, so this is tried first template class C, typename... CArgs, typename = decltype(&C::reserve)> void reserve(C &c, typename C::size_type s) { c.reserve(s); } // containers that don't have reserve() template void reserve(C &, typename C::size_type) { } } // anonymous // -------------------------------------------------------------------- // Different containers for input and output: // -------------------------------------------------------------------- // different container types for input and output, e.g. transforming a QList into a QSet // function without result type deduction: template // function type Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, F function) { ResultContainer result; reserve(result, typename ResultContainer::size_type(container.size())); std::transform(std::begin(container), std::end(container), inserter(result), function); return result; } // function with result type deduction: template class C, // result container type typename SC, // input container type typename F, // function type typename Value, typename Result, typename ResultContainer> Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, F function) { return transform(std::forward(container), function); } #ifdef Q_CC_CLANG template class C, // result container type typename SC, // input container type typename F, // function type typename Value, typename Result, typename ResultContainer> Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, F function) { return transform(std::forward(container), function); } #endif // member function without result type deduction: template class C, // result container type typename SC, // input container type typename R, typename S> Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, R (S::*p)() const) { return transform(std::forward(container), std::mem_fn(p)); } // member function with result type deduction: template Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, R (S::*p)() const) { return transform(std::forward(container), std::mem_fn(p)); } // member without result type deduction: template Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, R S::*p) { return transform(std::forward(container), std::mem_fn(p)); } // member with result type deduction: template class C, // result container typename SC, // input container typename R, typename S> Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, R S::*p) { return transform(std::forward(container), std::mem_fn(p)); } // same container types for input and output, const input // function: template class C, // container type typename F, // function type typename... CArgs> // Arguments to SC Q_REQUIRED_RESULT decltype(auto) transform(const C &container, F function) { return transform &>(container, function); } // member function: template class C, // container type typename R, typename S, typename... CArgs> // Arguments to SC Q_REQUIRED_RESULT decltype(auto) transform(const C &container, R (S::*p)() const) { return transform &>(container, std::mem_fn(p)); } // members: template class C, // container typename R, typename S, typename... CArgs> // Arguments to SC Q_REQUIRED_RESULT decltype(auto) transform(const C &container, R S::*p) { return transform &>(container, std::mem_fn(p)); } // same container types for input and output, non-const input // function: template class C, // container type typename F, // function type typename... CArgs> // Arguments to SC Q_REQUIRED_RESULT decltype(auto) transform(C &container, F function) { return transform &>(container, function); } // member function: template class C, // container type typename R, typename S, typename... CArgs> // Arguments to SC Q_REQUIRED_RESULT decltype(auto) transform(C &container, R (S::*p)() const) { return transform &>(container, std::mem_fn(p)); } // members: template class C, // container typename R, typename S, typename... CArgs> // Arguments to SC Q_REQUIRED_RESULT decltype(auto) transform(C &container, R S::*p) { return transform &>(container, std::mem_fn(p)); } // Specialization for QStringList: template class C = QList, // result container typename F> // Arguments to C Q_REQUIRED_RESULT decltype(auto) transform(const QStringList &container, F function) { return transform &>(static_cast>(container), function); } // member function: template class C = QList, // result container type typename R, typename S> Q_REQUIRED_RESULT decltype(auto) transform(const QStringList &container, R (S::*p)() const) { return transform &>(static_cast>(container), std::mem_fn(p)); } // members: template class C = QList, // result container typename R, typename S> Q_REQUIRED_RESULT decltype(auto) transform(const QStringList &container, R S::*p) { return transform &>(static_cast>(container), std::mem_fn(p)); } ////////////////// // filtered ///////////////// template Q_REQUIRED_RESULT C filtered(const C &container, F predicate) { C out; std::copy_if(std::begin(container), std::end(container), inserter(out), predicate); return out; } template Q_REQUIRED_RESULT C filtered(const C &container, R (S::*predicate)() const) { C out; std::copy_if(std::begin(container), std::end(container), inserter(out), std::mem_fn(predicate)); return out; } ////////////////// // filteredCast ///////////////// template Q_REQUIRED_RESULT R filteredCast(const C &container, F predicate) { R out; std::copy_if(std::begin(container), std::end(container), inserter(out), predicate); return out; } ////////////////// // partition ///////////////// // Recommended usage: // C hit; // C miss; // std::tie(hit, miss) = Utils::partition(container, predicate); template Q_REQUIRED_RESULT std::tuple partition(const C &container, F predicate) { C hit; C miss; reserve(hit, container.size()); reserve(miss, container.size()); auto hitIns = inserter(hit); auto missIns = inserter(miss); for (const auto &i : container) { if (predicate(i)) hitIns = i; else missIns = i; } return std::make_tuple(hit, miss); } template Q_REQUIRED_RESULT std::tuple partition(const C &container, R (S::*predicate)() const) { return partition(container, std::mem_fn(predicate)); } ////////////////// // filteredUnique ///////////////// template Q_REQUIRED_RESULT C filteredUnique(const C &container) { C result; auto ins = inserter(result); QSet seen; int setSize = 0; auto endIt = std::end(container); for (auto it = std::begin(container); it != endIt; ++it) { seen.insert(*it); if (setSize == seen.size()) // unchanged size => was already seen continue; ++setSize; ins = *it; } return result; } ////////////////// // qobject_container_cast ///////////////// template class Container, typename Base> Container qobject_container_cast(const Container &container) { Container result; auto ins = inserter(result); for (Base val : container) { if (T target = qobject_cast(val)) ins = target; } return result; } ////////////////// // static_container_cast ///////////////// template class Container, typename Base> Container static_container_cast(const Container &container) { Container result; reserve(result, container.size()); auto ins = inserter(result); for (Base val : container) ins = static_cast(val); return result; } ////////////////// // sort ///////////////// template inline void sort(Container &container) { std::stable_sort(std::begin(container), std::end(container)); } template inline void sort(Container &container, Predicate p) { std::stable_sort(std::begin(container), std::end(container), p); } template inline Container sorted(const Container &container) { Container c = container; sort(c); return c; } template inline Container sorted(Container &&container) { sort(container); return container; } template inline Container sorted(const Container &&container) { return sorted(container); } template inline Container sorted(const Container &container, Predicate p) { Container c = container; sort(c, p); return c; } template inline Container sorted(Container &&container, Predicate p) { sort(container, p); return container; } template inline Container sorted(const Container &&container, Predicate p) { return sorted(container, p); } // pointer to member template inline void sort(Container &container, R S::*member) { auto f = std::mem_fn(member); using const_ref = typename Container::const_reference; std::stable_sort(std::begin(container), std::end(container), [&f](const_ref a, const_ref b) { return f(a) < f(b); }); } template inline Container sorted(const Container &container, R S::*member) { Container c = container; sort(c, member); return c; } template inline Container sorted(Container &&container, R S::*member) { sort(container, member); return container; } template inline Container sorted(const Container &&container, R S::*member) { return sorted(container, member); } // pointer to member function template inline void sort(Container &container, R (S::*function)() const) { auto f = std::mem_fn(function); using const_ref = typename Container::const_reference; std::stable_sort(std::begin(container), std::end(container), [&f](const_ref a, const_ref b) { return f(a) < f(b); }); } template inline Container sorted(const Container &container, R (S::*function)() const) { Container c = container; sort(c, function); return c; } template inline Container sorted(Container &&container, R (S::*function)() const) { sort(container, function); return container; } template inline Container sorted(const Container &&container, R (S::*function)() const) { return sorted(container, function); } ////////////////// // reverseForeach ///////////////// template inline void reverseForeach(const Container &c, const Op &operation) { auto rend = c.rend(); for (auto it = c.rbegin(); it != rend; ++it) operation(*it); } ////////////////// // toReferences ///////////////// template class ResultContainer, typename SourceContainer> auto toReferences(SourceContainer &sources) { return transform(sources, [] (auto &value) { return std::ref(value); }); } template auto toReferences(SourceContainer &sources) { return transform(sources, [] (auto &value) { return std::ref(value); }); } ////////////////// // toConstReferences ///////////////// template class ResultContainer, typename SourceContainer> auto toConstReferences(const SourceContainer &sources) { return transform(sources, [] (const auto &value) { return std::cref(value); }); } template auto toConstReferences(const SourceContainer &sources) { return transform(sources, [] (const auto &value) { return std::cref(value); }); } ////////////////// // take: ///////////////// template Q_REQUIRED_RESULT std::optional take(C &container, P predicate) { const auto end = std::end(container); const auto it = std::find_if(std::begin(container), end, predicate); if (it == end) return std::nullopt; std::optional result = std::make_optional(std::move(*it)); container.erase(it); return result; } // pointer to member template Q_REQUIRED_RESULT decltype(auto) take(C &container, R S::*member) { return take(container, std::mem_fn(member)); } // pointer to member function template Q_REQUIRED_RESULT decltype(auto) take(C &container, R (S::*function)() const) { return take(container, std::mem_fn(function)); } ////////////////// // setUnionMerge: Works like std::set_union but provides a merge function for items that match // !(a > b) && !(b > a) which normally means that there is an "equal" match. // It uses iterators to support move_iterators. ///////////////// template OutputIt setUnionMerge(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first, Merge merge, Compare comp) { for (; first1 != last1; ++d_first) { if (first2 == last2) return std::copy(first1, last1, d_first); if (comp(*first2, *first1)) { *d_first = *first2++; } else { if (comp(*first1, *first2)) { *d_first = *first1; } else { *d_first = merge(*first1, *first2); ++first2; } ++first1; } } return std::copy(first2, last2, d_first); } template OutputIt setUnionMerge(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first, Merge merge) { return setUnionMerge(first1, last1, first2, last2, d_first, merge, std::less>{}); } template OutputContainer setUnionMerge(InputContainer1 &&input1, InputContainer2 &&input2, Merge merge, Compare comp) { OutputContainer results; results.reserve(input1.size() + input2.size()); setUnionMerge(std::make_move_iterator(std::begin(input1)), std::make_move_iterator(std::end(input1)), std::make_move_iterator(std::begin(input2)), std::make_move_iterator(std::end(input2)), std::back_inserter(results), merge, comp); return results; } template OutputContainer setUnionMerge(InputContainer1 &&input1, InputContainer2 &&input2, Merge merge) { return setUnionMerge(std::forward(input1), std::forward(input2), merge, std::less>{}); } template std::make_unsigned_t usize(Container container) { return static_cast>(container.size()); } template std::make_signed_t ssize(Container container) { return static_cast>(container.size()); } template struct CompareIter { Compare compare; explicit constexpr CompareIter(Compare compare) : compare(std::move(compare)) {} template constexpr bool operator()(Iterator1 it1, Iterator2 it2) { return bool(compare(*it1, *it2)); } }; template OutputIterator set_union_impl(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp) { auto compare = CompareIter(comp); while (first1 != last1 && first2 != last2) { if (compare(first1, first2)) { *result = *first1; ++first1; } else if (compare(first2, first1)) { *result = *first2; ++first2; } else { *result = *first1; ++first1; ++first2; } ++result; } return std::copy(first2, last2, std::copy(first1, last1, result)); } template OutputIterator set_union(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp) { return Utils::set_union_impl(first1, last1, first2, last2, result, comp); } template OutputIterator set_union(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result) { return Utils::set_union_impl( first1, last1, first2, last2, result, std::less{}); } // Replacement for deprecated Qt functionality template QSet toSet(const QList &list) { return QSet(list.begin(), list.end()); } template QList toList(const QSet &set) { return QList(set.begin(), set.end()); } template void addToHash(QHash *result, const QHash &additionalContents) { result->insert(additionalContents); } } // namespace Utils