00001 /* 00002 * This file is part of openMask � INRIA, CNRS, Universite de Rennes 1 1993-2002, thereinafter the Software 00003 * 00004 * The Software has been developped within the Siames Project. 00005 * INRIA, the University of Rennes 1 and CNRS jointly hold intellectual property rights 00006 * 00007 * The Software has been registered with the Agence pour la Protection des 00008 * Programmes (APP) under registration number IDDN.FR.001.510008.00.S.P.2001.000.41200 00009 * 00010 * This file may be distributed under the terms of the Q Public License 00011 * version 1.0 as defined by Trolltech AS of Norway and appearing in the file 00012 * LICENSE.QPL included in the packaging of this file. 00013 * 00014 * Licensees holding valid specific licenses issued by INRIA, CNRS or Universit� de Rennes 1 00015 * for the software may use this file in accordance with that specific license 00016 * 00017 */ 00018 #ifndef OutputHEADER 00019 #define OutputHEADER 00020 00021 #include "OMKOutputNT.h" 00022 #include "OMKAbstractFifo.h" 00023 #include "OMKPolator.h" 00024 #include "OMKName.h" 00025 #include "OMKController.h" 00026 #include "OMKSimulatedObject.h" 00027 #include "OMKUnInitialisedOutputException.h" 00028 #include "OMKCurrentActiveObject.h" 00029 #include <typeinfo> 00030 00031 namespace OMK 00032 { 00033 template< typename T > class OutputAlias ; 00034 00052 template< typename T > 00053 class Output : public OutputNT 00054 { 00055 public : 00056 00063 Output( const Name & outputName, 00064 SimulatedObject & owner, 00065 const int historySize, 00066 OMK::Type::PolatorNT * polator = 0 ) ; 00067 00070 virtual ~Output() ; 00071 00072 00081 virtual const T& get( int & distanceToExactValue, 00082 const int precisionLevel, 00083 const Date & deltaT, 00084 T& calculatedResult ) const ; 00085 00086 00089 virtual const T& getLastExactValue() const ; 00090 00091 00094 virtual const Date & getDateOfLastExactValue() const ; 00095 00096 00101 virtual void set( const T& newValue, bool alwaysUpdate = false ) ; 00102 00103 00107 virtual void suggest( const T& suggestedValue ) ; 00108 00109 00112 virtual T& getNextPlaceHolder() ; 00113 00116 virtual void setInPlace( const T& ) ; 00117 00118 00121 virtual void connectedMyself( InputNT * input ) ; 00122 00123 00126 virtual void disconnectedMyself( InputNT * input ) ; 00127 00128 00132 00135 virtual void extract( std::istream & = std::cin ) ; 00136 00139 virtual void insertInStream( std::ostream & = std::cout ) const ; 00140 00141 00145 virtual void pack( OutgoingSynchronisationMessage & ) const ; 00146 00147 00151 virtual void packAllValues( OutgoingSynchronisationMessage & ) const ; 00152 00153 00157 virtual void unpack( IncomingSynchronisationMessage & ) ; 00158 00162 virtual void unpackAllValues( IncomingSynchronisationMessage & ) ; 00164 00165 00169 virtual void printDebuggingInformation( std::ostream & err ) const ; 00170 00173 void printHistory() const ; 00174 00176 virtual void empty() ; 00177 00181 virtual void setUsedOutput( Output< T > * output ) ; 00182 00184 virtual void setAlias( OutputAlias< T > * output ) ; 00185 00187 virtual void unsetAlias() ; 00188 00190 virtual Output< T > * getUsedOutput() const ; 00191 00192 00194 virtual OutputAlias< T > * getAlias() const ; 00195 00196 00198 protected : 00202 virtual void setValidity( bool ) ; 00203 00205 friend class OutputAlias< T > ; 00206 00208 virtual const T& localGet( int & validiteRes, 00209 const int niveauInterpol, 00210 const Date & deltaT, 00211 T& resultPlaceHolder ) const ; 00212 00213 00215 virtual void localInsert( std::ostream & = std::cout ) const ; 00216 00218 OutputAlias< T > * _aliasOfOutput ; 00219 00221 Output< T > * _usedOutput ; 00222 00224 AbstractFifo < T > * _history ; 00225 00227 const Date & _date ; 00228 00229 public: 00231 OMK::Type::Polator < T > * _polator; 00232 00233 protected: 00235 std::list<Input < T > *> _listOfConnectedUnsensitiveInputs; 00236 00240 #ifdef _OMK_MUTEX_ 00241 OMKMutexLock _myMutex ; 00242 #endif 00243 00245 bool _validity ; 00246 } ; // Output 00247 00248 } // namespace OMK 00249 00250 00251 //----------------------------------------------------------------------------- 00252 //----------------------------------------------------------------------------- 00253 00254 00255 #include "OMKOutputAlias.h" 00256 00257 namespace OMK 00258 { 00259 00260 //----------------------------------------------------------------------------- 00261 00262 template< typename T > 00263 inline Output< T >::Output( const Name & outputName, 00264 SimulatedObject & owner, 00265 const int historyLength, 00266 OMK::Type::PolatorNT * polator ) 00267 : KernelAttribute( owner, outputName ), 00268 OutputNT( owner, outputName ), 00269 _aliasOfOutput( 0 ), 00270 _date( owner.getController().getSimulatedDate() ), 00271 _validity( false ) 00272 { 00273 /* Thread safety assessement : 00274 * thread safe because only on construction of the object 00275 */ 00276 00277 if( polator == 0 ) 00278 { 00279 // any type has a static method that creates a default polator 00280 T aTypeInstance ; // because createPolator isn't static 00281 _polator = static_cast< OMK::Type::Polator< T > * >( 00282 aTypeInstance.createPolator() ) ; 00283 00284 if( _polator != 0 ) 00285 { 00286 OMTRACEID( OMK_DEBUG_OMK_POL, 00287 "Created default polator for output \"" 00288 << getName() << "\" of object \"" 00289 << owner.getName() << "\", with type " 00290 << typeid( _polator ).name() ) ; 00291 } 00292 else 00293 { 00294 OMERROR( "Created default polator for output \"" 00295 << getName() << "\" of object \"" 00296 << owner.getName() << " is not of type \"" 00297 << " OMK::Type::Polator <" 00298 << typeid( T ).name() << "> *\"" ) ; 00299 } 00300 } 00301 else 00302 { 00303 _polator = dynamic_cast< OMK::Type::Polator< T > * >( polator ) ; 00304 if( _polator != 0) 00305 { 00306 OMTRACEID( OMK_DEBUG_OMK_POL, 00307 "Given polator for output \"" 00308 << getName() << "\" of object \"" 00309 << owner.getName() << "\", with type " 00310 << typeid( _polator ).name() 00311 << " has been associated with this output" ) ; 00312 } 00313 else 00314 { 00315 OMERROR( "Created polator for output \"" 00316 << getName() << "\" of object \"" 00317 << owner.getName() << " is not of type \"" 00318 << " OMK::Type::Polator <" 00319 << typeid( T ).name() << "> *\"" ) ; 00320 } 00321 } 00322 if( _polator == 0 ) 00323 { 00324 OMFATALERROR( "No polator has been made for output \"" 00325 << getName() << "\" of object \"" 00326 << owner.getName() << "\"" ) ; 00327 } 00328 00329 // calculate the appropriate history fifo length 00330 int realSize = 00331 historyLength + _polator->getNumberOfNeededValuesForMaxPrecisionPolation() ; 00332 _history = new Fifo< T >( realSize ) ; 00333 _polator->setFifo( _history ) ; 00334 00335 _usedOutput = this ; 00336 } 00337 00338 //----------------------------------------------------------------------------- 00339 00340 template< typename T > 00341 inline Output< T >::~Output() 00342 { 00343 /* Thread safety assessement : 00344 * thread safe because only one destruction of the object 00345 */ 00346 #ifdef _OMK_MUTEX_ 00347 _myMutex.protect() ; 00348 #endif 00349 00350 typename std::list< Input< T > * >::iterator j ; 00351 for( j = _listOfConnectedUnsensitiveInputs.begin() ; 00352 j != _listOfConnectedUnsensitiveInputs.end() ; 00353 j++ ) 00354 { 00355 (*j)->outputDestroyed() ; 00356 } 00357 00358 #ifdef _OMK_MUTEX_ 00359 _myMutex.unprotect() ; 00360 #endif 00361 00362 if( _aliasOfOutput != 0 ) 00363 { 00364 _aliasOfOutput->aliasedOutputDeleted() ; 00365 } 00366 delete _history ; 00367 } 00368 00369 //----------------------------------------------------------------------------- 00370 00371 template <class T> 00372 inline void Output< T >::setUsedOutput( Output< T > * output ) 00373 { 00374 /* Thread safety assessement : 00375 * multiple simultaneous access possible, and doesn't compromise thread 00376 * safety : last one out wins 00377 */ 00378 _usedOutput = output ; 00379 } 00380 00381 //----------------------------------------------------------------------------- 00382 00383 template< typename T > 00384 inline void Output< T >::setValidity( bool b ) 00385 { 00386 /* Thread safety assessement : 00387 * protected method, used to change protected member : thread safety should 00388 * be insured by callers 00389 */ 00390 _validity = b ; 00391 } 00392 00393 //----------------------------------------------------------------------------- 00394 00395 template< typename T > 00396 inline void Output< T >::unsetAlias() 00397 { 00398 /* Thread safety assessement : 00399 * multiple simultaneous access possible, but they don't compromise thread 00400 * safety : last one out wins 00401 */ 00402 _aliasOfOutput = 0 ; 00403 setUsedOutput( this ) ; 00404 } 00405 00406 //----------------------------------------------------------------------------- 00407 00408 template< typename T > 00409 inline void Output< T >::setAlias( OutputAlias< T > * output ) 00410 { 00411 /* Thread safety assessement : 00412 * multiple simultaneous access possible, but they don't compromise thread 00413 * safety : last one out wins 00414 */ 00415 _aliasOfOutput = output ; 00416 } 00417 00418 //----------------------------------------------------------------------------- 00419 00420 template< typename T > 00421 inline Output< T > * Output< T >::getUsedOutput() const 00422 { 00423 /* Thread safety assessement : 00424 * protected method 00425 * multiple simultaneous access possible, but as long as this method is only 00426 * used onced by each access patern, the OMKOutput stays coherant 00427 */ 00428 return _usedOutput ; 00429 } 00430 00431 //----------------------------------------------------------------------------- 00432 00433 template< typename T > 00434 inline OutputAlias< T > * Output< T >::getAlias() const 00435 { 00436 /* Thread safety assessement : 00437 * protected method 00438 * multiple simultaneous access possible, but as long as this method is only 00439 * used onced by each access patern, the OMKOuptut stays coherant 00440 */ 00441 return _aliasOfOutput ; 00442 } 00443 00444 //----------------------------------------------------------------------------- 00445 00446 template< typename T > 00447 inline const T& Output< T >::get( int & validiteRes, 00448 const int niveauInterpol, 00449 const Date & deltaT, 00450 T& resultPlaceHolder ) const 00451 { 00452 /* Thread safety assessement : 00453 * As thread safe as localGet 00454 */ 00455 #ifdef _DEBUGTYPEUTIL 00456 std::cerr << "Output< T >::get" << std::endl ; 00457 std::cerr << "used Output: "<< getUsedOutpute() << std::endl ; 00458 std::cerr << "file: " << _history << std::endl ; 00459 _history->printDebuggingInformation() ; 00460 informations() ; 00461 #endif 00462 OMASSERT( getUsedOutput() != 0 ) ; 00463 return getUsedOutput()->localGet( 00464 validiteRes, niveauInterpol, deltaT, resultPlaceHolder ) ; 00465 } 00466 00467 //----------------------------------------------------------------------------- 00468 00469 template< typename T > 00470 const T& Output< T >::localGet( int & validiteRes, 00471 const int niveauInterpol, 00472 const Date & deltaT, 00473 T& resultPlaceHolder ) const 00474 { 00475 /* Thread safety assessement : 00476 * As thread safe as polate from OMKInterplateur. But be careful : in a 00477 * multithreaded environment this member function can generate more 00478 * exceptions than expected 00479 */ 00480 touch() ; 00481 if( !_validity ) 00482 { 00483 throw UnInitialisedOutputException( *this, "Output< T >::localGet \n" ) ; 00484 } 00485 00486 #ifdef _DEBUGTYPEUTIL 00487 std::cerr << "Output< T >::localGet" << std::endl ; 00488 std::cerr << owner.getController().getSimulatedDate() << std::endl ; 00489 std::cerr << "Interpolateur : "<< _polator << std::endl ; 00490 #endif 00491 Date date = _owner.getController().getSimulatedDate() - deltaT ; 00492 return _polator->polate( 00493 niveauInterpol, date, validiteRes, resultPlaceHolder ) ; 00494 } 00495 00496 //----------------------------------------------------------------------------- 00497 00498 template< typename T > 00499 void Output< T >::connectedMyself( InputNT * input ) 00500 { 00501 /* Thread safety assessement : 00502 * Critical data is mutex protected 00503 */ 00504 touch() ; 00505 #ifdef _OMK_MUTEX_ 00506 _myMutex.protect() ; 00507 #endif 00508 00509 Input< T > * standardInput = dynamic_cast<Input< T > * >( input ) ; 00510 OMASSERT( standardInput != 0 ) ; 00511 _listOfConnectedUnsensitiveInputs.push_back( standardInput ) ; 00512 00513 #ifdef _OMK_MUTEX_ 00514 _myMutex.unprotect() ; 00515 #endif 00516 } 00517 00518 //----------------------------------------------------------------------------- 00519 00520 template< typename T > 00521 void Output< T >::disconnectedMyself( InputNT * input ) 00522 { 00523 #ifdef _DEBUGALIAS 00524 std::cerr << "Output< T >::disconnectedMyself" << std::endl ; 00525 #endif 00526 00527 /* Thread safety assessement : 00528 * critical data is mutex protected 00529 */ 00530 #ifdef _OMK_MUTEX_ 00531 _myMutex.protect() ; 00532 #endif 00533 00534 Input < T > * unsensitiveInput = dynamic_cast< Input < T > * >( input ) ; 00535 _listOfConnectedUnsensitiveInputs.remove( unsensitiveInput ) ; 00536 00537 #ifdef _OMK_MUTEX_ 00538 _myMutex.unprotect() ; 00539 #endif 00540 } 00541 00542 //----------------------------------------------------------------------------- 00543 00544 template< typename T > 00545 inline void Output< T >::set( const T& newValue, 00546 bool alwaysUpdate /*= false*/ ) 00547 { 00550 #ifndef NDEBUG 00551 if( CurrentActiveObject::getCurrentActiveObject() != &_owner 00552 && CurrentActiveObject::getCurrentActiveObject() != &_owner.getController() 00553 && CurrentActiveObject::getCurrentActiveObject() ) 00554 { 00555 OMERROR( ":-( Error in Output<" << typeid( T ).name() 00556 << ">::set: Unable to set the output \"" 00557 << getName().getString() << "\"" 00558 << std::endl 00559 << "The output owner [" << _owner.getName() 00560 << "] is not the active object [" 00561 << ( CurrentActiveObject::getCurrentActiveObject() ? 00562 CurrentActiveObject::getCurrentActiveObject()->getName().getString() : 00563 std::string( "no active object" ) ) 00564 << "]" ) ; 00565 } 00566 #endif 00567 00568 /*OMASSERT( &_owner == CurrentActiveObject::getCurrentActiveObject() 00569 || CurrentActiveObject::getCurrentActiveObject() == & _owner.getController() 00570 || CurrentActiveObject::getCurrentActiveObject() == 0 ) ;*/ 00571 /* Thread safety assessement : 00572 * localGet and set could collide. Thread safety can only be assured if the 00573 * fifo and the interpolator are thread safe with respect to the value in the 00574 * fifo. 00575 * Only one set at a time. 00576 */ 00577 _history->set( newValue, _date ) ; 00578 setValidity( true ) ; 00579 } 00580 00581 //----------------------------------------------------------------------------- 00582 00583 template< typename T > 00584 inline void Output< T >::extract( std::istream & in ) 00585 { 00586 /* Thread safety assessement : 00587 * localGet and extract could collide. Thread safety can only be assured if 00588 * the fifo and the interpolator are thread safe with respect to the values 00589 * in the fifo. 00590 * Only one extract at a time. 00591 */ 00592 in >> *_history ; 00593 setValidity( true ) ; 00594 } 00595 00596 //----------------------------------------------------------------------------- 00597 00598 template< typename T > 00599 void Output< T >::pack( OutgoingSynchronisationMessage & out ) const 00600 { 00601 //std::cerr << "Output< T >::pack" << std::endl ; 00602 //packs the name of the output, then any usefull information 00603 /* Thread safety assement : 00604 * Thread safe : collides with set and localInsert on the AbstractFifo. But 00605 * they should only be activated by the owner. So as long as the owner isn't 00606 * multithreaded... 00607 * Nota : in a multithreaded environment this member function could generate 00608 * more exceptions than expected 00609 */ 00610 if( _validity && out.getMessageDate() == _history->getPreceedingDate( 0 ) ) 00611 { 00612 getName().pack( out ) ; 00613 _history->pack( out ) ; 00614 } 00615 //else : do not pack anything, therefore mirror will remain uninitialised 00616 //std::cerr << "Output< T >:" << this << ":pack done" << std::endl ; 00617 } 00618 00619 //----------------------------------------------------------------------------- 00620 00621 template< typename T > 00622 void Output< T >::packAllValues( OutgoingSynchronisationMessage & out ) const 00623 { 00624 //std::cerr<<"packAllValues output \"" << getName() << "\"" ) ; 00625 //packs the name of the output, then all initial information 00626 /* Thread safety assement : 00627 * Thread safe : collides with set and localInsert on the AbstractFifo. But 00628 * they should only be activated by the owner. So as long as the owner isn't 00629 * multithreaded, or that the kernel doesn't call this member function during 00630 * activation of the owner... 00631 * Nota : in a multithreaded environment this member function could generate 00632 * more exceptions than expected 00633 */ 00634 if( _validity ) 00635 { 00636 getName().pack( out ) ; 00637 _history->packAllValues( out ) ; 00638 } 00639 //else : do not pack anything, therefore mirror will remain uninitialised 00640 //std::cerr<<"Output< T >:" << this << ":packAllValues done" << std::endl ; 00641 } 00642 00643 //----------------------------------------------------------------------------- 00644 00645 template< typename T > 00646 void Output< T >::unpack( IncomingSynchronisationMessage & in ) 00647 { 00648 // shouldn't unpack the name, but all other usefull information packed 00649 /* Thread safety assessement : 00650 * localGet and extract could collide. Thread safety can only be assured if 00651 * the fifo and the interpolator are thread safe with respect to the values 00652 * in the fifo. 00653 * Only one extract at a time. 00654 */ 00655 _history->unpack( in ) ; 00656 setValidity( true ) ; 00657 } 00658 00659 //----------------------------------------------------------------------------- 00660 00661 template< typename T > 00662 void Output< T >::unpackAllValues( IncomingSynchronisationMessage & in ) 00663 { 00664 // shouldn't unpack the name, but all other usefull information packed 00665 /* Thread safety assessement : 00666 * localGet and extract could collide. Thread safety can only be assured if 00667 * the fifo and the interpolator are thread safe with respect to the values 00668 * in the fifo. 00669 * Only one extract at a time. 00670 */ 00671 _history->unpackAllValues( in ) ; 00672 setValidity( true ) ; 00673 } 00674 00675 //----------------------------------------------------------------------------- 00676 00677 template< typename T > 00678 inline void Output< T >::insertInStream( std::ostream & out ) const 00679 { 00680 /* Thread safety assessement : 00681 * As thread safe as localInsert 00682 */ 00683 getUsedOutput()->localInsert( out ) ; 00684 } 00685 00686 //----------------------------------------------------------------------------- 00687 00688 template< typename T > 00689 inline void Output< T >::localInsert( std::ostream & out ) const 00690 { 00691 /* Thread safety assement 00692 * Thread safe : collides with set on the AbstractFifo. But they should only 00693 * be activated by the owner. So as lmong as the owner isn't multithreaded... 00694 * Nota : in a multithreaded environment this member function could generate 00695 * more exceptions than expected 00696 */ 00697 if( !_validity ) 00698 { 00699 UnInitialisedOutputException exception( *this, 00700 "Output< T >::localInsert\n" ) ; 00701 exception << "Cannot read uninitailised output of " 00702 << _owner.getName().getCString() ; 00703 throw exception ; 00704 } 00705 else 00706 { 00707 out << *_history << " " ; 00708 } 00709 } 00710 00711 //----------------------------------------------------------------------------- 00712 00713 template< typename T > 00714 inline void Output< T >::printHistory() const 00715 { 00716 /* thread safety assessement : 00717 * const method : should be thread safe if printDebuggingInformation of 00718 * AbstractFifo is thread safe 00719 */ 00720 _history->printDebuggingInformation() ; 00721 } 00722 00723 //----------------------------------------------------------------------------- 00724 00725 template< typename T > 00726 inline void Output< T >::printDebuggingInformation( std::ostream & err ) const 00727 { 00728 /* thread safety assessement : 00729 * const method : thread safe. shown value may not be a coherant image of 00730 * an Output 00731 */ 00732 err << std::endl 00733 << "**********************************************************" 00734 << std::endl 00735 << "Class Output" << std::endl 00736 << "Owner : " << _owner.getName() << std::endl 00737 << "Output Name : "<< _name << std::endl 00738 << "T of output : "<< typeid( T ).name() << std::endl 00739 << "Output primary alias : " << getAlias() << std::endl 00740 << "Used Output : " << getUsedOutput() << std::endl 00741 << "History Fifo: " << _history << std::endl ; 00742 } 00743 00744 //----------------------------------------------------------------------------- 00745 00746 template< typename T > 00747 inline void Output< T >::empty() 00748 { 00749 /* Thread safety assessement : 00750 * as thread safe as clear of fifo. Only one simultaneous acces possible (in 00751 * theory). 00752 */ 00753 _history->clear() ; 00754 setValidity( false ) ; 00755 } 00756 00757 //----------------------------------------------------------------------------- 00758 00759 template< typename T > 00760 inline const T& Output< T >::getLastExactValue() const 00761 { 00762 touch() ; 00763 // this bypasses any Polator 00764 if( _history->getNumberOfPresentValues( 1 ) < 1 ) // if no value is stored 00765 { 00766 UnInitialisedOutputException exception( 00767 *this, "Output< T >::getLastExactValue\n" ) ; 00768 exception << "Impossible to get a value from an uninitialised output of " 00769 << _owner.getName().getCString() ; 00770 throw exception ; 00771 } 00772 return _history->getPreceedingValue( 0 ) ; 00773 } 00774 00775 //----------------------------------------------------------------------------- 00776 00777 template< typename T > 00778 inline const Date & Output< T >::getDateOfLastExactValue() const 00779 { 00780 touch() ; 00781 // this bypasses any Polator 00782 if( _history->getNumberOfPresentValues( 1 ) < 1 ) // if no value is stored 00783 { 00784 UnInitialisedOutputException exception( 00785 *this, "Output< T >::getLastExactValue\n" ) ; 00786 exception << "Impossible to get a value from an uninitialised output of " 00787 << _owner.getName().getCString() ; 00788 throw exception ; 00789 } 00790 return _history->getPreceedingDate( 0 ) ; 00791 } 00792 00793 //----------------------------------------------------------------------------- 00794 00795 template< typename T > 00796 inline T& Output< T >::getNextPlaceHolder() 00797 { 00798 return _history->getNextPlaceHolder() ; 00799 } 00800 00801 //----------------------------------------------------------------------------- 00802 00803 template< typename T > 00804 inline void Output< T >::setInPlace( const T& newValue ) 00805 { 00806 _history->setInPlace( newValue, _date ) ; 00807 setValidity( true ) ; 00808 } 00809 00810 //----------------------------------------------------------------------------- 00811 00812 template< typename T > 00813 inline void Output< T >::suggest( const T& newValue ) 00814 { 00815 if( !_validity ) 00816 { 00817 _history->set( newValue , _owner.getController().getSimulatedDate() ) ; 00818 setValidity( true ) ; 00819 } 00820 } 00821 00822 //----------------------------------------------------------------------------- 00823 00824 } // namespace OMK 00825 00826 #endif
Documentation generated on Mon Jun 9 11:45:57 2008 |
Generated with doxygen by Dimitri van Heesch , 1997-2007 |