<commit_before>//  Powiter
//
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
 *Created by <NAME> on 6/1/2012.
 *contact: immarespond at gmail dot com
 *
 */

#ifndef POWITER_ENGINE_VIDEOENGINE_H_
#define POWITER_ENGINE_VIDEOENGINE_H_

// FIXME: can the definitions of classes EngineMainEntry, Worker, and RowRunnable be moved to VideoEngine.cpp?
#include <cassert>
#include <vector>
#include <QtCore/QObject>
#include <QtCore/QThreadPool>
#include <QtCore/QMutex>
#include <QtCore/QWaitCondition>

#include <QFutureWatcher>
#include <QtCore/QRunnable> // for RowRunnable => to remove if class RowRunnable is moved to VideoEngine.cpp

#ifndef Q_MOC_RUN
#include <boost/noncopyable.hpp>
#endif

#include "Global/Macros.h"
#include "Global/GlobalDefines.h"
#include "Gui/Texture.h" // for TextureRect
#include "Engine/Format.h"

class FrameEntry;
class InputNode;
class OutputNode;
class ViewerGL;
class Node;
class Row;
class ReaderInfo;
class Reader;
class Model;
class ViewerNode;
class Writer;
class Timer;
class OfxNode;
class EngineMainEntry;
class Worker;


/**
 *@class VideoEngine
 *@brief This is the engine that runs the playback. It handles all graph computations for the time range given by
 *the graph. A lot of optimisations are made in here to keep the main thread refreshing the GUI and also do some
 *OpenGL computations. Take a look at the drawing in the source file if you want to understand the succession of calls
 *that are made by the video engine. This class is non copyable and for now the software can only support 1 engine.
 *That means that you cannot have 2 computations running at the same time. A future version will most likely introduce
 *multi-engine processing but this is not a priority.
 **/
class VideoEngine : public QThread{
    Q_OBJECT
    
    friend class EngineMainEntry;
    friend class Worker;
    
public:
    
    
    
    /**
     *@class DAG
     *@brief This class represents the direct acyclic graph as seen internally by the video engine.
     *It provides means to sort the graph and access to the nodes in topological order. It also
     *provides access to the input nodes and the output node of the graph.
     *An input node is a node that does not depend on any upstream node,i.e :
     *it can generate data.
     *An output node is a node whose output cannot be connected to any other node and whose
     *sole purpose is to visulize the data flowing through the graph in a given configuration.
     *A DAG is represented by 1 output node, connected to its input, and so on recursively.
     *
     **/
    class DAG{
        
    public:
        typedef std::vector<Node*>::const_iterator DAGIterator;
        typedef std::vector<Node*>::const_reverse_iterator DAGReverseIterator;
        typedef std::vector<Node*>::const_iterator InputsIterator;
        
        /**
         *@brief Construct an empty DAG that can be filled with nodes.
         *To actually fill the dag you need to call DAG::resetAndSort(OutputNode*,bool) .
         *Once filled up, you can access the nodes in topological order with the iterators.
         *The reverse iterator will give you the opposite of the topological order.
         */
        DAG():_output(0),_isViewer(false),_isOutputOpenFXNode(false){}
        
        /**
         *@brief Clears the structure and fill it with a new graph, represented by the OutputNode.
         *@param out[in] This is the output of the graph, i.e either a viewer or a writer. The rest
         *of the graph is fetched recursivly starting from this node.
         *@param isViewer[in] If true, it indicates the DAG that the output node is a viewer, hence
         *allowing some optimisations to be made by the engine. The type of the output node should always
         *be known when calling this function.
         *@TODO Throw some exception to detect cycles in the graph
         */
        
        void resetAndSort(OutputNode* out, bool isViewer);
        
        /**
         *@brief Clears out the structure. As a result the graph will do nothing.
         */
        void reset();
        
        /**
         *@brief Returns an iterator pointing to the first node in the graph in topological order.
         *Generally the first node is an input node.
         */
        DAGIterator begin() const {return _sorted.begin();}
        
        /**
         *@brief Returns an iterator pointing after the last node in the graph in topological order.
         *Generally the last node is an output node.
         */
        DAGIterator end() const {return _sorted.end();}
        
