7#include "Stroika/Foundation/Execution/Common.h"
10#include "Stroika/Foundation/Execution/UserCanceledException.h"
11#include "Stroika/Foundation/Math/Common.h"
22 class ProgressMonitor::Rep_ :
public Memory::UseBlockAllocationIfAppropriate<Rep_> {
26 Synchronized<Containers::Sequence<shared_ptr<ChangedCallbackType>>> fCallbacks_;
27 atomic<bool> fCanceled_{
false};
28 atomic<ProgressRangeType> fCurrentProgress_{0.0};
29 Synchronized<CurrentTaskInfo> fCurrentTaskInfo_;
30 Thread::Ptr fWorkThread_;
38 inline ProgressMonitor::CurrentTaskInfo::CurrentTaskInfo (
const Characters::String& taskName,
const DataExchange::VariantValue& details)
49 inline ProgressMonitor::ProgressMonitor (
const shared_ptr<Rep_>& rep)
53 inline ProgressMonitor::ProgressRangeType ProgressMonitor::GetProgress ()
const
56 Ensure (0.0 <= fRep_->fCurrentProgress_ and fRep_->fCurrentProgress_ <= 1.0);
57 return fRep_->fCurrentProgress_;
62 return fRep_->fCurrentTaskInfo_;
64 inline ProgressMonitor::operator
Updater ()
74 inline ProgressMonitor::Updater::Updater (nullptr_t)
77 inline ProgressMonitor::Updater::Updater (
const Updater& parentTask, ProgressRangeType fromProg, ProgressRangeType toProg,
bool restoreTaskInfoOnDTOR)
78 : fRep_{parentTask.fRep_}
79 , fFromProg_{parentTask.fFromProg_ + fromProg * (parentTask.fToProg_ - parentTask.fFromProg_)}
80 , fToProg_{parentTask.fFromProg_ + toProg * (parentTask.fToProg_ - parentTask.fFromProg_)}
82 fFromProg_ = Math::PinToSpecialPoint (fFromProg_, parentTask.fFromProg_);
83 fToProg_ = Math::PinToSpecialPoint (fToProg_, parentTask.fToProg_);
84 Require ((0.0f <= parentTask.fFromProg_) and (parentTask.fFromProg_ <= fFromProg_) and (fFromProg_ < fToProg_) and
85 (fToProg_ <= parentTask.fToProg_) and (parentTask.fToProg_ <= 1.0f));
86 if (restoreTaskInfoOnDTOR and fRep_ !=
nullptr) {
87 fRestoreTaskInfo_ = fRep_->fCurrentTaskInfo_.load ();
91 const CurrentTaskInfo& taskInfo,
bool restoreTaskInfoOnDTOR)
92 : Updater{parentTask, fromProg, toProg, restoreTaskInfoOnDTOR}
94 SetCurrentTaskInfo (taskInfo);
100 inline ProgressMonitor::Updater::~Updater ()
102 if (fRestoreTaskInfo_) {
103 fRestoreTaskInfo_ = fRep_->fCurrentTaskInfo_.load ();
104 CallNotifyProgress_ ();
110 if (fRep_ !=
nullptr) {
112 p = Math::PinToSpecialPoint (Math::PinToSpecialPoint (p, 1.0f), 0.0f);
113 Assert (0.0 <= p and p <= 1.0);
114 p = fFromProg_ + p * (fToProg_ - fFromProg_);
115 p = Math::PinToSpecialPoint (Math::PinToSpecialPoint (p, 1.0f), 0.0f);
116 Assert (0.0 <= p and p <= 1.0);
118 p = Math::PinToSpecialPoint (p, fRep_->fCurrentProgress_.load ());
120 Require (p >= fRep_->fCurrentProgress_);
121 if (fRep_->fCurrentProgress_.exchange (p) != p) {
123 CallNotifyProgress_ ();
129 if (fRep_ !=
nullptr and fRep_->fCanceled_) {
130 if (fRep_->fWorkThread_ !=
nullptr) {
131 fRep_->fWorkThread_.Abort ();
133 Throw (UserCanceledException::kThe);
137 inline void ProgressMonitor::Updater::SetCurrentTaskInfo (
const CurrentTaskInfo& taskInfo)
139 if (fRep_ !=
nullptr) {
140 bool changed = fRep_->fCurrentTaskInfo_ != taskInfo;
141 fRep_->fCurrentTaskInfo_ = taskInfo;
143 CallNotifyProgress_ ();
148 inline void ProgressMonitor::Updater::SetCurrentProgressAndThrowIfCanceled (ProgressRangeType currentProgress)
150 if (fRep_ !=
nullptr) {
151 SetProgress (currentProgress);
161 template <
typename T>
166 using ProgressType = ProgressMonitor::ProgressRangeType;
169 , fProgress_{progress}
171 , fHighWaterMark_{fInitialSeek_}
173 , fEstimatedEnd_{
static_cast<ProgressType
> (fKnownEnd_.value_or (fInitialSeek_ + 1024))}
179 auto r = inherited::fRealIn.ReadOrThrow (intoBuffer, blockFlag);
181 fHighWaterMark_ = max (curOff, fHighWaterMark_);
182 if (not fKnownEnd_ and curOff > 0.75 * fEstimatedEnd_) {
183 fEstimatedEnd_ *= 1.5;
185 ProgressType progress =
186 static_cast<ProgressType
> (fHighWaterMark_ - fInitialSeek_) /
static_cast<ProgressType
> (fEstimatedEnd_ - fInitialSeek_);
187 if (progress > fLastProgressSent_) [[likely]] {
189 fLastProgressSent_ = progress;
196 optional<Streams::SeekOffsetType> fKnownEnd_;
197 ProgressType fEstimatedEnd_;
198 ProgressType fLastProgressSent_{0};
#define RequireNotNull(p)
#define WeakAssert(c)
A WeakAssert() is for things that aren't guaranteed to be true, but are overwhelmingly likely to be t...
NoDataAvailableHandling
If eDontBlock passed to most Stream APIs, then when the code would do a blocking read,...
nonvirtual void ThrowIfCanceled()
nonvirtual void SetProgress(ProgressRangeType p)
void CheckForInterruption()
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...
Streams::InputStream::Ptr< T > MakeInputStreamWithProgress(const Streams::InputStream::Ptr< T > &in, ProgressMonitor::Updater progress)