Changeset 487
- Timestamp:
- Oct 14, 2007, 12:20:17 AM (15 years ago)
- Location:
- trunk
- Files:
-
- 9 edited
- 2 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/bin/svndigest.cc
r452 r487 24 24 #include "Parameter.h" 25 25 26 #include "ClassicStats.h" 26 27 #include "Configuration.h" 27 28 #include "css.h" … … 143 144 if (option->verbose()) 144 145 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())); 147 147 148 148 if (option->report()) { -
trunk/lib/ClassicStats.cc
r482 r487 23 23 */ 24 24 25 #include " Stats.h"25 #include "ClassicStats.h" 26 26 27 27 #include "Functor.h" … … 50 50 51 51 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 62 59 { 63 60 // sum of all users 64 std::vector<u_int> sum(revision _+1);61 std::vector<u_int> sum(revision()+1); 65 62 sum=std::accumulate(map.begin(), map.end(), sum, 66 63 PairValuePlus<std::string,u_int>()); … … 73 70 } 74 71 75 std::vector<u_int> Stats::accumulated(const Map_& map,72 std::vector<u_int> ClassicStats::accumulated(const Map_& map, 76 73 const std::string& user) const 77 74 { 78 75 if (!map.count(user)) 79 return std::vector<u_int>(last_changed_rev _,0);76 return std::vector<u_int>(last_changed_rev(),0); 80 77 std::vector<u_int> vec=(map.find(user))->second; 81 78 82 79 // 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); 85 82 86 83 std::vector<u_int> accum(vec.size()); … … 89 86 } 90 87 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) 93 90 { 94 91 assert(user.size()); 95 a uthors_.insert(user);92 add_author(user); 96 93 97 94 std::vector<u_int>* total = &(total_[user]); 98 95 assert(total); 99 96 if (total->size() < rev+1){ 100 total->reserve(revision _+ 1);97 total->reserve(revision() + 1); 101 98 total->insert(total->end(), rev - total->size(), 0); 102 99 total->push_back(1); … … 108 105 assert(code); 109 106 if (code->size() < rev+1){ 110 code->reserve(revision _+ 1);107 code->reserve(revision() + 1); 111 108 code->insert(code->end(), rev - code->size(), 0); 112 109 if (lt == Parser::code) … … 121 118 assert(comments); 122 119 if (comments->size() < rev+1){ 123 comments->reserve(revision _+ 1);120 comments->reserve(revision() + 1); 124 121 comments->insert(comments->end(), rev - comments->size(), 0); 125 122 if (lt == Parser::comment) … … 134 131 assert(empty); 135 132 if (empty->size() < rev+1){ 136 empty->reserve(revision _+ 1);133 empty->reserve(revision() + 1); 137 134 empty->insert(empty->end(), rev - empty->size(), 0); 138 135 if (lt == Parser::empty) … … 146 143 147 144 148 bool Stats::load_cache(std::istream& is)145 bool ClassicStats::do_load_cache(std::istream& is) 149 146 { 150 147 svn_revnum_t rev; 151 148 is >> rev; 152 if (rev<last_changed_rev _){149 if (rev<last_changed_rev()){ 153 150 return false; // cache is not up to date 154 151 } 152 reset(); 155 153 size_t a_size=0; 156 authors_.clear();157 154 is >> a_size; 158 155 std::string str; 159 while (authors _.size()<a_size){156 while (authors().size()<a_size){ 160 157 getline(is, str); 161 158 assert(str.size()); 162 a uthors_.insert(str);159 add_author(str); 163 160 } 164 161 getline(is, str); … … 191 188 192 189 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()) { 197 193 std::string name; 198 194 std::getline(is, name); … … 211 207 212 208 213 void Stats::parse(const std::string& path)209 void ClassicStats::do_parse(const std::string& path) 214 210 { 215 211 Parser parser(path); … … 222 218 ++count; 223 219 } 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 230 225 { 231 226 plot_init(filename); … … 288 283 289 284 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(), 354 291 std::ostream_iterator<std::string>(os, "\n")); 355 292 os << code_cache() << "\n"; 356 print(os, code_);293 do_print(os, code_); 357 294 os << "\n" << comments_cache() << "\n"; 358 print(os, comments_);295 do_print(os, comments_); 359 296 os << "\n" << empty_cache() << "\n"; 360 print(os, empty_);297 do_print(os, empty_); 361 298 os << "\n" << total_cache() << "\n"; 362 print(os, total_);299 do_print(os, total_); 363 300 os << "\n" << end_of_cache() << "\n"; 364 301 } 365 302 366 303 367 void Stats::print(std::ostream& os, const Map_& m) const304 void ClassicStats::do_print(std::ostream& os, const Map_& m) const 368 305 { 369 306 for (MapConstIter_ i(m.begin()); i!=m.end(); ++i){ … … 375 312 } 376 313 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) 379 341 { 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_); 399 346 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); 422 348 return *this; 423 349 } -
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_ 3 3 4 4 // $Id$ … … 27 27 */ 28 28 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" 38 30 39 31 namespace theplu{ … … 43 35 /// Class taking care of statistics from svn. 44 36 /// 45 class Stats37 class ClassicStats : public Stats 46 38 { 47 39 public: … … 49 41 /// @brief Default Constructor 50 42 /// 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); 57 44 58 45 /// … … 90 77 91 78 /// 92 ///93 ///94 inline u_int last_changed_rev(void) const { return last_changed_rev_; }95 96 ///97 79 /// 98 80 /// … … 105 87 { return accumulated(total_, user).back(); } 106 88 107 /**108 Load object from a stream.109 110 \return true if successful111 */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 126 89 /// 127 90 /// Summary plot for the first page 128 91 /// 129 92 void plot_summary(const std::string& output) const; 130 131 /**132 */133 void print(std::ostream&) const;134 135 ///136 /// @brief Clear all statistics137 ///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 project146 ///147 inline u_int revision(void) const { return revision_; }148 93 149 94 /// … … 156 101 /// @return resulting Stats 157 102 /// 158 Stats& operator+=(constStats&);103 ClassicStats& operator+=(const ClassicStats&); 159 104 160 105 private: … … 164 109 typedef Map_::const_iterator MapConstIter_; 165 110 166 /// 167 /// Copy constructor (not implemented) 168 /// 169 Stats(const Stats& other); 111 /// using compiler generated copy 112 //ClassicStats(const ClassicStats& other); 170 113 171 114 /// … … 186 129 const Parser::line_type&); 187 130 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 188 157 // Change this string if cache format is changed in such a way 189 158 // 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";} 195 161 196 162 163 std::vector<u_int> vector(std::string type, std::string user) const; 197 164 /** 198 165 Load map from stream … … 200 167 void load(std::istream&, Map_&); 201 168 202 void print(std::ostream& os, const Map_& map) const;169 void do_print(std::ostream& os, const Map_& map) const; 203 170 204 svn_revnum_t revision_; // Should be the latest revision for whole project205 svn_revnum_t last_changed_rev_; // Should be the latest revision for file206 207 std::set<std::string> authors_;208 171 Map_ code_; 209 172 Map_ comments_; -
trunk/lib/Directory.cc
r482 r487 129 129 } 130 130 131 const Stats& Directory::parse(const bool verbose)131 const ClassicStats& Directory::parse(const bool verbose) 132 132 { 133 133 stats_.reset(); -
trunk/lib/Directory.h
r452 r487 81 81 std::string output_path(void) const; 82 82 83 const Stats& parse(const bool verbose=false);83 const ClassicStats& parse(const bool verbose=false); 84 84 85 85 void print_copyright(std::map<std::string, Alias>&, bool verbose) const; -
trunk/lib/File.cc
r483 r487 189 189 190 190 191 const Stats& File::parse(const bool verbose)191 const ClassicStats& File::parse(const bool verbose) 192 192 { 193 193 if (verbose) -
trunk/lib/File.h
r462 r487 64 64 /// @return Stats object of the file 65 65 /// 66 const Stats& parse(const bool verbose=false);66 const ClassicStats& parse(const bool verbose=false); 67 67 68 68 /** -
trunk/lib/Makefile.am
r465 r487 26 26 noinst_LTLIBRARIES = libsvndigest.la 27 27 28 noinst_HEADERS = Alias.h ColumnStream.h Commitment.h Configuration.h css.h\ 28 noinst_HEADERS = Alias.h ClassicStats.h ColumnStream.h \ 29 Commitment.h Configuration.h css.h\ 29 30 Date.h Directory.h File.h first_page.h Functor.h Gnuplot.h GnuplotFE.h \ 30 31 HtmlStream.h html_utility.h LogIterator.h Node.h Parser.h rmdirhier.h \ … … 32 33 SVNinfo.h SVNlog.h SVNproperty.h Trac.h utility.h 33 34 34 libsvndigest_la_SOURCES = Alias.cc C olumnStream.cc \35 libsvndigest_la_SOURCES = Alias.cc ClassicStats.cc ColumnStream.cc \ 35 36 Commitment.cc Configuration.cc \ 36 37 css.cc Date.cc Directory.cc File.cc first_page.cc\ -
trunk/lib/Node.h
r482 r487 26 26 27 27 #include "html_utility.h" 28 #include " Stats.h"28 #include "ClassicStats.h" 29 29 #include "SVNinfo.h" 30 30 #include "SVNlog.h" … … 151 151 /// @brief parsing file using svn blame. 152 152 /// 153 virtual const Stats& parse(const bool verbose=false)=0;153 virtual const ClassicStats& parse(const bool verbose=false)=0; 154 154 155 155 /// … … 198 198 std::string path_; // absolute path 199 199 static std::string project_; 200 Stats stats_;200 ClassicStats stats_; 201 201 202 202 private: -
trunk/lib/Stats.cc
r483 r487 51 51 52 52 Stats::Stats(const std::string& path) 53 : valid_(true) 53 54 { 54 55 // Make sure latest revision is set properly … … 59 60 60 61 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 } 103 89 } 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 } 147 160 148 161 bool Stats::load_cache(std::istream& is) 149 162 { 163 150 164 svn_revnum_t rev; 151 165 is >> rev; … … 163 177 authors_.insert(str); 164 178 } 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(); 211 192 } 212 193 … … 214 195 void Stats::parse(const std::string& path) 215 196 { 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 } 228 204 229 205 std::string Stats::plot(const std::string& filename, 230 206 const std::string& linetype) const 231 207 { 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); 288 209 } 289 210 … … 304 225 void Stats::plot_summary(const std::string& filename) const 305 226 { 227 assert(valid()); 306 228 plot_init(filename); 307 229 GnuplotFE* gp=GnuplotFE::instance(); 308 std::vector<u_int> total =accumulated(total_);230 std::vector<u_int> total = get_vector(total_, "all"); 309 231 double yrange_max=1.03*total.back()+1; 310 232 gp->yrange(yrange_max); … … 312 234 313 235 ss.str(""); 314 std::vector<u_int> x =accumulated(code_);236 std::vector<u_int> x(get_vector(code_, "all")); 315 237 ss << x.back() << " code"; 316 238 gp->command("set key height 2"); … … 320 242 321 243 ss.str(""); 322 x =accumulated(comments_);244 x = get_vector(code_, "all"); 323 245 ss << x.back() << " comment"; 324 246 gp->command("set key height 4"); … … 328 250 329 251 ss.str(""); 330 x =accumulated(empty_);252 x = get_vector(code_, "all"); 331 253 ss << x.back() << " other"; 332 254 gp->command("set key height 6"); … … 354 276 std::copy(authors_.begin(), authors_.end(), 355 277 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); 375 300 } 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 425 313 426 314 }} // end of namespace svndigest and namespace theplu -
trunk/lib/Stats.h
r484 r487 51 51 explicit Stats(const std::string& path); 52 52 53 /** 54 \brief Destructor 55 */ 56 virtual ~Stats(void); 57 53 58 /// 54 59 /// @return set of authors 55 60 /// 56 inline const std::set<std::string>& authors(void) const { return authors_; }61 const std::set<std::string>& authors(void) const; 57 62 58 63 /// 59 64 /// 60 65 /// 61 inline u_int code(void) const { return accumulated(code_).back(); } 66 u_int code(const std::string& user="all") const; 67 62 68 63 69 /// 64 70 /// 65 71 /// 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; 68 73 69 74 /// 70 75 /// 71 76 /// 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; 73 83 74 84 /// 75 85 /// 76 86 /// 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; 106 88 107 89 /** … … 112 94 bool load_cache(std::istream&); 113 95 96 /** 97 Do the parsing 98 */ 114 99 void parse(const std::string&); 115 100 … … 120 105 121 106 /// 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). 128 109 /// 129 110 void plot_summary(const std::string& output) const; 130 111 131 112 /** 113 Send Stats to a stream. 132 114 */ 133 115 void print(std::ostream&) const; … … 136 118 /// @brief Clear all statistics 137 119 /// 138 inline void reset(void) 139 { 140 code_.clear(); comments_.clear(); empty_.clear(); total_.clear(); 141 authors_.clear(); 142 } 120 void reset(void); 143 121 144 122 /// 145 123 /// \return latest revision for whole project 146 124 /// 147 inline u_int revision(void) const { return revision_; }125 svn_revnum_t revision(void) const { return revision_; } 148 126 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: 192 128 inline std::string code_cache(void) const {return "CACHE CODE";} 193 129 inline std::string comments_cache(void) const {return "CACHE COMMENTS";} 194 130 inline std::string empty_cache(void) const {return "CACHE EMPTY";} 195 131 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); 197 138 198 139 /** 199 Load map from stream140 Function to be called from children's operator+= 200 141 */ 201 void load(std::istream&, Map_&);142 void base_add(const Stats&); 202 143 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); 204 149 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_; 205 172 svn_revnum_t revision_; // Should be the latest revision for whole project 206 173 svn_revnum_t last_changed_rev_; // Should be the latest revision for file 207 174 208 175 std::set<std::string> authors_; 209 Map_ code_;210 Map_ comments_;211 Map_ empty_;212 Map_ total_;213 176 }; 214 177 }} // end of namespace svndigest end of namespace theplu
Note: See TracChangeset
for help on using the changeset viewer.