/
Ant010ff
/
ffpp
Обзор
Документация
Войти
/
Ant010ff
/
ffpp
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
include/sequencechainer.hpp
450 строк
14 KB
Ant010ff
Version 2.11.3.
08 авг 2026, 16:44
08 авг 2026, 16:44
fd187d3
Код
Авторство
О чём код?
/* This header is part of a Functional Flow Processing Primitives (FFPP) library, version 2.11.3. Official repository: https://gitlab.com/ant010ff/ffpp Licensed under the MIT License <http://opensource.org/licenses/MIT>. SPDX-License-Identifier: MIT Copyright (c) 2021 - 2026 Anton Nasonov <ant010fff @ gmail . com>. */ #ifndef FFPP_SEQUENCE_CHAINER_HPP #define FFPP_SEQUENCE_CHAINER_HPP namespace FFPP { template<bool t_bAutosubmit, Concepts::Tuple TArguments, typename TFunctionalSequence, typename... TDependants> class SequenceChainer { public: using ResourcePolicyT = TFunctionalSequence::ResourcePolicyT; template<typename TSignature, bool t_bUnique = true> using FunctionT = ResourcePolicyT::template FunctionT<TSignature, t_bUnique>; template<typename Type> using SharedT = ResourcePolicyT::template SharedT<Type>; using DependantsT = std::tuple<TDependants...>; template<typename TNextArguments> using SequenceChainerT = SequenceChainer<t_bAutosubmit, TNextArguments, TFunctionalSequence, TDependants...>; using ArgumentsVariantT = std::variant<TArguments, VoidT>; template<typename TFunctional, typename TCurrentArguments = TArguments> using ResultT = AsTupleT<ApplyResultT<TFunctional, TCurrentArguments>>; template<typename TFunctional, typename TCurrentArguments = TArguments> using ResultVariantT = std::variant<ResultT<TFunctional, TCurrentArguments>, VoidT>; SequenceChainer() { } SequenceChainer(SharedT<TFunctionalSequence>&& spSequence, bool bSubmit, bool bChained) : bSubmit_ (bSubmit) , bChained_ (bChained) , spSequence_ (std::move(spSequence)) { } SequenceChainer( SharedT<TFunctionalSequence> const& spSequence, SharedT<ArgumentsVariantT> const& svrArguments, bool bSubmit, bool bChained ) : bSubmit_ (bSubmit) , bChained_ (bChained) , spSequence_ (spSequence) , svrArguments_ (svrArguments) { } SequenceChainer( SharedT<TFunctionalSequence>&& spSequence, SharedT<ArgumentsVariantT>&& svrArguments, bool bSubmit, bool bChained ) : bSubmit_ (bSubmit) , bChained_ (bChained) , spSequence_ (std::move(spSequence)) , svrArguments_ (std::move(svrArguments)) { } SequenceChainer( SharedT<TFunctionalSequence>&& spSequence, bool bSubmit, bool bChained, std::tuple<TDependants...>&& tDependants ) : bSubmit_ (bSubmit) , bChained_ (bChained) , spSequence_ (std::move(spSequence)) , tDependants_ (std::move(tDependants)) { } SequenceChainer( SharedT<TFunctionalSequence>&& spSequence, SharedT<ArgumentsVariantT>&& svrArguments, bool bSubmit, bool bChained, std::tuple<TDependants...>&& tDependants ) : bSubmit_ (bSubmit) , bChained_ (bChained) , spSequence_ (std::move(spSequence)) , svrArguments_ (std::move(svrArguments)) , tDependants_ (std::move(tDependants)) { } SequenceChainer(SequenceChainer&& that) { spSequence_ = std::move(that.spSequence_); svrArguments_ = std::move(that.svrArguments_); bSubmit_ = std::exchange(that.bSubmit_, false); bChained_ = that.bChained_; tDependants_ = std::move(that.tDependants_); } SequenceChainer(SequenceChainer const&) = delete; ~SequenceChainer() noexcept(false) { //If Submit throws exception it must be handled directly in the calling code, where chain was constructed, as well as //exceptions thrown from methods of this class. if constexpr(t_bAutosubmit) { if(spSequence_ == nullptr) return; //Sequence pointer always moves to next chainer instance. if(std::uncaught_exceptions() > 0) return; //Auto submission disabled when exception is present. } tDependants_ = DependantsT { }; if constexpr(t_bAutosubmit && TFunctionalSequence::IsSubmittable()) { if(bSubmit_ && bChained_) spSequence_->Submit(); } } SequenceChainer& operator = (SequenceChainer&& that) { spSequence_ = std::move(that.spSequence_); svrArguments_ = std::move(that.svrArguments_); tDependants_ = std::move(that.tDependants_); bSubmit_ = std::exchange(that.bSubmit_, false); bChained_ = that.bChained_; return *this; } SequenceChainer& operator = (SequenceChainer const&) = delete; template<typename TDependant> SequenceChainer<t_bAutosubmit, TArguments, TFunctionalSequence, TDependants..., TDependant> Take(TDependant&& dep) { if constexpr(sizeof...(TDependants) == 0) return { std::move(spSequence_), std::move(svrArguments_), std::exchange(bSubmit_, false), bChained_, std::make_tuple(std::move(dep)) }; else return { std::move(spSequence_), std::move(svrArguments_), std::exchange(bSubmit_, false), bChained_, std::tuple_cat(std::move(tDependants_), std::make_tuple(std::move(dep))) }; } auto GetSequence() const noexcept { return spSequence_; } FunctionT<void(), false> Finalize(Flags flgContext = Flags::Undefined) const { if(!!(flgContext & Flags::Weak)) { return [flgContext, wpSequence = ResourcePolicyT::AsWeak(spSequence_)] () { auto spSequence = wpSequence.lock(); if(spSequence) spSequence->Finalize(flgContext); }; } else { return [flgContext, spSequence = spSequence_] () { spSequence->Finalize(flgContext); }; } } template<typename TValue> TValue Get() { return std::get<TValue>(Get()); } template<size_t t_iValue> auto Get() { return std::get<t_iValue>(Get()); } auto Get() { auto svrArguments = Wait().svrArguments_; if(std::holds_alternative<VoidT>(*svrArguments)) Except<>::Throw("Void result."); return std::get<TArguments>(std::exchange(*svrArguments, VoidT { })); } auto operator -> () const noexcept { return spSequence_; } operator bool () const noexcept { return bChained_; } template<typename TMessage> SequenceChainerT<TArguments> Emit(TMessage&& msg, uint32_t idQueue = 0, Flags flgContext = Flags::Undefined) { if(bChained_) bChained_ = spSequence_->Enqueue(std::forward<TMessage>(msg), idQueue, flgContext); return { std::move(spSequence_), std::move(svrArguments_), std::exchange(bSubmit_, false), bChained_, std::move(tDependants_) }; } template<typename TFunctional> auto Chain( TFunctional&& fnTask, uint32_t idQueue = 0, Flags flgContext = Flags::Undefined ) { if constexpr(!Concepts::Applicable<TFunctional, TArguments>) { static_assert( Concepts::Invalid<TArguments>::value, "Invalid Chain stage, expecting arguments (TPreviousResult...)." ); return SequenceChainerT<VoidT> { }; } else { bool constexpr c_bArguments = (0 < std::tuple_size_v<TArguments>) , c_bResult = (0 < std::tuple_size_v<ResultT<TFunctional>>) ; if constexpr(c_bArguments && c_bResult) { return Chain11(std::forward<TFunctional>(fnTask), idQueue, flgContext); } else if constexpr(c_bArguments && !c_bResult) { return Chain10(std::forward<TFunctional>(fnTask), idQueue, flgContext); } else if constexpr(!c_bArguments && c_bResult) { return Chain01(std::forward<TFunctional>(fnTask), idQueue, flgContext); } else { return Chain00(std::forward<TFunctional>(fnTask), idQueue, flgContext); } } } SequenceChainerT<TArguments> Process(bool bAll = false, uint32_t idQueue = TFunctionalSequence::InvalidQueueId()) { std::apply([bAll, idQueue] (auto&... deps) { ( [] (auto& deps, bool bAll, uint32_t idQueue) { if constexpr(requires { deps.Process(bool { }, uint32_t { }); }) deps.Process(bAll, idQueue); } (deps, bAll, idQueue) , ... ); }, tDependants_); if(bChained_ && bSubmit_) spSequence_->Process(bAll, idQueue); return { std::move(spSequence_), std::move(svrArguments_), std::exchange(bSubmit_, false), bChained_, std::move(tDependants_) }; } template<std::invocable<TFunctionalSequence*> TFunctional> SequenceChainerT<TArguments> Complete(Flags flgContext, TFunctional&& onComplete) { std::apply([flgContext] (auto&... deps) { ( [] (auto& deps, Flags flgContext) { if constexpr(requires { deps.Complete(Flags::Undefined); }) deps.Complete(flgContext); } (deps, flgContext) , ... ); }, tDependants_); if(bChained_) bChained_ = spSequence_->Complete(flgContext, std::forward<TFunctional>(onComplete)); return { std::move(spSequence_), std::move(svrArguments_), std::exchange(bSubmit_, false), bChained_, std::move(tDependants_) }; } template<std::invocable<TFunctionalSequence*> TFunctional> SequenceChainerT<TArguments> Complete(TFunctional&& onComplete) { return Complete(Flags::Undefined, std::forward<TFunctional>(onComplete)); } SequenceChainerT<TArguments> Complete(Flags flgContext) { return Complete(flgContext, FunctionT<void(TFunctionalSequence*)> { }); } SequenceChainerT<TArguments> Complete() { return Complete(Flags::Undefined, FunctionT<void(TFunctionalSequence*)> { }); } SequenceChainerT<TArguments> Wait() { if(bChained_ && spSequence_) { std::apply([] (auto&... deps) { ( [] (auto& deps) { if constexpr(requires { deps.Wait(); }) deps.Wait(); } (deps) , ... ); }, tDependants_); auto prJoin = BeginJoin<false, ResourcePolicyT>(); bChained_ = spSequence_->Enqueue([sgJoin = prJoin.second] (auto*) { }); if(bSubmit_) { bSubmit_ = false; if constexpr(TFunctionalSequence::IsSubmittable()) spSequence_->Submit(); } } return { std::move(spSequence_), std::move(svrArguments_), std::exchange(bSubmit_, false), bChained_, std::move(tDependants_) }; } SequenceChainerT<TArguments> Submit(Flags flgContext = Flags::Undefined) { if(!!(flgContext & Flags::Complete)) { return Complete().Submit(flgContext & ~Flags::Complete); } else { std::apply([flgContext] (auto&... deps) { ( [] (auto& deps, Flags flgContext) { if constexpr(requires { deps.Submit(Flags::Undefined); }) deps.Submit(flgContext); } (deps, flgContext) , ... ); }, tDependants_); if(bChained_ && bSubmit_ && spSequence_) { bSubmit_ = false; if constexpr(TFunctionalSequence::IsSubmittable()) spSequence_->Submit(); } return { std::move(spSequence_), std::move(svrArguments_), false, bChained_, std::move(tDependants_) }; } } SequenceChainerT<TArguments> Cancel(Flags flgContext) { bSubmit_ = false; std::apply([flgContext] (auto&... deps) { ( [] (auto& deps, Flags flgContext) { if constexpr(requires { deps.Cancel(Flags::Undefined); }) deps.Cancel(flgContext); } (deps, flgContext) , ... ); }, tDependants_); if(flgContext != Flags::Undefined && spSequence_) spSequence_->Finalize(flgContext); return { std::move(spSequence_), std::move(svrArguments_), false, bChained_, std::move(tDependants_) }; } SequenceChainerT<TArguments> Defer() { bSubmit_ = false; return { std::move(spSequence_), std::move(svrArguments_), false, bChained_, std::move(tDependants_) }; } protected: bool bSubmit_ = false, bChained_ = true; SharedT<TFunctionalSequence> spSequence_; SharedT<ArgumentsVariantT> svrArguments_; DependantsT tDependants_; template<typename TFunctional> SequenceChainerT<ResultT<TFunctional>> Chain11(TFunctional&& fnTask, uint32_t idQueue, Flags flgContext) { auto svrResult = ResourcePolicyT::template AllocateShared<ResultVariantT<TFunctional>>(); if(bChained_) bChained_ = spSequence_->Enqueue( [fnTask = std::move(fnTask), svrArguments = svrArguments_, svrResult] (auto) mutable { if(std::holds_alternative<VoidT>(*svrArguments)) Except<>::Throw("Void arguments."); *svrResult = AsTuple(std::apply(fnTask, std::get<TArguments>(std::exchange(*svrArguments, VoidT { })))); }, idQueue, flgContext ); return { std::move(spSequence_), std::move(svrResult), std::exchange(bSubmit_, false), bChained_, std::move(tDependants_) }; } template<typename TFunctional> SequenceChainerT<ResultT<TFunctional>> Chain10(TFunctional&& fnTask, uint32_t idQueue, Flags flgContext) { if(bChained_) bChained_ = spSequence_->Enqueue( [fnTask = std::move(fnTask), svrArguments = svrArguments_] (auto) mutable { if(std::holds_alternative<VoidT>(*svrArguments)) Except<>::Throw("Void arguments."); std::apply(fnTask, std::get<TArguments>(std::exchange(*svrArguments, VoidT { }))); }, idQueue, flgContext ); return { std::move(spSequence_), std::exchange(bSubmit_, false), bChained_, std::move(tDependants_) }; } template<typename TFunctional> SequenceChainerT<ResultT<TFunctional>> Chain01(TFunctional&& fnTask, uint32_t idQueue, Flags flgContext) { auto svrResult = ResourcePolicyT::template AllocateShared<ResultVariantT<TFunctional>>(); if(bChained_) bChained_ = spSequence_->Enqueue( [fnTask = std::move(fnTask), svrResult] (auto) mutable { *svrResult = AsTuple(std::invoke(fnTask)); }, idQueue, flgContext ); return { std::move(spSequence_), std::move(svrResult), std::exchange(bSubmit_, false), bChained_, std::move(tDependants_) }; } template<typename TFunctional> SequenceChainerT<ResultT<TFunctional>> Chain00(TFunctional&& fnTask, uint32_t idQueue, Flags flgContext) { if(bChained_) bChained_ = spSequence_->Enqueue( [fnTask = std::move(fnTask)] (auto) mutable { std::invoke(fnTask); }, idQueue, flgContext ); return { std::move(spSequence_), std::exchange(bSubmit_, false), bChained_, std::move(tDependants_) }; } };//SequenceChainer }//FFPP #endif//FFPP_SEQUENCE_CHAINER_HPP