Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added propagation control functions and fix implicit string conversion in headers. #367

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

rayment
Copy link
Contributor

@rayment rayment commented Jan 28, 2023

I've added the ability to explicitly control propagation of data in DataFlowGraphModel through the use of a new virtual function canPropagate(ConnectionId), and another function propagate(NodeId) to request a propagation without having to update connections or input/output. The user can also change onOutPortDataUpdated and propagateEmptyDataTo with deriviative functions to change the output of the propagation for each connection.

These functions are both virtual so that derivative dataflow models can specify their own control model, but this may go against the design of DataFlowGraphModel. Feel free to deny or change as you wish. As an example:

My project has nodes of text data ranging in the gigabytes. I use a global execution state to control when data is propagated and clone node outputs when there is more than one connection stemming from an output. This can be achieved with custom functions:

Controlled data propagation

PipedGraphModel::
PipedGraphModel(std::shared_ptr<NodeDelegateModelRegistry> registry) :
    DataFlowGraphModel(registry)
{
    executing = false;
}

PipedGraphModel::~PipedGraphModel(void)
{}

bool
PipedGraphModel::canPropagate(const ConnectionId conn)
{
    if (executing)
        return true;
    // data should only be passed on if the graph is being executed
    // or if the node is capable of performing the calculation in
    // such a negligible amount of time that it may as well calculate
    // immediately (think math or array nodes)
    Node *delegate = this->delegateModel<Node>(conn.inNodeId);
    return delegate->canInstantCompute();
}

void
PipedGraphModel::stopExecute(void)
{
    executing = false;
}

void
PipedGraphModel::execute(void)
{
    executing = true;
    for (NodeId id : this->allNodeIds())
    {
        // check each node for any inputs, and if it contains none, then
        // it must be an input node, from which we can propagate the rest of the
        // graph
        Node *delegate = this->delegateModel<Node>(id);
        if (delegate->numInputs() == 0 && delegate->numOutputs() > 0)
            this->propagate(id);
    }
    executing = false;
}

void
PipedGraphModel::onOutPortDataUpdated(NodeId const nodeId,
                                      PortIndex const portIndex)
{
    const std::unordered_set<ConnectionId> &connected =
        connections(nodeId, PortType::Out, portIndex);

    const QVariant portDataToPropagate =
        portData(nodeId, PortType::Out, portIndex, PortRole::Data);
    const std::shared_ptr<PipedNodeData> data =
        qvariant_cast<std::shared_ptr<PipedNodeData>>(portDataToPropagate);

    int con = 0;
    for (auto const &cn : connected) {
        if (canPropagate(cn)) {
            setPortData(cn.inNodeId,
                        PortType::In,
                        cn.inPortIndex,
                        con > 0 ? QVariant::fromValue(data->clone()) :
                                  QVariant::fromValue(data), // fork connections
                        PortRole::Data);
            ++con;
        }
    }
}

Added the ability to explicitly control propagation of data in
DataFlowGraphModel through the use of a new virtual function
canPropagate(ConnectionId), and another function propagate(NodeId) to
request a propagation without having to update input/output data.

These functions are both virtual so that deriviative dataflow models can
specify their own control model.

Signed-off-by: Finn Rayment <[email protected]>
The library will fail to compile if QT_NO_CAST_FROM_ASCII is set in any
project that uses it due to implicit conversion of const char * to QString.

Wrapping the constants moves string initialisation to compile-time and
succeeds build.

Signed-off-by: Finn Rayment <[email protected]>
@rayment
Copy link
Contributor Author

rayment commented Jan 29, 2023

I've added another commit which surrounds strings that are present in headers with QLatin1String(...) because the library refuses to compile into my project if QT_NO_CAST_FROM_ASCII is defined. In a sense it optimises the code because strings are no longer being implicitly converted to QString at runtime, but I have not done the same for any of the source files (I would be happy to share my fix if it's worth it).

Just thought it would be useful to add here rather than open another PR...

@rayment rayment changed the title Added propagation control functions. Added propagation control functions and fix implicit string conversion in headers. Jan 29, 2023
@rayment
Copy link
Contributor Author

rayment commented Jun 9, 2023

Hi @paceholder, I understand you are probably busy with life at the moment (aren't we all?) but I was hoping to ask you to review this change when you have the chance (I'm mostly worried about 7f9d7ab as the project fails to build if we turn on QT_NO_CAST_FROM_ASCII).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants