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 on the needed value. And, this method returns ProgressRange object
42 //! that takes responsibility of making the specified step at its destruction.
43 //! The ProgressRange can be used to create a new progress sub-scope.
45 //! It is important that sub-scope must have life time less than
46 //! the life time of its parent scope that provided the range.
48 //! The scope has a name that can be used in visualization of the progress.
49 //! It can be null. Note that the string is not copied, just pointer is stored.
50 //! So, the pointer must point to the string with life time
51 //! greater than that of the scope object.
53 //! In multithreaded programs, for each task running concurrently it is recommended
54 //! to create a separate progress scope. The same instance of the progress scope
55 //! must not be used concurrently from different threads.
57 //! A progress scope created with empty constructor is not connected to any
58 //! progress indicator, and passing the range created on it to any algorithm
59 //! allows it executing safely without progress indication.
61 //! Example of preparation of progress indicator:
64 //! Handle(Message_ProgressIndicator) aProgress = ...; // assume it can be null
65 //! func (Message_ProgressIndicator::Start (aProgress));
68 //! Example of usage in sequential process:
71 //! Message_ProgressScope aWholePS(aRange, "Whole process", 100);
73 //! // do one step taking 20%
74 //! func1 (aWholePS.Next (20)); // func1 will take 20% of the whole scope
75 //! if (aWholePS.UserBreak()) // exit prematurely if the user requested break
78 //! // ... do next step taking 50%
79 //! func2 (aWholePS.Next (50));
80 //! if (aWholePS.UserBreak())
84 //! Example of usage in nested cycle:
88 //! Message_ProgressScope anOuter (theProgress, "Outer", nbOuter);
89 //! for (Standard_Integer i = 0; i < nbOuter && anOuter.More(); i++)
92 //! Message_ProgressScope anInner (anOuter.Next(), "Inner", nbInner);
93 //! for (Standard_Integer j = 0; j < nbInner && anInner.More(); j++)
96 //! func (anInner.Next());
101 //! Example of use in function:
104 //! //! Implementation of iterative algorithm showing its progress
105 //! func (const Message_ProgressRange& theProgress)
107 //! // Create local scope covering the given progress range.
108 //! // Set this scope to count aNbSteps steps.
109 //! Message_ProgressScope aScope (theProgress, "", aNbSteps);
110 //! for (Standard_Integer i = 0; i < aNbSteps && aScope.More(); i++)
112 //! // Optional: pass range returned by method Next() to the nested algorithm
113 //! // to allow it to show its progress too (by creating its own scope object).
114 //! // In any case the progress will advance to the next step by the end of the func2 call.
115 //! func2 (aScope.Next());
120 //! Example of usage in parallel process:
126 //! Message_ProgressRange Range;
128 //! Task (const Data& theData, const Message_ProgressRange& theRange)
129 //! : Data (theData), Range (theRange) {}
133 //! void operator() (Task& theTask) const
135 //! // Note: it is essential that this method is executed only once
136 //! // for the same Task object
137 //! Message_ProgressScope aPS (theTask.Range, "Processing task", 1);
140 //! // ... process data
146 //! std::vector<Data> aData = ...;
147 //! std::vector<Task> aTasks;
149 //! Message_ProgressScope aPS (aRootRange, "Data processing", aData.size());
150 //! for (Standard_Integer i = 0; i < aData.size(); ++i)
151 //! aTasks.push_back (Task (aData[i], aPS.Next()));
153 //! OSD_Parallel::ForEach (aTasks.begin(), aTasks.end(), Functor());
156 class Message_ProgressScope
159 class NullString; //!< auxiliary type for passing NULL name to Message_ProgressScope constructor
160 public: //! @name Preparation methods
162 //! Creates dummy scope.
163 //! It can be safely passed to algorithms; no progress indication will be done.
164 Message_ProgressScope()
168 myPortion (1.), myMax (1.), myValue (0.),
174 //! Creates a new scope taking responsibility of the part of the progress
175 //! scale described by theRange. The new scope has own range from 0 to
176 //! theMax, which is mapped to the given range.
178 //! The topmost scope is created and owned by Message_ProgressIndicator
179 //! and its pointer is contained in the Message_ProgressRange returned by the Start() method of progress indicator.
181 //! @param theRange [in][out] range to fill (will be disarmed)
182 //! @param theName [in] new scope name
183 //! @param theMax [in] number of steps in scope
184 //! @param isInfinite [in] infinite flag
185 Message_ProgressScope (const Message_ProgressRange& theRange,
186 const TCollection_AsciiString& theName,
187 Standard_Real theMax,
188 Standard_Boolean isInfinite = false);
190 //! Creates a new scope taking responsibility of the part of the progress
191 //! scale described by theRange. The new scope has own range from 0 to
192 //! theMax, which is mapped to the given range.
194 //! The topmost scope is created and owned by Message_ProgressIndicator
195 //! and its pointer is contained in the Message_ProgressRange returned by the Start() method of progress indicator.
197 //! @param theRange [in][out] range to fill (will be disarmed)
198 //! @param theName [in] new scope name constant (will be stored by pointer with no deep copy)
199 //! @param theMax [in] number of steps in scope
200 //! @param isInfinite [in] infinite flag
202 Message_ProgressScope (const Message_ProgressRange& theRange,
203 const char (&theName)[N],
204 Standard_Real theMax,
205 Standard_Boolean isInfinite = false);
207 //! Creates a new scope taking responsibility of the part of the progress
208 //! scale described by theRange. The new scope has own range from 0 to
209 //! theMax, which is mapped to the given range.
211 //! The topmost scope is created and owned by Message_ProgressIndicator
212 //! and its pointer is contained in the Message_ProgressRange returned by the Start() method of progress indicator.
214 //! @param theRange [in][out] range to fill (will be disarmed)
215 //! @param theName [in] empty scope name (only NULL is accepted as argument)
216 //! @param theMax [in] number of steps in scope
217 //! @param isInfinite [in] infinite flag
218 Message_ProgressScope (const Message_ProgressRange& theRange,
219 const NullString* theName,
220 Standard_Real theMax,
221 Standard_Boolean isInfinite = false);
223 //! Sets the name of the scope.
224 void SetName (const TCollection_AsciiString& theName)
228 Standard::Free (myName);
232 if (!theName.IsEmpty())
235 myName = (char* )Standard::Allocate (theName.Length() + 1);
236 char* aName = (char* )myName;
237 memcpy (aName, theName.ToCString(), theName.Length());
238 aName[theName.Length()] = '\0';
242 //! Sets the name of the scope; can be null.
243 //! Note! Just pointer to the given string is copied,
244 //! so do not pass string from a temporary variable whose
245 //! lifetime is less than that of this object.
247 void SetName (const char (&theName)[N])
251 Standard::Free (myName);
257 public: //! @name Advance by iterations
259 //! Returns true if ProgressIndicator signals UserBreak
260 Standard_Boolean UserBreak() const;
262 //! Returns false if ProgressIndicator signals UserBreak
263 Standard_Boolean More() const
268 //! Advances position by specified step and returns the range
269 //! covering this step
270 Message_ProgressRange Next (Standard_Real theStep = 1.);
272 public: //! @name Auxiliary methods to use in ProgressIndicator
274 //! Force update of presentation of the progress indicator.
275 //! Should not be called concurrently.
278 //! Returns true if this progress scope is attached to some indicator.
279 Standard_Boolean IsActive() const
284 //! Returns the name of the scope (may be null).
285 //! Scopes with null name (e.g. root scope) should
286 //! be bypassed when reporting progress to the user.
287 Standard_CString Name() const
292 //! Returns parent scope (null for top-level scope)
293 const Message_ProgressScope* Parent() const
298 //! Returns the maximal value of progress in this scope
299 Standard_Real MaxValue() const
304 //! Returns the current value of progress in this scope.
305 //! If this scope is being advanced by sub-scoping, that value is
306 //! computed by mapping current global progress into this scope range.
307 Standard_Real Value() const
309 return myIsActive ? myValue : myMax;
312 //! Returns the infinite flag
313 Standard_Boolean IsInfinite() const
318 //! Get the portion of the indicator covered by this scope (from 0 to 1)
319 Standard_Real GetPortion() const
324 public: //! @name Destruction, allocation
326 //! Destructor - closes the scope and adds its scale to the total progress
327 ~Message_ProgressScope()
332 Standard::Free (myName);
338 //! Closes the scope and adds its scale to the total progress.
339 //! Relieved scope should not be used.
342 DEFINE_STANDARD_ALLOC
344 private: //! @name Internal methods
346 //! Creates a top-level scope with default range [0,1] and step 1.
347 //! Called only by Message_ProgressIndicator constructor.
348 Message_ProgressScope (Message_ProgressIndicator* theProgress);
350 //! Convert value from this scale to global one
351 Standard_Real localToGlobal(const Standard_Real theVal) const;
353 //! Convert value from global scale to this one
354 Standard_Real globalToLocal(const Standard_Real theVal) const;
357 //! Copy constructor is prohibited
358 Message_ProgressScope (const Message_ProgressScope& theOther);
360 //! Copy assignment is prohibited
361 Message_ProgressScope& operator= (const Message_ProgressScope& theOther);
365 Message_ProgressIndicator* myProgress; //!< Pointer to progress indicator instance
366 const Message_ProgressScope* myParent; //!< Pointer to parent scope
367 Standard_CString myName; //!< Name of the operation being done in this scope, or null
369 Standard_Real myPortion; //!< The portion of the global scale covered by this scope (from 0 to 1)
370 Standard_Real myMax; //!< Maximal value of progress in this scope
371 Standard_Real myValue; //!< Current position advanced within this scope [0, Max]
373 Standard_Boolean myIsActive; //!< flag indicating armed/disarmed state
374 Standard_Boolean myIsOwnName; //!< flag indicating if name was allocated or not
375 Standard_Boolean myIsInfinite; //!< Option to advance by hyperbolic law
378 friend class Message_ProgressIndicator;
379 friend class Message_ProgressRange;
382 #include <Message_ProgressRange.hxx>
384 //=======================================================================
385 //function : Message_ProgressScope
387 //=======================================================================
388 inline Message_ProgressScope::Message_ProgressScope (Message_ProgressIndicator* theProgress)
389 : myProgress(theProgress),
395 myIsActive(theProgress != NULL),
401 //=======================================================================
402 //function : Message_ProgressScope
404 //=======================================================================
405 inline Message_ProgressScope::Message_ProgressScope (const Message_ProgressRange& theRange,
406 const TCollection_AsciiString& theName,
407 Standard_Real theMax,
408 Standard_Boolean isInfinite)
409 : myProgress (theRange.myParentScope != NULL ? theRange.myParentScope->myProgress : NULL),
410 myParent (theRange.myParentScope),
412 myPortion (theRange.myDelta),
413 myMax (Max (1.e-6, theMax)), // protection against zero range
415 myIsActive (myProgress != NULL && !theRange.myWasUsed),
417 myIsInfinite (isInfinite)
420 Standard_ASSERT_VOID (! theRange.myWasUsed, "Message_ProgressRange is used to initialize more than one scope");
421 theRange.myWasUsed = true; // Disarm the range
424 //=======================================================================
425 //function : Message_ProgressScope
427 //=======================================================================
429 Message_ProgressScope::Message_ProgressScope (const Message_ProgressRange& theRange,
430 const char (&theName)[N],
431 Standard_Real theMax,
432 Standard_Boolean isInfinite)
433 : myProgress (theRange.myParentScope != NULL ? theRange.myParentScope->myProgress : NULL),
434 myParent (theRange.myParentScope),
436 myPortion (theRange.myDelta),
437 myMax (Max (1.e-6, theMax)), // protection against zero range
439 myIsActive (myProgress != NULL && !theRange.myWasUsed),
441 myIsInfinite (isInfinite)
443 Standard_ASSERT_VOID (! theRange.myWasUsed, "Message_ProgressRange is used to initialize more than one scope");
444 theRange.myWasUsed = true; // Disarm the range
447 //=======================================================================
448 //function : Message_ProgressScope
450 //=======================================================================
451 inline Message_ProgressScope::Message_ProgressScope (const Message_ProgressRange& theRange,
453 Standard_Real theMax,
454 Standard_Boolean isInfinite)
455 : myProgress (theRange.myParentScope != NULL ? theRange.myParentScope->myProgress : NULL),
456 myParent (theRange.myParentScope),
458 myPortion (theRange.myDelta),
459 myMax (Max (1.e-6, theMax)), // protection against zero range
461 myIsActive (myProgress != NULL && !theRange.myWasUsed),
463 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 //=======================================================================
472 //=======================================================================
473 inline void Message_ProgressScope::Relieve()
480 // Advance indicator to the end of the scope
481 Standard_Real aCurr = localToGlobal (myValue);
482 myValue = (myIsInfinite ? Precision::Infinite() : myMax);
483 Standard_Real aDelta = myPortion - aCurr;
486 myProgress->Increment (aDelta, *this);
488 Standard_ASSERT_VOID (myParent == 0 || myParent->myIsActive,
489 "Parent progress scope has been closed before child");
494 //=======================================================================
495 //function : UserBreak
497 //=======================================================================
498 inline Standard_Boolean Message_ProgressScope::UserBreak() const
500 return myProgress && myProgress->UserBreak();
503 //=======================================================================
506 //=======================================================================
507 inline Message_ProgressRange Message_ProgressScope::Next (Standard_Real theStep)
513 Standard_Real aCurr = localToGlobal (myValue);
514 Standard_Real aNext = localToGlobal (myValue += theStep);
515 Standard_Real aDelta = aNext - aCurr;
518 return Message_ProgressRange (*this, aDelta);
522 return Message_ProgressRange();
525 //=======================================================================
528 //=======================================================================
530 inline void Message_ProgressScope::Show ()
534 myProgress->Show (*this, Standard_True);
538 //=======================================================================
539 //function : localToGlobal
541 //=======================================================================
542 inline Standard_Real Message_ProgressScope::localToGlobal (const Standard_Real theVal) const
549 if (myMax - theVal < RealSmall())
551 return myPortion * theVal / myMax;
554 double x = theVal / myMax;
555 // return myPortion * ( 1. - std::exp ( -x ) ); // exponent
556 return myPortion * x / (1. + x); // hyperbola
559 //=======================================================================
560 //function : globalToLocal
562 //=======================================================================
564 inline Standard_Real Message_ProgressScope::globalToLocal (const Standard_Real theVal) const
566 // if at end of the scope (or behind), report the maximum
567 Standard_Real aDist = myPortion - theVal;
568 if (aDist <= Precision::Confusion())
569 return myIsInfinite ? Precision::Infinite() : myMax;
572 return myMax * theVal / myPortion;
574 // Standard_Real x = log (theVal / aDist); // exponent
575 Standard_Real x = theVal / aDist; // hyperbola
579 #endif // _Message_ProgressScope_HeaderFile