        /**
         *@brief Returns an iterator pointing to the last node in the graph in topological order.
         *Generally the last node is an output node.
         */
        DAGReverseIterator rbegin() const {return _sorted.rbegin();}
        
        /**
         *@brief Returns an iterator pointing before the first node in the graph in topological order.
         *Generally the first node is an input node.
         */
        DAGReverseIterator rend() const {return _sorted.rend();}
        
        /**
         *@brief Returns a pointer to the output node of the graph.
         *WARNING : It will return NULL if DAG::resetAndSort(OutputNode*,bool) has never been called.
         */
        OutputNode* getOutput() const {return _output;}
        
        
        /**
         *@brief Convenience function. Returns NULL in case the output node is not of the requested type.
         *WARNING : It will return NULL if DAG::resetAndSort(OutputNode*,bool) has never been called.
         */
        ViewerNode* outputAsViewer() const;
        
        /**
         *@brief Convenience function. Returns NULL in case the output node is not of the requested type.
         *WARNING : It will return NULL if DAG::resetAndSort(OutputNode*,bool) has never been called.
         */
        Writer* outputAsWriter() const;
        
        /**
         *@brief Convenience function. Returns NULL in case the output node is not of the requested type.
         *WARNING : It will return NULL if DAG::resetAndSort(OutputNode*,bool) has never been called.
         */
        OfxNode* outputAsOpenFXNode() const;
        
        /**
         *@brief Returns true if the output node is a viewer.
         */
        bool isOutputAViewer() const {return _isViewer;}
        
        
        /**
         *@brief Returns true if the output node is an OpenFX node.
         */
        bool isOutputAnOpenFXNode() const {return _isOutputOpenFXNode;}
        
        /**
         *@brief Accesses the input nodes of the graph.
         *@returns A reference to a vector filled with all input nodes of the graph.
         */
        const std::vector<Node*>& getInputs()const{return _inputs;}
        
        /**
         *@brief The first frame supported by the graph.
         *@decription The first frame is the minimum frame number that an input node of the graph can generate.
         *E.G: Imagine the DAG has 2 readers A and B. A has a frame range of 30-50 and B a frame range of 20-40.
         *The first frame in that case is 20.
         *@returns Returns the first frame number that can be read in the graph.
         */
        int firstFrame() const ;
        
        /**
         *@brief The last frame supported by the graph.
         *@decription The last frame is the maximum frame number that an input node of the graph can generate.
         *E.G: Imagine the DAG has 2 readers A and B. A has a frame range of 30-50 and B a frame range of 20-40.
         *The last frame in that case is 50.
         *@returns Returns the last frame number that can be read in the graph.
         */
        int lastFrame() const;
        
        /**
         *@brief Validates that all nodes parameters can fit together in the graph.
         *This function will propagate in topological order all infos in the graph,
         *starting from input nodes and finishing to the output node. During that pass all frame ranges
         *are merged (retaining only the minimum and the maximum) and some other influencial infos are
         *passed as well. i.e : channels that a node needs from its input, the requested region of processing...etc
         *@param doFullWork[in] If true,this pass will actually do more work and will make sure to propagate all infos
         *through the graph. Generally this is called AFTER that all readers have read the headers of their current frame
         *so they know what display window/channels...etc to pass down to their outputs.
         *If false, validate is much lighter and will only merge the frame range.
         *@returns Returns true if the validation passed detected that there is no issue in the graph. Otherwise returns
         *false and all subsequent computations should be canceled.
         *@TODO: validate should throw a detailed exception of what failed.
         */
        bool validate(bool doFullWork);
        
        void debug();
    private:
        
        /*recursive topological sort*/
        void topologicalSort();
        /*function called internally by the sorting
         *algorithm*/
        void _depthCycle(Node* n);
        /*called by resetAndSort(...) to fill the structure
         *upstream of the output given in parameter of resetAndSort(...)*/
        void fillGraph(Node* n);
        /*clears out the structure*/
        void clearGraph();
        
