Changeset 487


Ignore:
Timestamp:
Oct 14, 2007, 12:20:17 AM (11 years ago)
Author:
peter
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.