|
|
|||
File indexing completed on 2026-06-12 08:32:20
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 //! Creates dummy scope. 0198 //! It can be safely passed to algorithms; no progress indication will be done. 0199 Message_ProgressScope() 0200 : myProgress(0), 0201 myParent(0), 0202 myName(0), 0203 myStart(0.), 0204 myPortion(1.), 0205 myMax(1.), 0206 myValue(0.), 0207 myIsActive(false), 0208 myIsOwnName(false), 0209 myIsInfinite(false) 0210 { 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 0219 //! progress indicator. 0220 //! 0221 //! @param[in][out] theRange range to fill (will be disarmed) 0222 //! @param[in] theName new scope name 0223 //! @param[in] theMax number of steps in scope 0224 //! @param[in] isInfinite infinite flag 0225 Message_ProgressScope(const Message_ProgressRange& theRange, 0226 const TCollection_AsciiString& theName, 0227 Standard_Real theMax, 0228 Standard_Boolean isInfinite = false); 0229 0230 //! Creates a new scope taking responsibility of the part of the progress 0231 //! scale described by theRange. The new scope has own range from 0 to 0232 //! theMax, which is mapped to the given range. 0233 //! 0234 //! The topmost scope is created and owned by Message_ProgressIndicator 0235 //! and its pointer is contained in the Message_ProgressRange returned by the Start() method of 0236 //! progress indicator. 0237 //! 0238 //! @param[in][out] theRange range to fill (will be disarmed) 0239 //! @param[in] theName new scope name constant (will be stored by pointer with no deep 0240 //! copy) 0241 //! @param[in] theMax number of steps in scope 0242 //! @param[in] isInfinite infinite flag 0243 template <size_t N> 0244 Message_ProgressScope(const Message_ProgressRange& theRange, 0245 const char (&theName)[N], 0246 Standard_Real theMax, 0247 Standard_Boolean isInfinite = false); 0248 0249 //! Creates a new scope taking responsibility of the part of the progress 0250 //! scale described by theRange. The new scope has own range from 0 to 0251 //! theMax, which is mapped to the given range. 0252 //! 0253 //! The topmost scope is created and owned by Message_ProgressIndicator 0254 //! and its pointer is contained in the Message_ProgressRange returned by the Start() method of 0255 //! progress indicator. 0256 //! 0257 //! @param[in][out] theRange range to fill (will be disarmed) 0258 //! @param[in] theName empty scope name (only NULL is accepted as argument) 0259 //! @param[in] theMax number of steps in scope 0260 //! @param[in] isInfinite infinite flag 0261 Message_ProgressScope(const Message_ProgressRange& theRange, 0262 const NullString* theName, 0263 Standard_Real theMax, 0264 Standard_Boolean isInfinite = false); 0265 0266 //! Sets the name of the scope. 0267 void SetName(const TCollection_AsciiString& theName) 0268 { 0269 if (myIsOwnName) 0270 { 0271 Standard::Free(myName); 0272 myIsOwnName = false; 0273 } 0274 myName = NULL; 0275 if (!theName.IsEmpty()) 0276 { 0277 myIsOwnName = true; 0278 myName = (char*)Standard::AllocateOptimal(Standard_Size(theName.Length()) + Standard_Size(1)); 0279 char* aName = (char*)myName; 0280 memcpy(aName, theName.ToCString(), theName.Length()); 0281 aName[theName.Length()] = '\0'; 0282 } 0283 } 0284 0285 //! Sets the name of the scope; can be null. 0286 //! Note! Just pointer to the given string is copied, 0287 //! so do not pass string from a temporary variable whose 0288 //! lifetime is less than that of this object. 0289 template <size_t N> 0290 void SetName(const char (&theName)[N]) 0291 { 0292 if (myIsOwnName) 0293 { 0294 Standard::Free(myName); 0295 myIsOwnName = false; 0296 } 0297 myName = theName; 0298 } 0299 0300 public: //! @name Advance by iterations 0301 //! Returns true if ProgressIndicator signals UserBreak 0302 Standard_Boolean UserBreak() const; 0303 0304 //! Returns false if ProgressIndicator signals UserBreak 0305 Standard_Boolean More() const { return !UserBreak(); } 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 //! Force update of presentation of the progress indicator. 0313 //! Should not be called concurrently. 0314 void Show(); 0315 0316 //! Returns true if this progress scope is attached to some indicator. 0317 Standard_Boolean IsActive() const { return myIsActive; } 0318 0319 //! Returns the name of the scope (may be null). 0320 //! Scopes with null name (e.g. root scope) should 0321 //! be bypassed when reporting progress to the user. 0322 Standard_CString Name() const { return myName; } 0323 0324 //! Returns parent scope (null for top-level scope) 0325 const Message_ProgressScope* Parent() const { return myParent; } 0326 0327 //! Returns the maximal value of progress in this scope 0328 Standard_Real MaxValue() const { return myMax; } 0329 0330 //! Returns the current value of progress in this scope. 0331 //! 0332 //! The value is computed by mapping current global progress into 0333 //! this scope range; the result is rounded up to integer. 0334 //! Note that if MaxValue() is not an integer, Value() can be 0335 //! greater than MaxValue() due to that rounding. 0336 //! 0337 //! This method should not be called concurrently while the progress 0338 //! is advancing, except from implementation of method Show() in 0339 //! descendant of Message_ProgressIndicator. 0340 Standard_Real Value() const; 0341 0342 //! Returns the infinite flag 0343 Standard_Boolean IsInfinite() const { return myIsInfinite; } 0344 0345 //! Get the portion of the indicator covered by this scope (from 0 to 1) 0346 Standard_Real GetPortion() const { return myPortion; } 0347 0348 public: //! @name Destruction, allocation 0349 //! Destructor - closes the scope and adds its scale to the total progress 0350 ~Message_ProgressScope() 0351 { 0352 Close(); 0353 if (myIsOwnName) 0354 { 0355 Standard::Free(myName); 0356 myIsOwnName = false; 0357 myName = NULL; 0358 } 0359 } 0360 0361 //! Closes the scope and advances the progress to its end. 0362 //! Closed scope should not be used. 0363 void Close(); 0364 0365 DEFINE_STANDARD_ALLOC 0366 0367 private: //! @name Internal methods 0368 //! Creates a top-level scope with default range [0,1] and step 1. 0369 //! Called only by Message_ProgressIndicator constructor. 0370 Message_ProgressScope(Message_ProgressIndicator* theProgress); 0371 0372 //! Convert value from this scope to global scale, but disregarding 0373 //! start position of the scope, in the range [0, myPortion] 0374 Standard_Real localToGlobal(const Standard_Real theVal) const; 0375 0376 private: 0377 //! Copy constructor is prohibited 0378 Message_ProgressScope(const Message_ProgressScope& theOther); 0379 0380 //! Copy assignment is prohibited 0381 Message_ProgressScope& operator=(const Message_ProgressScope& theOther); 0382 0383 private: 0384 Message_ProgressIndicator* myProgress; //!< Pointer to progress indicator instance 0385 const Message_ProgressScope* myParent; //!< Pointer to parent scope 0386 Standard_CString myName; //!< Name of the operation being done in this scope, or null 0387 0388 Standard_Real myStart; //!< Start position on the global scale [0, 1] 0389 // clang-format off 0390 Standard_Real myPortion; //!< The portion of the global scale covered by this scope [0, 1] 0391 // clang-format on 0392 0393 Standard_Real myMax; //!< Maximal value of progress in this scope 0394 Standard_Real myValue; //!< Current position advanced within this scope [0, Max] 0395 0396 Standard_Boolean myIsActive; //!< flag indicating armed/disarmed state 0397 Standard_Boolean myIsOwnName; //!< flag indicating if name was allocated or not 0398 Standard_Boolean myIsInfinite; //!< Option to advance by hyperbolic law 0399 0400 private: 0401 friend class Message_ProgressIndicator; 0402 friend class Message_ProgressRange; 0403 }; 0404 0405 #include <Message_ProgressRange.hxx> 0406 0407 //======================================================================= 0408 // function : Message_ProgressScope 0409 // purpose : 0410 //======================================================================= 0411 inline Message_ProgressScope::Message_ProgressScope(Message_ProgressIndicator* theProgress) 0412 : myProgress(theProgress), 0413 myParent(0), 0414 myName(0), 0415 myStart(0.), 0416 myPortion(1.), 0417 myMax(1.), 0418 myValue(0.), 0419 myIsActive(theProgress != NULL), 0420 myIsOwnName(false), 0421 myIsInfinite(false) 0422 { 0423 } 0424 0425 //======================================================================= 0426 // function : Message_ProgressScope 0427 // purpose : 0428 //======================================================================= 0429 inline Message_ProgressScope::Message_ProgressScope(const Message_ProgressRange& theRange, 0430 const TCollection_AsciiString& theName, 0431 Standard_Real theMax, 0432 Standard_Boolean isInfinite) 0433 : myProgress(theRange.myParentScope != NULL ? theRange.myParentScope->myProgress : NULL), 0434 myParent(theRange.myParentScope), 0435 myName(NULL), 0436 myStart(theRange.myStart), 0437 myPortion(theRange.myDelta), 0438 myMax(Max(1.e-6, theMax)), // protection against zero range 0439 myValue(0.), 0440 myIsActive(myProgress != NULL && !theRange.myWasUsed), 0441 myIsOwnName(false), 0442 myIsInfinite(isInfinite) 0443 { 0444 SetName(theName); 0445 Standard_ASSERT_VOID(!theRange.myWasUsed, 0446 "Message_ProgressRange is used to initialize more than one scope"); 0447 theRange.myWasUsed = true; // Disarm the range 0448 } 0449 0450 //======================================================================= 0451 // function : Message_ProgressScope 0452 // purpose : 0453 //======================================================================= 0454 template <size_t N> 0455 Message_ProgressScope::Message_ProgressScope(const Message_ProgressRange& theRange, 0456 const char (&theName)[N], 0457 Standard_Real theMax, 0458 Standard_Boolean isInfinite) 0459 : myProgress(theRange.myParentScope != NULL ? theRange.myParentScope->myProgress : NULL), 0460 myParent(theRange.myParentScope), 0461 myName(theName), 0462 myStart(theRange.myStart), 0463 myPortion(theRange.myDelta), 0464 myMax(Max(1.e-6, theMax)), // protection against zero range 0465 myValue(0.), 0466 myIsActive(myProgress != NULL && !theRange.myWasUsed), 0467 myIsOwnName(false), 0468 myIsInfinite(isInfinite) 0469 { 0470 Standard_ASSERT_VOID(!theRange.myWasUsed, 0471 "Message_ProgressRange is used to initialize more than one scope"); 0472 theRange.myWasUsed = true; // Disarm the range 0473 } 0474 0475 //======================================================================= 0476 // function : Message_ProgressScope 0477 // purpose : 0478 //======================================================================= 0479 inline Message_ProgressScope::Message_ProgressScope(const Message_ProgressRange& theRange, 0480 const NullString*, 0481 Standard_Real theMax, 0482 Standard_Boolean isInfinite) 0483 : myProgress(theRange.myParentScope != NULL ? theRange.myParentScope->myProgress : NULL), 0484 myParent(theRange.myParentScope), 0485 myName(NULL), 0486 myStart(theRange.myStart), 0487 myPortion(theRange.myDelta), 0488 myMax(Max(1.e-6, theMax)), // protection against zero range 0489 myValue(0.), 0490 myIsActive(myProgress != NULL && !theRange.myWasUsed), 0491 myIsOwnName(false), 0492 myIsInfinite(isInfinite) 0493 { 0494 Standard_ASSERT_VOID(!theRange.myWasUsed, 0495 "Message_ProgressRange is used to initialize more than one scope"); 0496 theRange.myWasUsed = true; // Disarm the range 0497 } 0498 0499 //======================================================================= 0500 // function : Close 0501 // purpose : 0502 //======================================================================= 0503 inline void Message_ProgressScope::Close() 0504 { 0505 if (!myIsActive) 0506 { 0507 return; 0508 } 0509 0510 // Advance indicator to the end of the scope 0511 Standard_Real aCurr = localToGlobal(myValue); 0512 myValue = (myIsInfinite ? Precision::Infinite() : myMax); 0513 Standard_Real aDelta = myPortion - aCurr; 0514 if (aDelta > 0.) 0515 { 0516 myProgress->Increment(aDelta, *this); 0517 } 0518 Standard_ASSERT_VOID(myParent == 0 || myParent->myIsActive, 0519 "Parent progress scope has been closed before child"); 0520 0521 myIsActive = false; 0522 } 0523 0524 //======================================================================= 0525 // function : UserBreak 0526 // purpose : 0527 //======================================================================= 0528 inline Standard_Boolean Message_ProgressScope::UserBreak() const 0529 { 0530 return myProgress && myProgress->UserBreak(); 0531 } 0532 0533 //======================================================================= 0534 // function : Next 0535 // purpose : 0536 //======================================================================= 0537 inline Message_ProgressRange Message_ProgressScope::Next(Standard_Real theStep) 0538 { 0539 if (myIsActive && theStep > 0.) 0540 { 0541 Standard_Real aCurr = localToGlobal(myValue); 0542 Standard_Real aNext = localToGlobal(myValue += theStep); 0543 Standard_Real aDelta = aNext - aCurr; 0544 if (aDelta > 0.) 0545 { 0546 return Message_ProgressRange(*this, myStart + aCurr, aDelta); 0547 } 0548 } 0549 return Message_ProgressRange(); 0550 } 0551 0552 //======================================================================= 0553 // function : Show 0554 // purpose : 0555 //======================================================================= 0556 0557 inline void Message_ProgressScope::Show() 0558 { 0559 if (myIsActive) 0560 { 0561 myProgress->Show(*this, Standard_True); 0562 } 0563 } 0564 0565 //======================================================================= 0566 // function : localToGlobal 0567 // purpose : 0568 //======================================================================= 0569 inline Standard_Real Message_ProgressScope::localToGlobal(const Standard_Real theVal) const 0570 { 0571 if (theVal <= 0.) 0572 return 0.; 0573 0574 if (!myIsInfinite) 0575 { 0576 if (myMax - theVal < RealSmall()) 0577 return myPortion; 0578 return myPortion * theVal / myMax; 0579 } 0580 0581 double x = theVal / myMax; 0582 // return myPortion * ( 1. - std::exp ( -x ) ); // exponent 0583 return myPortion * x / (1. + x); // hyperbola 0584 } 0585 0586 //======================================================================= 0587 // function : Value 0588 // purpose : 0589 //======================================================================= 0590 0591 inline Standard_Real Message_ProgressScope::Value() const 0592 { 0593 if (!myIsActive) 0594 { 0595 return myIsInfinite ? Precision::Infinite() : myMax; 0596 } 0597 0598 // get current progress on the global scale counted 0599 // from the start of this scope 0600 Standard_Real aVal = myProgress->GetPosition() - myStart; 0601 0602 // if progress has not reached yet the start of this scope, return 0 0603 if (aVal <= 0.) 0604 return 0.; 0605 0606 // if at end of the scope (or behind), report the maximum 0607 Standard_Real aDist = myPortion - aVal; 0608 if (aDist <= Precision::Confusion()) 0609 return myIsInfinite ? Precision::Infinite() : myMax; 0610 0611 // map the value to the range of this scope [0, Max], 0612 // rounding up to integer, with small correction applied 0613 // to avoid rounding errors 0614 return std::ceil(myMax * aVal / (myIsInfinite ? aDist : myPortion) - Precision::Confusion()); 0615 } 0616 0617 #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 |
|