        OutputNode* _output; /*!<the output of the DAG*/
        std::vector<Node*> _graph;/*!<the un-sorted DAG*/
        std::vector<Node*> _sorted; /*!<the sorted DAG*/
        std::vector<Node*> _inputs; /*!<all the inputs of the dag*/
        bool _isViewer; /*!< true if the outputNode is a viewer, it avoids many dynamic_casts*/
        bool _isOutputOpenFXNode; /*!< true if the outputNode is an OpenFX node*/
    };
    
    /**
     *@struct EngineStatus
     *@brief This class is used as a return code from the function
     *VideoEngine::computeFrameRequest(bool,bool,bool).
     *The members of this class helps the video engine to know what decision to make after
     *the thread as returned from VideoEngine::computeFrameRequest(bool,bool,bool). Thanks to this class
     *the engine will either go in cache mode (i.e: reading data from the cache) or start computations
     *in the graph.
     **/
    struct EngineStatus{
        enum RetCode{NORMAL_ENGINE = 0 , CACHED_ENGINE = 1 , ABORTED = 2};
        
        EngineStatus():_cachedEntry(0),_key(0),_x(0),_r(0),_returnCode(NORMAL_ENGINE){}
        
        EngineStatus(FrameEntry* cachedEntry,U64 key,int x,int r,const std::vector<int> rows,EngineStatus::RetCode state):
        _cachedEntry(cachedEntry),
        _key(key),
        _x(x),
        _r(r),
        _rows(rows),
        _returnCode(state)
        {}
        
        EngineStatus(const EngineStatus& other): _cachedEntry(other._cachedEntry),
        _key(other._key),_x(other._x),_r(other._r),
        _rows(other._rows),_returnCode(other._returnCode){}
        
        
        ~EngineStatus(){}
        
        FrameEntry* _cachedEntry;
        U64 _key;
        int _x,_r;
        std::vector<int> _rows;
        RetCode _returnCode;
    };
    
private:
    
    friend class ViewerGL;
    
    /**
     *@brief A typedef used to represent a generic signature of a function that represent a user action like Play, Pause, Seek...etc
     */
    typedef void (VideoEngine::*VengineFunction)(int,int,bool,bool,bool,OutputNode*);
    
    /**
     *@struct VideoEngine::Task
     *@brief This class holds all necessary infos to store a function call that will be queued. This is used mainly to delay
     *user requested operation like "Seek" "Play" etc... so it doesn't mess with the currently running computations. Once
     *the engine finishes its computations, it will then execute the stored Task.
     **/
    struct Task{
        int _newFrameNB;
        int _frameCount;
        bool _initViewer;
        bool _forward;
        bool _sameFrame;
        OutputNode* _output;
        VengineFunction _func;
        Task(int newFrameNB,int frameCount,bool initViewer,bool forward,bool sameFrame,OutputNode* output,VengineFunction func):
        _newFrameNB(newFrameNB),_frameCount(frameCount),_initViewer(initViewer),_forward(forward),_sameFrame(sameFrame),
        _output(output),_func(func){}
        
    };
    
    /**
     * @brief The ViewerCacheArgs class is a convenience class storing the arguments
     * passed to the viewer cache for checking if a frame is cached or not.
     * This saves the burden of re-calling all the arguments separatly into
     * member variables or even re-compute some of them.
     */
    struct LastFrameInfos{
        LastFrameInfos():_cachedEntry(0),_dataSize(0){}
        
        FrameEntry* _cachedEntry;
        std::vector<int> _rows;
        TextureRect _textureRect;
        size_t _dataSize;
        
    };
    
    struct RunArgs{
        RunArgs():_zoomFactor(1.f),
        _sameFrame(false),
        _fitToViewer(false),
        _recursiveCall(false),
        _forward(true),
        _frameRequestsCount(0),
        _frameRequestIndex(0){}
        
        float _zoomFactor;
        bool _sameFrame;/*!< on if we want the subsequent videoEngine call to be on the same frame(zoom)*/
        bool _fitToViewer;
        bool _recursiveCall;
        bool _forward;/*!< forwards/backwards video engine*/
        int _frameRequestsCount;/*!< The index of the last frame +1 if the engine
                                 is forward (-1 otherwise). This value is -1 if we're looping.*/
        int _frameRequestIndex;/*!< counter of the frames computed:used to refresh the fps only every 24 frames*/
    };
    
