| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565 |
- // Copyright (C) 2016 The Qt Company Ltd.
- // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
- #pragma once
- #include "predicates.h"
- #include <qcompilerdetection.h> // for Q_REQUIRED_RESULT
- #include <algorithm>
- #include <map>
- #include <memory>
- #include <set>
- #include <tuple>
- #include <unordered_map>
- #include <unordered_set>
- #include <QHash>
- #include <QObject>
- #include <QSet>
- #include <QStringList>
- #include <memory>
- #include <optional>
- #include <tuple>
- #include <type_traits>
- #include <utility>
- namespace Utils
- {
- /////////////////////////
- // anyOf
- /////////////////////////
- template<typename T, typename F>
- bool anyOf(const T &container, F predicate);
- template<typename T, typename R, typename S>
- bool anyOf(const T &container, R (S::*predicate)() const);
- template<typename T, typename R, typename S>
- bool anyOf(const T &container, R S::*member);
- /////////////////////////
- // count
- /////////////////////////
- template<typename T, typename F>
- int count(const T &container, F predicate);
- /////////////////////////
- // allOf
- /////////////////////////
- template<typename T, typename F>
- bool allOf(const T &container, F predicate);
- /////////////////////////
- // erase
- /////////////////////////
- template<typename T, typename F>
- void erase(T &container, F predicate);
- template<typename T, typename F>
- bool eraseOne(T &container, F predicate);
- /////////////////////////
- // contains
- /////////////////////////
- template<typename T, typename F>
- bool contains(const T &container, F function);
- template<typename T, typename R, typename S>
- bool contains(const T &container, R (S::*function)() const);
- template<typename C, typename R, typename S>
- bool contains(const C &container, R S::*member);
- /////////////////////////
- // findOr
- /////////////////////////
- template<typename C, typename F>
- Q_REQUIRED_RESULT typename C::value_type findOr(const C &container,
- typename C::value_type other,
- F function);
- template<typename T, typename R, typename S>
- Q_REQUIRED_RESULT typename T::value_type findOr(const T &container,
- typename T::value_type other,
- R (S::*function)() const);
- template<typename T, typename R, typename S>
- Q_REQUIRED_RESULT typename T::value_type findOr(const T &container,
- typename T::value_type other,
- R S::*member);
- template<typename T, typename F>
- Q_REQUIRED_RESULT std::optional<typename T::value_type> findOr(const T &container,
- std::nullopt_t,
- F function);
- /////////////////////////
- // findOrDefault
- /////////////////////////
- template<typename C, typename F>
- Q_REQUIRED_RESULT typename std::enable_if_t<std::is_copy_assignable<typename C::value_type>::value,
- typename C::value_type>
- findOrDefault(const C &container, F function);
- template<typename C, typename R, typename S>
- Q_REQUIRED_RESULT typename std::enable_if_t<std::is_copy_assignable<typename C::value_type>::value,
- typename C::value_type>
- findOrDefault(const C &container, R (S::*function)() const);
- template<typename C, typename R, typename S>
- Q_REQUIRED_RESULT typename std::enable_if_t<std::is_copy_assignable<typename C::value_type>::value,
- typename C::value_type>
- findOrDefault(const C &container, R S::*member);
- /////////////////////////
- // indexOf
- /////////////////////////
- template<typename C, typename F>
- Q_REQUIRED_RESULT int indexOf(const C &container, F function);
- /////////////////////////
- // maxElementOr
- /////////////////////////
- template<typename T>
- typename T::value_type maxElementOr(const T &container, typename T::value_type other);
- /////////////////////////
- // filtered
- /////////////////////////
- template<typename C, typename F>
- Q_REQUIRED_RESULT C filtered(const C &container, F predicate);
- template<typename C, typename R, typename S>
- 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<typename C, typename F>
- Q_REQUIRED_RESULT std::tuple<C, C> partition(const C &container, F predicate);
- template<typename C, typename R, typename S>
- Q_REQUIRED_RESULT std::tuple<C, C> partition(const C &container, R (S::*predicate)() const);
- /////////////////////////
- // filteredUnique
- /////////////////////////
- template<typename C>
- Q_REQUIRED_RESULT C filteredUnique(const C &container);
- /////////////////////////
- // qobject_container_cast
- /////////////////////////
- template<class T, template<typename> class Container, typename Base>
- Container<T> qobject_container_cast(const Container<Base> &container);
- /////////////////////////
- // static_container_cast
- /////////////////////////
- template<class T, template<typename> class Container, typename Base>
- Container<T> static_container_cast(const Container<Base> &container);
- /////////////////////////
- // sort
- /////////////////////////
- template<typename Container>
- inline void sort(Container &container);
- template<typename Container, typename Predicate>
- inline void sort(Container &container, Predicate p);
- template<typename Container, typename R, typename S>
- inline void sort(Container &container, R S::*member);
- template<typename Container, typename R, typename S>
- inline void sort(Container &container, R (S::*function)() const);
- /////////////////////////
- // reverseForeach
- /////////////////////////
- template<typename Container, typename Op>
- inline void reverseForeach(const Container &c, const Op &operation);
- /////////////////////////
- // toReferences
- /////////////////////////
- template<template<typename...> class ResultContainer, typename SourceContainer>
- auto toReferences(SourceContainer &sources);
- template<typename SourceContainer>
- auto toReferences(SourceContainer &sources);
- /////////////////////////
- // toConstReferences
- /////////////////////////
- template<template<typename...> class ResultContainer, typename SourceContainer>
- auto toConstReferences(const SourceContainer &sources);
- template<typename SourceContainer>
- auto toConstReferences(const SourceContainer &sources);
- /////////////////////////
- // take
- /////////////////////////
- template<class C, typename P>
- Q_REQUIRED_RESULT std::optional<typename C::value_type> take(C &container, P predicate);
- template<typename C, typename R, typename S>
- Q_REQUIRED_RESULT decltype(auto) take(C &container, R S::*member);
- template<typename C, typename R, typename S>
- 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<class InputIt1, class InputIt2, class OutputIt, class Merge, class Compare>
- OutputIt setUnionMerge(InputIt1 first1,
- InputIt1 last1,
- InputIt2 first2,
- InputIt2 last2,
- OutputIt d_first,
- Merge merge,
- Compare comp);
- template<class InputIt1, class InputIt2, class OutputIt, class Merge>
- OutputIt setUnionMerge(
- InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first, Merge merge);
- template<class OutputContainer, class InputContainer1, class InputContainer2, class Merge, class Compare>
- OutputContainer setUnionMerge(InputContainer1 &&input1,
- InputContainer2 &&input2,
- Merge merge,
- Compare comp);
- template<class OutputContainer, class InputContainer1, class InputContainer2, class Merge>
- OutputContainer setUnionMerge(InputContainer1 &&input1, InputContainer2 &&input2, Merge merge);
- /////////////////////////
- // setUnion
- /////////////////////////
- template<typename InputIterator1, typename InputIterator2, typename OutputIterator, typename Compare>
- OutputIterator set_union(InputIterator1 first1,
- InputIterator1 last1,
- InputIterator2 first2,
- InputIterator2 last2,
- OutputIterator result,
- Compare comp);
- template<typename InputIterator1, typename InputIterator2, typename OutputIterator>
- OutputIterator set_union(InputIterator1 first1,
- InputIterator1 last1,
- InputIterator2 first2,
- InputIterator2 last2,
- OutputIterator result);
- /////////////////////////
- // transform
- /////////////////////////
- // function without result type deduction:
- template<typename ResultContainer, // complete result container type
- typename SC, // input container type
- typename F> // function type
- Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, F function);
- // function with result type deduction:
- template<template<typename> class C, // result container type
- typename SC, // input container type
- typename F, // function type
- typename Value = typename std::decay_t<SC>::value_type,
- typename Result = std::decay_t<std::invoke_result_t<F, Value&>>,
- typename ResultContainer = C<Result>>
- 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<template<typename, typename> class C, // result container type
- typename SC, // input container type
- typename F, // function type
- typename Value = typename std::decay_t<SC>::value_type,
- typename Result = std::decay_t<std::invoke_result_t<F, Value&>>,
- typename ResultContainer = C<Result, std::allocator<Result>>>
- Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, F function);
- #endif
- // member function without result type deduction:
- template<template<typename...> 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<typename ResultContainer, // complete 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 without result type deduction:
- template<typename ResultContainer, // complete result container type
- typename SC, // input container
- typename R,
- typename S>
- Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, R S::*p);
- // member with result type deduction:
- template<template<typename...> 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<template<typename...> class C, // container type
- typename F, // function type
- typename... CArgs> // Arguments to SC
- Q_REQUIRED_RESULT decltype(auto) transform(const C<CArgs...> &container, F function);
- // same container types for input and output, const input
- // member function:
- template<template<typename...> class C, // container type
- typename R,
- typename S,
- typename... CArgs> // Arguments to SC
- Q_REQUIRED_RESULT decltype(auto) transform(const C<CArgs...> &container, R (S::*p)() const);
- // same container types for input and output, const input
- // members:
- template<template<typename...> class C, // container
- typename R,
- typename S,
- typename... CArgs> // Arguments to SC
- Q_REQUIRED_RESULT decltype(auto) transform(const C<CArgs...> &container, R S::*p);
- // same container types for input and output, non-const input
- // function:
- template<template<typename...> class C, // container type
- typename F, // function type
- typename... CArgs> // Arguments to SC
- Q_REQUIRED_RESULT decltype(auto) transform(C<CArgs...> &container, F function);
- // same container types for input and output, non-const input
- // member function:
- template<template<typename...> class C, // container type
- typename R,
- typename S,
- typename... CArgs> // Arguments to SC
- Q_REQUIRED_RESULT decltype(auto) transform(C<CArgs...> &container, R (S::*p)() const);
- // same container types for input and output, non-const input
- // members:
- template<template<typename...> class C, // container
- typename R,
- typename S,
- typename... CArgs> // Arguments to SC
- Q_REQUIRED_RESULT decltype(auto) transform(C<CArgs...> &container, R S::*p);
- /////////////////////////////////////////////////////////////////////////////
- //////// Implementations //////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////
- //////////////////
- // anyOf
- /////////////////
- template<typename T, typename F>
- 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<typename T, typename R, typename S>
- 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<typename T, typename R, typename S>
- bool anyOf(const T &container, R S::*member)
- {
- return std::any_of(std::begin(container), std::end(container), std::mem_fn(member));
- }
- //////////////////
- // count
- /////////////////
- template<typename T, typename F>
- int count(const T &container, F predicate)
- {
- return std::count_if(std::begin(container), std::end(container), predicate);
- }
- //////////////////
- // allOf
- /////////////////
- template<typename T, typename F>
- bool allOf(const T &container, F predicate)
- {
- return std::all_of(std::begin(container), std::end(container), predicate);
- }
- template<typename T, typename F>
- bool allOf(const std::initializer_list<T> &initializerList, F predicate)
- {
- return std::all_of(std::begin(initializerList), std::end(initializerList), predicate);
- }
- // allOf taking a member function pointer
- template<typename T, typename R, typename S>
- 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<typename T, typename R, typename S>
- bool allOf(const T &container, R S::*member)
- {
- return std::all_of(std::begin(container), std::end(container), std::mem_fn(member));
- }
- //////////////////
- // erase
- /////////////////
- template<typename T, typename F>
- void erase(T &container, F predicate)
- {
- container.erase(std::remove_if(std::begin(container), std::end(container), predicate),
- std::end(container));
- }
- template<typename T, typename F>
- 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<typename T, typename F>
- bool contains(const T &container, F function)
- {
- return anyOf(container, function);
- }
- template<typename T, typename R, typename S>
- bool contains(const T &container, R (S::*function)() const)
- {
- return anyOf(container, function);
- }
- template<typename C, typename R, typename S>
- bool contains(const C &container, R S::*member)
- {
- return anyOf(container, std::mem_fn(member));
- }
- //////////////////
- // findOr
- /////////////////
- template<typename C, typename F>
- 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<typename T, typename R, typename S>
- 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<typename T, typename R, typename S>
- 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));
- }
- template<typename C, typename F>
- Q_REQUIRED_RESULT typename std::optional<typename C::value_type> findOr(const C &container,
- std::nullopt_t,
- 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);
- if (it == end)
- return std::nullopt;
- return *it;
- }
- //////////////////
- // findOrDefault
- //////////////////
- // Default implementation:
- template<typename C, typename F>
- Q_REQUIRED_RESULT
- typename std::enable_if_t<std::is_copy_assignable<typename C::value_type>::value, typename C::value_type>
- findOrDefault(const C &container, F function)
- {
- return findOr(container, typename C::value_type(), function);
- }
- template<typename C, typename R, typename S>
- Q_REQUIRED_RESULT
- typename std::enable_if_t<std::is_copy_assignable<typename C::value_type>::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<typename C, typename R, typename S>
- Q_REQUIRED_RESULT
- typename std::enable_if_t<std::is_copy_assignable<typename C::value_type>::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<typename C, typename F>
- 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>
- 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 Container>
- class SetInsertIterator
- {
- protected:
- Container *container;
- public:
- using iterator_category = std::output_iterator_tag;
- using container_type = Container;
- explicit SetInsertIterator(Container &x)
- : container(&x)
- {}
- SetInsertIterator<Container> &operator=(const typename Container::value_type &value)
- {
- container->insert(value);
- return *this;
- }
- SetInsertIterator<Container> &operator=(typename Container::value_type &&value)
- {
- container->insert(std::move(value));
- return *this;
- }
- SetInsertIterator<Container> &operator*() { return *this; }
- SetInsertIterator<Container> &operator++() { return *this; }
- SetInsertIterator<Container> operator++(int) { return *this; }
- };
- // for QMap / QHash, inserting a std::pair / QPair
- template<class Container>
- class MapInsertIterator
- {
- protected:
- Container *container;
- public:
- using iterator_category = std::output_iterator_tag;
- using container_type = Container;
- explicit MapInsertIterator(Container &x)
- : container(&x)
- {}
- MapInsertIterator<Container> &operator=(
- const std::pair<const typename Container::key_type, typename Container::mapped_type> &value)
- { container->insert(value.first, value.second); return *this; }
- MapInsertIterator<Container> &operator=(
- const QPair<typename Container::key_type, typename Container::mapped_type> &value)
- { container->insert(value.first, value.second); return *this; }
- MapInsertIterator<Container> &operator*() { return *this; }
- MapInsertIterator<Container> &operator++() { return *this; }
- MapInsertIterator<Container> operator++(int) { return *this; }
- };
- // because Qt container are not implementing the standard interface we need
- // this helper functions for generic code
- template<typename Type>
- void append(QList<Type> *container, QList<Type> &&input)
- {
- container->append(std::move(input));
- }
- template<typename Type>
- void append(QList<Type> *container, const QList<Type> &input)
- {
- container->append(input);
- }
- template<typename Container>
- void append(Container *container, Container &&input)
- {
- container->insert(container->end(),
- std::make_move_iterator(input.begin()),
- std::make_move_iterator(input.end()));
- }
- template<typename Container>
- void append(Container *container, const Container &input)
- {
- container->insert(container->end(), input.begin(), input.end());
- }
- // BackInsertIterator behaves like std::back_insert_iterator except is adds the back insertion for
- // container of the same type
- template<typename Container>
- class BackInsertIterator
- {
- public:
- using iterator_category = std::output_iterator_tag;
- using value_type = void;
- using difference_type = ptrdiff_t;
- using pointer = void;
- using reference = void;
- using container_type = Container;
- explicit constexpr BackInsertIterator(Container &container)
- : m_container(std::addressof(container))
- {}
- constexpr BackInsertIterator &operator=(const typename Container::value_type &value)
- {
- m_container->push_back(value);
- return *this;
- }
- constexpr BackInsertIterator &operator=(typename Container::value_type &&value)
- {
- m_container->push_back(std::move(value));
- return *this;
- }
- constexpr BackInsertIterator &operator=(const Container &container)
- {
- append(m_container, container);
- return *this;
- }
- constexpr BackInsertIterator &operator=(Container &&container)
- {
- append(m_container, container);
- return *this;
- }
- [[nodiscard]] constexpr BackInsertIterator &operator*() { return *this; }
- constexpr BackInsertIterator &operator++() { return *this; }
- constexpr BackInsertIterator operator++(int) { return *this; }
- private:
- Container *m_container;
- };
- // inserter helper function, returns a BackInsertIterator for most containers
- // and is overloaded for QSet<> and other containers without push_back, returning custom inserters
- template<typename Container>
- inline BackInsertIterator<Container> inserter(Container &container)
- {
- return BackInsertIterator(container);
- }
- template<typename X>
- inline SetInsertIterator<QSet<X>>
- inserter(QSet<X> &container)
- {
- return SetInsertIterator<QSet<X>>(container);
- }
- template<typename K, typename C, typename A>
- inline SetInsertIterator<std::set<K, C, A>>
- inserter(std::set<K, C, A> &container)
- {
- return SetInsertIterator<std::set<K, C, A>>(container);
- }
- template<typename K, typename H, typename C, typename A>
- inline SetInsertIterator<std::unordered_set<K, H, C, A>>
- inserter(std::unordered_set<K, H, C, A> &container)
- {
- return SetInsertIterator<std::unordered_set<K, H, C, A>>(container);
- }
- template<typename K, typename V, typename C, typename A>
- inline SetInsertIterator<std::map<K, V, C, A>>
- inserter(std::map<K, V, C, A> &container)
- {
- return SetInsertIterator<std::map<K, V, C, A>>(container);
- }
- template<typename K, typename V, typename H, typename C, typename A>
- inline SetInsertIterator<std::unordered_map<K, V, H, C, A>>
- inserter(std::unordered_map<K, V, H, C, A> &container)
- {
- return SetInsertIterator<std::unordered_map<K, V, H, C, A>>(container);
- }
- template<typename K, typename V>
- inline MapInsertIterator<QMap<K, V>>
- inserter(QMap<K, V> &container)
- {
- return MapInsertIterator<QMap<K, V>>(container);
- }
- template<typename K, typename V>
- inline MapInsertIterator<QHash<K, V>>
- inserter(QHash<K, V> &container)
- {
- return MapInsertIterator<QHash<K, V>>(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<template<typename...> class C, typename... CArgs,
- typename = decltype(&C<CArgs...>::reserve)>
- void reserve(C<CArgs...> &c, typename C<CArgs...>::size_type s)
- {
- c.reserve(s);
- }
- // containers that don't have reserve()
- template<typename C>
- 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<typename ResultContainer, // complete result container type
- typename SC, // input container type
- typename F> // 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<template<typename> 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<ResultContainer>(std::forward<SC>(container), function);
- }
- #ifdef Q_CC_CLANG
- template<template<typename, typename> 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<ResultContainer>(std::forward<SC>(container), function);
- }
- #endif
- // member function without result type deduction:
- template<template<typename...> 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<C>(std::forward<SC>(container), std::mem_fn(p));
- }
- // member function with result type deduction:
- template<typename ResultContainer, // complete 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<ResultContainer>(std::forward<SC>(container), std::mem_fn(p));
- }
- // member without result type deduction:
- template<typename ResultContainer, // complete result container type
- typename SC, // input container
- typename R,
- typename S>
- Q_REQUIRED_RESULT
- decltype(auto) transform(SC &&container, R S::*p)
- {
- return transform<ResultContainer>(std::forward<SC>(container), std::mem_fn(p));
- }
- // member with result type deduction:
- template<template<typename...> 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<C>(std::forward<SC>(container), std::mem_fn(p));
- }
- // same container types for input and output, const input
- // function:
- template<template<typename...> class C, // container type
- typename F, // function type
- typename... CArgs> // Arguments to SC
- Q_REQUIRED_RESULT
- decltype(auto) transform(const C<CArgs...> &container, F function)
- {
- return transform<C, const C<CArgs...> &>(container, function);
- }
- // member function:
- template<template<typename...> class C, // container type
- typename R,
- typename S,
- typename... CArgs> // Arguments to SC
- Q_REQUIRED_RESULT
- decltype(auto) transform(const C<CArgs...> &container, R (S::*p)() const)
- {
- return transform<C, const C<CArgs...> &>(container, std::mem_fn(p));
- }
- // members:
- template<template<typename...> class C, // container
- typename R,
- typename S,
- typename... CArgs> // Arguments to SC
- Q_REQUIRED_RESULT
- decltype(auto) transform(const C<CArgs...> &container, R S::*p)
- {
- return transform<C, const C<CArgs...> &>(container, std::mem_fn(p));
- }
- // same container types for input and output, non-const input
- // function:
- template<template<typename...> class C, // container type
- typename F, // function type
- typename... CArgs> // Arguments to SC
- Q_REQUIRED_RESULT
- auto transform(C<CArgs...> &container, F function) -> decltype(auto)
- {
- return transform<C, C<CArgs...> &>(container, function);
- }
- // member function:
- template<template<typename...> class C, // container type
- typename R,
- typename S,
- typename... CArgs> // Arguments to SC
- Q_REQUIRED_RESULT
- decltype(auto) transform(C<CArgs...> &container, R (S::*p)() const)
- {
- return transform<C, C<CArgs...> &>(container, std::mem_fn(p));
- }
- // members:
- template<template<typename...> class C, // container
- typename R,
- typename S,
- typename... CArgs> // Arguments to SC
- Q_REQUIRED_RESULT
- decltype(auto) transform(C<CArgs...> &container, R S::*p)
- {
- return transform<C, C<CArgs...> &>(container, std::mem_fn(p));
- }
- // Specialization for QStringList:
- template<template<typename...> class C = QList, // result container
- typename F> // Arguments to C
- Q_REQUIRED_RESULT
- auto transform(const QStringList &container, F function)
- {
- return transform<C, const QList<QString> &>(static_cast<QList<QString>>(container), function);
- }
- // member function:
- template<template<typename...> 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<C, const QList<QString> &>(static_cast<QList<QString>>(container), std::mem_fn(p));
- }
- // members:
- template<template<typename...> class C = QList, // result container
- typename R,
- typename S>
- Q_REQUIRED_RESULT
- decltype(auto) transform(const QStringList &container, R S::*p)
- {
- return transform<C, const QList<QString> &>(static_cast<QList<QString>>(container), std::mem_fn(p));
- }
- //////////////////
- // filtered
- /////////////////
- template<typename C, typename F>
- 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<typename C, typename R, typename S>
- 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;
- }
- template<typename C, typename R, typename S>
- Q_REQUIRED_RESULT C filtered(const C &container, R S::*predicate)
- {
- C out;
- std::copy_if(std::begin(container), std::end(container), inserter(out), std::mem_fn(predicate));
- return out;
- }
- //////////////////
- // filteredCast
- /////////////////
- template<typename R, typename C, typename F>
- 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<typename C, typename F>
- Q_REQUIRED_RESULT
- std::tuple<C, C> 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<typename C, typename R, typename S>
- Q_REQUIRED_RESULT
- std::tuple<C, C> partition(const C &container, R (S::*predicate)() const)
- {
- return partition(container, std::mem_fn(predicate));
- }
- //////////////////
- // filteredUnique
- /////////////////
- template<typename C>
- Q_REQUIRED_RESULT
- C filteredUnique(const C &container)
- {
- C result;
- auto ins = inserter(result);
- QSet<typename C::value_type> 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 T, template<typename> class Container, typename Base>
- Container<T> qobject_container_cast(const Container<Base> &container)
- {
- Container<T> result;
- auto ins = inserter(result);
- for (Base val : container) {
- if (T target = qobject_cast<T>(val))
- ins = target;
- }
- return result;
- }
- //////////////////
- // static_container_cast
- /////////////////
- template <class T, template<typename> class Container, typename Base>
- Container<T> static_container_cast(const Container<Base> &container)
- {
- Container<T> result;
- reserve(result, container.size());
- auto ins = inserter(result);
- for (Base val : container)
- ins = static_cast<T>(val);
- return result;
- }
- //////////////////
- // sort
- /////////////////
- template <typename Container>
- inline void sort(Container &container)
- {
- std::stable_sort(std::begin(container), std::end(container));
- }
- template <typename Container, typename Predicate>
- inline void sort(Container &container, Predicate p)
- {
- std::stable_sort(std::begin(container), std::end(container), p);
- }
- // const lvalue
- template<typename Container>
- inline Container sorted(const Container &container)
- {
- Container c = container;
- sort(c);
- return c;
- }
- // non-const lvalue
- // This is needed because otherwise the "universal" reference below is used, modifying the input
- // container.
- template<typename Container>
- inline Container sorted(Container &container)
- {
- Container c = container;
- sort(c);
- return c;
- }
- // non-const rvalue (actually rvalue or lvalue, but lvalue is handled above)
- template<typename Container>
- inline Container sorted(Container &&container)
- {
- sort(container);
- return std::move(container);
- }
- // const rvalue
- template<typename Container>
- inline Container sorted(const Container &&container)
- {
- return sorted(container);
- }
- // const lvalue
- template<typename Container, typename Predicate>
- inline Container sorted(const Container &container, Predicate p)
- {
- Container c = container;
- sort(c, p);
- return c;
- }
- // non-const lvalue
- // This is needed because otherwise the "universal" reference below is used, modifying the input
- // container.
- template<typename Container, typename Predicate>
- inline Container sorted(Container &container, Predicate p)
- {
- Container c = container;
- sort(c, p);
- return c;
- }
- // non-const rvalue (actually rvalue or lvalue, but lvalue is handled above)
- template<typename Container, typename Predicate>
- inline Container sorted(Container &&container, Predicate p)
- {
- sort(container, p);
- return std::move(container);
- }
- // const rvalue
- template<typename Container, typename Predicate>
- inline Container sorted(const Container &&container, Predicate p)
- {
- return sorted(container, p);
- }
- // pointer to member
- template<typename Container, typename R, typename S>
- 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);
- });
- }
- // const lvalue
- template<typename Container, typename R, typename S>
- inline Container sorted(const Container &container, R S::*member)
- {
- Container c = container;
- sort(c, member);
- return c;
- }
- // non-const lvalue
- // This is needed because otherwise the "universal" reference below is used, modifying the input
- // container.
- template<typename Container, typename R, typename S>
- inline Container sorted(Container &container, R S::*member)
- {
- Container c = container;
- sort(c, member);
- return c;
- }
- // non-const rvalue (actually rvalue or lvalue, but lvalue is handled above)
- template<typename Container, typename R, typename S>
- inline Container sorted(Container &&container, R S::*member)
- {
- sort(container, member);
- return std::move(container);
- }
- // const rvalue
- template<typename Container, typename R, typename S>
- inline Container sorted(const Container &&container, R S::*member)
- {
- return sorted(container, member);
- }
- // pointer to member function
- template<typename Container, typename R, typename S>
- 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);
- });
- }
- // const lvalue
- template<typename Container, typename R, typename S>
- inline Container sorted(const Container &container, R (S::*function)() const)
- {
- Container c = container;
- sort(c, function);
- return c;
- }
- // non-const lvalue
- // This is needed because otherwise the "universal" reference below is used, modifying the input
- // container.
- template<typename Container, typename R, typename S>
- inline Container sorted(Container &container, R (S::*function)() const)
- {
- Container c = container;
- sort(c, function);
- return c;
- }
- // non-const rvalue (actually rvalue or lvalue, but lvalue is handled above)
- template<typename Container, typename R, typename S>
- inline Container sorted(Container &&container, R (S::*function)() const)
- {
- sort(container, function);
- return std::move(container);
- }
- // const rvalue
- template<typename Container, typename R, typename S>
- inline Container sorted(const Container &&container, R (S::*function)() const)
- {
- return sorted(container, function);
- }
- //////////////////
- // reverseForeach
- /////////////////
- template <typename Container, typename Op>
- 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 <template<typename...> class ResultContainer,
- typename SourceContainer>
- auto toReferences(SourceContainer &sources)
- {
- return transform<ResultContainer>(sources, [] (auto &value) { return std::ref(value); });
- }
- template <typename SourceContainer>
- auto toReferences(SourceContainer &sources)
- {
- return transform(sources, [] (auto &value) { return std::ref(value); });
- }
- //////////////////
- // toConstReferences
- /////////////////
- template <template<typename...> class ResultContainer,
- typename SourceContainer>
- auto toConstReferences(const SourceContainer &sources)
- {
- return transform<ResultContainer>(sources, [] (const auto &value) { return std::cref(value); });
- }
- template <typename SourceContainer>
- auto toConstReferences(const SourceContainer &sources)
- {
- return transform(sources, [] (const auto &value) { return std::cref(value); });
- }
- //////////////////
- // take:
- /////////////////
- template<class C, typename P>
- Q_REQUIRED_RESULT std::optional<typename C::value_type> 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<typename C::value_type> result = std::make_optional(std::move(*it));
- container.erase(it);
- return result;
- }
- // pointer to member
- template <typename C, typename R, typename S>
- Q_REQUIRED_RESULT decltype(auto) take(C &container, R S::*member)
- {
- return take(container, std::mem_fn(member));
- }
- // pointer to member function
- template <typename C, typename R, typename S>
- 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<class InputIt1,
- class InputIt2,
- class OutputIt,
- class Merge,
- class Compare>
- 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<class InputIt1,
- class InputIt2,
- class OutputIt,
- class Merge>
- 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<std::decay_t<decltype(*first1)>>{});
- }
- template<class OutputContainer,
- class InputContainer1,
- class InputContainer2,
- class Merge,
- class Compare>
- 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<class OutputContainer,
- class InputContainer1,
- class InputContainer2,
- class Merge>
- OutputContainer setUnionMerge(InputContainer1 &&input1,
- InputContainer2 &&input2,
- Merge merge)
- {
- return setUnionMerge<OutputContainer>(std::forward<InputContainer1>(input1),
- std::forward<InputContainer2>(input2),
- merge,
- std::less<std::decay_t<decltype(*std::begin(input1))>>{});
- }
- template<typename Container>
- constexpr auto usize(const Container &container)
- {
- return static_cast<std::make_unsigned_t<decltype(std::size(container))>>(std::size(container));
- }
- template<typename Container>
- constexpr auto ssize(const Container &container)
- {
- return static_cast<std::make_signed_t<decltype(std::size(container))>>(std::size(container));
- }
- template<typename Compare>
- struct CompareIter
- {
- Compare compare;
- explicit constexpr CompareIter(Compare compare)
- : compare(std::move(compare))
- {}
- template<typename Iterator1, typename Iterator2>
- constexpr bool operator()(Iterator1 it1, Iterator2 it2)
- {
- return bool(compare(*it1, *it2));
- }
- };
- template<typename InputIterator1, typename InputIterator2, typename OutputIterator, typename Compare>
- OutputIterator set_union_impl(InputIterator1 first1,
- InputIterator1 last1,
- InputIterator2 first2,
- InputIterator2 last2,
- OutputIterator result,
- Compare comp)
- {
- auto compare = CompareIter<Compare>(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<typename InputIterator1, typename InputIterator2, typename OutputIterator, typename Compare>
- 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<typename InputIterator1, typename InputIterator2, typename OutputIterator>
- 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<typename InputIterator1::value_type>{});
- }
- // Replacement for deprecated Qt functionality
- template <class T>
- QSet<T> toSet(const QList<T> &list)
- {
- return QSet<T>(list.begin(), list.end());
- }
- template<class T>
- QList<T> toList(const QSet<T> &set)
- {
- return QList<T>(set.begin(), set.end());
- }
- template <class Key, class T>
- void addToHash(QHash<Key, T> *result, const QHash<Key, T> &additionalContents)
- {
- result->insert(additionalContents);
- }
- template <typename Tuple, std::size_t... I>
- static std::size_t tupleHashHelper(uint seed, const Tuple &tuple, std::index_sequence<I...>)
- {
- return qHashMulti(seed, (std::get<I>(tuple), ...));
- }
- template<typename... T> std::size_t qHash(const std::tuple<T...> &tuple, uint seed = 0)
- {
- return tupleHashHelper(seed, tuple, std::make_index_sequence<sizeof...(T)>());
- }
- // Workaround for missing information from QSet::insert()
- // Return type could be a pair like for std::set, but we never use the iterator anyway.
- template<typename T, typename U> [[nodiscard]] bool insert(QSet<T> &s, const U &v)
- {
- const int oldSize = s.size();
- s.insert(v);
- return s.size() > oldSize;
- }
- } // namespace Utils
|