Changeset 487


Ignore:
Timestamp:
Oct 14, 2007, 12:20:17 AM (11 years ago)
Author:
Peter Johansson
Message:

fixes #272 in trunk and also #211 - split stats class into inherited and base class

Location:
trunk
Files:
9 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/bin/svndigest.cc

    r452 r487  
    2424#include "Parameter.h"
    2525
     26#include "ClassicStats.h"
    2627#include "Configuration.h"
    2728#include "css.h"
     
    143144  if (option->verbose())
    144145    std::cout << "Parsing directory tree" << std::endl;
    145   Stats stats(option->root());
    146   stats+=tree->parse(option->verbose());
     146  ClassicStats stats(tree->parse(option->verbose()));
    147147
    148148  if (option->report()) {
  • trunk/lib/ClassicStats.cc

    r482 r487  
    2323*/
    2424
    25 #include "Stats.h"
     25#include "ClassicStats.h"
    2626
    2727#include "Functor.h"
     
    5050
    5151
    52   Stats::Stats(const std::string& path)
    53   {
    54     // Make sure latest revision is set properly
    55     SVNinfo svn_info(path);
    56     revision_=svn_info.rev();
    57     last_changed_rev_=svn_info.last_changed_rev();
    58   }
    59 
    60 
    61   std::vector<u_int> Stats::accumulated(const Map_& map) const
     52  ClassicStats::ClassicStats(const std::string& path)
     53    : Stats(path)
     54  {
     55  }
     56
     57
     58  std::vector<u_int> ClassicStats::accumulated(const Map_& map) const
    6259  {
    6360    // sum of all users
    64     std::vector<u_int> sum(revision_+1);
     61    std::vector<u_int> sum(revision()+1);
    6562    sum=std::accumulate(map.begin(), map.end(), sum,
    6663                        PairValuePlus<std::string,u_int>());
     
    7370  }
    7471
    75   std::vector<u_int> Stats::accumulated(const Map_& map,
     72  std::vector<u_int> ClassicStats::accumulated(const Map_& map,
    7673                                        const std::string& user) const
    7774  {
    7875    if (!map.count(user))
    79       return std::vector<u_int>(last_changed_rev_,0);
     76      return std::vector<u_int>(last_changed_rev(),0);
    8077    std::vector<u_int> vec=(map.find(user))->second;
    8178
    8279    // static_cast to remove annoying compiler warning
    83     if (vec.size() < static_cast<size_t>(revision_+1))
    84       vec.insert(vec.end(), revision_+1-vec.size(), 0);
     80    if (vec.size() < static_cast<size_t>(revision()+1))
     81      vec.insert(vec.end(), revision()+1-vec.size(), 0);
    8582
    8683    std::vector<u_int> accum(vec.size());
     
    8986  }
    9087
    91   void Stats::add(const std::string& user, const u_int& rev,
    92                   const Parser::line_type& lt)
     88  void ClassicStats::add(const std::string& user, const u_int& rev,
     89                         const Parser::line_type& lt)
    9390  {
    9491    assert(user.size());
    95     authors_.insert(user);
     92    add_author(user);
    9693
    9794    std::vector<u_int>* total = &(total_[user]);
    9895    assert(total);
    9996    if (total->size() < rev+1){
    100       total->reserve(revision_ + 1);
     97      total->reserve(revision() + 1);
    10198      total->insert(total->end(), rev - total->size(), 0);
    10299      total->push_back(1);
     
    108105    assert(code);
    109106    if (code->size() < rev+1){
    110       code->reserve(revision_ + 1);
     107      code->reserve(revision() + 1);
    111108      code->insert(code->end(), rev - code->size(), 0);
    112109      if (lt == Parser::code)
     
    121118    assert(comments);
    122119    if (comments->size() < rev+1){
    123       comments->reserve(revision_ + 1);
     120      comments->reserve(revision() + 1);
    124121      comments->insert(comments->end(), rev - comments->size(), 0);
    125122      if (lt == Parser::comment)
     
    134131    assert(empty);
    135132    if (empty->size() < rev+1){
    136       empty->reserve(revision_ + 1);
     133      empty->reserve(revision() + 1);
    137134      empty->insert(empty->end(), rev - empty->size(), 0);
    138135      if (lt == Parser::empty)
     
    146143
    147144
    148   bool Stats::load_cache(std::istream& is)
     145  bool ClassicStats::do_load_cache(std::istream& is)
    149146  {
    150147    svn_revnum_t rev;
    151148    is >> rev;
    152     if (rev<last_changed_rev_){
     149    if (rev<last_changed_rev()){
    153150      return false; // cache is not up to date
    154151    }
     152    reset();
    155153    size_t a_size=0;
    156     authors_.clear();
    157154    is >> a_size;
    158155    std::string str;
    159     while (authors_.size()<a_size){
     156    while (authors().size()<a_size){
    160157      getline(is, str);
    161158      assert(str.size());
    162       authors_.insert(str);
     159      add_author(str);
    163160    }
    164161    getline(is, str);
     
    191188
    192189
    193   void Stats::load(std::istream& is, Map_& m)
    194   {
    195     m.clear();
    196     while (m.size() < authors_.size() && is.good()) {
     190  void ClassicStats::load(std::istream& is, Map_& m)
     191  {
     192    while (m.size() < authors().size() && is.good()) {
    197193      std::string name;
    198194      std::getline(is, name);
     
    211207
    212208
    213   void Stats::parse(const std::string& path)
     209  void ClassicStats::do_parse(const std::string& path)
    214210  {
    215211    Parser parser(path);
     
    222218      ++count;
    223219    }
    224    
    225   }
    226 
    227 
    228   std::string Stats::plot(const std::string& filename,
    229                           const std::string& linetype) const
     220  }
     221
     222
     223  std::string ClassicStats::do_plot(const std::string& filename,
     224                                    const std::string& linetype) const
    230225  {
    231226    plot_init(filename);
     
    288283
    289284
    290   void Stats::plot_init(const std::string& filename) const
    291   {
    292     GnuplotFE* gp=GnuplotFE::instance();
    293     gp->command("set term png");
    294     gp->command("set output '"+filename+"'");
    295     gp->command("set xtics nomirror");
    296     gp->command("set ytics nomirror");
    297     gp->command("set key default");
    298     gp->command("set key left Left reverse");
    299     gp->command("set multiplot");
    300   }
    301 
    302 
    303   void Stats::plot_summary(const std::string& filename) const
    304   {
    305     plot_init(filename);
    306     GnuplotFE* gp=GnuplotFE::instance();
    307     std::vector<u_int> total=accumulated(total_);   
    308     double yrange_max=1.03*total.back()+1;
    309     gp->yrange(yrange_max);
    310     std::stringstream ss;
    311    
    312     ss.str("");
    313     std::vector<u_int> x=accumulated(code_);   
    314     ss << x.back() << " code";
    315     gp->command("set key height 2");
    316     gp->linetitle(ss.str());
    317     gp->linestyle("steps 2");
    318     gp->plot(x);
    319 
    320     ss.str("");
    321     x=accumulated(comments_);   
    322     ss << x.back() << " comment";
    323     gp->command("set key height 4");
    324     gp->linetitle(ss.str());
    325     gp->linestyle("steps 3");
    326     gp->plot(x);
    327 
    328     ss.str("");
    329     x=accumulated(empty_);   
    330     ss << x.back() << " other";
    331     gp->command("set key height 6");
    332     gp->linetitle(ss.str());
    333     gp->linestyle("steps 4");
    334     gp->plot(x);
    335 
    336     ss.str("");
    337     ss << total.back() << " total";
    338     gp->command("set key height 0");
    339     gp->linetitle(ss.str());
    340     gp->linestyle("steps 1");
    341     gp->plot(total);
    342 
    343     gp->command("unset multiplot");
    344     gp->yrange();
    345   }
    346 
    347 
    348   void Stats::print(std::ostream& os) const
    349   {
    350     os << last_changed_rev_ << " ";
    351     os << authors_.size() << " ";
    352 
    353     std::copy(authors_.begin(), authors_.end(),
     285  void ClassicStats::do_print(std::ostream& os) const
     286  {
     287    os << last_changed_rev() << " ";
     288    os << authors().size() << " ";
     289
     290    std::copy(authors().begin(), authors().end(),
    354291              std::ostream_iterator<std::string>(os, "\n"));
    355292    os << code_cache() << "\n";
    356     print(os, code_);
     293    do_print(os, code_);
    357294    os << "\n" << comments_cache() << "\n";
    358     print(os, comments_);
     295    do_print(os, comments_);
    359296    os << "\n" << empty_cache() << "\n";
    360     print(os, empty_);
     297    do_print(os, empty_);
    361298    os << "\n" << total_cache() << "\n";
    362     print(os, total_);
     299    do_print(os, total_);
    363300    os << "\n" << end_of_cache() << "\n";
    364301  }
    365302
    366303
    367   void Stats::print(std::ostream& os, const Map_& m) const
     304  void ClassicStats::do_print(std::ostream& os, const Map_& m) const
    368305  {
    369306    for (MapConstIter_ i(m.begin()); i!=m.end(); ++i){
     
    375312  }
    376313
    377 
    378   Stats& Stats::operator+=(const Stats& other)
     314 
     315  std::vector<u_int> ClassicStats::vector(std::string type,
     316                                          std::string user) const
     317  {
     318    const Map_* map = NULL;
     319    if (type=="code")
     320      map = &code_;
     321    else if (type=="comments")
     322      map = &comments_;
     323    else if (type=="other")
     324      map = &empty_;
     325    assert(map && "type is of invalid type");
     326    if (!map->count(user))
     327      return std::vector<u_int>(last_changed_rev(),0);
     328    const std::vector<u_int>& vec=(map->find(user))->second;
     329   
     330    std::vector<u_int> accum(vec.size());
     331    std::partial_sum(vec.begin(),vec.end(),accum.begin());
     332    // static_cast to remove annoying compiler warning
     333    if (accum.size() < static_cast<size_t>(revision()+1))
     334      accum.insert(accum.end(), revision()+1-vec.size(), accum.back());
     335    return accum;
     336
     337  }
     338
     339
     340  ClassicStats& ClassicStats::operator+=(const ClassicStats& rhs)
    379341  {
    380     for (MapConstIter_ o_i= other.code_.begin();
    381          o_i != other.code_.end(); ++o_i)
    382     {
    383       std::pair<MapIter_,bool> result = code_.insert(*o_i);
    384       if (!result.second)
    385         code_[(*(result.first)).first] =
    386           VectorPlus<u_int>()( (*(result.first)).second, (*o_i).second );
    387  
    388     }
    389  
    390     for (MapConstIter_ o_i= other.comments_.begin();
    391          o_i != other.comments_.end(); ++o_i)
    392     {
    393       std::pair<MapIter_,bool> result = comments_.insert(*o_i);
    394       if (!result.second)
    395         comments_[(*(result.first)).first] =
    396           VectorPlus<u_int>()( (*(result.first)).second, (*o_i).second );
    397  
    398     }
     342    base_add(rhs.code_.begin(), rhs.code_.end(), code_);
     343    base_add(rhs.comments_.begin(), rhs.comments_.end(), comments_);
     344    base_add(rhs.empty_.begin(), rhs.empty_.end(), empty_);
     345    base_add(rhs.total_.begin(), rhs.total_.end(), total_);
    399346   
    400     for (MapConstIter_ o_i= other.empty_.begin();
    401          o_i != other.empty_.end(); ++o_i)
    402     {
    403       std::pair<MapIter_,bool> result = empty_.insert(*o_i);
    404       if (!result.second)
    405         empty_[(*(result.first)).first] =
    406           VectorPlus<u_int>()( (*(result.first)).second, (*o_i).second );
    407  
    408     }
    409    
    410     for (MapConstIter_ o_i= other.total_.begin();
    411          o_i != other.total_.end(); ++o_i)
    412     {
    413       std::pair<MapIter_,bool> result = total_.insert(*o_i);
    414       if (!result.second)
    415         total_[(*(result.first)).first] =
    416           VectorPlus<u_int>()( (*(result.first)).second, (*o_i).second );
    417  
    418     }
    419    
    420     if (!other.authors().empty())
    421       authors_.insert(other.authors().begin(), other.authors().end());
     347    base_add(rhs);
    422348    return *this;
    423349  }
  • trunk/lib/ClassicStats.h

    r482 r487  
    1 #ifndef _theplu_svndigest_stats_
    2 #define _theplu_svndigest_stats_
     1#ifndef _theplu_svndigest_classic_stats_
     2#define _theplu_svndigest_classic_stats_
    33
    44// $Id$
     
    2727*/
    2828
    29 #include "Parser.h"
    30 
    31 #include <subversion-1/svn_types.h>
    32 
    33 #include <map>
    34 #include <istream>
    35 #include <set>
    36 #include <string>
    37 #include <vector>
     29#include "Stats.h"
    3830
    3931namespace theplu{
     
    4335  /// Class taking care of statistics from svn.
    4436  ///
    45   class Stats
     37  class ClassicStats : public Stats
    4638  {
    4739  public:
     
    4941    /// @brief Default Constructor
    5042    ///
    51     explicit Stats(const std::string& path);
    52 
    53     ///
    54     /// @return set of authors
    55     ///
    56     inline const std::set<std::string>& authors(void) const { return authors_; }
     43    explicit ClassicStats(const std::string& path);
    5744
    5845    ///
     
    9077
    9178    ///
    92     ///
    93     ///
    94     inline u_int last_changed_rev(void) const { return last_changed_rev_; }
    95 
    96     ///
    9779    ///
    9880    ///
     
    10587    { return accumulated(total_, user).back(); }
    10688
    107     /**
    108        Load object from a stream.
    109        
    110        \return true if successful
    111      */
    112     bool load_cache(std::istream&);
    113 
    114     void parse(const std::string&);
    115 
    116     ///
    117     /// Create statistics graph.
    118     ///
    119     std::string plot(const std::string&, const std::string&) const;
    120 
    121     ///
    122     /// Create statistics graph.
    123     ///
    124     void plot_init(const std::string& output) const;
    125 
    12689    ///
    12790    /// Summary plot for the first page
    12891    ///
    12992    void plot_summary(const std::string& output) const;
    130 
    131     /**
    132      */
    133     void print(std::ostream&) const;
    134 
    135     ///
    136     /// @brief Clear all statistics
    137     ///
    138     inline void reset(void)
    139     {
    140       code_.clear(); comments_.clear(); empty_.clear(); total_.clear();
    141       authors_.clear();
    142     }
    143 
    144     ///
    145     /// \return latest revision for whole project
    146     ///
    147     inline u_int revision(void) const { return revision_; }
    14893
    14994    ///
     
    156101    /// @return resulting Stats
    157102    ///
    158     Stats& operator+=(const Stats&);
     103    ClassicStats& operator+=(const ClassicStats&);
    159104
    160105  private:
     
    164109    typedef Map_::const_iterator MapConstIter_;
    165110
    166     ///
    167     /// Copy constructor (not implemented)
    168     ///
    169     Stats(const Stats& other);
     111    /// using compiler generated copy
     112    //ClassicStats(const ClassicStats& other);
    170113
    171114    ///
     
    186129             const Parser::line_type&);
    187130
     131    /**
     132       Load object from a stream.
     133       
     134       \return true if successful
     135     */
     136    bool do_load_cache(std::istream&);
     137
     138    void do_parse(const std::string&);
     139
     140    ///
     141    /// Create statistics graph.
     142    ///
     143    std::string do_plot(const std::string&, const std::string&) const;
     144
     145    /**
     146     */
     147    void do_print(std::ostream&) const;
     148
     149    ///
     150    /// @brief Clear all statistics
     151    ///
     152    inline void do_reset(void)
     153    {
     154      code_.clear(); comments_.clear(); empty_.clear(); total_.clear();
     155    }
     156
    188157    // Change this string if cache format is changed in such a way
    189158    // that all old cache files are obsolete.
    190     inline std::string end_of_cache(void) const {return "END OF OK CACHE FILE";}
    191     inline std::string code_cache(void) const {return "CACHE CODE";}
    192     inline std::string comments_cache(void) const {return "CACHE COMMENTS";}
    193     inline std::string empty_cache(void) const {return "CACHE EMPTY";}
    194     inline std::string total_cache(void) const {return "CACHE TOTAL";}
     159    inline std::string end_of_cache(void) const
     160    {return "END OF OK CACHE FILE VERSION 2";}
    195161   
    196162
     163    std::vector<u_int> vector(std::string type, std::string user) const;
    197164    /**
    198165       Load map from stream
     
    200167    void load(std::istream&, Map_&);
    201168
    202     void print(std::ostream& os, const Map_& map) const;
     169    void do_print(std::ostream& os, const Map_& map) const;
    203170
    204     svn_revnum_t revision_; // Should be the latest revision for whole project
    205     svn_revnum_t last_changed_rev_; // Should be the latest revision for file
    206 
    207     std::set<std::string> authors_;
    208171    Map_ code_;
    209172    Map_ comments_;
  • trunk/lib/Directory.cc

    r482 r487  
    129129  }
    130130
    131   const Stats& Directory::parse(const bool verbose)
     131  const ClassicStats& Directory::parse(const bool verbose)
    132132  {
    133133    stats_.reset();
  • trunk/lib/Directory.h

    r452 r487  
    8181    std::string output_path(void) const;
    8282
    83     const Stats& parse(const bool verbose=false);
     83    const ClassicStats& parse(const bool verbose=false);
    8484
    8585    void print_copyright(std::map<std::string, Alias>&, bool verbose) const;
  • trunk/lib/File.cc

    r483 r487  
    189189
    190190
    191   const Stats& File::parse(const bool verbose)
     191  const ClassicStats& File::parse(const bool verbose)
    192192  {
    193193    if (verbose)
  • trunk/lib/File.h

    r462 r487  
    6464    /// @return Stats object of the file
    6565    ///
    66     const Stats& parse(const bool verbose=false);
     66    const ClassicStats& parse(const bool verbose=false);
    6767
    6868    /**
  • trunk/lib/Makefile.am

    r465 r487  
    2626noinst_LTLIBRARIES = libsvndigest.la
    2727
    28 noinst_HEADERS = Alias.h ColumnStream.h Commitment.h Configuration.h css.h\
     28noinst_HEADERS = Alias.h ClassicStats.h ColumnStream.h \
     29  Commitment.h Configuration.h css.h\
    2930  Date.h Directory.h File.h first_page.h Functor.h Gnuplot.h GnuplotFE.h \
    3031  HtmlStream.h html_utility.h LogIterator.h Node.h Parser.h rmdirhier.h \
     
    3233  SVNinfo.h SVNlog.h SVNproperty.h Trac.h utility.h
    3334
    34 libsvndigest_la_SOURCES = Alias.cc ColumnStream.cc \
     35libsvndigest_la_SOURCES = Alias.cc ClassicStats.cc ColumnStream.cc \
    3536  Commitment.cc Configuration.cc \
    3637  css.cc Date.cc Directory.cc File.cc first_page.cc\
  • trunk/lib/Node.h

    r482 r487  
    2626
    2727#include "html_utility.h"
    28 #include "Stats.h"
     28#include "ClassicStats.h"
    2929#include "SVNinfo.h"
    3030#include "SVNlog.h"
     
    151151    /// @brief parsing file using svn blame.
    152152    ///
    153     virtual const Stats& parse(const bool verbose=false)=0;
     153    virtual const ClassicStats& parse(const bool verbose=false)=0;
    154154
    155155    ///
     
    198198    std::string path_; // absolute path
    199199    static std::string project_;
    200     Stats stats_;
     200    ClassicStats stats_;
    201201
    202202  private:
  • trunk/lib/Stats.cc

    r483 r487  
    5151
    5252  Stats::Stats(const std::string& path)
     53    : valid_(true)
    5354  {
    5455    // Make sure latest revision is set properly
     
    5960
    6061
    61   std::vector<u_int> Stats::accumulated(const Map_& map) const
    62   {
    63     // sum of all users
    64     std::vector<u_int> sum(revision_+1);
    65     sum=std::accumulate(map.begin(), map.end(), sum,
    66                         PairValuePlus<std::string,u_int>());
    67 
    68     // calculate accumulated sum
    69     std::vector<u_int> accum(sum.size());
    70     std::partial_sum(sum.begin(),sum.end(),accum.begin());
    71     assert(sum.size()==accum.size());
    72     return accum;
    73   }
    74 
    75   std::vector<u_int> Stats::accumulated(const Map_& map,
    76                                         const std::string& user) const
    77   {
    78     if (!map.count(user))
    79       return std::vector<u_int>(last_changed_rev_,0);
    80     std::vector<u_int> vec=(map.find(user))->second;
    81 
    82     // static_cast to remove annoying compiler warning
    83     if (vec.size() < static_cast<size_t>(revision_+1))
    84       vec.insert(vec.end(), revision_+1-vec.size(), 0);
    85 
    86     std::vector<u_int> accum(vec.size());
    87     std::partial_sum(vec.begin(),vec.end(),accum.begin());
    88     return accum;
    89   }
    90 
    91   void Stats::add(const std::string& user, const u_int& rev,
    92                   const Parser::line_type& lt)
    93   {
    94     assert(user.size());
    95     authors_.insert(user);
    96 
    97     std::vector<u_int>* total = &(total_[user]);
    98     assert(total);
    99     if (total->size() < rev+1){
    100       total->reserve(revision_ + 1);
    101       total->insert(total->end(), rev - total->size(), 0);
    102       total->push_back(1);
     62  Stats::~Stats(void)
     63  {
     64  }
     65
     66
     67  void Stats::base_add(v_map::const_iterator first1,
     68                       v_map::const_iterator last1, v_map& map)
     69  {
     70    v_map::iterator first2(map.begin());
     71    v_map::key_compare compare;
     72    while ( first1 != last1) {
     73      // key of first1 less than key of first2
     74      if (first2==map.end() || compare(first1->first,first2->first)) {
     75        first2 = map.insert(first2, *first1);
     76        ++first1;
     77      }
     78      // key of first2 less than key of first1
     79      else if ( compare(first2->first, first1->first)) {
     80        ++first2;
     81      }
     82      // keys are equivalent
     83      else {
     84        VectorPlus<v_map::mapped_type::value_type> vp;
     85        first2->second = vp(first1->second, first2->second);
     86        ++first1;
     87        ++first2;
     88      }
    10389    }
    104     else
    105       ++(*total)[rev];
    106 
    107     std::vector<u_int>* code = &(code_[user]);
    108     assert(code);
    109     if (code->size() < rev+1){
    110       code->reserve(revision_ + 1);
    111       code->insert(code->end(), rev - code->size(), 0);
    112       if (lt == Parser::code)
    113         code->push_back(1);
    114       else
    115         code->push_back(0);
    116     }
    117     else if (lt == Parser::code)
    118       ++(*code)[rev];
    119 
    120     std::vector<u_int>* comments = &(comments_[user]);
    121     assert(comments);
    122     if (comments->size() < rev+1){
    123       comments->reserve(revision_ + 1);
    124       comments->insert(comments->end(), rev - comments->size(), 0);
    125       if (lt == Parser::comment)
    126         comments->push_back(1);
    127       else
    128         comments->push_back(0);
    129     }
    130     else if (lt == Parser::comment)
    131       ++(*comments)[rev];
    132 
    133     std::vector<u_int>* empty = &(empty_[user]);
    134     assert(empty);
    135     if (empty->size() < rev+1){
    136       empty->reserve(revision_ + 1);
    137       empty->insert(empty->end(), rev - empty->size(), 0);
    138       if (lt == Parser::empty)
    139         empty->push_back(1);
    140       else
    141         empty->push_back(0);
    142     }
    143     else if (lt == Parser::empty)
    144       ++(*empty)[rev];
    145   }
    146 
     90  }
     91
     92
     93  void Stats::add_author(std::string name)
     94  {
     95    authors_.insert(name);
     96  }
     97
     98
     99  void Stats::add_authors(std::set<std::string>::const_iterator first,
     100                          std::set<std::string>::const_iterator last)
     101  {
     102    authors_.insert(first, last);
     103  }
     104
     105
     106  const std::set<std::string>& Stats::authors(void) const
     107  {
     108    return authors_;
     109  }
     110
     111
     112  void Stats::base_add(const Stats& rhs)
     113  {
     114    revision_ = std::max(revision_, rhs.revision_);
     115    last_changed_rev_ = std::max(last_changed_rev_, rhs.last_changed_rev_);
     116    add_authors(rhs.authors().begin(), rhs.authors().end());
     117    valid_ &= rhs.valid();
     118    // if cache not valid no need to update it
     119    if (valid()) {
     120      base_add(rhs.code_.begin(), rhs.code_.end(), code_);
     121      base_add(rhs.comments_.begin(), rhs.comments_.end(), comments_);
     122      base_add(rhs.other_.begin(), rhs.other_.end(), other_);
     123      base_add(rhs.total_.begin(), rhs.total_.end(), total_);
     124    }
     125  }
     126
     127
     128  u_int Stats::code(const std::string& user) const
     129  {
     130    return get_vector(code_, "all").back();
     131  }
     132
     133
     134  u_int Stats::comments(const std::string& user) const
     135  {
     136    return get_vector(comments_, "all").back();
     137  }
     138
     139
     140  u_int Stats::empty(const std::string& user) const
     141  {
     142    return get_vector(other_, "all").back();
     143  }
     144
     145
     146  const std::vector<u_int>& Stats::get_vector(const v_map& m,
     147                                              std::string user) const
     148  {
     149    // Peter, we should avoid calling this function prior all
     150    // statistics are calculated. If, for some reason, this is not
     151    // possible call update_stats() first, however, that function is
     152    // not const so some redesign is needed (e.g. making cache mutable
     153    // or making them pointers)
     154    assert(valid() && "trying to access invalid cache of statistics");
     155    v_map::const_iterator iter(m.find(std::string(user)));
     156    if (iter==m.end())
     157      throw std::runtime_error(user+std::string(" not found i Stats"));
     158    return iter->second;
     159  }
    147160
    148161  bool Stats::load_cache(std::istream& is)
    149162  {
     163
    150164    svn_revnum_t rev;
    151165    is >> rev;
     
    163177      authors_.insert(str);
    164178    }
    165     getline(is, str);
    166     if (str!=code_cache()){
    167       return false;
    168     }
    169     load(is, code_);
    170     getline(is, str);
    171     getline(is, str);
    172     if (str!=comments_cache()){
    173       return false;
    174     }
    175     load(is, comments_);
    176     getline(is, str);
    177     getline(is, str);
    178     if (str!=empty_cache()){
    179       return false;
    180     }
    181     load(is, empty_);
    182     getline(is, str);
    183     getline(is, str);
    184     if (str!=total_cache()){
    185       return false;
    186     }
    187     load(is, total_);
    188     getline(is,str);
    189     getline(is,str);
    190     return str==end_of_cache();
    191   }
    192 
    193 
    194   void Stats::load(std::istream& is, Map_& m)
    195   {
    196     m.clear();
    197     while (m.size() < authors_.size() && is.good()) {
    198       std::string name;
    199       std::getline(is, name);
    200       assert(name.size());
    201       std::vector<u_int>& vec=m[name];
    202       size_t revs=0;
    203       is >> revs;
    204       vec.reserve(revs);
    205       while (vec.size() < revs) {
    206         u_int tmp;
    207         is >> tmp;
    208         vec.push_back(tmp);
    209       }
    210     }
     179    return do_load_cache(is);
     180  }
     181
     182
     183  svn_revnum_t Stats::last_changed_rev(void) const
     184  {
     185    return last_changed_rev_;
     186  }
     187
     188
     189  u_int Stats::lines(const std::string& user) const
     190  {
     191    assert(valid()); return get_vector(total_, "all").back();
    211192  }
    212193
     
    214195  void Stats::parse(const std::string& path)
    215196  {
    216     Parser parser(path);
    217     std::vector<Parser::line_type>::const_iterator count=parser.type().begin();
    218 
    219     SVNblame svn_blame(path);
    220     while (svn_blame.valid()) {
    221       add(svn_blame.author(), svn_blame.revision(), *count);
    222       svn_blame.next_line();
    223       ++count;
    224     }
    225    
    226   }
    227 
     197    valid_=false;
     198    // First we let inherited class do parsing
     199    do_parse(path);
     200    // then we fill up with statistics
     201
     202    update_stats();
     203  }
    228204
    229205  std::string Stats::plot(const std::string& filename,
    230206                          const std::string& linetype) const
    231207  {
    232     plot_init(filename);
    233     GnuplotFE* gp=GnuplotFE::instance();
    234     const Map_* stat=NULL;
    235     if (linetype=="total")
    236       stat = &total_;
    237     else if (linetype=="code")
    238       stat = &code_;
    239     else if (linetype=="comments")
    240       stat = &comments_;
    241     else if (linetype=="empty")
    242       stat = &empty_;
    243     assert(stat);
    244     std::vector<u_int> total=accumulated(*stat);   
    245     double yrange_max=1.03*total.back()+1;
    246     gp->yrange(yrange_max);
    247 
    248     typedef std::vector<std::pair<std::string, std::vector<u_int> > > vec_type;
    249     vec_type author_cont;
    250     author_cont.reserve(stat->size());
    251     for (MapConstIter_ i= stat->begin(); i != stat->end(); ++i) {
    252       author_cont.push_back(std::make_pair(i->first,
    253                                            accumulated(*stat,i->first)));
    254     }
    255 
    256     LessReversed<std::vector<u_int> > lr;
    257     PairSecondCompare<std::string, std::vector<u_int>,
    258       LessReversed<std::vector<u_int> > > compare(lr);
    259     std::sort(author_cont.begin(), author_cont.end(), compare);
    260 
    261     size_t plotno=author_cont.size();
    262     std::stringstream ss;
    263     vec_type::iterator end(author_cont.end());
    264     for (vec_type::iterator i(author_cont.begin()); i!=end; ++i) {
    265       ss.str("");
    266       ss << "set key height " << 2*plotno;
    267       gp->command(ss.str());
    268       ss.str("");
    269       ss << i->second.back() << " " << i->first;
    270       gp->yrange(yrange_max);
    271       gp->linetitle(ss.str());
    272       ss.str("");
    273       ss << "steps " << --plotno+2;
    274       gp->linestyle(ss.str());
    275       gp->plot(i->second);
    276     }
    277     ss.str("");
    278     ss << total.back() << " total";
    279     gp->command("set key height 0");
    280     gp->linetitle(ss.str());
    281     gp->linestyle("steps 1");
    282     gp->plot(total);
    283 
    284     gp->command("unset multiplot");
    285     gp->yrange();
    286 
    287     return filename;
     208    return do_plot(filename, linetype);
    288209  }
    289210
     
    304225  void Stats::plot_summary(const std::string& filename) const
    305226  {
     227    assert(valid());
    306228    plot_init(filename);
    307229    GnuplotFE* gp=GnuplotFE::instance();
    308     std::vector<u_int> total=accumulated(total_);   
     230    std::vector<u_int> total = get_vector(total_, "all");
    309231    double yrange_max=1.03*total.back()+1;
    310232    gp->yrange(yrange_max);
     
    312234   
    313235    ss.str("");
    314     std::vector<u_int> x=accumulated(code_);   
     236    std::vector<u_int> x(get_vector(code_, "all"));
    315237    ss << x.back() << " code";
    316238    gp->command("set key height 2");
     
    320242
    321243    ss.str("");
    322     x=accumulated(comments_);   
     244    x = get_vector(code_, "all");
    323245    ss << x.back() << " comment";
    324246    gp->command("set key height 4");
     
    328250
    329251    ss.str("");
    330     x=accumulated(empty_);   
     252    x = get_vector(code_, "all");
    331253    ss << x.back() << " other";
    332254    gp->command("set key height 6");
     
    354276    std::copy(authors_.begin(), authors_.end(),
    355277              std::ostream_iterator<std::string>(os, "\n"));
    356     os << code_cache() << "\n";
    357     print(os, code_);
    358     os << "\n" << comments_cache() << "\n";
    359     print(os, comments_);
    360     os << "\n" << empty_cache() << "\n";
    361     print(os, empty_);
    362     os << "\n" << total_cache() << "\n";
    363     print(os, total_);
    364     os << "\n" << end_of_cache() << "\n";
    365   }
    366 
    367 
    368   void Stats::print(std::ostream& os, const Map_& m) const
    369   {
    370     for (MapConstIter_ i(m.begin()); i!=m.end(); ++i){
    371       os << i->first << "\n";
    372       os << i->second.size() << " ";
    373       std::copy(i->second.begin(), i->second.end(),
    374                 std::ostream_iterator<u_int>(os, " "));
     278    do_print(os);
     279  }
     280
     281
     282  void Stats::reset(void)
     283  {
     284    do_reset();
     285  }
     286
     287
     288  void Stats::update_stats(void)
     289  {
     290    for (std::set<std::string>::const_iterator iter(authors_.begin());
     291         iter!=authors_.end(); ++iter) {
     292      std::vector<u_int> code(vector("code", *iter));
     293      code_[*iter] = code;
     294      std::vector<u_int> comments(vector("comments", *iter));
     295      comments_[*iter] = comments;
     296      std::vector<u_int> other(vector("other", *iter));
     297      other_[*iter] = other;
     298      VectorPlus<u_int> vp;
     299      total_[*iter] = vp(vp(code, comments),other);
    375300    }
    376   }
    377 
    378 
    379   Stats& Stats::operator+=(const Stats& other)
    380   {
    381     for (MapConstIter_ o_i= other.code_.begin();
    382          o_i != other.code_.end(); ++o_i)
    383     {
    384       std::pair<MapIter_,bool> result = code_.insert(*o_i);
    385       if (!result.second)
    386         code_[(*(result.first)).first] =
    387           VectorPlus<u_int>()( (*(result.first)).second, (*o_i).second );
    388  
    389     }
    390  
    391     for (MapConstIter_ o_i= other.comments_.begin();
    392          o_i != other.comments_.end(); ++o_i)
    393     {
    394       std::pair<MapIter_,bool> result = comments_.insert(*o_i);
    395       if (!result.second)
    396         comments_[(*(result.first)).first] =
    397           VectorPlus<u_int>()( (*(result.first)).second, (*o_i).second );
    398  
    399     }
    400    
    401     for (MapConstIter_ o_i= other.empty_.begin();
    402          o_i != other.empty_.end(); ++o_i)
    403     {
    404       std::pair<MapIter_,bool> result = empty_.insert(*o_i);
    405       if (!result.second)
    406         empty_[(*(result.first)).first] =
    407           VectorPlus<u_int>()( (*(result.first)).second, (*o_i).second );
    408  
    409     }
    410    
    411     for (MapConstIter_ o_i= other.total_.begin();
    412          o_i != other.total_.end(); ++o_i)
    413     {
    414       std::pair<MapIter_,bool> result = total_.insert(*o_i);
    415       if (!result.second)
    416         total_[(*(result.first)).first] =
    417           VectorPlus<u_int>()( (*(result.first)).second, (*o_i).second );
    418  
    419     }
    420    
    421     if (!other.authors().empty())
    422       authors_.insert(other.authors().begin(), other.authors().end());
    423     return *this;
    424   }
     301    std::vector<u_int> init(revision()+1);
     302    code_["all"]=std::accumulate(code_.begin(), code_.end(), init,
     303                                 PairValuePlus<std::string,u_int>());
     304    comments_["all"]=std::accumulate(comments_.begin(), comments_.end(), init,
     305                                     PairValuePlus<std::string,u_int>());
     306    other_["all"]=std::accumulate(other_.begin(), other_.end(), init,
     307                                  PairValuePlus<std::string,u_int>());
     308    VectorPlus<u_int> vp;
     309    total_["all"] = vp(vp(code_["all"], comments_["all"]), other_["all"]);
     310    valid_=true;
     311  }
     312
    425313
    426314}} // end of namespace svndigest and namespace theplu
  • trunk/lib/Stats.h

    r484 r487  
    5151    explicit Stats(const std::string& path);
    5252
     53    /**
     54       \brief Destructor
     55    */
     56    virtual ~Stats(void);
     57
    5358    ///
    5459    /// @return set of authors
    5560    ///
    56     inline const std::set<std::string>& authors(void) const { return authors_; }
     61    const std::set<std::string>& authors(void) const;
    5762
    5863    ///
    5964    ///
    6065    ///
    61     inline u_int code(void) const { return accumulated(code_).back(); }
     66    u_int code(const std::string& user="all") const;
     67
    6268
    6369    ///
    6470    ///
    6571    ///
    66     inline u_int code(const std::string& user) const
    67     { return accumulated(code_, user).back(); }
     72    u_int comments(const std::string& user="all") const;
    6873
    6974    ///
    7075    ///
    7176    ///
    72     inline u_int comments(void) const { return accumulated(comments_).back(); }
     77    u_int empty(const std::string& user="all") const;
     78
     79    ///
     80    ///
     81    ///
     82    svn_revnum_t last_changed_rev(void) const;
    7383
    7484    ///
    7585    ///
    7686    ///
    77     inline u_int comments(const std::string& user) const
    78     { return accumulated(comments_, user).back(); }
    79 
    80     ///
    81     ///
    82     ///
    83     inline u_int empty(void) const { return accumulated(empty_).back(); }
    84 
    85     ///
    86     ///
    87     ///
    88     inline u_int empty(const std::string& user) const
    89     { return accumulated(empty_, user).back(); }
    90 
    91     ///
    92     ///
    93     ///
    94     inline u_int last_changed_rev(void) const { return last_changed_rev_; }
    95 
    96     ///
    97     ///
    98     ///
    99     inline u_int lines(void) const { return accumulated(total_).back(); }
    100 
    101     ///
    102     ///
    103     ///
    104     inline u_int lines(const std::string& user) const
    105     { return accumulated(total_, user).back(); }
     87    u_int lines(const std::string& user="all") const;
    10688
    10789    /**
     
    11294    bool load_cache(std::istream&);
    11395
     96    /**
     97       Do the parsing
     98    */
    11499    void parse(const std::string&);
    115100
     
    120105
    121106    ///
    122     /// Create statistics graph.
    123     ///
    124     void plot_init(const std::string& output) const;
    125 
    126     ///
    127     /// Summary plot for the first page
     107    /// Plotting code, comment, other, and total in same plot (for
     108    /// 'all' not individual authors).
    128109    ///
    129110    void plot_summary(const std::string& output) const;
    130111
    131112    /**
     113       Send Stats to a stream.
    132114     */
    133115    void print(std::ostream&) const;
     
    136118    /// @brief Clear all statistics
    137119    ///
    138     inline void reset(void)
    139     {
    140       code_.clear(); comments_.clear(); empty_.clear(); total_.clear();
    141       authors_.clear();
    142     }
     120    void reset(void);
    143121
    144122    ///
    145123    /// \return latest revision for whole project
    146124    ///
    147     inline u_int revision(void) const { return revision_; }
     125    svn_revnum_t revision(void) const { return revision_; }
    148126
    149     ///
    150     ///
    151     ///
    152     inline std::vector<u_int> total(const std::string& user) const
    153     { return accumulated(total_, user); }
    154 
    155     ///
    156     /// @return resulting Stats
    157     ///
    158     Stats& operator+=(const Stats&);
    159 
    160   private:
    161     // Peter, if the vector is sparse make it a map
    162     typedef std::map<std::string, std::vector<u_int> > Map_;
    163     typedef Map_::iterator MapIter_;
    164     typedef Map_::const_iterator MapConstIter_;
    165 
    166     ///
    167     /// Copy constructor (not implemented)
    168     ///
    169     Stats(const Stats& other);
    170 
    171     ///
    172     /// @return accumulated vector of total
    173     ///
    174     std::vector<u_int> accumulated(const Map_&) const;
    175 
    176     ///
    177     /// @return accumulated vector of stats_[user]
    178     ///
    179     std::vector<u_int> accumulated(const Map_&,
    180                                    const std::string& user) const;
    181 
    182     ///
    183     /// @brief adding a line to user from revision to the stats
    184     ///
    185     void add(const std::string& user, const u_int& revision,
    186              const Parser::line_type&);
    187 
    188     // Change this string if cache format is changed in such a way
    189     // that all old cache files are obsolete.
    190     inline std::string end_of_cache(void) const
    191     {return "END OF OK CACHE FILE VERSION 2";}
     127  protected:
    192128    inline std::string code_cache(void) const {return "CACHE CODE";}
    193129    inline std::string comments_cache(void) const {return "CACHE COMMENTS";}
    194130    inline std::string empty_cache(void) const {return "CACHE EMPTY";}
    195131    inline std::string total_cache(void) const {return "CACHE TOTAL";}
    196    
     132
     133    typedef std::map<std::string, std::vector<u_int> > v_map;
     134
     135    void add_author(std::string);
     136    void add_authors(std::set<std::string>::const_iterator,
     137                     std::set<std::string>::const_iterator);
    197138
    198139    /**
    199        Load map from stream
     140       Function to be called from children's operator+=
    200141     */
    201     void load(std::istream&, Map_&);
     142    void base_add(const Stats&);
    202143
    203     void print(std::ostream& os, const Map_& map) const;
     144    /**
     145       add range [\a first, \a last) to \a map
     146     */
     147    void base_add(v_map::const_iterator first, v_map::const_iterator last,
     148                  v_map& map);
    204149
     150    ///
     151    /// Init statistics graph.
     152    ///
     153    void plot_init(const std::string& output) const;
     154    inline bool valid(void) const {return valid_;}
     155  private:
     156    virtual bool do_load_cache(std::istream&)=0;
     157    virtual void do_parse(const std::string&)=0;
     158    virtual std::string do_plot(const std::string&, const std::string&) const=0;
     159    virtual void do_print(std::ostream& ) const=0;
     160    virtual void do_reset(void)=0;
     161   
     162    const std::vector<u_int>& get_vector(const v_map&, std::string user) const;
     163    virtual std::vector<u_int> vector(std::string type,
     164                                      std::string user) const=0;
     165    void update_stats(void);
     166
     167    v_map total_;
     168    v_map code_;
     169    v_map comments_;
     170    v_map other_;
     171    bool valid_;
    205172    svn_revnum_t revision_; // Should be the latest revision for whole project
    206173    svn_revnum_t last_changed_rev_; // Should be the latest revision for file
    207174
    208175    std::set<std::string> authors_;
    209     Map_ code_;
    210     Map_ comments_;
    211     Map_ empty_;
    212     Map_ total_;
    213176  };
    214177}} // end of namespace svndigest end of namespace theplu
Note: See TracChangeset for help on using the changeset viewer.