    Model* _model;
    
    std::vector<Task> _waitingTasks; /*!< The queue of the user's waiting tasks.*/
        
	bool _working; /*!< True if the engine is working.*/
    
    DAG _dag; /*!< The internal DAG instance.*/
    
    Timer* _timer; /*!< Timer regulating the engine execution. It is controlled by the GUI.*/
    
    bool _aborted ;/*!< true when the engine has been aborted, i.e: the user disconnected the viewer*/
    
    bool _mustQuit;/*!< true when we quit the engine*/
    
    U64 _treeVersion;/*!< the hash key associated to the current graph*/
    bool _treeVersionValid;/*!< was _treeVersion initialized? */
    
    bool _loopMode; /*!< on if the player will loop*/
        
    bool _autoSaveOnNextRun; /*!< on if we need to to an autosave at the end of the next compute frame.*/
    
    QFutureWatcher<void>* _workerThreadsWatcher;/*!< watcher of the thread pool running the meta engine for all rows of
                                                 the current frame. Its finished() signal will call
                                                 Worker::finishComputeFrameRequest()*/    
    QVector<Row*> _sequence;
    
    QFutureWatcher<void>* _computeFrameWatcher;/*!< watcher of the thread running the function
                                                EngineMainEntry::computeFrameRequest. It stores the
                                                results of the function and calls
                                                VideoEngine::dispatchComputeFrameRequestThread()
                                                when finished.*/
    // QThreadPool* _threadPool;
    
    QWaitCondition* _openGLCondition;
    
    QWaitCondition _startCondition;
    
    QMutex* _mutex;
    
    RunArgs _lastRunArgs;
        
    LastFrameInfos _lastFrameInfos; /*!< The stored infos generated for the last frame. Used by the gui thread slots.*/
    
    timeval _lastComputeFrameTime;/*!< stores the time at which the QtConcurrent::map call was made*/
    
protected:
    virtual void run();
    
    public slots:<commit_msg>clean up constructor/destructor<commit_after>//  Powiter
//
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
 *Created by <NAME> on 6/1/2012.
 *contact: immarespond at gmail dot com
 *
 */

#ifndef POWITER_ENGINE_VIDEOENGINE_H_
#define POWITER_ENGINE_VIDEOENGINE_H_

// FIXME: can the definitions of classes EngineMainEntry, Worker, and RowRunnable be moved to VideoEngine.cpp?
#include <cassert>
#include <vector>
#include <boost/scoped_ptr.hpp>
#include <QtCore/QObject>
#include <QtCore/QThreadPool>
#include <QtCore/QMutex>
#include <QtCore/QWaitCondition>

#include <QFutureWatcher>
#include <QtCore/QRunnable> // for RowRunnable => to remove if class RowRunnable is moved to VideoEngine.cpp

#ifndef Q_MOC_RUN
#include <boost/noncopyable.hpp>
#endif

#include "Global/Macros.h"
#include "Global/GlobalDefines.h"
#include "Gui/Texture.h" // for TextureRect
#include "Engine/Format.h"

class FrameEntry;
class InputNode;
class OutputNode;
class ViewerGL;
class Node;
class Row;
class ReaderInfo;
class Reader;
class Model;
class ViewerNode;
class Writer;
class Timer;
class OfxNode;
class EngineMainEntry;
class Worker;


/**
 *@class VideoEngine
 *@brief This is the engine that runs the playback. It handles all graph computations for the time range given by
 *the graph. A lot of optimisations are made in here to keep the main thread refreshing the GUI and also do some
 *OpenGL computations. Take a look at the drawing in the source file if you want to understand the succession of calls
 *that are made by the video engine. This class is non copyable and for now the software can only support 1 engine.
 *That means that you cannot have 2 computations running at the same time. A future version will most likely introduce
 *multi-engine processing but this is not a priority.
 **/
class VideoEngine : public QThread{
    Q_OBJECT
    
    friend class EngineMainEntry;
    friend class Worker;
    
public:
    
    
    
