7#include "Stroika/Foundation/Math/Common.h"
14#include "UserCanceledException.h"
23 class ProgressMonitor::Rep_ :
public Memory::UseBlockAllocationIfAppropriate<Rep_> {
27 Synchronized<Containers::Sequence<shared_ptr<ChangedCallbackType>>> fCallbacks_;
28 atomic<bool> fCanceled_{
false};
29 atomic<ProgressRangeType> fCurrentProgress_{0.0};
30 Synchronized<CurrentTaskInfo> fCurrentTaskInfo_;
31 Thread::Ptr fWorkThread_;
39 inline ProgressMonitor::CurrentTaskInfo::CurrentTaskInfo (
const Characters::String& taskName,
const DataExchange::VariantValue& details)
50 inline ProgressMonitor::ProgressMonitor (
const shared_ptr<Rep_>& rep)
54 inline ProgressMonitor::ProgressRangeType ProgressMonitor::GetProgress ()
const
57 Ensure (0.0 <= fRep_->fCurrentProgress_ and fRep_->fCurrentProgress_ <= 1.0);
58 return fRep_->fCurrentProgress_;
63 return fRep_->fCurrentTaskInfo_;
65 inline ProgressMonitor::operator
Updater ()
75 inline ProgressMonitor::Updater::Updater (nullptr_t)
78 inline ProgressMonitor::Updater::Updater (
const Updater& parentTask, ProgressRangeType fromProg, ProgressRangeType toProg,
bool restoreTaskInfoOnDTOR)
79 : fRep_{parentTask.fRep_}
80 , fFromProg_{parentTask.fFromProg_ + fromProg * (parentTask.fToProg_ - parentTask.fFromProg_)}
81 , fToProg_{parentTask.fFromProg_ + toProg * (parentTask.fToProg_ - parentTask.fFromProg_)}
83 fFromProg_ = Math::PinToSpecialPoint (fFromProg_, parentTask.fFromProg_);
84 fToProg_ = Math::PinToSpecialPoint (fToProg_, parentTask.fToProg_);
85 Require ((0.0f <= parentTask.fFromProg_) and (parentTask.fFromProg_ <= fFromProg_) and (fFromProg_ < fToProg_) and
86 (fToProg_ <= parentTask.fToProg_) and (parentTask.fToProg_ <= 1.0f));
87 if (restoreTaskInfoOnDTOR and fRep_ !=
nullptr) {
88 fRestoreTaskInfo_ = fRep_->fCurrentTaskInfo_.load ();
92 const CurrentTaskInfo& taskInfo,
bool restoreTaskInfoOnDTOR)
93 : Updater{parentTask, fromProg, toProg, restoreTaskInfoOnDTOR}
95 SetCurrentTaskInfo (taskInfo);
101 inline ProgressMonitor::Updater::~Updater ()
103 if (fRestoreTaskInfo_) {
104 fRestoreTaskInfo_ = fRep_->fCurrentTaskInfo_.load ();
105 CallNotifyProgress_ ();
111 if (fRep_ !=
nullptr) {
113 p = Math::PinToSpecialPoint (Math::PinToSpecialPoint (p, 1.0f), 0.0f);
114 Assert (0.0 <= p and p <= 1.0);
115 p = fFromProg_ + p * (fToProg_ - fFromProg_);
116 p = Math::PinToSpecialPoint (Math::PinToSpecialPoint (p, 1.0f), 0.0f);
117 Assert (0.0 <= p and p <= 1.0);
119 p = Math::PinToSpecialPoint (p, fRep_->fCurrentProgress_.load ());
121 Require (p >= fRep_->fCurrentProgress_);
122 if (fRep_->fCurrentProgress_.exchange (p) != p) {
124 CallNotifyProgress_ ();
130 if (fRep_ !=
nullptr and fRep_->fCanceled_) {
131 if (fRep_->fWorkThread_ !=
nullptr) {
132 fRep_->fWorkThread_.Abort ();
134 Throw (UserCanceledException::kThe);
138 inline void ProgressMonitor::Updater::SetCurrentTaskInfo (
const CurrentTaskInfo& taskInfo)
140 if (fRep_ !=
nullptr) {
141 bool changed = fRep_->fCurrentTaskInfo_ != taskInfo;
142 fRep_->fCurrentTaskInfo_ = taskInfo;
144 CallNotifyProgress_ ();
149 inline void ProgressMonitor::Updater::SetCurrentProgressAndThrowIfCanceled (ProgressRangeType currentProgress)
151 if (fRep_ !=
nullptr) {
152 SetProgress (currentProgress);
162 template <
typename T>
167 using ProgressType = ProgressMonitor::ProgressRangeType;
170 , fProgress_{progress}
172 , fHighWaterMark_{fInitialSeek_}
174 , fEstimatedEnd_{
static_cast<ProgressType
> (fKnownEnd_.value_or (fInitialSeek_ + 1024))}
180 auto r = inherited::fRealIn.ReadOrThrow (intoBuffer, blockFlag);
182 fHighWaterMark_ = max (curOff, fHighWaterMark_);
183 if (not fKnownEnd_ and curOff > 0.75 * fEstimatedEnd_) {
184 fEstimatedEnd_ *= 1.5;
186 ProgressType progress =
187 static_cast<ProgressType
> (fHighWaterMark_ - fInitialSeek_) /
static_cast<ProgressType
> (fEstimatedEnd_ - fInitialSeek_);
188 if (progress > fLastProgressSent_) [[likely]] {
190 fLastProgressSent_ = progress;
197 optional<Streams::SeekOffsetType> fKnownEnd_;
198 ProgressType fEstimatedEnd_;
199 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)