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