    /**
     *@class DAG
     *@brief This class represents the direct acyclic graph as seen internally by the video engine.
     *It provides means to sort the graph and access to the nodes in topological order. It also
     *provides access to the input nodes and the output node of the graph.
     *An input node is a node that does not depend on any upstream node,i.e :
     *it can generate data.
     *An output node is a node whose output cannot be connected to any other node and whose
     *sole purpose is to visulize the data flowing through the graph in a given configuration.
     *A DAG is represented by 1 output node, connected to its input, and so on recursively.
     *
     **/
    class DAG{
        
    public:
        typedef std::vector<Node*>::const_iterator DAGIterator;
        typedef std::vector<Node*>::const_reverse_iterator DAGReverseIterator;
        typedef std::vector<Node*>::const_iterator InputsIterator;
        
        /**
         *@brief Construct an empty DAG that can be filled with nodes.
         *To actually fill the dag you need to call DAG::resetAndSort(OutputNode*,bool) .
         *Once filled up, you can access the nodes in topological order with the iterators.
         *The reverse iterator will give you the opposite of the topological order.
         */
        DAG():_output(0),_isViewer(false),_isOutputOpenFXNode(false){}
        
        /**
         *@brief Clears the structure and fill it with a new graph, represented by the OutputNode.
         *@param out[in] This is the output of the graph, i.e either a viewer or a writer. The rest
         *of the graph is fetched recursivly starting from this node.
         *@param isViewer[in] If true, it indicates the DAG that the output node is a viewer, hence
         *allowing some optimisations to be made by the engine. The type of the output node should always
         *be known when calling this function.
         *@TODO Throw some exception to detect cycles in the graph
         */
        
        void resetAndSort(OutputNode* out, bool isViewer);
        
        /**
         *@brief Clears out the structure. As a result the graph will do nothing.
         */
        void reset();
        
        /**
         *@brief Returns an iterator pointing to the first node in the graph in topological order.
         *Generally the first node is an input node.
         */
        DAGIterator begin() const {return _sorted.begin();}
        
        /**
         *@brief Returns an iterator pointing after the last node in the graph in topological order.
         *Generally the last node is an output node.
         */
        DAGIterator end() const {return _sorted.end();}
        
        /**
         *@brief Returns an iterator pointing to the last node in the graph in topological order.
         *Generally the last node is an output node.
         */
        DAGReverseIterator rbegin() const {return _sorted.rbegin();}
        
        /**
         *@brief Returns an iterator pointing before the first node in the graph in topological order.
         *Generally the first node is an input node.
         */
        DAGReverseIterator rend() const {return _sorted.rend();}
        
        /**
         *@brief Returns a pointer to the output node of the graph.
         *WARNING : It will return NULL if DAG::resetAndSort(OutputNode*,bool) has never been called.
         */
        OutputNode* getOutput() const {return _output;}
        
        
        /**
         *@brief Convenience function. Returns NULL in case the output node is not of the requested type.
         *WARNING : It will return NULL if DAG::resetAndSort(OutputNode*,bool) has never been called.
         */
        ViewerNode* outputAsViewer() const;
        
        /**
         *@brief Convenience function. Returns NULL in case the output node is not of the requested type.
         *WARNING : It will return NULL if DAG::resetAndSort(OutputNode*,bool) has never been called.
         */
        Writer* outputAsWriter() const;
        
        /**
         *@brief Convenience function. Returns NULL in case the output node is not of the requested type.
         *WARNING : It will return NULL if DAG::resetAndSort(OutputNode*,bool) has never been called.
         */
        OfxNode* outputAsOpenFXNode() const;
        
        /**
         *@brief Returns true if the output node is a viewer.
         */
        bool isOutputAViewer() const {return _isViewer;}
        
        
        /**
         *@brief Returns true if the output node is an OpenFX node.
         */
        bool isOutputAnOpenFXNode() const {return _isOutputOpenFXNode;}
        
        /**
         *@brief Accesses the input nodes of the graph.
         *@returns A reference to a vector filled with all input nodes of the graph.
         */
        const std::vector<Node*>& getInputs()const{return _inputs;}
        
