OpenWalnut  1.4.0
WProgressCombiner.cpp
00001 //---------------------------------------------------------------------------
00002 //
00003 // Project: OpenWalnut ( http://www.openwalnut.org )
00004 //
00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
00006 // For more information see http://www.openwalnut.org/copying
00007 //
00008 // This file is part of OpenWalnut.
00009 //
00010 // OpenWalnut is free software: you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as published by
00012 // the Free Software Foundation, either version 3 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // OpenWalnut is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public License
00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
00022 //
00023 //---------------------------------------------------------------------------
00024 
00025 #include <sstream>
00026 #include <string>
00027 #include <set>
00028 
00029 #include <boost/utility.hpp>
00030 
00031 #include "WProgressCombiner.h"
00032 
00033 WProgressCombiner::WProgressCombiner( std::string name ):
00034     WProgress( name, 1 ),
00035     m_name( name ),
00036     m_progress( 0.0 )
00037 {
00038     // initialize members
00039     m_pending = false;
00040 }
00041 
00042 WProgressCombiner::~WProgressCombiner()
00043 {
00044     // cleanup
00045 }
00046 
00047 void WProgressCombiner::update()
00048 {
00049     // This updates the internal state. Here, all states from child progress' get combined.
00050 
00051     // get read lock
00052     boost::shared_lock< boost::shared_mutex > rlock;
00053     rlock = boost::shared_lock< boost::shared_mutex >( m_updateLock );
00054 
00055     m_pending = false;
00056     m_determined = true;
00057     m_progress = 0.0;
00058     unsigned int numPendingChildren = 0;
00059 
00060     // as the children define this progress' state -> iterate children
00061     for( std::set< boost::shared_ptr< WProgress > >::iterator i = m_children.begin(); i != m_children.end(); ++i )
00062     {
00063         // enforce child to update
00064         ( *i )->update();
00065 
00066         // update own state basing on child states.
00067         if( ( *i )->isPending() )
00068         {
00069             // This actually builds the mean value. This might cause backstepping in progress, which is not wanted.
00070             m_pending = true;
00071             m_determined &= ( *i )->isDetermined();
00072             m_progress += ( *i )->getProgress();
00073             numPendingChildren++;
00074         }
00075     }
00076     if( numPendingChildren )
00077     {
00078         m_progress /= static_cast< float >( numPendingChildren );
00079     }
00080 
00081     rlock.unlock();
00082 }
00083 
00084 std::string WProgressCombiner::getCombinedNames( bool excludeFinished ) const
00085 {
00086     // read lock combiner
00087     boost::shared_lock< boost::shared_mutex > rlock = boost::shared_lock< boost::shared_mutex >( m_updateLock );
00088 
00089     std::stringstream ss;
00090     bool addComma = false; // when true, a "," is appended before printing the next name. This is needed as we do not know if an element is the
00091                            // last one if excludeFinished == true.
00092     for( std::set< boost::shared_ptr< WProgress > >::const_iterator i = m_children.begin(); i != m_children.end(); ++i )
00093     {
00094         if( !( !( *i )->isPending() && excludeFinished ) )
00095         {
00096             if( addComma )
00097             {
00098                 ss << ", ";
00099             }
00100 
00101             // enforce child to update
00102             ss << ( *i )->getName();
00103             // in next step, add a comma
00104             addComma = true;
00105         }
00106     }
00107 
00108     // Done. Free lock.
00109     rlock.unlock();
00110     return ss.str();
00111 }
00112 
00113 void WProgressCombiner::addSubProgress( boost::shared_ptr< WProgress > progress )
00114 {
00115     boost::unique_lock<boost::shared_mutex> lock = boost::unique_lock<boost::shared_mutex>( m_updateLock );
00116     // add the progress to the children list
00117     m_children.insert( progress );
00118     lock.unlock();
00119 }
00120 
00121 void WProgressCombiner::removeSubProgress( boost::shared_ptr< WProgress > progress )
00122 {
00123     boost::unique_lock<boost::shared_mutex> lock = boost::unique_lock<boost::shared_mutex>( m_updateLock );
00124     // add the progress to the children list
00125     m_children.erase( progress );
00126     lock.unlock();
00127 }
00128 
00129 void WProgressCombiner::finish()
00130 {
00131     // combiner just propagate the finish request down to all children
00132     boost::unique_lock<boost::shared_mutex> lock = boost::unique_lock<boost::shared_mutex>( m_updateLock );
00133 
00134     // as the children define this progress' state -> iterate children
00135     for( std::set< boost::shared_ptr< WProgress > >::iterator i = m_children.begin(); i != m_children.end(); ++i )
00136     {
00137         // enforce child to update
00138         ( *i )->finish();
00139         ( *i )->update();
00140     }
00141 
00142     // remove the children
00143     m_children.clear();
00144 
00145     // set the defaults
00146     WProgress::finish();
00147     m_progress = 0.0;
00148 
00149     lock.unlock();
00150 }
00151 
00152 WProgressCombiner& WProgressCombiner::operator++()
00153 {
00154     // in progress combiners, this can be ignored. The progress is defined by the children.
00155     return *this;
00156 }
00157 
00158 float WProgressCombiner::getProgress()
00159 {
00160     return m_progress;
00161 }
00162