##// END OF EJS Templates
Mostly working Spectrograms...
Mostly working Spectrograms Signed-off-by: Alexis Jeandet <alexis.jeandet@member.fsf.org>

File last commit:

r69:cc26524fb5d1
r84:483146a07a5f
Show More
VariableController2.cpp
447 lines | 13.4 KiB | text/x-c | CppLexer
/ src / Variable / VariableController2.cpp
First init from SciQLop Core module...
r0 #include "Variable/VariableController2.h"
Added new TS classes and tiny cleanup...
r60
Added DateTimeRange unit Tests...
r6 #include "Variable/VariableSynchronizationGroup2.h"
Added new TS classes and tiny cleanup...
r60
Basic serial variable creation and update...
r2 #include <Common/containers.h>
#include <Common/debug.h>
#include <Data/DataProviderParameters.h>
Basic asynchronous variable update, still a lot to do...
r17 #include <Data/DateTimeRange.h>
Added new TS classes and tiny cleanup...
r60 #include <Data/DateTimeRangeHelper.h>
#include <QCoreApplication>
#include <QDataStream>
#include <QObject>
#include <QQueue>
#include <QRunnable>
#include <QThreadPool>
Basic asynchronous variable update, still a lot to do...
r17 #include <Variable/private/VCTransaction.h>
First init from SciQLop Core module...
r0
Basic serial variable creation and update...
r2 class VariableController2::VariableController2Private
First init from SciQLop Core module...
r0 {
Added new TS classes and tiny cleanup...
r60 struct threadSafeVaraiblesMaps
{
inline void
Switched to new TS impl, but quite broken!...
r67 addVariable(const std::shared_ptr<Variable2>& variable,
Added new TS classes and tiny cleanup...
r60 const std::shared_ptr<IDataProvider>& provider,
const std::shared_ptr<VariableSynchronizationGroup2>&
synchronizationGroup)
Moved all maps in VC2 to a dedicated struct to ease thread safety more...
r19 {
Added new TS classes and tiny cleanup...
r60 QWriteLocker lock{&_lock};
_variables[*variable] = variable;
_providers[*variable] = provider;
_synchronizationGroups[*variable] = synchronizationGroup;
Basic asynchronous variable update, still a lot to do...
r17 }
Made downloader thread safe, added debugging helper for DateTimeRange...
r34
Switched to new TS impl, but quite broken!...
r67 inline void removeVariable(const std::shared_ptr<Variable2>& variable)
Deleting a variable which has pending transactions did lead to a segfault...
r47 {
Added new TS classes and tiny cleanup...
r60 QWriteLocker lock{&_lock};
_variables.erase(*variable);
_providers.remove(*variable);
_synchronizationGroups.remove(*variable);
Deleting a variable which has pending transactions did lead to a segfault...
r47 }
Added new TS classes and tiny cleanup...
r60 inline void
Switched to new TS impl, but quite broken!...
r67 synchronize(const std::shared_ptr<Variable2>& variable,
const std::optional<std::shared_ptr<Variable2>>& with)
Basic asynchronous variable update, still a lot to do...
r17 {
Added new TS classes and tiny cleanup...
r60 QWriteLocker lock{&_lock};
if(with.has_value())
{
auto newGroup = _synchronizationGroups[*with.value()];
newGroup->addVariable(*variable);
_synchronizationGroups[*variable] = newGroup;
}
else
{
_synchronizationGroups[*variable] =
std::make_shared<VariableSynchronizationGroup2>(*variable);
}
Basic asynchronous variable update, still a lot to do...
r17 }
Switched to new TS impl, but quite broken!...
r67 inline std::shared_ptr<Variable2> variable(QUuid variable)
Basic asynchronous variable update, still a lot to do...
r17 {
Added new TS classes and tiny cleanup...
r60 QReadLocker lock{&_lock};
auto it = _variables.find(variable);
New TimeSeries integration WIP...
r62 #if __cplusplus > 201703L
[[unlikely]]
#endif
if(it == _variables.end())
Added new TS classes and tiny cleanup...
r60 SCIQLOP_ERROR(threadSafeVaraiblesMaps, "Unknown Variable");
return (*it).second;
Basic asynchronous variable update, still a lot to do...
r17 }
Switched to new TS impl, but quite broken!...
r67 inline std::shared_ptr<Variable2> variable(int index)
Many fixes plus implemented var synchronization...
r9 {
Added new TS classes and tiny cleanup...
r60 QReadLocker lock{&_lock};
New TimeSeries integration WIP...
r62 #if __cplusplus > 201703L
[[unlikely]]
#endif
if(!_variables.size() > index)
Added new TS classes and tiny cleanup...
r60 SCIQLOP_ERROR(threadSafeVaraiblesMaps, "Index is out of bounds");
auto it = _variables.cbegin();
while(index != 0)
{
index -= 1;
it++;
}
return (*(it)).second;
Basic asynchronous variable update, still a lot to do...
r17 }
Switched to new TS impl, but quite broken!...
r67 inline const std::vector<std::shared_ptr<Variable2>> variables()
Basic asynchronous variable update, still a lot to do...
r17 {
Switched to new TS impl, but quite broken!...
r67 std::vector<std::shared_ptr<Variable2>> vars;
Added new TS classes and tiny cleanup...
r60 QReadLocker lock{&_lock};
for(const auto& [id, var] : _variables)
{
vars.push_back(var);
}
return vars;
Basic asynchronous variable update, still a lot to do...
r17 }
Added new TS classes and tiny cleanup...
r60
inline std::shared_ptr<IDataProvider> provider(QUuid variable)
Basic asynchronous variable update, still a lot to do...
r17 {
Added new TS classes and tiny cleanup...
r60 QReadLocker lock{&_lock};
New TimeSeries integration WIP...
r62 #if __cplusplus > 201703L
[[unlikely]]
#endif
if(!_providers.contains(variable))
Added new TS classes and tiny cleanup...
r60 SCIQLOP_ERROR(threadSafeVaraiblesMaps, "Unknown Variable");
return _providers[variable];
Many fixes plus implemented var synchronization...
r9 }
Added new TS classes and tiny cleanup...
r60
inline std::shared_ptr<VariableSynchronizationGroup2> group(QUuid variable)
Basic serial variable creation and update...
r2 {
Added new TS classes and tiny cleanup...
r60 QReadLocker lock{&_lock};
New TimeSeries integration WIP...
r62 #if __cplusplus > 201703L
[[unlikely]]
#endif
if(!_synchronizationGroups.contains(variable))
Added new TS classes and tiny cleanup...
r60 SCIQLOP_ERROR(threadSafeVaraiblesMaps, "Unknown Variable");
return _synchronizationGroups[variable];
Basic serial variable creation and update...
r2 }
Switched to new TS impl, but quite broken!...
r67 inline bool has(const std::shared_ptr<Variable2>& variable)
Basic asynchronous variable update, still a lot to do...
r17 {
Added new TS classes and tiny cleanup...
r60 QReadLocker lock{&_lock};
return _variables.find(*variable) == _variables.end();
Basic asynchronous variable update, still a lot to do...
r17 }
Basic serial variable creation and update...
r2
Added new TS classes and tiny cleanup...
r60 private:
Switched to new TS impl, but quite broken!...
r67 std::map<QUuid, std::shared_ptr<Variable2>> _variables;
Added new TS classes and tiny cleanup...
r60 QMap<QUuid, std::shared_ptr<IDataProvider>> _providers;
QMap<QUuid, std::shared_ptr<VariableSynchronizationGroup2>>
_synchronizationGroups;
QReadWriteLock _lock{QReadWriteLock::Recursive};
} _maps;
std::vector<QUuid> _variablesToRemove;
QThreadPool* _ThreadPool;
VCTransactionsQueues _transactions;
void _transactionComplete(QUuid group,
std::shared_ptr<VCTransaction> transaction)
{
if(transaction->done()) { _transactions.complete(group); }
this->_processTransactions();
}
void _cleanupVariables()
{
for(auto id : _variablesToRemove)
First init from SciQLop Core module...
r0 {
Added new TS classes and tiny cleanup...
r60 auto v = this->variable(id);
if(!hasPendingTransactions(v))
{
_variablesToRemove.erase(std::remove(_variablesToRemove.begin(),
_variablesToRemove.end(), id),
_variablesToRemove.end());
this->deleteVariable(v);
}
Basic serial variable creation and update...
r2 }
Added new TS classes and tiny cleanup...
r60 }
Basic serial variable creation and update...
r2
Added new TS classes and tiny cleanup...
r60 void _processTransactions(bool fragmented = false)
{
auto nextTransactions = _transactions.nextTransactions();
auto pendingTransactions = _transactions.pendingTransactions();
for(auto [groupID, newTransaction] : nextTransactions)
Few methods added to ease integration in existing GUI...
r25 {
Added new TS classes and tiny cleanup...
r60 if(newTransaction.has_value() &&
!pendingTransactions[groupID].has_value())
{
_transactions.start(groupID);
auto refVar = _maps.variable(newTransaction.value()->refVar);
auto ranges =
_computeAllRangesInGroup(refVar, newTransaction.value()->range);
for(auto const& [ID, range] : ranges)
{
auto provider = _maps.provider(ID);
auto variable = _maps.variable(ID);
if(fragmented)
{
Switched to new TS impl, but quite broken!...
r67 auto missingRanges = _computeMissingRanges(variable, range);
Added new TS classes and tiny cleanup...
r60
Switched to new TS impl, but quite broken!...
r67 auto exe =
new TransactionExe(variable, provider, missingRanges, range);
Added new TS classes and tiny cleanup...
r60 QObject::connect(
exe, &TransactionExe::transactionComplete,
[groupID = groupID, transaction = newTransaction.value(),
this]() { this->_transactionComplete(groupID, transaction); });
_ThreadPool->start(exe);
}
else
{
Switched to new TS impl, but quite broken!...
r67 auto exe = new TransactionExe(variable, provider, {range}, range);
Added new TS classes and tiny cleanup...
r60 QObject::connect(
exe, &TransactionExe::transactionComplete,
[groupID = groupID, transaction = newTransaction.value(),
this]() { this->_transactionComplete(groupID, transaction); });
_ThreadPool->start(exe);
}
}
}
Few methods added to ease integration in existing GUI...
r25 }
Added new TS classes and tiny cleanup...
r60 // after each transaction update we get a new distribution of idle and
// working variables so we can delete variables which are waiting to be
// deleted if they are now idle
_cleanupVariables();
}
std::map<QUuid, DateTimeRange>
Switched to new TS impl, but quite broken!...
r67 _computeAllRangesInGroup(const std::shared_ptr<Variable2>& refVar,
Added new TS classes and tiny cleanup...
r60 DateTimeRange r)
{
std::map<QUuid, DateTimeRange> ranges;
if(!DateTimeRangeHelper::hasnan(r))
Few methods added to ease integration in existing GUI...
r25 {
Added new TS classes and tiny cleanup...
r60 auto group = _maps.group(*refVar);
if(auto transformation =
DateTimeRangeHelper::computeTransformation(refVar->range(), r);
transformation.has_value())
{
for(auto varId : group->variables())
{
auto var = _maps.variable(varId);
auto newRange = var->range().transform(transformation.value());
ranges[varId] = newRange;
}
}
else // force new range to all variables -> may be weird if more than one
// var in the group
// @TODO ensure that there is no side effects
{
for(auto varId : group->variables())
{
auto var = _maps.variable(varId);
ranges[varId] = r;
}
}
Few methods added to ease integration in existing GUI...
r25 }
Added new TS classes and tiny cleanup...
r60 else
Implemented variable duplication and some code move...
r20 {
Added new TS classes and tiny cleanup...
r60 SCIQLOP_ERROR(VariableController2Private, "Invalid range containing NaN");
Implemented variable duplication and some code move...
r20 }
Added new TS classes and tiny cleanup...
r60 return ranges;
}
Switched to new TS impl, but quite broken!...
r67 std::vector<DateTimeRange>
_computeMissingRanges(const std::shared_ptr<Variable2>& var, DateTimeRange r)
Added new TS classes and tiny cleanup...
r60 {
Switched to new TS impl, but quite broken!...
r67 return r - var->range();
Added new TS classes and tiny cleanup...
r60 }
void _changeRange(QUuid id, DateTimeRange r)
{
_changeRange(_maps.variable(id), r);
}
Switched to new TS impl, but quite broken!...
r67 void _changeRange(const std::shared_ptr<Variable2>& var, DateTimeRange r)
Added new TS classes and tiny cleanup...
r60 {
Switched to new TS impl, but quite broken!...
r67 auto provider = _maps.provider(*var);
auto missingRanges = _computeMissingRanges(var, r);
std::vector<TimeSeries::ITimeSerie*> data;
Added new TS classes and tiny cleanup...
r60 for(auto range : missingRanges)
Basic serial variable creation and update...
r2 {
Added new TS classes and tiny cleanup...
r60 data.push_back(
provider->getData(DataProviderParameters{{range}, var->metadata()}));
Basic serial variable creation and update...
r2 }
Fixed all tests \o/ with new TS impl...
r68 data.push_back(var->data().get()); // might be smarter
Switched to new TS impl, but quite broken!...
r67 var->setData(data, r, true);
Added new TS classes and tiny cleanup...
r60 }
Basic serial variable creation and update...
r2
Added new TS classes and tiny cleanup...
r60 public:
VariableController2Private(QObject* parent = Q_NULLPTR)
{
Q_UNUSED(parent);
this->_ThreadPool = new QThreadPool();
this->_ThreadPool->setMaxThreadCount(32);
}
/*
* This dtor has to like this even if this is ugly, because default dtor would
* rely on declaration order to destruct members and that would always lead to
* regressions when modifying class members
*/
~VariableController2Private() { delete this->_ThreadPool; }
Switched to new TS impl, but quite broken!...
r67 std::shared_ptr<Variable2>
Added new TS classes and tiny cleanup...
r60 createVariable(const QString& name, const QVariantHash& metadata,
std::shared_ptr<IDataProvider> provider)
{
Switched to new TS impl, but quite broken!...
r67 auto newVar = std::make_shared<Variable2>(name, metadata);
Added new TS classes and tiny cleanup...
r60 auto group = std::make_shared<VariableSynchronizationGroup2>(newVar->ID());
_maps.addVariable(newVar, std::move(provider), group);
this->_transactions.addEntry(*group);
return newVar;
}
Switched to new TS impl, but quite broken!...
r67 std::shared_ptr<Variable2> variable(QUuid ID) { return _maps.variable(ID); }
Added new TS classes and tiny cleanup...
r60
Switched to new TS impl, but quite broken!...
r67 std::shared_ptr<Variable2> variable(int index)
Added new TS classes and tiny cleanup...
r60 {
return _maps.variable(index);
}
Switched to new TS impl, but quite broken!...
r67 std::shared_ptr<Variable2>
cloneVariable(const std::shared_ptr<Variable2>& variable)
Added new TS classes and tiny cleanup...
r60 {
auto newVar = variable->clone();
_maps.synchronize(newVar, std::nullopt);
_maps.addVariable(newVar, _maps.provider(*variable), _maps.group(*newVar));
this->_transactions.addEntry(*_maps.group(*newVar));
return newVar;
}
Switched to new TS impl, but quite broken!...
r67 bool hasPendingTransactions(const std::shared_ptr<Variable2>& variable)
Added new TS classes and tiny cleanup...
r60 {
return _transactions.active(*_maps.group(*variable));
}
bool hasPendingTransactions()
{
bool has = false;
for(const auto& var : _maps.variables())
Basic serial variable creation and update...
r2 {
Added new TS classes and tiny cleanup...
r60 has |= _transactions.active(*_maps.group(*var));
Basic serial variable creation and update...
r2 }
Added new TS classes and tiny cleanup...
r60 return has;
}
Basic serial variable creation and update...
r2
Switched to new TS impl, but quite broken!...
r67 void deleteVariable(const std::shared_ptr<Variable2>& variable)
Added new TS classes and tiny cleanup...
r60 {
if(!hasPendingTransactions(variable))
_maps.removeVariable(variable);
else
_variablesToRemove.push_back(variable->ID());
}
Switched to new TS impl, but quite broken!...
r67 void asyncChangeRange(const std::shared_ptr<Variable2>& variable,
Added new TS classes and tiny cleanup...
r60 const DateTimeRange& r)
{
if(!DateTimeRangeHelper::hasnan(r))
Basic asynchronous variable update, still a lot to do...
r17 {
Added new TS classes and tiny cleanup...
r60 auto group = _maps.group(*variable);
// Just overwrite next transaction
{
_transactions.enqueue(*group,
std::make_shared<VCTransaction>(
variable->ID(), r,
static_cast<int>(group->variables().size())));
}
_processTransactions();
Basic asynchronous variable update, still a lot to do...
r17 }
Added new TS classes and tiny cleanup...
r60 else
Added more features in DateTimeRange to prepare variable synchronization...
r8 {
Added new TS classes and tiny cleanup...
r60 SCIQLOP_ERROR(VariableController2Private, "Invalid range containing NaN");
Added more features in DateTimeRange to prepare variable synchronization...
r8 }
Added new TS classes and tiny cleanup...
r60 }
Basic serial variable creation and update...
r2
Switched to new TS impl, but quite broken!...
r67 void changeRange(const std::shared_ptr<Variable2>& variable, DateTimeRange r)
Added new TS classes and tiny cleanup...
r60 {
asyncChangeRange(variable, r);
while(hasPendingTransactions(variable))
Basic serial variable creation and update...
r2 {
Added new TS classes and tiny cleanup...
r60 QCoreApplication::processEvents();
First init from SciQLop Core module...
r0 }
Added new TS classes and tiny cleanup...
r60 }
Switched to new TS impl, but quite broken!...
r67 inline void synchronize(const std::shared_ptr<Variable2>& var,
const std::shared_ptr<Variable2>& with)
Added new TS classes and tiny cleanup...
r60 {
_maps.synchronize(var, with);
}
Switched to new TS impl, but quite broken!...
r67 inline const std::vector<std::shared_ptr<Variable2>> variables()
Added new TS classes and tiny cleanup...
r60 {
return _maps.variables();
}
First init from SciQLop Core module...
r0 };
VariableController2::VariableController2()
Added new TS classes and tiny cleanup...
r60 : impl{spimpl::make_unique_impl<VariableController2Private>()}
First init from SciQLop Core module...
r0 {}
Switched to new TS impl, but quite broken!...
r67 std::shared_ptr<Variable2> VariableController2::createVariable(
Added new TS classes and tiny cleanup...
r60 const QString& name, const QVariantHash& metadata,
const std::shared_ptr<IDataProvider>& provider, const DateTimeRange& range)
First init from SciQLop Core module...
r0 {
Added new TS classes and tiny cleanup...
r60 auto var = impl->createVariable(name, metadata, provider);
var->setRange(range); // even with no data this is it's range
if(!DateTimeRangeHelper::hasnan(range))
impl->asyncChangeRange(var, range);
else
SCIQLOP_ERROR(VariableController2, "Creating a variable with default "
"constructed DateTimeRange is an error");
emit variableAdded(var);
return var;
Basic serial variable creation and update...
r2 }
Switched to new TS impl, but quite broken!...
r67 std::shared_ptr<Variable2>
VariableController2::cloneVariable(const std::shared_ptr<Variable2>& variable)
Implemented variable duplication and some code move...
r20 {
Added new TS classes and tiny cleanup...
r60 return impl->cloneVariable(variable);
Implemented variable duplication and some code move...
r20 }
Added new TS classes and tiny cleanup...
r60 void VariableController2::deleteVariable(
Switched to new TS impl, but quite broken!...
r67 const std::shared_ptr<Variable2>& variable)
Basic serial variable creation and update...
r2 {
Added new TS classes and tiny cleanup...
r60 impl->deleteVariable(variable);
emit variableDeleted(variable);
Basic serial variable creation and update...
r2 }
Switched to new TS impl, but quite broken!...
r67 void VariableController2::changeRange(
const std::shared_ptr<Variable2>& variable, const DateTimeRange& r)
Basic serial variable creation and update...
r2 {
Added new TS classes and tiny cleanup...
r60 impl->changeRange(variable, r);
Basic serial variable creation and update...
r2 }
Added new TS classes and tiny cleanup...
r60 void VariableController2::asyncChangeRange(
Switched to new TS impl, but quite broken!...
r67 const std::shared_ptr<Variable2>& variable, const DateTimeRange& r)
Some refactoring on Variable class...
r15 {
Added new TS classes and tiny cleanup...
r60 impl->asyncChangeRange(variable, r);
Some refactoring on Variable class...
r15 }
Switched to new TS impl, but quite broken!...
r67 const std::vector<std::shared_ptr<Variable2>> VariableController2::variables()
Basic serial variable creation and update...
r2 {
Added new TS classes and tiny cleanup...
r60 return impl->variables();
First init from SciQLop Core module...
r0 }
Switched to new TS impl, but quite broken!...
r67 bool VariableController2::isReady(const std::shared_ptr<Variable2>& variable)
Basic asynchronous variable update, still a lot to do...
r17 {
Added new TS classes and tiny cleanup...
r60 return !impl->hasPendingTransactions(variable);
Fixed tests due to async var creation, plus minor stuff...
r30 }
Added new TS classes and tiny cleanup...
r60 bool VariableController2::isReady() { return !impl->hasPendingTransactions(); }
Basic asynchronous variable update, still a lot to do...
r17
Switched to new TS impl, but quite broken!...
r67 void VariableController2::synchronize(const std::shared_ptr<Variable2>& var,
const std::shared_ptr<Variable2>& with)
Added more features in DateTimeRange to prepare variable synchronization...
r8 {
Added new TS classes and tiny cleanup...
r60 impl->synchronize(var, with);
Added more features in DateTimeRange to prepare variable synchronization...
r8 }
Quick variable model copied from existing one...
r21
Switched to new TS impl, but quite broken!...
r67 const std::vector<std::shared_ptr<Variable2>>
Added new TS classes and tiny cleanup...
r60 VariableController2::variables(const std::vector<QUuid>& ids)
Few methods added to ease integration in existing GUI...
r25 {
Switched to new TS impl, but quite broken!...
r67 std::vector<std::shared_ptr<Variable2>> variables;
Added new TS classes and tiny cleanup...
r60 std::transform(std::cbegin(ids), std::cend(ids),
std::back_inserter(variables),
[this](const auto& id) { return impl->variable(id); });
return variables;
Few methods added to ease integration in existing GUI...
r25 }