        /**
         *@brief The first frame supported by the graph.
         *@decription The first frame is the minimum frame number that an input node of the graph can generate.
         *E.G: Imagine the DAG has 2 readers A and B. A has a frame range of 30-50 and B a frame range of 20-40.
         *The first frame in that case is 20.
         *@returns Returns the first frame number that can be read in the graph.
         */
        int firstFrame() const ;
        
        /**
         *@brief The last frame supported by the graph.
         *@decription The last frame is the maximum frame number that an input node of the graph can generate.
         *E.G: Imagine the DAG has 2 readers A and B. A has a frame range of 30-50 and B a frame range of 20-40.
         *The last frame in that case is 50.
         *@returns Returns the last frame number that can be read in the graph.
         */
        int lastFrame() const;
        
        /**
         *@brief Validates that all nodes parameters can fit together in the graph.
         *This function will propagate in topological order all infos in the graph,
         *starting from input nodes and finishing to the output node. During that pass all frame ranges
         *are merged (retaining only the minimum and the maximum) and some other influencial infos are
         *passed as well. i.e : channels that a node needs from its input, the requested region of processing...etc
         *@param doFullWork[in] If true,this pass will actually do more work and will make sure to propagate all infos
         *through the graph. Generally this is called AFTER that all readers have read the headers of their current frame
         *so they know what display window/channels...etc to pass down to their outputs.
         *If false, validate is much lighter and will only merge the frame range.
         *@returns Returns true if the validation passed detected that there is no issue in the graph. Otherwise returns
         *false and all subsequent computations should be canceled.
         *@TODO: validate should throw a detailed exception of what failed.
         */
        bool validate(bool doFullWork);
        
        void debug();
    private:
        
        /*recursive topological sort*/
        void topologicalSort();
        /*function called internally by the sorting
         *algorithm*/
        void _depthCycle(Node* n);
        /*called by resetAndSort(...) to fill the structure
         *upstream of the output given in parameter of resetAndSort(...)*/
        void fillGraph(Node* n);
        /*clears out the structure*/
        void clearGraph();
        
        OutputNode* _output; /*!<the output of the DAG*/
        std::vector<Node*> _graph;/*!<the un-sorted DAG*/
        std::vector<Node*> _sorted; /*!<the sorted DAG*/
        std::vector<Node*> _inputs; /*!<all the inputs of the dag*/
        bool _isViewer; /*!< true if the outputNode is a viewer, it avoids many dynamic_casts*/
        bool _isOutputOpenFXNode; /*!< true if the outputNode is an OpenFX node*/
    };
    
    /**
     *@struct EngineStatus
     *@brief This class is used as a return code from the function
     *VideoEngine::computeFrameRequest(bool,bool,bool).
     *The members of this class helps the video engine to know what decision to make after
     *the thread as returned from VideoEngine::computeFrameRequest(bool,bool,bool). Thanks to this class
     *the engine will either go in cache mode (i.e: reading data from the cache) or start computations
     *in the graph.
     **/
    struct EngineStatus{
        enum RetCode{NORMAL_ENGINE = 0 , CACHED_ENGINE = 1 , ABORTED = 2};
        
        EngineStatus():_cachedEntry(0),_key(0),_x(0),_r(0),_returnCode(NORMAL_ENGINE){}
        
        EngineStatus(FrameEntry* cachedEntry,U64 key,int x,int r,const std::vector<int> rows,EngineStatus::RetCode state):
        _cachedEntry(cachedEntry),
        _key(key),
        _x(x),
        _r(r),
        _rows(rows),
        _returnCode(state)
        {}
        
        EngineStatus(const EngineStatus& other): _cachedEntry(other._cachedEntry),
        _key(other._key),_x(other._x),_r(other._r),
        _rows(other._rows),_returnCode(other._returnCode){}
        
        
        ~EngineStatus(){}
        
        FrameEntry* _cachedEntry;
        U64 _key;
        int _x,_r;
        std::vector<int> _rows;
        RetCode _returnCode;
    };
    
private:
    
    friend class ViewerGL;
    
    /**
     *@brief A typedef used to represent a generic signature of a function that represent a user action like Play, Pause, Seek...etc
     */
    typedef void (VideoEngine::*VengineFunction)(int,int,bool,bool,bool,OutputNode*);
    
