Boost logo

Boost :

Subject: [boost] [Progress]
From: Pierre (pmoulon_at_[hidden])
Date: 2009-07-15 10:02:06


Hello,
I have a suggestion over boost/progress.hpp.

The class is very good. But I have a critic to announce.
If we want to use the class to just keep an eye of the evolution of the
process (we do not can just say we don't want a stream output (i'm
right??)).
I.E : to send the progress pourcentage to a graphical progress bar.

So I purpose something like the following :
  A basic class to manage the evolution of a process.
  A class to display the evolution of the process that use the precedent
one.

It's possible I misunderstanding the progress_display class to tell it
that we don't want stream output (example to feed a graphical progress
bar).

The body of the functions and classes will be something like :

#include <iostream>
#include <string>
using namespace std;
// CProgress --------------------------------------------------------//

// CProgress manage the appropriate count_step of progress

// Usage :
// CProgress progress( COUNT );
// for(int i=0; i < COUNT; ++i, ++progress)
//{
// ... //do something
//}
//-- you can access to internal data :
// //cout<< "Count : " << my_progress_bar.count() << " pourcent " <<
my_progress_bar.count()/(float)my_progress_bar.expected_count()*100;

class CProgress
{
  public:
    explicit CProgress ( unsigned long expected_count=1 )
    { restart ( expected_count ); }

    virtual void restart ( unsigned long expected_count )
    // Effects: display appropriate scale
    // Postconditions: count()==0, expected_count()==expected_count
    {
      _count = _next_tic_count = _tic = 0;
      _expected_count = expected_count;

      if ( !_expected_count ) _expected_count = 1; // prevent divide by
zero
    } // restart

    unsigned long operator+= ( unsigned long increment )
    // Effects: Increment appropriate progress tic if needed.
    // Postconditions: count()== original count() + increment
    // Returns: count().
    {
      if ( ( _count += increment ) >= _next_tic_count ) { inc_tic(); }
      return _count;
    }

    unsigned long operator++() { return operator+= ( 1 ); }

    //-- Accessor
    unsigned long count() const { return _count; }
    unsigned long expected_count() const { return _expected_count; }

  protected:

    unsigned long _count, _expected_count, _next_tic_count;
    unsigned int _tic;

  private:
    virtual void inc_tic()
    {
      _next_tic_count = static_cast<unsigned long> ( ( _tic/50.0 )
*_expected_count );
    } // inc_tic
};

// CProgress_display
--------------------------------------------------------//

// CProgress_display displays an appropriate indication of
// progress at an appropriate place in an appropriate form.

// Usage :
// CProgress_display my_progress_bar( fileList.size() );
// for (list<string>::const_iterator it = fileList.begin(); it !=
fileList.end(); ++it, ++my_progress_bar)
// the CProgress_display::operator++ take in charge the display of the
progression (***)
// {
// const string & filename = *it;
// ... // do something
// }
//
//0% 10 20 30 40 50 60 70 80 90 100%
//|----|----|----|----|----|----|----|----|----|----|
//************************** ...

class CProgress_display : public CProgress
{
  public:
    explicit CProgress_display ( unsigned long expected_count,
                                     std::ostream & os = std::cout,
                                     const std::string & s1 = "\n",
//leading strings
                                     const std::string & s2 = "",
                                     const std::string & s3 = "" )
    // os is hint; implementation may ignore, particularly in embedded
systems
        : m_os ( os ), m_s1 ( s1 ), m_s2 ( s2 ), m_s3 ( s3 ) { restart (
expected_count ); }

    void restart ( unsigned long expected_count )
    // Effects: display appropriate scale
    // Postconditions: count()==0, expected_count()==expected_count
    {
      CLTU_Progress::restart ( expected_count ); //-- Initialize the base
class

      m_os << m_s1 << "0% 10 20 30 40 50 60 70 80 90
100%\n"
      << m_s2 << "|----|----|----|----|----|----|----|----|----|----|"
      << std::endl // endl implies flush, which ensures display
      << m_s3;
    } // restart

  private:
    std::ostream & m_os; // may not be present in all imps
    // string is more general, safer than const char *, and efficiency or
size are not issues
    const std::string m_s1, m_s2, m_s3; // formatting display

    void inc_tic()
    {
      // use of floating point ensures that both large and small counts
      // work correctly. static_cast<>() is also used several places
      // to suppress spurious compiler warnings.
      unsigned int tics_needed = static_cast<unsigned int> ( (
static_cast<double> ( _count ) /_expected_count ) *50.0 );
      do { m_os << '*' << std::flush; }
      while ( ++_tic < tics_needed );
      _next_tic_count = static_cast<unsigned long> ( ( _tic/50.0 )
*_expected_count );
      if ( _count == _expected_count )
      {
        if ( _tic < 51 )
          m_os << '*';
        m_os << std::endl;
      }
    } // display_tic
};

_________
I'm sure the community will be open to discuss about it.

Talk to you,
Best,
Pierre


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk