Utils: Remove functiontraits.h, mapreduce.h and runextensions.h

Change-Id: I61d0f95d4120c0de0045c1a817fd13a09eeb5402
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Jarek Kobus
2023-05-24 18:06:54 +02:00
parent 80326d8743
commit 1cbd417906
17 changed files with 1 additions and 2196 deletions

View File

@@ -6,7 +6,6 @@ add_qtc_library(Utils
SOURCES
../3rdparty/span/span.hpp
../3rdparty/tl_expected/include/tl/expected.hpp
QtConcurrentTools
algorithm.h
ansiescapecodehandler.cpp ansiescapecodehandler.h
appinfo.cpp appinfo.h
@@ -66,7 +65,6 @@ add_qtc_library(Utils
flowlayout.cpp flowlayout.h
fsengine/fsengine.cpp fsengine/fsengine.h
fsengine/fileiconprovider.cpp fsengine/fileiconprovider.h
functiontraits.h
futuresynchronizer.cpp futuresynchronizer.h
fuzzymatcher.cpp fuzzymatcher.h
genericconstants.h
@@ -93,7 +91,6 @@ add_qtc_library(Utils
listmodel.h
listutils.h
macroexpander.cpp macroexpander.h
mapreduce.h
mathutils.cpp mathutils.h
mimeutils.h
minimizableinfobars.cpp
@@ -143,7 +140,6 @@ add_qtc_library(Utils
ranges.h
reloadpromptutils.cpp reloadpromptutils.h
removefiledialog.cpp removefiledialog.h
runextensions.cpp runextensions.h
savefile.cpp savefile.h
scopedswap.h
scopedtimer.cpp scopedtimer.h

View File

@@ -1,4 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "runextensions.h"

View File

@@ -1,169 +0,0 @@
// 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 <tuple>
namespace Utils {
/*
struct functionTraits<Function>
{
using ResultType; // Return type of Function
struct argument<unsigned index>
{
using type; // type of Function argument at index (starting with 0)
}
}
struct functionTakesArgument<Function, unsigned index, ArgumentType>;
Is derived from std::true_type if Function takes an argument of type ArgumentType at index.
Otherwise derived from std::false_type.
*/
////////////////////
// functionTraits
////////////////////
// for callables. defined below.
template <typename Callable>
struct functionTraits;
// function
template <typename Result, typename... Args>
struct functionTraits<Result(Args...)>
{
using ResultType = Result;
static const unsigned arity = sizeof...(Args); // TODO const -> constexpr with MSVC2015
template <unsigned i>
struct argument
{
using type = typename std::tuple_element<i, std::tuple<Args...>>::type;
};
};
// function pointer
template <typename Result, typename... Args>
struct functionTraits<Result(*)(Args...)> : public functionTraits<Result(Args...)>
{
};
// const function pointer
template <typename Result, typename... Args>
struct functionTraits<Result(* const)(Args...)> : public functionTraits<Result(Args...)>
{
};
// member function
template <typename Type, typename Result, typename... Args>
struct functionTraits<Result(Type::*)(Args...)> : public functionTraits<Result(Type&,Args...)>
{
};
// const member function
template <typename Type, typename Result, typename... Args>
struct functionTraits<Result(Type::*)(Args...) const> : public functionTraits<Result(Type&,Args...)>
{
};
// const pointer to member function
template <typename Type, typename Result, typename... Args>
struct functionTraits<Result(Type::* const)(Args...)> : public functionTraits<Result(Type&,Args...)>
{
};
// const pointer to const member function
template <typename Type, typename Result, typename... Args>
struct functionTraits<Result(Type::* const)(Args...) const> : public functionTraits<Result(Type&,Args...)>
{
};
// TODO: enable lvalue and rvalue ref member function later (MSVC 2015?)
//// lvalue ref member function
//template <typename Type, typename Result, typename... Args>
//struct functionTraits<Result(Type::*)(Args...) &> : public functionTraits<Result(Type&,Args...)>
//{
//};
//// const lvalue ref member function
//template <typename Type, typename Result, typename... Args>
//struct functionTraits<Result(Type::*)(Args...) const &> : public functionTraits<Result(Type&,Args...)>
//{
//};
//// rvalue ref member function
//template <typename Type, typename Result, typename... Args>
//struct functionTraits<Result(Type::*)(Args...) &&> : public functionTraits<Result(Type&,Args...)>
//{
//};
// callables. only works if operator() is not overloaded.
template <typename Callable>
struct functionTraits
{
using callableTraits = functionTraits<decltype(&Callable::operator())>;
using ResultType = typename callableTraits::ResultType;
static const unsigned arity = callableTraits::arity - 1; // ignore object pointer arg // TODO const -> constexpr with MSVC2015
template <unsigned i>
struct argument
{
using type = typename callableTraits::template argument<i+1>::type; // ignore object pointer arg
};
};
// lvalue ref callables
template <typename Callable>
struct functionTraits<Callable&> : public functionTraits<Callable>
{
};
// const lvalue ref callables
template <typename Callable>
struct functionTraits<const Callable&> : public functionTraits<Callable>
{
};
// rvalue ref callables
template <typename Callable>
struct functionTraits<Callable&&> : public functionTraits<Callable>
{
};
template <typename F>
using functionResult_t = typename functionTraits<F>::ResultType;
////////////////////
// functionTakesArgument
////////////////////
namespace Internal {
template <typename HasArity/*true_type or false_type*/,
typename Function, unsigned index, typename T>
struct functionTakesArgumentArityDispatch;
template <typename Function, unsigned index, typename T>
struct functionTakesArgumentArityDispatch<std::false_type, Function, index, T>
: public std::false_type
{
};
template <typename Function, unsigned index, typename T>
struct functionTakesArgumentArityDispatch<std::true_type, Function, index, T>
: public std::is_same<T, typename functionTraits<Function>::template argument<index>::type>
{
};
} // Internal
template <typename Function, unsigned index, typename T>
struct functionTakesArgument : public Internal::functionTakesArgumentArityDispatch<
std::integral_constant<bool, (functionTraits<Function>::arity > index)>,
Function, index, T>
{
};
} // Utils

View File

@@ -1,594 +0,0 @@
// 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 "utils_global.h"
#include "algorithm.h"
#include "runextensions.h"
#include <QFutureWatcher>
#include <iterator>
namespace Utils {
enum class MapReduceOption
{
Ordered,
Unordered
};
namespace Internal {
class QTCREATOR_UTILS_EXPORT MapReduceObject : public QObject
{
Q_OBJECT
};
template <typename ForwardIterator, typename MapResult, typename MapFunction, typename State, typename ReduceResult, typename ReduceFunction>
class MapReduceBase : public MapReduceObject
{
protected:
static const int MAX_PROGRESS = 1000000;
// either const or non-const reference wrapper for items from the iterator
using ItemReferenceWrapper = std::reference_wrapper<
std::remove_reference_t<typename std::iterator_traits<ForwardIterator>::reference>>;
public:
MapReduceBase(QFutureInterface<ReduceResult> &futureInterface, ForwardIterator begin, ForwardIterator end,
MapFunction &&map, State &state, ReduceFunction &&reduce,
MapReduceOption option, QThreadPool *pool, int size)
: m_futureInterface(futureInterface),
m_iterator(begin),
m_end(end),
m_map(std::forward<MapFunction>(map)),
m_state(state),
m_reduce(std::forward<ReduceFunction>(reduce)),
m_threadPool(pool),
m_handleProgress(size >= 0),
m_size(size),
m_option(option)
{
if (!m_threadPool)
m_threadPool = new QThreadPool(this);
if (m_handleProgress) // progress is handled by us
m_futureInterface.setProgressRange(0, MAX_PROGRESS);
connect(&m_selfWatcher, &QFutureWatcher<void>::canceled,
this, &MapReduceBase::cancelAll);
m_selfWatcher.setFuture(QFuture<void>(futureInterface.future()));
}
void exec()
{
// do not enter event loop for empty containers or if already canceled
if (!m_futureInterface.isCanceled() && schedule())
m_loop.exec();
}
protected:
virtual void reduce(QFutureWatcher<MapResult> *watcher, int index) = 0;
bool schedule()
{
bool didSchedule = false;
while (m_iterator != m_end
&& m_mapWatcher.size() < std::max(m_threadPool->maxThreadCount(), 1)) {
didSchedule = true;
auto watcher = new QFutureWatcher<MapResult>();
connect(watcher, &QFutureWatcher<MapResult>::finished, this, [this, watcher] {
mapFinished(watcher);
});
if (m_handleProgress) {
connect(watcher, &QFutureWatcher<MapResult>::progressValueChanged,
this, &MapReduceBase::updateProgress);
connect(watcher, &QFutureWatcher<MapResult>::progressRangeChanged,
this, &MapReduceBase::updateProgress);
}
m_mapWatcher.append(watcher);
m_watcherIndex.append(m_currentIndex);
++m_currentIndex;
watcher->setFuture(runAsync(m_threadPool, std::cref(m_map),
ItemReferenceWrapper(*m_iterator)));
++m_iterator;
}
return didSchedule;
}
void mapFinished(QFutureWatcher<MapResult> *watcher)
{
int index = m_mapWatcher.indexOf(watcher);
int watcherIndex = m_watcherIndex.at(index);
m_mapWatcher.removeAt(index); // remove so we can schedule next one
m_watcherIndex.removeAt(index);
bool didSchedule = false;
if (!m_futureInterface.isCanceled()) {
// first schedule the next map...
didSchedule = schedule();
++m_successfullyFinishedMapCount;
updateProgress();
// ...then reduce
reduce(watcher, watcherIndex);
}
delete watcher;
if (!didSchedule && m_mapWatcher.isEmpty())
m_loop.quit();
}
void updateProgress()
{
if (!m_handleProgress) // cannot compute progress
return;
if (m_size == 0 || m_successfullyFinishedMapCount == m_size) {
m_futureInterface.setProgressValue(MAX_PROGRESS);
return;
}
if (!m_futureInterface.isProgressUpdateNeeded())
return;
const double progressPerMap = MAX_PROGRESS / double(m_size);
double progress = m_successfullyFinishedMapCount * progressPerMap;
for (const QFutureWatcher<MapResult> *watcher : std::as_const(m_mapWatcher)) {
if (watcher->progressMinimum() != watcher->progressMaximum()) {
const double range = watcher->progressMaximum() - watcher->progressMinimum();
progress += (watcher->progressValue() - watcher->progressMinimum()) / range * progressPerMap;
}
}
m_futureInterface.setProgressValue(int(progress));
}
void cancelAll()
{
for (QFutureWatcher<MapResult> *watcher : std::as_const(m_mapWatcher))
watcher->cancel();
}
QFutureWatcher<void> m_selfWatcher;
QFutureInterface<ReduceResult> &m_futureInterface;
ForwardIterator m_iterator;
const ForwardIterator m_end;
MapFunction m_map;
State &m_state;
ReduceFunction m_reduce;
QEventLoop m_loop;
QThreadPool *m_threadPool; // for reusing threads
QList<QFutureWatcher<MapResult> *> m_mapWatcher;
QList<int> m_watcherIndex;
int m_currentIndex = 0;
const bool m_handleProgress;
const int m_size;
int m_successfullyFinishedMapCount = 0;
MapReduceOption m_option;
};
// non-void result of map function.
template <typename ForwardIterator, typename MapResult, typename MapFunction, typename State, typename ReduceResult, typename ReduceFunction>
class MapReduce : public MapReduceBase<ForwardIterator, MapResult, MapFunction, State, ReduceResult, ReduceFunction>
{
using BaseType = MapReduceBase<ForwardIterator, MapResult, MapFunction, State, ReduceResult, ReduceFunction>;
public:
MapReduce(QFutureInterface<ReduceResult> &futureInterface, ForwardIterator begin, ForwardIterator end,
MapFunction &&map, State &state, ReduceFunction &&reduce, MapReduceOption option,
QThreadPool *pool, int size)
: BaseType(futureInterface, begin, end, std::forward<MapFunction>(map), state,
std::forward<ReduceFunction>(reduce), option, pool, size)
{
}
protected:
void reduce(QFutureWatcher<MapResult> *watcher, int index) override
{
if (BaseType::m_option == MapReduceOption::Unordered) {
reduceOne(watcher->future().results());
} else {
if (m_nextIndex == index) {
// handle this result and all directly following
reduceOne(watcher->future().results());
++m_nextIndex;
while (!m_pendingResults.isEmpty() && m_pendingResults.firstKey() == m_nextIndex) {
reduceOne(m_pendingResults.take(m_nextIndex));
++m_nextIndex;
}
} else {
// add result to pending results
m_pendingResults.insert(index, watcher->future().results());
}
}
}
private:
void reduceOne(const QList<MapResult> &results)
{
const int resultCount = results.size();
for (int i = 0; i < resultCount; ++i) {
Internal::runAsyncImpl(BaseType::m_futureInterface, BaseType::m_reduce,
BaseType::m_state, results.at(i));
}
}
QMap<int, QList<MapResult>> m_pendingResults;
int m_nextIndex = 0;
};
// specialization for void result of map function. Reducing is a no-op.
template <typename ForwardIterator, typename MapFunction, typename State, typename ReduceResult, typename ReduceFunction>
class MapReduce<ForwardIterator, void, MapFunction, State, ReduceResult, ReduceFunction> : public MapReduceBase<ForwardIterator, void, MapFunction, State, ReduceResult, ReduceFunction>
{
using BaseType = MapReduceBase<ForwardIterator, void, MapFunction, State, ReduceResult, ReduceFunction>;
public:
MapReduce(QFutureInterface<ReduceResult> &futureInterface, ForwardIterator begin, ForwardIterator end,
MapFunction &&map, State &state, ReduceFunction &&reduce, MapReduceOption option,
QThreadPool *pool, int size)
: BaseType(futureInterface, begin, end, std::forward<MapFunction>(map), state,
std::forward<ReduceFunction>(reduce), option, pool, size)
{
}
protected:
void reduce(QFutureWatcher<void> *, int) override
{
}
};
template <typename ResultType, typename Function, typename... Args>
functionResult_t<Function>
callWithMaybeFutureInterfaceDispatch(std::false_type, QFutureInterface<ResultType> &,
Function &&function, Args&&... args)
{
return function(std::forward<Args>(args)...);
}
template <typename ResultType, typename Function, typename... Args>
functionResult_t<Function>
callWithMaybeFutureInterfaceDispatch(std::true_type, QFutureInterface<ResultType> &futureInterface,
Function &&function, Args&&... args)
{
return function(futureInterface, std::forward<Args>(args)...);
}
template <typename ResultType, typename Function, typename... Args>
functionResult_t<Function>
callWithMaybeFutureInterface(QFutureInterface<ResultType> &futureInterface,
Function &&function, Args&&... args)
{
return callWithMaybeFutureInterfaceDispatch(
functionTakesArgument<Function, 0, QFutureInterface<ResultType>&>(),
futureInterface, std::forward<Function>(function), std::forward<Args>(args)...);
}
template <typename ForwardIterator, typename InitFunction, typename MapFunction, typename ReduceResult,
typename ReduceFunction, typename CleanUpFunction>
void blockingIteratorMapReduce(QFutureInterface<ReduceResult> &futureInterface, ForwardIterator begin, ForwardIterator end,
InitFunction &&init, MapFunction &&map,
ReduceFunction &&reduce, CleanUpFunction &&cleanup,
MapReduceOption option, QThreadPool *pool, int size)
{
auto state = callWithMaybeFutureInterface<ReduceResult, InitFunction>
(futureInterface, std::forward<InitFunction>(init));
MapReduce<ForwardIterator, typename Internal::resultType<MapFunction>::type, MapFunction, decltype(state), ReduceResult, ReduceFunction>
mr(futureInterface, begin, end, std::forward<MapFunction>(map), state,
std::forward<ReduceFunction>(reduce), option, pool, size);
mr.exec();
callWithMaybeFutureInterface<ReduceResult, CleanUpFunction, std::remove_reference_t<decltype(state)>&>
(futureInterface, std::forward<CleanUpFunction>(cleanup), state);
}
template <typename Container, typename InitFunction, typename MapFunction, typename ReduceResult,
typename ReduceFunction, typename CleanUpFunction>
void blockingContainerMapReduce(QFutureInterface<ReduceResult> &futureInterface, Container &&container,
InitFunction &&init, MapFunction &&map,
ReduceFunction &&reduce, CleanUpFunction &&cleanup,
MapReduceOption option, QThreadPool *pool)
{
blockingIteratorMapReduce(futureInterface, std::begin(container), std::end(container),
std::forward<InitFunction>(init), std::forward<MapFunction>(map),
std::forward<ReduceFunction>(reduce),
std::forward<CleanUpFunction>(cleanup),
option, pool, static_cast<int>(container.size()));
}
template <typename Container, typename InitFunction, typename MapFunction, typename ReduceResult,
typename ReduceFunction, typename CleanUpFunction>
void blockingContainerRefMapReduce(QFutureInterface<ReduceResult> &futureInterface,
std::reference_wrapper<Container> containerWrapper,
InitFunction &&init, MapFunction &&map,
ReduceFunction &&reduce, CleanUpFunction &&cleanup,
MapReduceOption option, QThreadPool *pool)
{
blockingContainerMapReduce(futureInterface, containerWrapper.get(),
std::forward<InitFunction>(init), std::forward<MapFunction>(map),
std::forward<ReduceFunction>(reduce),
std::forward<CleanUpFunction>(cleanup),
option, pool);
}
template <typename ReduceResult>
static void *dummyInit() { return nullptr; }
// copies or moves state to member, and then moves it to the result of the call operator
template <typename State>
struct StateWrapper {
using StateResult = std::decay_t<State>; // State is const& or & for lvalues
StateWrapper(State &&state) : m_state(std::forward<State>(state)) { }
StateResult operator()()
{
return std::move(m_state); // invalidates m_state
}
StateResult m_state;
};
// copies or moves reduce function to member, calls the reduce function with state and mapped value
template <typename StateResult, typename MapResult, typename ReduceFunction>
struct ReduceWrapper {
using Reduce = std::decay_t<ReduceFunction>;
ReduceWrapper(ReduceFunction &&reduce) : m_reduce(std::forward<ReduceFunction>(reduce)) { }
void operator()(QFutureInterface<StateResult> &, StateResult &state, const MapResult &mapResult)
{
m_reduce(state, mapResult);
}
Reduce m_reduce;
};
template <typename MapResult>
struct DummyReduce {
MapResult operator()(void *, const MapResult &result) const { return result; }
};
template <>
struct DummyReduce<void> {
void operator()() const { } // needed for resultType<DummyReduce> with MSVC2013
};
template <typename ReduceResult>
static void dummyCleanup(void *) { }
template <typename StateResult>
static void cleanupReportingState(QFutureInterface<StateResult> &fi, StateResult &state)
{
fi.reportResult(state);
}
} // Internal
template <typename ForwardIterator, typename InitFunction, typename MapFunction,
typename ReduceFunction, typename CleanUpFunction,
typename ReduceResult = typename Internal::resultType<ReduceFunction>::type>
QFuture<ReduceResult>
mapReduce(ForwardIterator begin, ForwardIterator end, InitFunction &&init, MapFunction &&map,
ReduceFunction &&reduce, CleanUpFunction &&cleanup,
MapReduceOption option = MapReduceOption::Unordered,
QThreadPool *pool = nullptr, QThread::Priority priority = QThread::InheritPriority,
int size = -1)
{
return runAsync(priority,
Internal::blockingIteratorMapReduce<
ForwardIterator,
std::decay_t<InitFunction>,
std::decay_t<MapFunction>,
std::decay_t<ReduceResult>,
std::decay_t<ReduceFunction>,
std::decay_t<CleanUpFunction>>,
begin, end, std::forward<InitFunction>(init), std::forward<MapFunction>(map),
std::forward<ReduceFunction>(reduce), std::forward<CleanUpFunction>(cleanup),
option, pool, size);
}
/*!
Calls the map function on all items in \a container in parallel through Utils::runAsync.
The reduce function is called in the mapReduce thread with each of the reported results from
the map function, in arbitrary order, but never in parallel.
It gets passed a reference to a user defined state object, and a result from the map function.
If it takes a QFutureInterface reference as its first argument, it can report results
for the mapReduce operation through that. Otherwise, any values returned by the reduce function
are reported as results of the mapReduce operation.
The init function is called in the mapReduce thread before the actual mapping starts,
and must return the initial state object for the reduce function. It gets the QFutureInterface
of the mapReduce operation passed as an argument.
The cleanup function is called in the mapReduce thread after all map and reduce calls have
finished, with the QFutureInterface of the mapReduce operation and the final state object
as arguments, and can be used to clean up any resources, or report a final result of the
mapReduce.
Container<ItemType>
StateType InitFunction(QFutureInterface<ReduceResultType>&)
or
StateType InitFunction()
void MapFunction(QFutureInterface<MapResultType>&, const ItemType&)
or
MapResultType MapFunction(const ItempType&)
void ReduceFunction(QFutureInterface<ReduceResultType>&, StateType&, const MapResultType&)
or
ReduceResultType ReduceFunction(StateType&, const MapResultType&)
void CleanUpFunction(QFutureInterface<ReduceResultType>&, StateType&)
or
void CleanUpFunction(StateType&)
Notes:
\list
\li Container can be a move-only type or a temporary. If it is a lvalue reference, it will
be copied to the mapReduce thread. You can avoid that by using
the version that takes iterators, or by using std::ref/cref to pass a reference_wrapper.
\li ItemType can be a move-only type, if the map function takes (const) references to ItemType.
\li StateType can be a move-only type.
\li The init, map, reduce and cleanup functions can be move-only types and are moved to the
mapReduce thread if they are rvalues.
\endlist
*/
template <typename Container, typename InitFunction, typename MapFunction,
typename ReduceFunction, typename CleanUpFunction,
typename ReduceResult = typename Internal::resultType<ReduceFunction>::type>
QFuture<ReduceResult>
mapReduce(Container &&container, InitFunction &&init, MapFunction &&map,
ReduceFunction &&reduce, CleanUpFunction &&cleanup,
MapReduceOption option = MapReduceOption::Unordered,
QThreadPool *pool = nullptr, QThread::Priority priority = QThread::InheritPriority)
{
return runAsync(priority,
Internal::blockingContainerMapReduce<
std::decay_t<Container>,
std::decay_t<InitFunction>,
std::decay_t<MapFunction>,
std::decay_t<ReduceResult>,
std::decay_t<ReduceFunction>,
std::decay_t<CleanUpFunction>>,
std::forward<Container>(container),
std::forward<InitFunction>(init), std::forward<MapFunction>(map),
std::forward<ReduceFunction>(reduce), std::forward<CleanUpFunction>(cleanup),
option, pool);
}
template <typename Container, typename InitFunction, typename MapFunction,
typename ReduceFunction, typename CleanUpFunction,
typename ReduceResult = typename Internal::resultType<ReduceFunction>::type>
QFuture<ReduceResult>
mapReduce(std::reference_wrapper<Container> containerWrapper, InitFunction &&init, MapFunction &&map,
ReduceFunction &&reduce, CleanUpFunction &&cleanup,
MapReduceOption option = MapReduceOption::Unordered,
QThreadPool *pool = nullptr, QThread::Priority priority = QThread::InheritPriority)
{
return runAsync(priority,
Internal::blockingContainerRefMapReduce<
Container,
std::decay_t<InitFunction>,
std::decay_t<MapFunction>,
std::decay_t<ReduceResult>,
std::decay_t<ReduceFunction>,
std::decay_t<CleanUpFunction>>,
containerWrapper,
std::forward<InitFunction>(init), std::forward<MapFunction>(map),
std::forward<ReduceFunction>(reduce), std::forward<CleanUpFunction>(cleanup),
option, pool);
}
template <typename ForwardIterator, typename MapFunction, typename State, typename ReduceFunction,
typename StateResult = std::decay_t<State>, // State = T& or const T& for lvalues, so decay that away
typename MapResult = typename Internal::resultType<MapFunction>::type>
QFuture<StateResult>
mapReduce(ForwardIterator begin, ForwardIterator end, MapFunction &&map, State &&initialState,
ReduceFunction &&reduce, MapReduceOption option = MapReduceOption::Unordered,
QThreadPool *pool = nullptr, QThread::Priority priority = QThread::InheritPriority,
int size = -1)
{
return mapReduce(begin, end,
Internal::StateWrapper<State>(std::forward<State>(initialState)),
std::forward<MapFunction>(map),
Internal::ReduceWrapper<StateResult, MapResult, ReduceFunction>(std::forward<ReduceFunction>(reduce)),
&Internal::cleanupReportingState<StateResult>,
option, pool, priority, size);
}
template <typename Container, typename MapFunction, typename State, typename ReduceFunction,
typename StateResult = std::decay_t<State>, // State = T& or const T& for lvalues, so decay that away
typename MapResult = typename Internal::resultType<MapFunction>::type>
QFuture<StateResult>
mapReduce(Container &&container, MapFunction &&map, State &&initialState, ReduceFunction &&reduce,
MapReduceOption option = MapReduceOption::Unordered,
QThreadPool *pool = nullptr, QThread::Priority priority = QThread::InheritPriority)
{
return mapReduce(std::forward<Container>(container),
Internal::StateWrapper<State>(std::forward<State>(initialState)),
std::forward<MapFunction>(map),
Internal::ReduceWrapper<StateResult, MapResult, ReduceFunction>(std::forward<ReduceFunction>(reduce)),
&Internal::cleanupReportingState<StateResult>,
option, pool, priority);
}
template <typename ForwardIterator, typename MapFunction, typename State, typename ReduceFunction,
typename StateResult = std::decay_t<State>, // State = T& or const T& for lvalues, so decay that away
typename MapResult = typename Internal::resultType<MapFunction>::type>
Q_REQUIRED_RESULT
StateResult
mappedReduced(ForwardIterator begin, ForwardIterator end, MapFunction &&map, State &&initialState,
ReduceFunction &&reduce, MapReduceOption option = MapReduceOption::Unordered,
QThreadPool *pool = nullptr, QThread::Priority priority = QThread::InheritPriority,
int size = -1)
{
return mapReduce(begin, end,
std::forward<MapFunction>(map), std::forward<State>(initialState),
std::forward<ReduceFunction>(reduce),
option, pool, priority, size).result();
}
template <typename Container, typename MapFunction, typename State, typename ReduceFunction,
typename StateResult = std::decay_t<State>, // State = T& or const T& for lvalues, so decay that away
typename MapResult = typename Internal::resultType<MapFunction>::type>
Q_REQUIRED_RESULT
StateResult
mappedReduced(Container &&container, MapFunction &&map, State &&initialState, ReduceFunction &&reduce,
MapReduceOption option = MapReduceOption::Unordered,
QThreadPool *pool = nullptr, QThread::Priority priority = QThread::InheritPriority)
{
return mapReduce(std::forward<Container>(container), std::forward<MapFunction>(map),
std::forward<State>(initialState), std::forward<ReduceFunction>(reduce),
option, pool, priority).result();
}
template <typename ForwardIterator, typename MapFunction,
typename MapResult = typename Internal::resultType<MapFunction>::type>
QFuture<MapResult>
map(ForwardIterator begin, ForwardIterator end, MapFunction &&map,
MapReduceOption option = MapReduceOption::Ordered,
QThreadPool *pool = nullptr, QThread::Priority priority = QThread::InheritPriority,
int size = -1)
{
return mapReduce(begin, end,
&Internal::dummyInit<MapResult>,
std::forward<MapFunction>(map),
Internal::DummyReduce<MapResult>(),
&Internal::dummyCleanup<MapResult>,
option, pool, priority, size);
}
template <typename Container, typename MapFunction,
typename MapResult = typename Internal::resultType<MapFunction>::type>
QFuture<MapResult>
map(Container &&container, MapFunction &&map, MapReduceOption option = MapReduceOption::Ordered,
QThreadPool *pool = nullptr, QThread::Priority priority = QThread::InheritPriority)
{
return mapReduce(std::forward<Container>(container),
Internal::dummyInit<MapResult>,
std::forward<MapFunction>(map),
Internal::DummyReduce<MapResult>(),
Internal::dummyCleanup<MapResult>,
option, pool, priority);
}
template <template<typename> class ResultContainer, typename ForwardIterator, typename MapFunction,
typename MapResult = typename Internal::resultType<MapFunction>::type>
Q_REQUIRED_RESULT
ResultContainer<MapResult>
mapped(ForwardIterator begin, ForwardIterator end, MapFunction &&mapFun,
MapReduceOption option = MapReduceOption::Ordered,
QThreadPool *pool = nullptr, QThread::Priority priority = QThread::InheritPriority, int size = -1)
{
return Utils::transform<ResultContainer>(map(begin, end,
std::forward<MapFunction>(mapFun),
option, pool, priority, size).results(),
[](const MapResult &r) { return r; });
}
template <template<typename> class ResultContainer, typename Container, typename MapFunction,
typename MapResult = typename Internal::resultType<MapFunction>::type>
Q_REQUIRED_RESULT
ResultContainer<MapResult>
mapped(Container &&container, MapFunction &&mapFun,
MapReduceOption option = MapReduceOption::Ordered,
QThreadPool *pool = nullptr, QThread::Priority priority = QThread::InheritPriority)
{
return Utils::transform<ResultContainer>(map(container,
std::forward<MapFunction>(mapFun),
option, pool, priority).results(),
[](const MapResult &r) { return r; });
}
} // Utils

View File

@@ -1,23 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "runextensions.h"
namespace Utils {
namespace Internal {
RunnableThread::RunnableThread(QRunnable *runnable, QObject *parent)
: QThread(parent),
m_runnable(runnable)
{
}
void RunnableThread::run()
{
m_runnable->run();
if (m_runnable->autoDelete())
delete m_runnable;
}
} // Internal
} // Utils

View File

@@ -1,479 +0,0 @@
// 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 "utils_global.h"
#include "functiontraits.h"
#include <QCoreApplication>
#include <QFuture>
#include <QFutureInterface>
#include <QFutureWatcher>
#include <QRunnable>
#include <QThread>
#include <QThreadPool>
#include <functional>
// hasCallOperator & Co must be outside of any namespace
// because of internal compiler error with MSVC2015 Update 2
using testCallOperatorYes = char;
using testCallOperatorNo = struct { char foo[2]; };
template<typename C>
static testCallOperatorYes testCallOperator(decltype(&C::operator()));
template<typename>
static testCallOperatorNo testCallOperator(...);
template<typename T>
struct hasCallOperator
{
static const bool value = (sizeof(testCallOperator<T>(nullptr)) == sizeof(testCallOperatorYes));
};
namespace Utils {
namespace Internal {
/*
resultType<F>::type
Returns the type of results that would be reported by a callable of type F
when called through the runAsync methods. I.e. the ResultType in
void f(QFutureInterface<Result> &fi, ...)
ResultType f(...)
Returns void if F is not callable, and if F is a callable that does not take
a QFutureInterface& as its first parameter and returns void.
*/
template <typename Function>
struct resultType;
template <typename Function, typename Arg>
struct resultTypeWithArgument;
template <typename Function, int index, bool>
struct resultTypeTakesArguments;
template <typename Function, bool>
struct resultTypeIsMemberFunction;
template <typename Function, bool>
struct resultTypeIsFunctionLike;
template <typename Function, bool>
struct resultTypeHasCallOperator;
template <typename Function, typename ResultType>
struct resultTypeWithArgument<Function, QFutureInterface<ResultType>&>
{
using type = ResultType;
};
template <typename Function, typename Arg>
struct resultTypeWithArgument
{
using type = functionResult_t<Function>;
};
template <typename Function, int index>
struct resultTypeTakesArguments<Function, index, true>
: public resultTypeWithArgument<Function, typename functionTraits<Function>::template argument<index>::type>
{
};
template <typename Function, int index>
struct resultTypeTakesArguments<Function, index, false>
{
using type = functionResult_t<Function>;
};
template <typename Function>
struct resultTypeIsFunctionLike<Function, true>
: public resultTypeTakesArguments<Function, 0, (functionTraits<Function>::arity > 0)>
{
};
template <typename Function>
struct resultTypeIsMemberFunction<Function, true>
: public resultTypeTakesArguments<Function, 1, (functionTraits<Function>::arity > 1)>
{
};
template <typename Function>
struct resultTypeIsMemberFunction<Function, false>
{
using type = void;
};
template <typename Function>
struct resultTypeIsFunctionLike<Function, false>
: public resultTypeIsMemberFunction<Function, std::is_member_function_pointer<Function>::value>
{
};
template <typename Function>
struct resultTypeHasCallOperator<Function, false>
: public resultTypeIsFunctionLike<Function, std::is_function<std::remove_pointer_t<std::decay_t<Function>>>::value>
{
};
template <typename Callable>
struct resultTypeHasCallOperator<Callable, true>
: public resultTypeTakesArguments<Callable, 0, (functionTraits<Callable>::arity > 0)>
{
};
template <typename Function>
struct resultType
: public resultTypeHasCallOperator<Function, hasCallOperator<Function>::value>
{
};
template <typename Function>
struct resultType<Function&> : public resultType<Function>
{
};
template <typename Function>
struct resultType<const Function&> : public resultType<Function>
{
};
template <typename Function>
struct resultType<Function &&> : public resultType<Function>
{
};
template <typename Function>
struct resultType<std::reference_wrapper<Function>> : public resultType<Function>
{
};
template <typename Function>
struct resultType<std::reference_wrapper<const Function>> : public resultType<Function>
{
};
/*
Callable object that wraps a member function pointer with the object it
will be called on.
*/
template <typename Function>
class MemberCallable;
template <typename Result, typename Obj, typename... Args>
class MemberCallable<Result(Obj::*)(Args...) const>
{
public:
MemberCallable(Result(Obj::* function)(Args...) const, const Obj *obj)
: m_function(function),
m_obj(obj)
{
}
Result operator()(Args&&... args) const
{
return ((*m_obj).*m_function)(std::forward<Args>(args)...);
}
private:
Result(Obj::* m_function)(Args...) const;
const Obj *m_obj;
};
template <typename Result, typename Obj, typename... Args>
class MemberCallable<Result(Obj::*)(Args...)>
{
public:
MemberCallable(Result(Obj::* function)(Args...), Obj *obj)
: m_function(function),
m_obj(obj)
{
}
Result operator()(Args&&... args) const
{
return ((*m_obj).*m_function)(std::forward<Args>(args)...);
}
private:
Result(Obj::* m_function)(Args...);
Obj *m_obj;
};
/*
Helper functions for runAsync that run in the started thread.
*/
// void function that does not take QFutureInterface
template <typename ResultType, typename Function, typename... Args>
void runAsyncReturnVoidDispatch(std::true_type, QFutureInterface<ResultType> &, Function &&function, Args&&... args)
{
function(std::forward<Args>(args)...);
}
// non-void function that does not take QFutureInterface
template <typename ResultType, typename Function, typename... Args>
void runAsyncReturnVoidDispatch(std::false_type, QFutureInterface<ResultType> &futureInterface, Function &&function, Args&&... args)
{
futureInterface.reportResult(function(std::forward<Args>(args)...));
}
// function that takes QFutureInterface
template <typename ResultType, typename Function, typename... Args>
void runAsyncQFutureInterfaceDispatch(std::true_type, QFutureInterface<ResultType> &futureInterface, Function &&function, Args&&... args)
{
function(futureInterface, std::forward<Args>(args)...);
}
// function that does not take QFutureInterface
template <typename ResultType, typename Function, typename... Args>
void runAsyncQFutureInterfaceDispatch(std::false_type, QFutureInterface<ResultType> &futureInterface, Function &&function, Args&&... args)
{
runAsyncReturnVoidDispatch(std::is_void<std::invoke_result_t<Function, Args...>>(),
futureInterface, std::forward<Function>(function), std::forward<Args>(args)...);
}
// function, function pointer, or other callable object that is no member pointer
template <typename ResultType, typename Function, typename... Args,
typename = std::enable_if_t<!std::is_member_pointer<std::decay_t<Function>>::value>
>
void runAsyncMemberDispatch(QFutureInterface<ResultType> &futureInterface, Function &&function, Args&&... args)
{
runAsyncQFutureInterfaceDispatch(functionTakesArgument<Function, 0, QFutureInterface<ResultType>&>(),
futureInterface, std::forward<Function>(function), std::forward<Args>(args)...);
}
// Function = member function
template <typename ResultType, typename Function, typename Obj, typename... Args,
typename = std::enable_if_t<std::is_member_pointer<std::decay_t<Function>>::value>
>
void runAsyncMemberDispatch(QFutureInterface<ResultType> &futureInterface, Function &&function, Obj &&obj, Args&&... args)
{
// Wrap member function with object into callable
runAsyncImpl(futureInterface,
MemberCallable<std::decay_t<Function>>(std::forward<Function>(function), std::forward<Obj>(obj)),
std::forward<Args>(args)...);
}
// cref to function/callable
template <typename ResultType, typename Function, typename... Args>
void runAsyncImpl(QFutureInterface<ResultType> &futureInterface,
std::reference_wrapper<Function> functionWrapper, Args&&... args)
{
runAsyncMemberDispatch(futureInterface, functionWrapper.get(), std::forward<Args>(args)...);
}
// function/callable, no cref
template <typename ResultType, typename Function, typename... Args>
void runAsyncImpl(QFutureInterface<ResultType> &futureInterface,
Function &&function, Args&&... args)
{
runAsyncMemberDispatch(futureInterface, std::forward<Function>(function),
std::forward<Args>(args)...);
}
/*
AsyncJob is a QRunnable that wraps a function with the
arguments that are passed to it when it is run in a thread.
*/
template <class T>
std::decay_t<T>
decayCopy(T&& v)
{
return std::forward<T>(v);
}
template <typename ResultType, typename Function, typename... Args>
class AsyncJob : public QRunnable
{
public:
AsyncJob(Function &&function, Args&&... args)
// decay copy like std::thread
: data(decayCopy(std::forward<Function>(function)), decayCopy(std::forward<Args>(args))...)
{
// we need to report it as started even though it isn't yet, because someone might
// call waitForFinished on the future, which does _not_ block if the future is not started
futureInterface.setRunnable(this);
futureInterface.reportStarted();
}
~AsyncJob() override
{
// QThreadPool can delete runnables even if they were never run (e.g. QThreadPool::clear).
// Since we reported them as started, we make sure that we always report them as finished.
// reportFinished only actually sends the signal if it wasn't already finished.
futureInterface.reportFinished();
}
QFuture<ResultType> future() { return futureInterface.future(); }
void run() override
{
if (priority != QThread::InheritPriority)
if (QThread *thread = QThread::currentThread())
if (thread != qApp->thread())
thread->setPriority(priority);
if (futureInterface.isCanceled()) {
futureInterface.reportFinished();
return;
}
runHelper(std::make_index_sequence<std::tuple_size<Data>::value>());
}
void setThreadPool(QThreadPool *pool)
{
futureInterface.setThreadPool(pool);
}
void setThreadPriority(QThread::Priority p)
{
priority = p;
}
private:
using Data = std::tuple<std::decay_t<Function>, std::decay_t<Args>...>;
template <std::size_t... index>
void runHelper(std::index_sequence<index...>)
{
// invalidates data, which is moved into the call
runAsyncImpl(futureInterface, std::move(std::get<index>(data))...);
if (futureInterface.isPaused())
futureInterface.waitForResume();
futureInterface.reportFinished();
}
Data data;
QFutureInterface<ResultType> futureInterface;
QThread::Priority priority = QThread::InheritPriority;
};
class QTCREATOR_UTILS_EXPORT RunnableThread : public QThread
{
public:
explicit RunnableThread(QRunnable *runnable, QObject *parent = nullptr);
protected:
void run() override;
private:
QRunnable *m_runnable;
};
template<typename Function,
typename... Args,
typename ResultType = typename Internal::resultType<Function>::type>
QFuture<ResultType> runAsync_internal(QThreadPool *pool,
QThread::Priority priority,
Function &&function,
Args &&... args)
{
auto job = new Internal::AsyncJob<ResultType,Function,Args...>
(std::forward<Function>(function), std::forward<Args>(args)...);
job->setThreadPriority(priority);
QFuture<ResultType> future = job->future();
if (pool) {
job->setThreadPool(pool);
pool->start(job);
} else {
auto thread = new Internal::RunnableThread(job);
thread->moveToThread(qApp->thread()); // make sure thread gets deleteLater on main thread
QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater);
thread->start(priority);
}
return future;
}
} // Internal
/*!
The interface of \c {runAsync} is similar to the std::thread constructor and \c {std::invoke}.
The \a function argument can be a member function,
an object with \c {operator()} (with no overloads),
a \c {std::function}, lambda, function pointer or function reference.
The \a args are passed to the function call after they are copied/moved to the thread.
The \a function can take a \c {QFutureInterface<ResultType>&} as its first argument, followed by
other custom arguments which need to be passed to this function.
If it does not take a \c {QFutureInterface<ResultType>&} as its first argument
and its return type is not void, the function call's result is reported to the QFuture.
If \a function is a (non-static) member function, the first argument in \a args is expected
to be the object that the function is called on.
If a thread \a pool is given, the function is run there. Otherwise a new, independent thread
is started.
\sa std::thread
\sa std::invoke
\sa QThreadPool
\sa QThread::Priority
*/
template <typename Function, typename... Args,
typename ResultType = typename Internal::resultType<Function>::type>
QFuture<ResultType>
runAsync(QThreadPool *pool, QThread::Priority priority, Function &&function, Args&&... args)
{
return Internal::runAsync_internal(pool,
priority,
std::forward<Function>(function),
std::forward<Args>(args)...);
}
/*!
Runs \a function with \a args in a new thread with given thread \a priority.
\sa runAsync(QThreadPool*,QThread::Priority,Function&&,Args&&...)
\sa QThread::Priority
*/
template <typename Function, typename... Args,
typename ResultType = typename Internal::resultType<Function>::type>
QFuture<ResultType>
runAsync(QThread::Priority priority, Function &&function, Args&&... args)
{
return runAsync(static_cast<QThreadPool *>(nullptr), priority,
std::forward<Function>(function), std::forward<Args>(args)...);
}
/*!
Runs \a function with \a args in a new thread with thread priority QThread::InheritPriority.
\sa runAsync(QThreadPool*,QThread::Priority,Function&&,Args&&...)
\sa QThread::Priority
*/
template <typename Function, typename... Args,
typename = std::enable_if_t<
!std::is_same<std::decay_t<Function>, QThreadPool>::value
&& !std::is_same<std::decay_t<Function>, QThread::Priority>::value
>,
typename ResultType = typename Internal::resultType<Function>::type>
QFuture<ResultType>
runAsync(Function &&function, Args&&... args)
{
return runAsync(static_cast<QThreadPool *>(nullptr),
QThread::InheritPriority, std::forward<Function>(function),
std::forward<Args>(args)...);
}
/*!
Runs \a function with \a args in a thread \a pool with thread priority QThread::InheritPriority.
\sa runAsync(QThreadPool*,QThread::Priority,Function&&,Args&&...)
\sa QThread::Priority
*/
template <typename Function, typename... Args,
typename = std::enable_if_t<!std::is_same<std::decay_t<Function>, QThread::Priority>::value>,
typename ResultType = typename Internal::resultType<Function>::type>
QFuture<ResultType>
runAsync(QThreadPool *pool, Function &&function, Args&&... args)
{
return runAsync(pool, QThread::InheritPriority, std::forward<Function>(function),
std::forward<Args>(args)...);
}
} // namespace Utils

View File

@@ -40,7 +40,6 @@ Project {
Depends { name: "ptyqt" }
files: [
"QtConcurrentTools",
"algorithm.h",
"ansiescapecodehandler.cpp",
"ansiescapecodehandler.h",
@@ -147,7 +146,6 @@ Project {
"fixedsizeclicklabel.h",
"flowlayout.cpp",
"flowlayout.h",
"functiontraits.h",
"futuresynchronizer.cpp",
"futuresynchronizer.h",
"fuzzymatcher.cpp",
@@ -193,7 +191,6 @@ Project {
"listutils.h",
"macroexpander.cpp",
"macroexpander.h",
"mapreduce.h",
"mathutils.cpp",
"mathutils.h",
"mimeutils.h",
@@ -270,8 +267,6 @@ Project {
"reloadpromptutils.h",
"removefiledialog.cpp",
"removefiledialog.h",
"runextensions.cpp",
"runextensions.h",
"savefile.cpp",
"savefile.h",
"scopedswap.h",

View File

@@ -39,7 +39,7 @@
\c init() is called in the GUI thread and can be used to query the
project for any information you need.
\c run() is run via Utils::runAsync in a separate thread. If you need an
\c run() is run via Utils::asyncRun in a separate thread. If you need an
event loop, you need to create it yourself.
*/

View File

@@ -28,7 +28,6 @@
#include <texteditor/tabsettings.h>
#include <texteditor/texteditorsettings.h>
#include <utils/QtConcurrentTools>
#include <utils/algorithm.h>
#include <utils/async.h>
#include <utils/filesystemwatcher.h>

View File

@@ -13,11 +13,9 @@ add_subdirectory(filesearch)
add_subdirectory(haskell)
add_subdirectory(json)
add_subdirectory(languageserverprotocol)
add_subdirectory(mapreduce)
add_subdirectory(pointeralgorithm)
add_subdirectory(profilewriter)
add_subdirectory(qml)
add_subdirectory(runextensions)
add_subdirectory(sdktool)
add_subdirectory(solutions)
add_subdirectory(texteditor)

View File

@@ -20,7 +20,6 @@ Project {
"languageserverprotocol/languageserverprotocol.qbs",
"profilewriter/profilewriter.qbs",
"qml/qml.qbs",
"runextensions/runextensions.qbs",
"sdktool/sdktool.qbs",
"solutions/solutions.qbs",
"texteditor/texteditor.qbs",

View File

@@ -1,4 +0,0 @@
add_qtc_test(tst_mapreduce
DEPENDS Utils
SOURCES tst_mapreduce.cpp
)

View File

@@ -1,10 +0,0 @@
import qbs
QtcAutotest {
name: "Map reduce autotest"
Depends { name: "Utils" }
files: [
"tst_mapreduce.cpp",
]
}

View File

@@ -1,345 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <utils/algorithm.h>
#include <utils/mapreduce.h>
#include <QThreadPool>
#include <QtTest>
#if !defined(Q_CC_MSVC) || _MSC_VER >= 1900 // MSVC2015
#define SUPPORTS_MOVE
#endif
class tst_MapReduce : public QObject
{
Q_OBJECT
private slots:
void mapReduce();
void mapReduceRvalueContainer();
void map();
void orderedMapReduce();
#ifdef SUPPORTS_MOVE
void moveOnlyType();
#endif
};
static int returnxx(int x)
{
return x*x;
}
static void returnxxThroughFutureInterface(QFutureInterface<int> &fi, int x)
{
fi.reportResult(x*x);
}
void tst_MapReduce::mapReduce()
{
QThreadPool pool;
const auto initWithFutureInterface = [](QFutureInterface<double> &fi) -> double {
fi.reportResult(0.);
return 0.;
};
const auto reduceWithFutureInterface = [](QFutureInterface<double> &fi, double &state, int value) {
state += value;
fi.reportResult(value);
};
const auto reduceWithReturn = [](double &state, int value) -> double {
state += value;
return value;
};
const auto cleanupWithFutureInterface = [](QFutureInterface<double> &fi, double &state) {
state /= 2.;
fi.reportResult(state);
};
{
// map without future interface
QList<double> results = Utils::mapReduce(QVector<int>({1, 2, 3, 4, 5}),
initWithFutureInterface,
returnxx,
reduceWithFutureInterface,
cleanupWithFutureInterface)
.results();
Utils::sort(results); // mapping order is undefined
QCOMPARE(results, QList<double>({0., 1., 4., 9., 16., 25., 27.5}));
}
{
// map with future interface
QList<double> results = Utils::mapReduce(QList<int>({1, 2, 3, 4, 5}),
initWithFutureInterface, returnxxThroughFutureInterface,
reduceWithFutureInterface, cleanupWithFutureInterface)
.results();
Utils::sort(results); // mapping order is undefined
QCOMPARE(results, QList<double>({0., 1., 4., 9., 16., 25., 27.5}));
}
{
// reduce without future interface
QList<double> results = Utils::mapReduce(QList<int>({1, 2, 3, 4, 5}),
initWithFutureInterface, returnxx,
reduceWithReturn, cleanupWithFutureInterface)
.results();
Utils::sort(results); // mapping order is undefined
QCOMPARE(results, QList<double>({0., 1., 4., 9., 16., 25., 27.5}));
}
{
// reduce with threadpool
QList<double> results = Utils::mapReduce(QList<int>({1, 2, 3, 4, 5}),
initWithFutureInterface, returnxx,
reduceWithReturn, cleanupWithFutureInterface,
Utils::MapReduceOption::Unordered, &pool)
.results();
Utils::sort(results); // mapping order is undefined
QCOMPARE(results, QList<double>({0., 1., 4., 9., 16., 25., 27.5}));
}
{
// lvalue ref container
QList<int> container({1, 2, 3, 4, 5});
QList<double> results = Utils::mapReduce(container,
initWithFutureInterface, returnxx,
reduceWithReturn, cleanupWithFutureInterface)
.results();
Utils::sort(results); // mapping order is undefined
QCOMPARE(results, QList<double>({0., 1., 4., 9., 16., 25., 27.5}));
}
{
// std::cref
QList<int> container({1, 2, 3, 4, 5});
QCOMPARE(Utils::mapReduce(std::cref(container),
initWithFutureInterface, returnxx,
reduceWithReturn, cleanupWithFutureInterface,
Utils::MapReduceOption::Ordered).results(),
QList<double>({0., 1., 4., 9., 16., 25., 27.5}));
}
{
// std::cref with threadpool
QList<int> container({1, 2, 3, 4, 5});
QCOMPARE(Utils::mapReduce(std::cref(container),
initWithFutureInterface, returnxx,
reduceWithReturn, cleanupWithFutureInterface,
Utils::MapReduceOption::Ordered, &pool).results(),
QList<double>({0., 1., 4., 9., 16., 25., 27.5}));
}
{
// std::ref
QList<int> container({1, 2, 3, 4, 5});
QCOMPARE(Utils::mapReduce(std::ref(container),
initWithFutureInterface, returnxx,
reduceWithReturn, cleanupWithFutureInterface,
Utils::MapReduceOption::Ordered).results(),
QList<double>({0., 1., 4., 9., 16., 25., 27.5}));
}
{
// init and cleanup without future interface
QCOMPARE(Utils::mapReduce(QList<int>({1, 2, 3}),
[]() { return 0.; },
[](int v) { return v*2; },
[](double &state, int v) { return state += v/4.; },
[](double &) { },
Utils::MapReduceOption::Ordered).results(),
QList<double>({.5, 1.5, 3.}));
}
{
// simplified map reduce without init and cleanup
QCOMPARE(Utils::mapReduce(QList<QString>({QLatin1String("blubb"), QLatin1String("foo"), QLatin1String("blah")}),
[](const QString &val) { return val.size(); },
90.,
[](double &state, int val) {
state /= double(val);
},
Utils::MapReduceOption::Ordered).result(),
1.5);
}
{
// simplified map reduce without init and cleanup with threadpool
QCOMPARE(Utils::mapReduce(QList<QString>({QLatin1String("blubb"), QLatin1String("foo"), QLatin1String("blah")}),
[](const QString &val) { return val.size(); },
90.,
[](double &state, int val) {
state /= double(val);
},
Utils::MapReduceOption::Ordered, &pool).result(),
1.5);
}
{
// simplified map reduce
// std::cref
QList<int> container({1, 2, 3});
QCOMPARE(Utils::mapReduce(std::cref(container), [](int val) { return 2*val; }, 10,
[](int &state, int val) { state += val; }).result(),
22);
}
{
// simplified map reduce
// std::cref with threadpool
QList<int> container({1, 2, 3});
QCOMPARE(Utils::mapReduce(std::cref(container), [](int val) { return 2*val; }, 10,
[](int &state, int val) { state += val; },
Utils::MapReduceOption::Unordered, &pool).result(),
22);
}
{
// simplified map reduce
// std::ref
QList<int> container({1, 2, 3});
QCOMPARE(Utils::mapReduce(std::ref(container), [](int &val) { return 2*val; }, 10,
[](int &state, int val) { state += val; }).result(),
22);
}
{
// blocking mapReduce = mappedReduced
QCOMPARE(Utils::mappedReduced(QList<int>({1, 2, 3}), [](int &val) { return 2*val; }, 10,
[](int &state, int val) { state += val; }),
22);
}
{
// blocking mapReduce = mappedReduced
// with threadpool
QCOMPARE(Utils::mappedReduced(QList<int>({1, 2, 3}), [](int &val) { return 2*val; }, 10,
[](int &state, int val) { state += val; },
Utils::MapReduceOption::Unordered, &pool),
22);
}
}
void tst_MapReduce::mapReduceRvalueContainer()
{
{
QFuture<int> future = Utils::mapReduce(QList<int>({1, 2, 3, 4, 5}),
[]() { return 0; },
[](int value) { return value; },
[](QFutureInterface<int> &, int &state, int value) { state += value; },
[](QFutureInterface<int> &fi, int &state) { fi.reportResult(state); });
// here, lifetime of the QList temporary ends
QCOMPARE(future.results(), QList<int>({15}));
}
}
void tst_MapReduce::map()
{
QCOMPARE(Utils::map(QList<int>({2, 5, 1}), [](int x) { return x*2.5; }).results(),
QList<double>({5., 12.5, 2.5}));
{
// void result
QList<int> results;
QMutex mutex;
Utils::map(
// container
QList<int>({2, 5, 1}),
// map
[&mutex, &results](int x) { QMutexLocker l(&mutex); results.append(x); }
).waitForFinished();
// Utils::map is "ordered" by default, but that means that result reporting is ordered,
// the map function is still called out-of-order
Utils::sort(results);
QCOMPARE(results, QList<int>({1, 2, 5}));
}
{
// inplace editing
QList<int> container({2, 5, 1});
Utils::map(std::ref(container), [](int &x) { x *= 2; }).waitForFinished();
QCOMPARE(container, QList<int>({4, 10, 2}));
Utils::map(container.begin(), container.end(), [](int &x) { x *= 2; },
Utils::MapReduceOption::Unordered,
nullptr, QThread::InheritPriority, 3).waitForFinished();
QCOMPARE(container, QList<int>({8, 20, 4}));
}
// blocking map = mapped
{
const QSet<qsizetype> sizes = Utils::mapped<QSet>(
QStringList({QLatin1String("foo"), QLatin1String("bar"), QLatin1String("blah")}),
[](const QString &s) { return s.size(); });
QList<qsizetype> vals = sizes.values();
Utils::sort(vals);
QCOMPARE(vals, QList<qsizetype>({3, 4}));
}
{
const QStringList list({QLatin1String("foo"), QLatin1String("bar"), QLatin1String("blah")});
const QSet<qsizetype> sizes = Utils::mapped<QSet>(list.cbegin(),
list.cend(),
[](const QString &s) {
return s.size();
});
QList<qsizetype> vals = sizes.values();
Utils::sort(vals);
QCOMPARE(vals, QList<qsizetype>({3, 4}));
}
}
void tst_MapReduce::orderedMapReduce()
{
QCOMPARE(Utils::mapReduce(QList<int>({1, 2, 3, 4}),
[]() { return 0; },
[](int i) { return i*2; },
[](int &state, int val) { state += val; return state; },
[](int &) { },
Utils::MapReduceOption::Ordered).results(),
QList<int>({2, 6, 12, 20}));
}
#ifdef SUPPORTS_MOVE
class MoveOnlyType
{
public:
MoveOnlyType() noexcept {} // <- with GCC 5 the defaulted one is noexcept(false)
MoveOnlyType(const MoveOnlyType &) = delete;
MoveOnlyType(MoveOnlyType &&) = default;
MoveOnlyType &operator=(const MoveOnlyType &) = delete;
MoveOnlyType &operator=(MoveOnlyType &&) = default;
};
class MoveOnlyState : public MoveOnlyType
{
public:
int count = 0;
};
class MoveOnlyInit : public MoveOnlyType
{
public:
MoveOnlyState operator()(QFutureInterface<int> &) const { return MoveOnlyState(); }
};
class MoveOnlyMap : public MoveOnlyType
{
public:
int operator()(const MoveOnlyType &) const { return 1; }
};
class MoveOnlyReduce : public MoveOnlyType
{
public:
void operator()(QFutureInterface<int> &, MoveOnlyState &state, int) { ++state.count; }
};
class MoveOnlyList : public std::vector<MoveOnlyType>
{
public:
MoveOnlyList() { emplace_back(MoveOnlyType()); emplace_back(MoveOnlyType()); }
MoveOnlyList(const MoveOnlyList &) = delete;
MoveOnlyList(MoveOnlyList &&) = default;
MoveOnlyList &operator=(const MoveOnlyList &) = delete;
MoveOnlyList &operator=(MoveOnlyList &&) = default;
};
void tst_MapReduce::moveOnlyType()
{
QCOMPARE(Utils::mapReduce(MoveOnlyList(),
MoveOnlyInit(),
MoveOnlyMap(),
MoveOnlyReduce(),
[](QFutureInterface<int> &fi, MoveOnlyState &state) { fi.reportResult(state.count); }
).results(),
QList<int>({2}));
}
#endif
QTEST_GUILESS_MAIN(tst_MapReduce)
#include "tst_mapreduce.moc"

View File

@@ -1,4 +0,0 @@
add_qtc_test(tst_runextensions
DEPENDS Utils
SOURCES tst_runextensions.cpp
)

View File

@@ -1,10 +0,0 @@
import qbs
QtcAutotest {
name: "Run extensions autotest"
Depends { name: "Utils" }
files: [
"tst_runextensions.cpp",
]
}

View File

@@ -1,540 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <utils/runextensions.h>
#include <QtTest>
#if !defined(Q_CC_MSVC) || _MSC_VER >= 1900 // MSVC2015
#define SUPPORTS_MOVE
#endif
class tst_RunExtensions : public QObject
{
Q_OBJECT
private slots:
void runAsync();
void runInThreadPool();
#ifdef SUPPORTS_MOVE
void moveOnlyType();
#endif
void threadPriority();
void runAsyncNoFutureInterface();
void crefFunction();
};
void report3(QFutureInterface<int> &fi)
{
fi.reportResults({0, 2, 1});
}
void reportN(QFutureInterface<double> &fi, int n)
{
fi.reportResults(QVector<double>(n, 0));
}
void reportString1(QFutureInterface<QString> &fi, const QString &s)
{
fi.reportResult(s);
}
void reportString2(QFutureInterface<QString> &fi, QString s)
{
fi.reportResult(s);
}
class Callable {
public:
void operator()(QFutureInterface<double> &fi, int n) const
{
fi.reportResults(QVector<double>(n, 0));
}
};
class MyObject {
public:
static void staticMember0(QFutureInterface<double> &fi)
{
fi.reportResults({0, 2, 1});
}
static void staticMember1(QFutureInterface<double> &fi, int n)
{
fi.reportResults(QVector<double>(n, 0));
}
void member0(QFutureInterface<double> &fi) const
{
fi.reportResults({0, 2, 1});
}
void member1(QFutureInterface<double> &fi, int n) const
{
fi.reportResults(QVector<double>(n, 0));
}
void memberString1(QFutureInterface<QString> &fi, const QString &s) const
{
fi.reportResult(s);
}
void memberString2(QFutureInterface<QString> &fi, QString s) const
{
fi.reportResult(s);
}
void nonConstMember(QFutureInterface<double> &fi)
{
fi.reportResults({0, 2, 1});
}
};
void voidFunction(bool *value) // can be useful to get QFuture for watching when it is finished
{
*value = true;
}
int one()
{
return 1;
}
int identity(int input)
{
return input;
}
QString stringIdentity1(const QString &s)
{
return s;
}
QString stringIdentity2(QString s)
{
return s;
}
class CallableWithoutQFutureInterface {
public:
void operator()(bool *value) const
{
*value = true;
}
};
class MyObjectWithoutQFutureInterface {
public:
static void staticMember0(bool *value)
{
*value = true;
}
static double staticMember1(int n)
{
return n;
}
void member0(bool *value) const
{
*value = true;
}
double member1(int n) const
{
return n;
}
QString memberString1(const QString &s) const
{
return s;
}
QString memberString2(QString s) const
{
return s;
}
double nonConstMember(int n)
{
return n;
}
};
void tst_RunExtensions::runAsync()
{
// free function pointer
QCOMPARE(Utils::runAsync(&report3).results(),
QList<int>({0, 2, 1}));
QCOMPARE(Utils::runAsync(report3).results(),
QList<int>({0, 2, 1}));
QCOMPARE(Utils::runAsync(reportN, 4).results(),
QList<double>({0, 0, 0, 0}));
QCOMPARE(Utils::runAsync(reportN, 2).results(),
QList<double>({0, 0}));
QString s = QLatin1String("string");
const QString &crs = QLatin1String("cr string");
const QString cs = QLatin1String("c string");
QCOMPARE(Utils::runAsync(reportString1, s).results(),
QList<QString>({s}));
QCOMPARE(Utils::runAsync(reportString1, crs).results(),
QList<QString>({crs}));
QCOMPARE(Utils::runAsync(reportString1, cs).results(),
QList<QString>({cs}));
QCOMPARE(Utils::runAsync(reportString1, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))}));
QCOMPARE(Utils::runAsync(reportString2, s).results(),
QList<QString>({s}));
QCOMPARE(Utils::runAsync(reportString2, crs).results(),
QList<QString>({crs}));
QCOMPARE(Utils::runAsync(reportString2, cs).results(),
QList<QString>({cs}));
QCOMPARE(Utils::runAsync(reportString2, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))}));
// lambda
QCOMPARE(Utils::runAsync([](QFutureInterface<double> &fi, int n) {
fi.reportResults(QVector<double>(n, 0));
}, 3).results(),
QList<double>({0, 0, 0}));
// std::function
const std::function<void(QFutureInterface<double>&,int)> fun = [](QFutureInterface<double> &fi, int n) {
fi.reportResults(QVector<double>(n, 0));
};
QCOMPARE(Utils::runAsync(fun, 2).results(),
QList<double>({0, 0}));
// operator()
QCOMPARE(Utils::runAsync(Callable(), 3).results(),
QList<double>({0, 0, 0}));
const Callable c{};
QCOMPARE(Utils::runAsync(c, 2).results(),
QList<double>({0, 0}));
// static member functions
QCOMPARE(Utils::runAsync(&MyObject::staticMember0).results(),
QList<double>({0, 2, 1}));
QCOMPARE(Utils::runAsync(&MyObject::staticMember1, 2).results(),
QList<double>({0, 0}));
// member functions
const MyObject obj{};
QCOMPARE(Utils::runAsync(&MyObject::member0, &obj).results(),
QList<double>({0, 2, 1}));
QCOMPARE(Utils::runAsync(&MyObject::member1, &obj, 4).results(),
QList<double>({0, 0, 0, 0}));
QCOMPARE(Utils::runAsync(&MyObject::memberString1, &obj, s).results(),
QList<QString>({s}));
QCOMPARE(Utils::runAsync(&MyObject::memberString1, &obj, crs).results(),
QList<QString>({crs}));
QCOMPARE(Utils::runAsync(&MyObject::memberString1, &obj, cs).results(),
QList<QString>({cs}));
QCOMPARE(Utils::runAsync(&MyObject::memberString1, &obj, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))}));
QCOMPARE(Utils::runAsync(&MyObject::memberString2, &obj, s).results(),
QList<QString>({s}));
QCOMPARE(Utils::runAsync(&MyObject::memberString2, &obj, crs).results(),
QList<QString>({crs}));
QCOMPARE(Utils::runAsync(&MyObject::memberString2, &obj, cs).results(),
QList<QString>({cs}));
QCOMPARE(Utils::runAsync(&MyObject::memberString2, &obj, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))}));
MyObject nonConstObj{};
QCOMPARE(Utils::runAsync(&MyObject::nonConstMember, &nonConstObj).results(),
QList<double>({0, 2, 1}));
}
void tst_RunExtensions::runInThreadPool()
{
QScopedPointer<QThreadPool> pool(new QThreadPool);
// free function pointer
QCOMPARE(Utils::runAsync(pool.data(), &report3).results(),
QList<int>({0, 2, 1}));
QCOMPARE(Utils::runAsync(pool.data(), report3).results(),
QList<int>({0, 2, 1}));
QCOMPARE(Utils::runAsync(pool.data(), reportN, 4).results(),
QList<double>({0, 0, 0, 0}));
QCOMPARE(Utils::runAsync(pool.data(), reportN, 2).results(),
QList<double>({0, 0}));
QString s = QLatin1String("string");
const QString &crs = QLatin1String("cr string");
const QString cs = QLatin1String("c string");
QCOMPARE(Utils::runAsync(pool.data(), reportString1, s).results(),
QList<QString>({s}));
QCOMPARE(Utils::runAsync(pool.data(), reportString1, crs).results(),
QList<QString>({crs}));
QCOMPARE(Utils::runAsync(pool.data(), reportString1, cs).results(),
QList<QString>({cs}));
QCOMPARE(Utils::runAsync(pool.data(), reportString1, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))}));
QCOMPARE(Utils::runAsync(pool.data(), reportString2, s).results(),
QList<QString>({s}));
QCOMPARE(Utils::runAsync(pool.data(), reportString2, crs).results(),
QList<QString>({crs}));
QCOMPARE(Utils::runAsync(pool.data(), reportString2, cs).results(),
QList<QString>({cs}));
QCOMPARE(Utils::runAsync(pool.data(), reportString2, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))}));
// lambda
QCOMPARE(Utils::runAsync(pool.data(), [](QFutureInterface<double> &fi, int n) {
fi.reportResults(QVector<double>(n, 0));
}, 3).results(),
QList<double>({0, 0, 0}));
// std::function
const std::function<void(QFutureInterface<double>&,int)> fun = [](QFutureInterface<double> &fi, int n) {
fi.reportResults(QVector<double>(n, 0));
};
QCOMPARE(Utils::runAsync(pool.data(), fun, 2).results(),
QList<double>({0, 0}));
// operator()
QCOMPARE(Utils::runAsync(pool.data(), Callable(), 3).results(),
QList<double>({0, 0, 0}));
const Callable c{};
QCOMPARE(Utils::runAsync(pool.data(), c, 2).results(),
QList<double>({0, 0}));
// static member functions
QCOMPARE(Utils::runAsync(pool.data(), &MyObject::staticMember0).results(),
QList<double>({0, 2, 1}));
QCOMPARE(Utils::runAsync(pool.data(), &MyObject::staticMember1, 2).results(),
QList<double>({0, 0}));
// member functions
const MyObject obj{};
QCOMPARE(Utils::runAsync(pool.data(), &MyObject::member0, &obj).results(),
QList<double>({0, 2, 1}));
QCOMPARE(Utils::runAsync(pool.data(), &MyObject::member1, &obj, 4).results(),
QList<double>({0, 0, 0, 0}));
QCOMPARE(Utils::runAsync(pool.data(), &MyObject::memberString1, &obj, s).results(),
QList<QString>({s}));
QCOMPARE(Utils::runAsync(pool.data(), &MyObject::memberString1, &obj, crs).results(),
QList<QString>({crs}));
QCOMPARE(Utils::runAsync(pool.data(), &MyObject::memberString1, &obj, cs).results(),
QList<QString>({cs}));
QCOMPARE(Utils::runAsync(pool.data(), &MyObject::memberString1, &obj, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))}));
QCOMPARE(Utils::runAsync(pool.data(), &MyObject::memberString2, &obj, s).results(),
QList<QString>({s}));
QCOMPARE(Utils::runAsync(pool.data(), &MyObject::memberString2, &obj, crs).results(),
QList<QString>({crs}));
QCOMPARE(Utils::runAsync(pool.data(), &MyObject::memberString2, &obj, cs).results(),
QList<QString>({cs}));
QCOMPARE(Utils::runAsync(pool.data(), &MyObject::memberString2, &obj, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))}));
}
#ifdef SUPPORTS_MOVE
class MoveOnlyType
{
public:
MoveOnlyType() = default;
MoveOnlyType(const MoveOnlyType &) = delete;
MoveOnlyType(MoveOnlyType &&) = default;
MoveOnlyType &operator=(const MoveOnlyType &) = delete;
MoveOnlyType &operator=(MoveOnlyType &&) = default;
};
class MoveOnlyCallable : public MoveOnlyType
{
public:
void operator()(QFutureInterface<int> &fi, const MoveOnlyType &)
{
fi.reportResult(1);
}
};
void tst_RunExtensions::moveOnlyType()
{
QCOMPARE(Utils::runAsync(MoveOnlyCallable(), MoveOnlyType()).results(),
QList<int>({1}));
}
#endif
void tst_RunExtensions::threadPriority()
{
QScopedPointer<QThreadPool> pool(new QThreadPool);
// with pool
QCOMPARE(Utils::runAsync(pool.data(), QThread::LowestPriority, &report3).results(),
QList<int>({0, 2, 1}));
// without pool
QCOMPARE(Utils::runAsync(QThread::LowestPriority, report3).results(),
QList<int>({0, 2, 1}));
}
void tst_RunExtensions::runAsyncNoFutureInterface()
{
// free function pointer
bool value = false;
Utils::runAsync(voidFunction, &value).waitForFinished();
QCOMPARE(value, true);
QCOMPARE(Utils::runAsync(one).results(),
QList<int>({1}));
QCOMPARE(Utils::runAsync(identity, 5).results(),
QList<int>({5}));
QString s = QLatin1String("string");
const QString &crs = QLatin1String("cr string");
const QString cs = QLatin1String("c string");
QCOMPARE(Utils::runAsync(stringIdentity1, s).results(),
QList<QString>({s}));
QCOMPARE(Utils::runAsync(stringIdentity1, crs).results(),
QList<QString>({crs}));
QCOMPARE(Utils::runAsync(stringIdentity1, cs).results(),
QList<QString>({cs}));
QCOMPARE(Utils::runAsync(stringIdentity1, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))}));
QCOMPARE(Utils::runAsync(stringIdentity2, s).results(),
QList<QString>({s}));
QCOMPARE(Utils::runAsync(stringIdentity2, crs).results(),
QList<QString>({crs}));
QCOMPARE(Utils::runAsync(stringIdentity2, cs).results(),
QList<QString>({cs}));
QCOMPARE(Utils::runAsync(stringIdentity2, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))}));
// lambda
QCOMPARE(Utils::runAsync([](int n) -> double {
return n + 1;
}, 3).results(),
QList<double>({4}));
// std::function
const std::function<double(int)> fun = [](int n) {
return n + 1;
};
QCOMPARE(Utils::runAsync(fun, 2).results(),
QList<double>({3}));
// operator()
value = false;
Utils::runAsync(CallableWithoutQFutureInterface(), &value).waitForFinished();
QCOMPARE(value, true);
value = false;
const CallableWithoutQFutureInterface c{};
Utils::runAsync(c, &value).waitForFinished();
QCOMPARE(value, true);
// static member functions
value = false;
Utils::runAsync(&MyObjectWithoutQFutureInterface::staticMember0, &value).waitForFinished();
QCOMPARE(value, true);
QCOMPARE(Utils::runAsync(&MyObjectWithoutQFutureInterface::staticMember1, 2).results(),
QList<double>({2}));
// member functions
const MyObjectWithoutQFutureInterface obj{};
value = false;
Utils::runAsync(&MyObjectWithoutQFutureInterface::member0, &obj, &value).waitForFinished();
QCOMPARE(value, true);
QCOMPARE(Utils::runAsync(&MyObjectWithoutQFutureInterface::member1, &obj, 4).results(),
QList<double>({4}));
QCOMPARE(Utils::runAsync(&MyObjectWithoutQFutureInterface::memberString1, &obj, s).results(),
QList<QString>({s}));
QCOMPARE(Utils::runAsync(&MyObjectWithoutQFutureInterface::memberString1, &obj, crs).results(),
QList<QString>({crs}));
QCOMPARE(Utils::runAsync(&MyObjectWithoutQFutureInterface::memberString1, &obj, cs).results(),
QList<QString>({cs}));
QCOMPARE(Utils::runAsync(&MyObjectWithoutQFutureInterface::memberString1, &obj, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))}));
QCOMPARE(Utils::runAsync(&MyObjectWithoutQFutureInterface::memberString2, &obj, s).results(),
QList<QString>({s}));
QCOMPARE(Utils::runAsync(&MyObjectWithoutQFutureInterface::memberString2, &obj, crs).results(),
QList<QString>({crs}));
QCOMPARE(Utils::runAsync(&MyObjectWithoutQFutureInterface::memberString2, &obj, cs).results(),
QList<QString>({cs}));
QCOMPARE(Utils::runAsync(&MyObjectWithoutQFutureInterface::memberString2, &obj, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))}));
MyObjectWithoutQFutureInterface nonConstObj{};
QCOMPARE(Utils::runAsync(&MyObjectWithoutQFutureInterface::nonConstMember, &nonConstObj, 4).results(),
QList<double>({4}));
}
void tst_RunExtensions::crefFunction()
{
// free function pointer with future interface
auto fun = &report3;
QCOMPARE(Utils::runAsync(std::cref(fun)).results(),
QList<int>({0, 2, 1}));
// lambda with future interface
auto lambda = [](QFutureInterface<double> &fi, int n) {
fi.reportResults(QVector<double>(n, 0));
};
QCOMPARE(Utils::runAsync(std::cref(lambda), 3).results(),
QList<double>({0, 0, 0}));
// std::function with future interface
const std::function<void(QFutureInterface<double>&,int)> funObj = [](QFutureInterface<double> &fi, int n) {
fi.reportResults(QVector<double>(n, 0));
};
QCOMPARE(Utils::runAsync(std::cref(funObj), 2).results(),
QList<double>({0, 0}));
// callable with future interface
const Callable c{};
QCOMPARE(Utils::runAsync(std::cref(c), 2).results(),
QList<double>({0, 0}));
// member functions with future interface
auto member = &MyObject::member0;
const MyObject obj{};
QCOMPARE(Utils::runAsync(std::cref(member), &obj).results(),
QList<double>({0, 2, 1}));
// free function pointer without future interface
bool value = false;
auto voidFun = &voidFunction;
Utils::runAsync(std::cref(voidFun), &value).waitForFinished();
QCOMPARE(value, true);
auto oneFun = &one;
QCOMPARE(Utils::runAsync(std::cref(oneFun)).results(),
QList<int>({1}));
// lambda without future interface
auto lambda2 = [](int n) -> double {
return n + 1;
};
QCOMPARE(Utils::runAsync(std::cref(lambda2), 3).results(),
QList<double>({4}));
// std::function
const std::function<double(int)> funObj2 = [](int n) {
return n + 1;
};
QCOMPARE(Utils::runAsync(std::cref(funObj2), 2).results(),
QList<double>({3}));
// callable without future interface
const CallableWithoutQFutureInterface c2{};
Utils::runAsync(std::cref(c2), &value).waitForFinished();
QCOMPARE(value, true);
// member functions without future interface
const MyObjectWithoutQFutureInterface obj2{};
auto member2 = &MyObjectWithoutQFutureInterface::member0;
value = false;
Utils::runAsync(std::cref(member2), &obj2, &value).waitForFinished();
QCOMPARE(value, true);
}
QTEST_GUILESS_MAIN(tst_RunExtensions)
#include "tst_runextensions.moc"