    /**
     *@struct VideoEngine::Task
     *@brief This class holds all necessary infos to store a function call that will be queued. This is used mainly to delay
     *user requested operation like "Seek" "Play" etc... so it doesn't mess with the currently running computations. Once
     *the engine finishes its computations, it will then execute the stored Task.
     **/
    struct Task{
        int _newFrameNB;
        int _frameCount;
        bool _initViewer;
        bool _forward;
        bool _sameFrame;
        OutputNode* _output;
        VengineFunction _func;
        Task(int newFrameNB,int frameCount,bool initViewer,bool forward,bool sameFrame,OutputNode* output,VengineFunction func):
        _newFrameNB(newFrameNB),_frameCount(frameCount),_initViewer(initViewer),_forward(forward),_sameFrame(sameFrame),
        _output(output),_func(func){}
        
    };
    
    /**
     * @brief The ViewerCacheArgs class is a convenience class storing the arguments
     * passed to the viewer cache for checking if a frame is cached or not.
     * This saves the burden of re-calling all the arguments separatly into
     * member variables or even re-compute some of them.
     */
    struct LastFrameInfos{
        LastFrameInfos():_cachedEntry(0),_dataSize(0){}
        
        FrameEntry* _cachedEntry;
        std::vector<int> _rows;
        TextureRect _textureRect;
        size_t _dataSize;
        
    };
    
    struct RunArgs{
        RunArgs():_zoomFactor(1.f),
        _sameFrame(false),
        _fitToViewer(false),
        _recursiveCall(false),
        _forward(true),
        _frameRequestsCount(0),
        _frameRequestIndex(0){}
        
        float _zoomFactor;
        bool _sameFrame;/*!< on if we want the subsequent videoEngine call to be on the same frame(zoom)*/
        bool _fitToViewer;
        bool _recursiveCall;
        bool _forward;/*!< forwards/backwards video engine*/
        int _frameRequestsCount;/*!< The index of the last frame +1 if the engine
                                 is forward (-1 otherwise). This value is -1 if we're looping.*/
        int _frameRequestIndex;/*!< counter of the frames computed:used to refresh the fps only every 24 frames*/
    };
    
    Model* _model;
    
    std::vector<Task> _waitingTasks; /*!< The queue of the user's waiting tasks.*/
        
	bool _working; /*!< True if the engine is working.*/
    
    DAG _dag; /*!< The internal DAG instance.*/
    
    boost::scoped_ptr<Timer> _timer; /*!< Timer regulating the engine execution. It is controlled by the GUI.*/
    
    bool _aborted ;/*!< true when the engine has been aborted, i.e: the user disconnected the viewer*/
    
    bool _mustQuit;/*!< true when we quit the engine*/
    
    U64 _treeVersion;/*!< the hash key associated to the current graph*/
    bool _treeVersionValid;/*!< was _treeVersion initialized? */
    
    bool _loopMode; /*!< on if the player will loop*/
        
    bool _autoSaveOnNextRun; /*!< on if we need to to an autosave at the end of the next compute frame.*/
    
    boost::scoped_ptr<QFutureWatcher<void> > _workerThreadsWatcher;/*!< watcher of the thread pool running the meta engine for all rows of
                                                 the current frame. Its finished() signal will call
                                                 Worker::finishComputeFrameRequest()*/    
    QVector<Row*> _sequence;

    QWaitCondition* _openGLCondition;
    
    QWaitCondition _startCondition;
    
    QMutex* _mutex;
    
    RunArgs _lastRunArgs;
        
    LastFrameInfos _lastFrameInfos; /*!< The stored infos generated for the last frame. Used by the gui thread slots.*/
    
    struct timeval _lastComputeFrameTime;/*!< stores the time at which the QtConcurrent::map call was made*/
    
protected:
    virtual void run();
    
    public slots:
{'fraction_non_alphanumeric': 0.07691576646497925, 'fraction_numerical': 0.0037380809072765863, 'mean_word_length': 2.387124463519313, 'pattern_counts': {'":': 0, '<': 100, '<?xml version=': 0, '>': 55, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5731312', 'n_tokens_mistral': 8482, 'n_tokens_neox': 8289, 'n_words': 3540}