5652e6859b6ed6aadffa3b7b9ce813130da2448e
[occt.git] / src / Message / Message_ProgressScope.hxx
1 // Created on: 2002-02-22
2 // Created by: Andrey BETENEV
3 // Copyright (c) 2002-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
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.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #ifndef _Message_ProgressScope_HeaderFile
17 #define _Message_ProgressScope_HeaderFile
18
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>
25
26 class Message_ProgressRange;
27 class Message_ProgressIndicator;
28
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.
33 //!
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.
38 //!
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.
45 //!
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.
51 //!
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.
56 //!
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.
63 //!
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.
69 //!
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.
75 //!
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.
79 //!
80 //! Example of preparation of progress indicator:
81 //!
82 //! @code{.cpp}
83 //!   Handle(Message_ProgressIndicator) aProgress = ...; // assume it can be null
84 //!   func (Message_ProgressIndicator::Start (aProgress));
85 //! @endcode
86 //!
87 //! Example of usage in sequential process:
88 //!
89 //! @code{.cpp}
90 //!   Message_ProgressScope aWholePS(aRange, "Whole process", 100);
91 //!
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
95 //!     return;
96 //!
97 //!   // ... do next step taking 50%
98 //!   func2 (aWholePS.Next (50));
99 //!   if (aWholePS.UserBreak())
100 //!     return;
101 //! @endcode
102 //!
103 //! Example of usage in nested cycle:
104 //!
105 //! @code{.cpp}
106 //!   // Outer cycle
107 //!   Message_ProgressScope anOuter (theProgress, "Outer", nbOuter);
108 //!   for (Standard_Integer i = 0; i < nbOuter && anOuter.More(); i++)
109 //!   {
110 //!     // Inner cycle
111 //!     Message_ProgressScope anInner (anOuter.Next(), "Inner", nbInner);
112 //!     for (Standard_Integer j = 0; j < nbInner && anInner.More(); j++)
113 //!     {
114 //!       // Cycle body
115 //!       func (anInner.Next());
116 //!     }
117 //!   }
118 //! @endcode
119 //!
120 //! Example of use in function:
121 //!
122 //! @code{.cpp}
123 //! //! Implementation of iterative algorithm showing its progress
124 //! func (const Message_ProgressRange& theProgress)
125 //! {
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++)
130 //!   {
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());
135 //!   }
136 //! }
137 //! @endcode
138 //!
139 //! Example of usage in parallel process:
140 //!
141 //! @code{.cpp}
142 //! struct Task
143 //! {
144 //!   Data& Data;
145 //!   Message_ProgressRange Range;
146 //!
147 //!   Task (const Data& theData, const Message_ProgressRange& theRange)
148 //!     : Data (theData), Range (theRange) {}
149 //! };
150 //! struct Functor
151 //! {
152 //!   void operator() (Task& theTask) const
153 //!   {
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++)
157 //!     {
158 //!       do_job (theTask.Data.Item[i], aPS.Next());
159 //!     }
160 //!   }
161 //! };
162 //! ...
163 //! {
164 //!   std::vector<Data> aData = ...;
165 //!   std::vector<Task> aTasks;
166 //!
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()));
170 //!   
171 //!   OSD_Parallel::ForEach (aTasks.begin(), aTasks.end(), Functor());
172 //! }
173 //! @endcode
174 //!
175 //! For lightweight algorithms that do not need advancing the progress 
176 //! within individual tasks the code can be simplified to avoid inner scopes:
177 //!
178 //! @code
179 //! struct Functor
180 //! {
181 //!   void operator() (Task& theTask) const
182 //!   {
183 //!     if (theTask.Range.More())
184 //!     {
185 //!       do_job (theTask.Data);
186 //!       // advance the progress
187 //!       theTask.Range.Close();
188 //!     }
189 //!   }
190 //! };
191 //! @endcode
192 class Message_ProgressScope
193 {
194 public:
195   class NullString; //!< auxiliary type for passing NULL name to Message_ProgressScope constructor
196 public: //! @name Preparation methods
197
198   //! Creates dummy scope.
199   //! It can be safely passed to algorithms; no progress indication will be done.
200   Message_ProgressScope()
201   : myProgress (0),
202     myParent (0),
203     myName (0),
204     myStart (0.),
205     myPortion (1.),
206     myMax (1.),
207     myValue (0.),
208     myIsActive (false),
209     myIsOwnName (false),
210     myIsInfinite (false)
211   {}
212
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.
216   //!
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.
219   //!
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);
228
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.
232   //!
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.
235   //!
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
240   template<size_t N>
241   Message_ProgressScope (const Message_ProgressRange& theRange,
242                          const char (&theName)[N],
243                          Standard_Real theMax,
244                          Standard_Boolean isInfinite = false);
245
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.
249   //!
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.
252   //!
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);
261
262   //! Sets the name of the scope.
263   void SetName (const TCollection_AsciiString& theName)
264   {
265     if (myIsOwnName)
266     {
267       Standard::Free (myName);
268       myIsOwnName = false;
269     }
270     myName = NULL;
271     if (!theName.IsEmpty())
272     {
273       myIsOwnName = true;
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';
278     }
279   }
280
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.
285   template<size_t N>
286   void SetName (const char (&theName)[N])
287   {
288     if (myIsOwnName)
289     {
290       Standard::Free (myName);
291       myIsOwnName = false;
292     }
293     myName = theName;
294   }
295
296 public: //! @name Advance by iterations
297
298   //! Returns true if ProgressIndicator signals UserBreak
299   Standard_Boolean UserBreak() const;
300
301   //! Returns false if ProgressIndicator signals UserBreak
302   Standard_Boolean More() const
303   {
304     return !UserBreak();
305   }
306
307   //! Advances position by specified step and returns the range
308   //! covering this step
309   Message_ProgressRange Next (Standard_Real theStep = 1.);
310
311 public: //! @name Auxiliary methods to use in ProgressIndicator
312
313   //! Force update of presentation of the progress indicator.
314   //! Should not be called concurrently.
315   void Show();
316
317   //! Returns true if this progress scope is attached to some indicator.
318   Standard_Boolean IsActive() const
319   {
320     return myIsActive;
321   }
322
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
327   {
328     return myName;
329   }
330
331   //! Returns parent scope (null for top-level scope)
332   const Message_ProgressScope* Parent() const
333   {
334     return myParent;
335   }
336
337   //! Returns the maximal value of progress in this scope
338   Standard_Real MaxValue() const
339   {
340     return myMax;
341   }
342
343   //! Returns the current value of progress in this scope.
344   //!
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.
349   //!
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;
354
355   //! Returns the infinite flag
356   Standard_Boolean IsInfinite() const
357   {
358     return myIsInfinite;
359   }
360
361   //! Get the portion of the indicator covered by this scope (from 0 to 1)
362   Standard_Real GetPortion() const
363   {
364     return myPortion;
365   }
366
367 public: //! @name Destruction, allocation
368
369   //! Destructor - closes the scope and adds its scale to the total progress
370   ~Message_ProgressScope()
371   {
372     Close();
373     if (myIsOwnName)
374     {
375       Standard::Free (myName);
376       myIsOwnName = false;
377       myName = NULL;
378     }
379   }
380
381   //! Closes the scope and advances the progress to its end.
382   //! Closed scope should not be used.
383   void Close();
384
385   DEFINE_STANDARD_ALLOC
386
387 private: //! @name Internal methods
388   
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);
392
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;
396
397 private:
398   //! Copy constructor is prohibited
399   Message_ProgressScope (const Message_ProgressScope& theOther);
400
401   //! Copy assignment is prohibited
402   Message_ProgressScope& operator= (const Message_ProgressScope& theOther);
403
404 private:
405
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
409
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]
412
413   Standard_Real      myMax;         //!< Maximal value of progress in this scope
414   Standard_Real      myValue;       //!< Current position advanced within this scope [0, Max]
415
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
419
420 private:
421   friend class Message_ProgressIndicator;
422   friend class Message_ProgressRange;
423 };
424
425 #include <Message_ProgressRange.hxx>
426
427 //=======================================================================
428 //function : Message_ProgressScope
429 //purpose  :
430 //=======================================================================
431 inline Message_ProgressScope::Message_ProgressScope (Message_ProgressIndicator* theProgress)
432 : myProgress(theProgress),
433   myParent(0),
434   myName(0),
435   myStart(0.),
436   myPortion(1.),
437   myMax(1.),
438   myValue(0.),
439   myIsActive(theProgress != NULL),
440   myIsOwnName(false),
441   myIsInfinite(false)
442 {
443 }
444
445 //=======================================================================
446 //function : Message_ProgressScope
447 //purpose  :
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),
455   myName (NULL),
456   myStart (theRange.myStart),
457   myPortion (theRange.myDelta),
458   myMax (Max (1.e-6, theMax)), // protection against zero range
459   myValue (0.),
460   myIsActive (myProgress != NULL && !theRange.myWasUsed),
461   myIsOwnName (false),
462   myIsInfinite (isInfinite)
463 {
464   SetName (theName);
465   Standard_ASSERT_VOID (! theRange.myWasUsed, "Message_ProgressRange is used to initialize more than one scope");
466   theRange.myWasUsed = true; // Disarm the range
467 }
468
469 //=======================================================================
470 //function : Message_ProgressScope
471 //purpose  :
472 //=======================================================================
473 template<size_t N>
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),
480   myName (theName),
481   myStart (theRange.myStart),
482   myPortion (theRange.myDelta),
483   myMax (Max (1.e-6, theMax)), // protection against zero range
484   myValue (0.),
485   myIsActive (myProgress != NULL && !theRange.myWasUsed),
486   myIsOwnName (false),
487   myIsInfinite (isInfinite)
488 {
489   Standard_ASSERT_VOID (! theRange.myWasUsed, "Message_ProgressRange is used to initialize more than one scope");
490   theRange.myWasUsed = true; // Disarm the range
491 }
492
493 //=======================================================================
494 //function : Message_ProgressScope
495 //purpose  :
496 //=======================================================================
497 inline Message_ProgressScope::Message_ProgressScope (const Message_ProgressRange& theRange,
498                                                      const NullString* ,
499                                                      Standard_Real theMax,
500                                                      Standard_Boolean isInfinite)
501 : myProgress (theRange.myParentScope != NULL ? theRange.myParentScope->myProgress : NULL),
502   myParent (theRange.myParentScope),
503   myName (NULL),
504   myStart (theRange.myStart),
505   myPortion (theRange.myDelta),
506   myMax (Max (1.e-6, theMax)), // protection against zero range
507   myValue (0.),
508   myIsActive (myProgress != NULL && !theRange.myWasUsed),
509   myIsOwnName (false),
510   myIsInfinite (isInfinite)
511 {
512   Standard_ASSERT_VOID (! theRange.myWasUsed, "Message_ProgressRange is used to initialize more than one scope");
513   theRange.myWasUsed = true; // Disarm the range
514 }
515
516 //=======================================================================
517 //function : Close
518 //purpose  :
519 //=======================================================================
520 inline void Message_ProgressScope::Close()
521 {
522   if (!myIsActive)
523   {
524     return;
525   }
526
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;
531   if (aDelta > 0.)
532   {
533     myProgress->Increment (aDelta, *this);
534   }
535   Standard_ASSERT_VOID (myParent == 0 || myParent->myIsActive,
536     "Parent progress scope has been closed before child");
537
538   myIsActive = false;
539 }
540
541 //=======================================================================
542 //function : UserBreak
543 //purpose  :
544 //=======================================================================
545 inline Standard_Boolean Message_ProgressScope::UserBreak() const
546 {
547   return myProgress && myProgress->UserBreak();
548 }
549
550 //=======================================================================
551 //function : Next
552 //purpose  :
553 //=======================================================================
554 inline Message_ProgressRange Message_ProgressScope::Next (Standard_Real theStep)
555 {
556   if (myIsActive && theStep > 0.)
557   {
558     Standard_Real aCurr = localToGlobal(myValue);
559     Standard_Real aNext = localToGlobal(myValue += theStep);
560     Standard_Real aDelta = aNext - aCurr;
561     if (aDelta > 0.)
562     {
563       return Message_ProgressRange(*this, myStart + aCurr, aDelta);
564     }
565   }
566   return Message_ProgressRange();
567 }
568
569 //=======================================================================
570 //function : Show
571 //purpose  :
572 //=======================================================================
573
574 inline void Message_ProgressScope::Show ()
575 {
576   if (myIsActive)
577   {
578     myProgress->Show (*this, Standard_True);
579   }
580 }
581
582 //=======================================================================
583 //function : localToGlobal
584 //purpose  :
585 //=======================================================================
586 inline Standard_Real Message_ProgressScope::localToGlobal (const Standard_Real theVal) const
587 {
588   if (theVal <= 0.)
589     return 0.;
590
591   if (!myIsInfinite)
592   {
593     if (myMax - theVal < RealSmall())
594       return myPortion;
595     return myPortion * theVal / myMax;
596   }
597
598   double x = theVal / myMax;
599   // return myPortion * ( 1. - std::exp ( -x ) ); // exponent
600   return myPortion * x / (1. + x);  // hyperbola
601 }
602
603 //=======================================================================
604 //function : Value
605 //purpose  :
606 //=======================================================================
607
608 inline Standard_Real Message_ProgressScope::Value () const
609 {
610   if (!myIsActive)
611   {
612     return myIsInfinite ? Precision::Infinite() : myMax;
613   }
614
615   // get current progress on the global scale counted 
616   // from the start of this scope
617   Standard_Real aVal = myProgress->GetPosition() - myStart;
618
619   // if progress has not reached yet the start of this scope, return 0
620   if (aVal <= 0.)
621     return 0.;
622
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;
627
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());
632 }
633
634 #endif // _Message_ProgressScope_HeaderFile