1 // Created on: 2002-02-22
2 // Created by: Andrey BETENEV
3 // Copyright (c) 2002-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #ifndef _Message_ProgressScope_HeaderFile
17 #define _Message_ProgressScope_HeaderFile
19 #include <Standard_Assert.hxx>
20 #include <Standard_TypeDef.hxx>
21 #include <Standard_DefineAlloc.hxx>
22 #include <Standard_Handle.hxx>
23 #include <Precision.hxx>
24 #include <TCollection_AsciiString.hxx>
26 class Message_ProgressRange;
27 class Message_ProgressIndicator;
29 //! Message_ProgressScope class provides convenient way to advance progress
30 //! indicator in context of complex program organized in hierarchical way,
31 //! where usually it is difficult (or even not possible) to consider process
32 //! as linear with fixed step.
34 //! On every level (sub-operation) in hierarchy of operations
35 //! the local instance of the Message_ProgressScope class is created.
36 //! It takes a part of the upper-level scope (via Message_ProgressRange) and provides
37 //! a way to consider this part as independent scale with locally defined range.
39 //! The position on the local scale may be advanced using the method Next(),
40 //! which allows iteration-like advancement. This method can take argument to
41 //! advance by the specified value (with default step equal to 1).
42 //! This method returns Message_ProgressRange object that takes responsibility
43 //! of making the specified step, either directly at its destruction or by
44 //! delegating this task to another sub-scope created from that range object.
46 //! It is important that sub-scope must have life time less than
47 //! the life time of its parent scope that provided the range.
48 //! The usage pattern is to create scope objects as local variables in the
49 //! functions that do the job, and pass range objects returned by Next() to
50 //! the functions of the lower level, to allow them creating their own scopes.
52 //! The scope has a name that can be used in visualization of the progress.
53 //! It can be null. Note that when C string literal is used as a name, then its
54 //! value is not copied, just pointer is stored. In other variants (char pointer
55 //! or a string class) the string is copied, which is additional overhead.
57 //! The same instance of the progress scope! must not be used concurrently from different threads.
58 //! For the algorithm running its tasks in parallel threads, a common scope is
59 //! created before the parallel execution, and the range objects produced by method
60 //! Next() are used to initialise the data pertinent to each task.
61 //! Then the progress is advanced within each task using its own range object.
62 //! See example below.
64 //! Note that while a range of the scope is specified using Standard_Real
65 //! (double) parameter, it is expected to be a positive integer value.
66 //! If the range is not an integer, method Next() shall be called with
67 //! explicit step argument, and the rounded value returned by method Value()
68 //! may be not coherent with the step and range.
70 //! A scope can be created with option "infinite". This is useful when
71 //! the number of steps is not known by the time of the scope creation.
72 //! In this case the progress will be advanced logarithmically, approaching
73 //! the end of the scope at infinite number of steps. The parameter Max
74 //! for infinite scope indicates number of steps corresponding to mid-range.
76 //! A progress scope created with empty constructor is not connected to any
77 //! progress indicator, and passing the range created on it to any algorithm
78 //! allows it executing safely without actual progress indication.
80 //! Example of preparation of progress indicator:
83 //! Handle(Message_ProgressIndicator) aProgress = ...; // assume it can be null
84 //! func (Message_ProgressIndicator::Start (aProgress));
87 //! Example of usage in sequential process:
90 //! Message_ProgressScope aWholePS(aRange, "Whole process", 100);
92 //! // do one step taking 20%
93 //! func1 (aWholePS.Next (20)); // func1 will take 20% of the whole scope
94 //! if (aWholePS.UserBreak()) // exit prematurely if the user requested break
97 //! // ... do next step taking 50%
98 //! func2 (aWholePS.Next (50));
99 //! if (aWholePS.UserBreak())
103 //! Example of usage in nested cycle:
107 //! Message_ProgressScope anOuter (theProgress, "Outer", nbOuter);
108 //! for (Standard_Integer i = 0; i < nbOuter && anOuter.More(); i++)
111 //! Message_ProgressScope anInner (anOuter.Next(), "Inner", nbInner);
112 //! for (Standard_Integer j = 0; j < nbInner && anInner.More(); j++)
115 //! func (anInner.Next());
120 //! Example of use in function:
123 //! //! Implementation of iterative algorithm showing its progress
124 //! func (const Message_ProgressRange& theProgress)
126 //! // Create local scope covering the given progress range.
127 //! // Set this scope to count aNbSteps steps.
128 //! Message_ProgressScope aScope (theProgress, "", aNbSteps);
129 //! for (Standard_Integer i = 0; i < aNbSteps && aScope.More(); i++)
131 //! // Optional: pass range returned by method Next() to the nested algorithm
132 //! // to allow it to show its progress too (by creating its own scope object).
133 //! // In any case the progress will advance to the next step by the end of the func2 call.
134 //! func2 (aScope.Next());
139 //! Example of usage in parallel process:
145 //! Message_ProgressRange Range;
147 //! Task (const Data& theData, const Message_ProgressRange& theRange)
148 //! : Data (theData), Range (theRange) {}
152 //! void operator() (Task& theTask) const
154 //! // Note: it is essential that this method is executed only once for the same Task object
155 //! Message_ProgressScope aPS (theTask.Range, NULL, theTask.Data.NbItems);
156 //! for (Standard_Integer i = 0; i < theTask.Data.NbSteps && aPS.More(); i++)
158 //! do_job (theTask.Data.Item[i], aPS.Next());
164 //! std::vector<Data> aData = ...;
165 //! std::vector<Task> aTasks;
167 //! Message_ProgressScope aPS (aRootRange, "Data processing", aData.size());
168 //! for (Standard_Integer i = 0; i < aData.size(); ++i)
169 //! aTasks.push_back (Task (aData[i], aPS.Next()));
171 //! OSD_Parallel::ForEach (aTasks.begin(), aTasks.end(), Functor());
175 //! For lightweight algorithms that do not need advancing the progress
176 //! within individual tasks the code can be simplified to avoid inner scopes:
181 //! void operator() (Task& theTask) const
183 //! if (theTask.Range.More())
185 //! do_job (theTask.Data);
186 //! // advance the progress
187 //! theTask.Range.Close();
192 class Message_ProgressScope
195 class NullString; //!< auxiliary type for passing NULL name to Message_ProgressScope constructor
196 public: //! @name Preparation methods
198 //! Creates dummy scope.
199 //! It can be safely passed to algorithms; no progress indication will be done.
200 Message_ProgressScope()
213 //! Creates a new scope taking responsibility of the part of the progress
214 //! scale described by theRange. The new scope has own range from 0 to
215 //! theMax, which is mapped to the given range.
217 //! The topmost scope is created and owned by Message_ProgressIndicator
218 //! and its pointer is contained in the Message_ProgressRange returned by the Start() method of progress indicator.
220 //! @param theRange [in][out] range to fill (will be disarmed)
221 //! @param theName [in] new scope name
222 //! @param theMax [in] number of steps in scope
223 //! @param isInfinite [in] infinite flag
224 Message_ProgressScope (const Message_ProgressRange& theRange,
225 const TCollection_AsciiString& theName,
226 Standard_Real theMax,
227 Standard_Boolean isInfinite = false);
229 //! Creates a new scope taking responsibility of the part of the progress
230 //! scale described by theRange. The new scope has own range from 0 to
231 //! theMax, which is mapped to the given range.
233 //! The topmost scope is created and owned by Message_ProgressIndicator
234 //! and its pointer is contained in the Message_ProgressRange returned by the Start() method of progress indicator.
236 //! @param theRange [in][out] range to fill (will be disarmed)
237 //! @param theName [in] new scope name constant (will be stored by pointer with no deep copy)
238 //! @param theMax [in] number of steps in scope
239 //! @param isInfinite [in] infinite flag
241 Message_ProgressScope (const Message_ProgressRange& theRange,
242 const char (&theName)[N],
243 Standard_Real theMax,
244 Standard_Boolean isInfinite = false);
246 //! Creates a new scope taking responsibility of the part of the progress
247 //! scale described by theRange. The new scope has own range from 0 to
248 //! theMax, which is mapped to the given range.
250 //! The topmost scope is created and owned by Message_ProgressIndicator
251 //! and its pointer is contained in the Message_ProgressRange returned by the Start() method of progress indicator.
253 //! @param theRange [in][out] range to fill (will be disarmed)
254 //! @param theName [in] empty scope name (only NULL is accepted as argument)
255 //! @param theMax [in] number of steps in scope
256 //! @param isInfinite [in] infinite flag
257 Message_ProgressScope (const Message_ProgressRange& theRange,
258 const NullString* theName,
259 Standard_Real theMax,
260 Standard_Boolean isInfinite = false);
262 //! Sets the name of the scope.
263 void SetName (const TCollection_AsciiString& theName)
267 Standard::Free (myName);
271 if (!theName.IsEmpty())
274 myName = (char* )Standard::Allocate (theName.Length() + 1);
275 char* aName = (char* )myName;
276 memcpy (aName, theName.ToCString(), theName.Length());
277 aName[theName.Length()] = '\0';
281 //! Sets the name of the scope; can be null.
282 //! Note! Just pointer to the given string is copied,
283 //! so do not pass string from a temporary variable whose
284 //! lifetime is less than that of this object.
286 void SetName (const char (&theName)[N])
290 Standard::Free (myName);
296 public: //! @name Advance by iterations
298 //! Returns true if ProgressIndicator signals UserBreak
299 Standard_Boolean UserBreak() const;
301 //! Returns false if ProgressIndicator signals UserBreak
302 Standard_Boolean More() const
307 //! Advances position by specified step and returns the range
308 //! covering this step
309 Message_ProgressRange Next (Standard_Real theStep = 1.);
311 public: //! @name Auxiliary methods to use in ProgressIndicator
313 //! Force update of presentation of the progress indicator.
314 //! Should not be called concurrently.
317 //! Returns true if this progress scope is attached to some indicator.
318 Standard_Boolean IsActive() const
323 //! Returns the name of the scope (may be null).
324 //! Scopes with null name (e.g. root scope) should
325 //! be bypassed when reporting progress to the user.
326 Standard_CString Name() const
331 //! Returns parent scope (null for top-level scope)
332 const Message_ProgressScope* Parent() const
337 //! Returns the maximal value of progress in this scope
338 Standard_Real MaxValue() const
343 //! Returns the current value of progress in this scope.
345 //! The value is computed by mapping current global progress into
346 //! this scope range; the result is rounded up to integer.
347 //! Note that if MaxValue() is not an integer, Value() can be
348 //! greater than MaxValue() due to that rounding.
350 //! This method should not be called concurrently while the progress
351 //! is advancing, except from implementation of method Show() in
352 //! descendant of Message_ProgressIndicator.
353 Standard_Real Value() const;
355 //! Returns the infinite flag
356 Standard_Boolean IsInfinite() const
361 //! Get the portion of the indicator covered by this scope (from 0 to 1)
362 Standard_Real GetPortion() const
367 public: //! @name Destruction, allocation
369 //! Destructor - closes the scope and adds its scale to the total progress
370 ~Message_ProgressScope()
375 Standard::Free (myName);
381 //! Closes the scope and advances the progress to its end.
382 //! Closed scope should not be used.
385 DEFINE_STANDARD_ALLOC
387 private: //! @name Internal methods
389 //! Creates a top-level scope with default range [0,1] and step 1.
390 //! Called only by Message_ProgressIndicator constructor.
391 Message_ProgressScope (Message_ProgressIndicator* theProgress);
393 //! Convert value from this scope to global scale, but disregarding
394 //! start position of the scope, in the range [0, myPortion]
395 Standard_Real localToGlobal(const Standard_Real theVal) const;
398 //! Copy constructor is prohibited
399 Message_ProgressScope (const Message_ProgressScope& theOther);
401 //! Copy assignment is prohibited
402 Message_ProgressScope& operator= (const Message_ProgressScope& theOther);
406 Message_ProgressIndicator* myProgress; //!< Pointer to progress indicator instance
407 const Message_ProgressScope* myParent; //!< Pointer to parent scope
408 Standard_CString myName; //!< Name of the operation being done in this scope, or null
410 Standard_Real myStart; //!< Start position on the global scale [0, 1]
411 Standard_Real myPortion; //!< The portion of the global scale covered by this scope [0, 1]
413 Standard_Real myMax; //!< Maximal value of progress in this scope
414 Standard_Real myValue; //!< Current position advanced within this scope [0, Max]
416 Standard_Boolean myIsActive; //!< flag indicating armed/disarmed state
417 Standard_Boolean myIsOwnName; //!< flag indicating if name was allocated or not
418 Standard_Boolean myIsInfinite; //!< Option to advance by hyperbolic law
421 friend class Message_ProgressIndicator;
422 friend class Message_ProgressRange;
425 #include <Message_ProgressRange.hxx>
427 //=======================================================================
428 //function : Message_ProgressScope
430 //=======================================================================
431 inline Message_ProgressScope::Message_ProgressScope (Message_ProgressIndicator* theProgress)
432 : myProgress(theProgress),
439 myIsActive(theProgress != NULL),
445 //=======================================================================
446 //function : Message_ProgressScope
448 //=======================================================================
449 inline Message_ProgressScope::Message_ProgressScope (const Message_ProgressRange& theRange,
450 const TCollection_AsciiString& theName,
451 Standard_Real theMax,
452 Standard_Boolean isInfinite)
453 : myProgress (theRange.myParentScope != NULL ? theRange.myParentScope->myProgress : NULL),
454 myParent (theRange.myParentScope),
456 myStart (theRange.myStart),
457 myPortion (theRange.myDelta),
458 myMax (Max (1.e-6, theMax)), // protection against zero range
460 myIsActive (myProgress != NULL && !theRange.myWasUsed),
462 myIsInfinite (isInfinite)
465 Standard_ASSERT_VOID (! theRange.myWasUsed, "Message_ProgressRange is used to initialize more than one scope");
466 theRange.myWasUsed = true; // Disarm the range
469 //=======================================================================
470 //function : Message_ProgressScope
472 //=======================================================================
474 Message_ProgressScope::Message_ProgressScope (const Message_ProgressRange& theRange,
475 const char (&theName)[N],
476 Standard_Real theMax,
477 Standard_Boolean isInfinite)
478 : myProgress (theRange.myParentScope != NULL ? theRange.myParentScope->myProgress : NULL),
479 myParent (theRange.myParentScope),
481 myStart (theRange.myStart),
482 myPortion (theRange.myDelta),
483 myMax (Max (1.e-6, theMax)), // protection against zero range
485 myIsActive (myProgress != NULL && !theRange.myWasUsed),
487 myIsInfinite (isInfinite)
489 Standard_ASSERT_VOID (! theRange.myWasUsed, "Message_ProgressRange is used to initialize more than one scope");
490 theRange.myWasUsed = true; // Disarm the range
493 //=======================================================================
494 //function : Message_ProgressScope
496 //=======================================================================
497 inline Message_ProgressScope::Message_ProgressScope (const Message_ProgressRange& theRange,
499 Standard_Real theMax,
500 Standard_Boolean isInfinite)
501 : myProgress (theRange.myParentScope != NULL ? theRange.myParentScope->myProgress : NULL),
502 myParent (theRange.myParentScope),
504 myStart (theRange.myStart),
505 myPortion (theRange.myDelta),
506 myMax (Max (1.e-6, theMax)), // protection against zero range
508 myIsActive (myProgress != NULL && !theRange.myWasUsed),
510 myIsInfinite (isInfinite)
512 Standard_ASSERT_VOID (! theRange.myWasUsed, "Message_ProgressRange is used to initialize more than one scope");
513 theRange.myWasUsed = true; // Disarm the range
516 //=======================================================================
519 //=======================================================================
520 inline void Message_ProgressScope::Close()
527 // Advance indicator to the end of the scope
528 Standard_Real aCurr = localToGlobal (myValue);
529 myValue = (myIsInfinite ? Precision::Infinite() : myMax);
530 Standard_Real aDelta = myPortion - aCurr;
533 myProgress->Increment (aDelta, *this);
535 Standard_ASSERT_VOID (myParent == 0 || myParent->myIsActive,
536 "Parent progress scope has been closed before child");
541 //=======================================================================
542 //function : UserBreak
544 //=======================================================================
545 inline Standard_Boolean Message_ProgressScope::UserBreak() const
547 return myProgress && myProgress->UserBreak();
550 //=======================================================================
553 //=======================================================================
554 inline Message_ProgressRange Message_ProgressScope::Next (Standard_Real theStep)
556 if (myIsActive && theStep > 0.)
558 Standard_Real aCurr = localToGlobal(myValue);
559 Standard_Real aNext = localToGlobal(myValue += theStep);
560 Standard_Real aDelta = aNext - aCurr;
563 return Message_ProgressRange(*this, myStart + aCurr, aDelta);
566 return Message_ProgressRange();
569 //=======================================================================
572 //=======================================================================
574 inline void Message_ProgressScope::Show ()
578 myProgress->Show (*this, Standard_True);
582 //=======================================================================
583 //function : localToGlobal
585 //=======================================================================
586 inline Standard_Real Message_ProgressScope::localToGlobal (const Standard_Real theVal) const
593 if (myMax - theVal < RealSmall())
595 return myPortion * theVal / myMax;
598 double x = theVal / myMax;
599 // return myPortion * ( 1. - std::exp ( -x ) ); // exponent
600 return myPortion * x / (1. + x); // hyperbola
603 //=======================================================================
606 //=======================================================================
608 inline Standard_Real Message_ProgressScope::Value () const
612 return myIsInfinite ? Precision::Infinite() : myMax;
615 // get current progress on the global scale counted
616 // from the start of this scope
617 Standard_Real aVal = myProgress->GetPosition() - myStart;
619 // if progress has not reached yet the start of this scope, return 0
623 // if at end of the scope (or behind), report the maximum
624 Standard_Real aDist = myPortion - aVal;
625 if (aDist <= Precision::Confusion())
626 return myIsInfinite ? Precision::Infinite() : myMax;
628 // map the value to the range of this scope [0, Max],
629 // rounding up to integer, with small correction applied
630 // to avoid rounding errors
631 return std::ceil (myMax * aVal / (myIsInfinite ? aDist : myPortion) - Precision::Confusion());
634 #endif // _Message_ProgressScope_HeaderFile