|
||||
File indexing completed on 2025-01-18 10:04:17
0001 // Created on: 2002-02-22 0002 // Created by: Andrey BETENEV 0003 // Copyright (c) 2002-2014 OPEN CASCADE SAS 0004 // 0005 // This file is part of Open CASCADE Technology software library. 0006 // 0007 // This library is free software; you can redistribute it and/or modify it under 0008 // the terms of the GNU Lesser General Public License version 2.1 as published 0009 // by the Free Software Foundation, with special exception defined in the file 0010 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT 0011 // distribution for complete text of the license and disclaimer of any warranty. 0012 // 0013 // Alternatively, this file may be used under the terms of Open CASCADE 0014 // commercial license or contractual agreement. 0015 0016 #ifndef _Message_ProgressScope_HeaderFile 0017 #define _Message_ProgressScope_HeaderFile 0018 0019 #include <Standard_Assert.hxx> 0020 #include <Standard_TypeDef.hxx> 0021 #include <Standard_DefineAlloc.hxx> 0022 #include <Standard_Handle.hxx> 0023 #include <Precision.hxx> 0024 #include <TCollection_AsciiString.hxx> 0025 0026 class Message_ProgressRange; 0027 class Message_ProgressIndicator; 0028 0029 //! Message_ProgressScope class provides convenient way to advance progress 0030 //! indicator in context of complex program organized in hierarchical way, 0031 //! where usually it is difficult (or even not possible) to consider process 0032 //! as linear with fixed step. 0033 //! 0034 //! On every level (sub-operation) in hierarchy of operations 0035 //! the local instance of the Message_ProgressScope class is created. 0036 //! It takes a part of the upper-level scope (via Message_ProgressRange) and provides 0037 //! a way to consider this part as independent scale with locally defined range. 0038 //! 0039 //! The position on the local scale may be advanced using the method Next(), 0040 //! which allows iteration-like advancement. This method can take argument to 0041 //! advance by the specified value (with default step equal to 1). 0042 //! This method returns Message_ProgressRange object that takes responsibility 0043 //! of making the specified step, either directly at its destruction or by 0044 //! delegating this task to another sub-scope created from that range object. 0045 //! 0046 //! It is important that sub-scope must have life time less than 0047 //! the life time of its parent scope that provided the range. 0048 //! The usage pattern is to create scope objects as local variables in the 0049 //! functions that do the job, and pass range objects returned by Next() to 0050 //! the functions of the lower level, to allow them creating their own scopes. 0051 //! 0052 //! The scope has a name that can be used in visualization of the progress. 0053 //! It can be null. Note that when C string literal is used as a name, then its 0054 //! value is not copied, just pointer is stored. In other variants (char pointer 0055 //! or a string class) the string is copied, which is additional overhead. 0056 //! 0057 //! The same instance of the progress scope! must not be used concurrently from different threads. 0058 //! For the algorithm running its tasks in parallel threads, a common scope is 0059 //! created before the parallel execution, and the range objects produced by method 0060 //! Next() are used to initialise the data pertinent to each task. 0061 //! Then the progress is advanced within each task using its own range object. 0062 //! See example below. 0063 //! 0064 //! Note that while a range of the scope is specified using Standard_Real 0065 //! (double) parameter, it is expected to be a positive integer value. 0066 //! If the range is not an integer, method Next() shall be called with 0067 //! explicit step argument, and the rounded value returned by method Value() 0068 //! may be not coherent with the step and range. 0069 //! 0070 //! A scope can be created with option "infinite". This is useful when 0071 //! the number of steps is not known by the time of the scope creation. 0072 //! In this case the progress will be advanced logarithmically, approaching 0073 //! the end of the scope at infinite number of steps. The parameter Max 0074 //! for infinite scope indicates number of steps corresponding to mid-range. 0075 //! 0076 //! A progress scope created with empty constructor is not connected to any 0077 //! progress indicator, and passing the range created on it to any algorithm 0078 //! allows it executing safely without actual progress indication. 0079 //! 0080 //! Example of preparation of progress indicator: 0081 //! 0082 //! @code{.cpp} 0083 //! Handle(Message_ProgressIndicator) aProgress = ...; // assume it can be null 0084 //! func (Message_ProgressIndicator::Start (aProgress)); 0085 //! @endcode 0086 //! 0087 //! Example of usage in sequential process: 0088 //! 0089 //! @code{.cpp} 0090 //! Message_ProgressScope aWholePS(aRange, "Whole process", 100); 0091 //! 0092 //! // do one step taking 20% 0093 //! func1 (aWholePS.Next (20)); // func1 will take 20% of the whole scope 0094 //! if (aWholePS.UserBreak()) // exit prematurely if the user requested break 0095 //! return; 0096 //! 0097 //! // ... do next step taking 50% 0098 //! func2 (aWholePS.Next (50)); 0099 //! if (aWholePS.UserBreak()) 0100 //! return; 0101 //! @endcode 0102 //! 0103 //! Example of usage in nested cycle: 0104 //! 0105 //! @code{.cpp} 0106 //! // Outer cycle 0107 //! Message_ProgressScope anOuter (theProgress, "Outer", nbOuter); 0108 //! for (Standard_Integer i = 0; i < nbOuter && anOuter.More(); i++) 0109 //! { 0110 //! // Inner cycle 0111 //! Message_ProgressScope anInner (anOuter.Next(), "Inner", nbInner); 0112 //! for (Standard_Integer j = 0; j < nbInner && anInner.More(); j++) 0113 //! { 0114 //! // Cycle body 0115 //! func (anInner.Next()); 0116 //! } 0117 //! } 0118 //! @endcode 0119 //! 0120 //! Example of use in function: 0121 //! 0122 //! @code{.cpp} 0123 //! //! Implementation of iterative algorithm showing its progress 0124 //! func (const Message_ProgressRange& theProgress) 0125 //! { 0126 //! // Create local scope covering the given progress range. 0127 //! // Set this scope to count aNbSteps steps. 0128 //! Message_ProgressScope aScope (theProgress, "", aNbSteps); 0129 //! for (Standard_Integer i = 0; i < aNbSteps && aScope.More(); i++) 0130 //! { 0131 //! // Optional: pass range returned by method Next() to the nested algorithm 0132 //! // to allow it to show its progress too (by creating its own scope object). 0133 //! // In any case the progress will advance to the next step by the end of the func2 call. 0134 //! func2 (aScope.Next()); 0135 //! } 0136 //! } 0137 //! @endcode 0138 //! 0139 //! Example of usage in parallel process: 0140 //! 0141 //! @code{.cpp} 0142 //! struct Task 0143 //! { 0144 //! Data& Data; 0145 //! Message_ProgressRange Range; 0146 //! 0147 //! Task (const Data& theData, const Message_ProgressRange& theRange) 0148 //! : Data (theData), Range (theRange) {} 0149 //! }; 0150 //! struct Functor 0151 //! { 0152 //! void operator() (Task& theTask) const 0153 //! { 0154 //! // Note: it is essential that this method is executed only once for the same Task object 0155 //! Message_ProgressScope aPS (theTask.Range, NULL, theTask.Data.NbItems); 0156 //! for (Standard_Integer i = 0; i < theTask.Data.NbSteps && aPS.More(); i++) 0157 //! { 0158 //! do_job (theTask.Data.Item[i], aPS.Next()); 0159 //! } 0160 //! } 0161 //! }; 0162 //! ... 0163 //! { 0164 //! std::vector<Data> aData = ...; 0165 //! std::vector<Task> aTasks; 0166 //! 0167 //! Message_ProgressScope aPS (aRootRange, "Data processing", aData.size()); 0168 //! for (Standard_Integer i = 0; i < aData.size(); ++i) 0169 //! aTasks.push_back (Task (aData[i], aPS.Next())); 0170 //! 0171 //! OSD_Parallel::ForEach (aTasks.begin(), aTasks.end(), Functor()); 0172 //! } 0173 //! @endcode 0174 //! 0175 //! For lightweight algorithms that do not need advancing the progress 0176 //! within individual tasks the code can be simplified to avoid inner scopes: 0177 //! 0178 //! @code 0179 //! struct Functor 0180 //! { 0181 //! void operator() (Task& theTask) const 0182 //! { 0183 //! if (theTask.Range.More()) 0184 //! { 0185 //! do_job (theTask.Data); 0186 //! // advance the progress 0187 //! theTask.Range.Close(); 0188 //! } 0189 //! } 0190 //! }; 0191 //! @endcode 0192 class Message_ProgressScope 0193 { 0194 public: 0195 class NullString; //!< auxiliary type for passing NULL name to Message_ProgressScope constructor 0196 public: //! @name Preparation methods 0197 0198 //! Creates dummy scope. 0199 //! It can be safely passed to algorithms; no progress indication will be done. 0200 Message_ProgressScope() 0201 : myProgress (0), 0202 myParent (0), 0203 myName (0), 0204 myStart (0.), 0205 myPortion (1.), 0206 myMax (1.), 0207 myValue (0.), 0208 myIsActive (false), 0209 myIsOwnName (false), 0210 myIsInfinite (false) 0211 {} 0212 0213 //! Creates a new scope taking responsibility of the part of the progress 0214 //! scale described by theRange. The new scope has own range from 0 to 0215 //! theMax, which is mapped to the given range. 0216 //! 0217 //! The topmost scope is created and owned by Message_ProgressIndicator 0218 //! and its pointer is contained in the Message_ProgressRange returned by the Start() method of progress indicator. 0219 //! 0220 //! @param theRange [in][out] range to fill (will be disarmed) 0221 //! @param theName [in] new scope name 0222 //! @param theMax [in] number of steps in scope 0223 //! @param isInfinite [in] infinite flag 0224 Message_ProgressScope (const Message_ProgressRange& theRange, 0225 const TCollection_AsciiString& theName, 0226 Standard_Real theMax, 0227 Standard_Boolean isInfinite = false); 0228 0229 //! Creates a new scope taking responsibility of the part of the progress 0230 //! scale described by theRange. The new scope has own range from 0 to 0231 //! theMax, which is mapped to the given range. 0232 //! 0233 //! The topmost scope is created and owned by Message_ProgressIndicator 0234 //! and its pointer is contained in the Message_ProgressRange returned by the Start() method of progress indicator. 0235 //! 0236 //! @param theRange [in][out] range to fill (will be disarmed) 0237 //! @param theName [in] new scope name constant (will be stored by pointer with no deep copy) 0238 //! @param theMax [in] number of steps in scope 0239 //! @param isInfinite [in] infinite flag 0240 template<size_t N> 0241 Message_ProgressScope (const Message_ProgressRange& theRange, 0242 const char (&theName)[N], 0243 Standard_Real theMax, 0244 Standard_Boolean isInfinite = false); 0245 0246 //! Creates a new scope taking responsibility of the part of the progress 0247 //! scale described by theRange. The new scope has own range from 0 to 0248 //! theMax, which is mapped to the given range. 0249 //! 0250 //! The topmost scope is created and owned by Message_ProgressIndicator 0251 //! and its pointer is contained in the Message_ProgressRange returned by the Start() method of progress indicator. 0252 //! 0253 //! @param theRange [in][out] range to fill (will be disarmed) 0254 //! @param theName [in] empty scope name (only NULL is accepted as argument) 0255 //! @param theMax [in] number of steps in scope 0256 //! @param isInfinite [in] infinite flag 0257 Message_ProgressScope (const Message_ProgressRange& theRange, 0258 const NullString* theName, 0259 Standard_Real theMax, 0260 Standard_Boolean isInfinite = false); 0261 0262 //! Sets the name of the scope. 0263 void SetName (const TCollection_AsciiString& theName) 0264 { 0265 if (myIsOwnName) 0266 { 0267 Standard::Free (myName); 0268 myIsOwnName = false; 0269 } 0270 myName = NULL; 0271 if (!theName.IsEmpty()) 0272 { 0273 myIsOwnName = true; 0274 myName = (char* )Standard::AllocateOptimal(Standard_Size(theName.Length()) + Standard_Size(1)); 0275 char* aName = (char* )myName; 0276 memcpy (aName, theName.ToCString(), theName.Length()); 0277 aName[theName.Length()] = '\0'; 0278 } 0279 } 0280 0281 //! Sets the name of the scope; can be null. 0282 //! Note! Just pointer to the given string is copied, 0283 //! so do not pass string from a temporary variable whose 0284 //! lifetime is less than that of this object. 0285 template<size_t N> 0286 void SetName (const char (&theName)[N]) 0287 { 0288 if (myIsOwnName) 0289 { 0290 Standard::Free (myName); 0291 myIsOwnName = false; 0292 } 0293 myName = theName; 0294 } 0295 0296 public: //! @name Advance by iterations 0297 0298 //! Returns true if ProgressIndicator signals UserBreak 0299 Standard_Boolean UserBreak() const; 0300 0301 //! Returns false if ProgressIndicator signals UserBreak 0302 Standard_Boolean More() const 0303 { 0304 return !UserBreak(); 0305 } 0306 0307 //! Advances position by specified step and returns the range 0308 //! covering this step 0309 Message_ProgressRange Next (Standard_Real theStep = 1.); 0310 0311 public: //! @name Auxiliary methods to use in ProgressIndicator 0312 0313 //! Force update of presentation of the progress indicator. 0314 //! Should not be called concurrently. 0315 void Show(); 0316 0317 //! Returns true if this progress scope is attached to some indicator. 0318 Standard_Boolean IsActive() const 0319 { 0320 return myIsActive; 0321 } 0322 0323 //! Returns the name of the scope (may be null). 0324 //! Scopes with null name (e.g. root scope) should 0325 //! be bypassed when reporting progress to the user. 0326 Standard_CString Name() const 0327 { 0328 return myName; 0329 } 0330 0331 //! Returns parent scope (null for top-level scope) 0332 const Message_ProgressScope* Parent() const 0333 { 0334 return myParent; 0335 } 0336 0337 //! Returns the maximal value of progress in this scope 0338 Standard_Real MaxValue() const 0339 { 0340 return myMax; 0341 } 0342 0343 //! Returns the current value of progress in this scope. 0344 //! 0345 //! The value is computed by mapping current global progress into 0346 //! this scope range; the result is rounded up to integer. 0347 //! Note that if MaxValue() is not an integer, Value() can be 0348 //! greater than MaxValue() due to that rounding. 0349 //! 0350 //! This method should not be called concurrently while the progress 0351 //! is advancing, except from implementation of method Show() in 0352 //! descendant of Message_ProgressIndicator. 0353 Standard_Real Value() const; 0354 0355 //! Returns the infinite flag 0356 Standard_Boolean IsInfinite() const 0357 { 0358 return myIsInfinite; 0359 } 0360 0361 //! Get the portion of the indicator covered by this scope (from 0 to 1) 0362 Standard_Real GetPortion() const 0363 { 0364 return myPortion; 0365 } 0366 0367 public: //! @name Destruction, allocation 0368 0369 //! Destructor - closes the scope and adds its scale to the total progress 0370 ~Message_ProgressScope() 0371 { 0372 Close(); 0373 if (myIsOwnName) 0374 { 0375 Standard::Free (myName); 0376 myIsOwnName = false; 0377 myName = NULL; 0378 } 0379 } 0380 0381 //! Closes the scope and advances the progress to its end. 0382 //! Closed scope should not be used. 0383 void Close(); 0384 0385 DEFINE_STANDARD_ALLOC 0386 0387 private: //! @name Internal methods 0388 0389 //! Creates a top-level scope with default range [0,1] and step 1. 0390 //! Called only by Message_ProgressIndicator constructor. 0391 Message_ProgressScope (Message_ProgressIndicator* theProgress); 0392 0393 //! Convert value from this scope to global scale, but disregarding 0394 //! start position of the scope, in the range [0, myPortion] 0395 Standard_Real localToGlobal(const Standard_Real theVal) const; 0396 0397 private: 0398 //! Copy constructor is prohibited 0399 Message_ProgressScope (const Message_ProgressScope& theOther); 0400 0401 //! Copy assignment is prohibited 0402 Message_ProgressScope& operator= (const Message_ProgressScope& theOther); 0403 0404 private: 0405 0406 Message_ProgressIndicator* myProgress; //!< Pointer to progress indicator instance 0407 const Message_ProgressScope* myParent; //!< Pointer to parent scope 0408 Standard_CString myName; //!< Name of the operation being done in this scope, or null 0409 0410 Standard_Real myStart; //!< Start position on the global scale [0, 1] 0411 Standard_Real myPortion; //!< The portion of the global scale covered by this scope [0, 1] 0412 0413 Standard_Real myMax; //!< Maximal value of progress in this scope 0414 Standard_Real myValue; //!< Current position advanced within this scope [0, Max] 0415 0416 Standard_Boolean myIsActive; //!< flag indicating armed/disarmed state 0417 Standard_Boolean myIsOwnName; //!< flag indicating if name was allocated or not 0418 Standard_Boolean myIsInfinite; //!< Option to advance by hyperbolic law 0419 0420 private: 0421 friend class Message_ProgressIndicator; 0422 friend class Message_ProgressRange; 0423 }; 0424 0425 #include <Message_ProgressRange.hxx> 0426 0427 //======================================================================= 0428 //function : Message_ProgressScope 0429 //purpose : 0430 //======================================================================= 0431 inline Message_ProgressScope::Message_ProgressScope (Message_ProgressIndicator* theProgress) 0432 : myProgress(theProgress), 0433 myParent(0), 0434 myName(0), 0435 myStart(0.), 0436 myPortion(1.), 0437 myMax(1.), 0438 myValue(0.), 0439 myIsActive(theProgress != NULL), 0440 myIsOwnName(false), 0441 myIsInfinite(false) 0442 { 0443 } 0444 0445 //======================================================================= 0446 //function : Message_ProgressScope 0447 //purpose : 0448 //======================================================================= 0449 inline Message_ProgressScope::Message_ProgressScope (const Message_ProgressRange& theRange, 0450 const TCollection_AsciiString& theName, 0451 Standard_Real theMax, 0452 Standard_Boolean isInfinite) 0453 : myProgress (theRange.myParentScope != NULL ? theRange.myParentScope->myProgress : NULL), 0454 myParent (theRange.myParentScope), 0455 myName (NULL), 0456 myStart (theRange.myStart), 0457 myPortion (theRange.myDelta), 0458 myMax (Max (1.e-6, theMax)), // protection against zero range 0459 myValue (0.), 0460 myIsActive (myProgress != NULL && !theRange.myWasUsed), 0461 myIsOwnName (false), 0462 myIsInfinite (isInfinite) 0463 { 0464 SetName (theName); 0465 Standard_ASSERT_VOID (! theRange.myWasUsed, "Message_ProgressRange is used to initialize more than one scope"); 0466 theRange.myWasUsed = true; // Disarm the range 0467 } 0468 0469 //======================================================================= 0470 //function : Message_ProgressScope 0471 //purpose : 0472 //======================================================================= 0473 template<size_t N> 0474 Message_ProgressScope::Message_ProgressScope (const Message_ProgressRange& theRange, 0475 const char (&theName)[N], 0476 Standard_Real theMax, 0477 Standard_Boolean isInfinite) 0478 : myProgress (theRange.myParentScope != NULL ? theRange.myParentScope->myProgress : NULL), 0479 myParent (theRange.myParentScope), 0480 myName (theName), 0481 myStart (theRange.myStart), 0482 myPortion (theRange.myDelta), 0483 myMax (Max (1.e-6, theMax)), // protection against zero range 0484 myValue (0.), 0485 myIsActive (myProgress != NULL && !theRange.myWasUsed), 0486 myIsOwnName (false), 0487 myIsInfinite (isInfinite) 0488 { 0489 Standard_ASSERT_VOID (! theRange.myWasUsed, "Message_ProgressRange is used to initialize more than one scope"); 0490 theRange.myWasUsed = true; // Disarm the range 0491 } 0492 0493 //======================================================================= 0494 //function : Message_ProgressScope 0495 //purpose : 0496 //======================================================================= 0497 inline Message_ProgressScope::Message_ProgressScope (const Message_ProgressRange& theRange, 0498 const NullString* , 0499 Standard_Real theMax, 0500 Standard_Boolean isInfinite) 0501 : myProgress (theRange.myParentScope != NULL ? theRange.myParentScope->myProgress : NULL), 0502 myParent (theRange.myParentScope), 0503 myName (NULL), 0504 myStart (theRange.myStart), 0505 myPortion (theRange.myDelta), 0506 myMax (Max (1.e-6, theMax)), // protection against zero range 0507 myValue (0.), 0508 myIsActive (myProgress != NULL && !theRange.myWasUsed), 0509 myIsOwnName (false), 0510 myIsInfinite (isInfinite) 0511 { 0512 Standard_ASSERT_VOID (! theRange.myWasUsed, "Message_ProgressRange is used to initialize more than one scope"); 0513 theRange.myWasUsed = true; // Disarm the range 0514 } 0515 0516 //======================================================================= 0517 //function : Close 0518 //purpose : 0519 //======================================================================= 0520 inline void Message_ProgressScope::Close() 0521 { 0522 if (!myIsActive) 0523 { 0524 return; 0525 } 0526 0527 // Advance indicator to the end of the scope 0528 Standard_Real aCurr = localToGlobal (myValue); 0529 myValue = (myIsInfinite ? Precision::Infinite() : myMax); 0530 Standard_Real aDelta = myPortion - aCurr; 0531 if (aDelta > 0.) 0532 { 0533 myProgress->Increment (aDelta, *this); 0534 } 0535 Standard_ASSERT_VOID (myParent == 0 || myParent->myIsActive, 0536 "Parent progress scope has been closed before child"); 0537 0538 myIsActive = false; 0539 } 0540 0541 //======================================================================= 0542 //function : UserBreak 0543 //purpose : 0544 //======================================================================= 0545 inline Standard_Boolean Message_ProgressScope::UserBreak() const 0546 { 0547 return myProgress && myProgress->UserBreak(); 0548 } 0549 0550 //======================================================================= 0551 //function : Next 0552 //purpose : 0553 //======================================================================= 0554 inline Message_ProgressRange Message_ProgressScope::Next (Standard_Real theStep) 0555 { 0556 if (myIsActive && theStep > 0.) 0557 { 0558 Standard_Real aCurr = localToGlobal(myValue); 0559 Standard_Real aNext = localToGlobal(myValue += theStep); 0560 Standard_Real aDelta = aNext - aCurr; 0561 if (aDelta > 0.) 0562 { 0563 return Message_ProgressRange(*this, myStart + aCurr, aDelta); 0564 } 0565 } 0566 return Message_ProgressRange(); 0567 } 0568 0569 //======================================================================= 0570 //function : Show 0571 //purpose : 0572 //======================================================================= 0573 0574 inline void Message_ProgressScope::Show () 0575 { 0576 if (myIsActive) 0577 { 0578 myProgress->Show (*this, Standard_True); 0579 } 0580 } 0581 0582 //======================================================================= 0583 //function : localToGlobal 0584 //purpose : 0585 //======================================================================= 0586 inline Standard_Real Message_ProgressScope::localToGlobal (const Standard_Real theVal) const 0587 { 0588 if (theVal <= 0.) 0589 return 0.; 0590 0591 if (!myIsInfinite) 0592 { 0593 if (myMax - theVal < RealSmall()) 0594 return myPortion; 0595 return myPortion * theVal / myMax; 0596 } 0597 0598 double x = theVal / myMax; 0599 // return myPortion * ( 1. - std::exp ( -x ) ); // exponent 0600 return myPortion * x / (1. + x); // hyperbola 0601 } 0602 0603 //======================================================================= 0604 //function : Value 0605 //purpose : 0606 //======================================================================= 0607 0608 inline Standard_Real Message_ProgressScope::Value () const 0609 { 0610 if (!myIsActive) 0611 { 0612 return myIsInfinite ? Precision::Infinite() : myMax; 0613 } 0614 0615 // get current progress on the global scale counted 0616 // from the start of this scope 0617 Standard_Real aVal = myProgress->GetPosition() - myStart; 0618 0619 // if progress has not reached yet the start of this scope, return 0 0620 if (aVal <= 0.) 0621 return 0.; 0622 0623 // if at end of the scope (or behind), report the maximum 0624 Standard_Real aDist = myPortion - aVal; 0625 if (aDist <= Precision::Confusion()) 0626 return myIsInfinite ? Precision::Infinite() : myMax; 0627 0628 // map the value to the range of this scope [0, Max], 0629 // rounding up to integer, with small correction applied 0630 // to avoid rounding errors 0631 return std::ceil (myMax * aVal / (myIsInfinite ? aDist : myPortion) - Precision::Confusion()); 0632 } 0633 0634 #endif // _Message_ProgressScope_HeaderFile
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |