source: trunk/lib/Stats.cc @ 528

Last change on this file since 528 was 528, checked in by Peter Johansson, 14 years ago

fixes #280 - keep on refactoring of Stats class

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 7.7 KB
Line 
1// $Id: Stats.cc 528 2007-12-25 10:23:04Z peter $
2
3/*
4  Copyright (C) 2005 Peter Johansson
5  Copyright (C) 2006, 2007 Jari Häkkinen, Peter Johansson
6
7  This file is part of svndigest, http://trac.thep.lu.se/svndigest
8
9  svndigest is free software; you can redistribute it and/or modify it
10  under the terms of the GNU General Public License as published by
11  the Free Software Foundation; either version 2 of the License, or
12  (at your option) any later version.
13
14  svndigest is distributed in the hope that it will be useful, but
15  WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  General Public License for more details.
18
19  You should have received a copy of the GNU General Public License
20  along with this program; if not, write to the Free Software
21  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
22  02111-1307, USA.
23*/
24
25#include "Stats.h"
26
27#include "Functor.h"
28#include "GnuplotFE.h"
29#include "SVNblame.h"
30#include "SVNinfo.h"
31#include "utility.h"
32
33#include <algorithm>
34#include <cassert>
35#include <cstdlib>
36#include <fstream>
37#include <iostream>
38#include <iterator>
39#include <map>
40#include <numeric>
41#include <string>
42#include <sstream>
43#include <unistd.h>
44#include <utility>
45#include <vector>
46
47
48namespace theplu{
49namespace svndigest{
50
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    std::vector<u_int> vec(last_changed_rev_+1, 0);
59    code_["all"] = vec;
60    comments_["all"] = vec;
61    other_["all"] = vec;
62    total_["all"] = vec;
63  }
64
65
66  Stats::~Stats(void)
67  {
68  }
69
70
71  void Stats::accumulate(std::vector<u_int>& vec) const
72  {
73    if (vec.empty()){
74      vec.resize(last_changed_rev(),0);
75      return;
76    }
77    std::partial_sum(vec.begin(),vec.end(),vec.begin());
78    // static_cast to remove annoying compiler warning
79    if (vec.size() < static_cast<size_t>(revision()+1))
80      vec.insert(vec.end(), revision()+1-vec.size(), vec.back());
81  }
82
83
84  void Stats::accumulate_stats(void)
85  {
86    for (std::set<std::string>::const_iterator iter(authors().begin());
87         iter!=authors().end(); ++iter) {
88      std::vector<u_int>& code = code_[*iter];
89      accumulate(code);
90      std::vector<u_int>& comments = comments_[*iter];
91      accumulate(comments);
92      std::vector<u_int>& other = other_[*iter];
93      accumulate(other);
94
95      VectorPlus<u_int> vp;
96      total_[*iter] = vp(vp(code, comments),other);
97    }
98    std::vector<u_int> init(revision()+1);
99    code_["all"]=std::accumulate(code_.begin(), code_.end(), init,
100                                 PairValuePlus<std::string,u_int>());
101    comments_["all"]=std::accumulate(comments_.begin(), comments_.end(), init,
102                                     PairValuePlus<std::string,u_int>());
103    other_["all"]=std::accumulate(other_.begin(), other_.end(), init,
104                                  PairValuePlus<std::string,u_int>());
105    VectorPlus<u_int> vp;
106    total_["all"] = vp(vp(code_["all"], comments_["all"]), other_["all"]);
107  }
108
109
110  void Stats::add_author(std::string name)
111  {
112    authors_.insert(name);
113  }
114
115
116  void Stats::add_authors(std::set<std::string>::const_iterator first, 
117                          std::set<std::string>::const_iterator last)
118  {
119    authors_.insert(first, last);
120  }
121
122
123  const std::set<std::string>& Stats::authors(void) const
124  {
125    return authors_;
126  }
127
128
129  u_int Stats::code(const std::string& user) const
130  {
131    return get_back(code_, user);
132  }
133
134
135  u_int Stats::comments(const std::string& user) const
136  {
137    return get_back(comments_, user);
138  }
139
140
141  u_int Stats::empty(const std::string& user) const
142  {
143    return get_back(other_, user);
144  }
145
146
147  u_int Stats::get_back(const Author2Vector& m, std::string user) const
148  {
149    A2VConstIter iter(m.find(std::string(user)));
150    if (iter==m.end() || iter->second.empty()) 
151      return 0;
152    return iter->second.back();
153  }
154
155
156  const std::vector<u_int>& Stats::get_vector(const Author2Vector& m, 
157                                              std::string user) const
158  {
159    A2VConstIter iter(m.find(std::string(user)));
160    if (iter==m.end()) 
161      throw std::runtime_error(user+std::string(" not found i Stats"));
162    return iter->second;
163  }
164
165
166  bool Stats::load_cache(std::istream& is)
167  {
168
169    svn_revnum_t rev;
170    is >> rev;
171    if (rev<last_changed_rev_){
172      return false; // cache is not up to date
173    }
174    size_t a_size=0;
175    authors_.clear();
176    is >> a_size;
177    std::string str;
178    getline(is, str);
179    while (authors_.size()<a_size){
180      getline(is, str);
181      assert(str.size());
182      authors_.insert(str);
183    }
184    return do_load_cache(is);
185  }
186
187
188  svn_revnum_t Stats::last_changed_rev(void) const
189  {
190    return last_changed_rev_;
191  }
192
193
194  u_int Stats::lines(const std::string& user) const
195  {
196    return get_back(total_, user);
197  }
198
199
200  void Stats::map_add(A2VConstIter first1, A2VConstIter last1, 
201                      Author2Vector& map)
202  {
203    A2VIter first2(map.begin());
204    Author2Vector::key_compare compare;
205    while ( first1 != last1) { 
206      // key of first1 less than key of first2
207      if (first2==map.end() || compare(first1->first,first2->first)) {
208        first2 = map.insert(first2, *first1);
209        ++first1;
210      }
211      // key of first2 less than key of first1
212      else if ( compare(first2->first, first1->first)) {
213        ++first2;
214      }
215      // keys are equivalent
216      else {
217        VectorPlus<Author2Vector::mapped_type::value_type> vp;
218        first2->second = vp(first1->second, first2->second);
219        ++first1;
220        ++first2;
221      }
222    }
223  }
224
225
226  void Stats::parse(const std::string& path)
227  {
228    do_parse(path);
229    accumulate_stats();
230  }
231
232  std::string Stats::plot(const std::string& filename,
233                          const std::string& linetype) const
234  {
235    return do_plot(filename, linetype);
236  }
237
238
239  void Stats::plot_init(const std::string& filename) const
240  {
241    GnuplotFE* gp=GnuplotFE::instance();
242    gp->command("set term png");
243    gp->command("set output '"+filename+"'");
244    gp->command("set xtics nomirror");
245    gp->command("set ytics nomirror");
246    gp->command("set key default");
247    gp->command("set key left Left reverse");
248    gp->command("set multiplot");
249  }
250
251
252  void Stats::plot_summary(const std::string& filename) const
253  {
254    plot_init(filename);
255    GnuplotFE* gp=GnuplotFE::instance();
256    std::vector<u_int> total = get_vector(total_, "all");
257    double yrange_max=1.03*total.back()+1;
258    gp->yrange(yrange_max);
259    std::stringstream ss;
260   
261    ss.str("");
262    std::vector<u_int> x(get_vector(code_, "all"));
263    ss << x.back() << " code";
264    gp->command("set key height 2");
265    gp->linetitle(ss.str());
266    gp->linestyle("steps 2");
267    gp->plot(x);
268
269    ss.str("");
270    x = get_vector(comments_, "all");
271    ss << x.back() << " comment";
272    gp->command("set key height 4");
273    gp->linetitle(ss.str());
274    gp->linestyle("steps 3");
275    gp->plot(x);
276
277    ss.str("");
278    x = get_vector(other_, "all");
279    ss << x.back() << " other";
280    gp->command("set key height 6");
281    gp->linetitle(ss.str());
282    gp->linestyle("steps 4");
283    gp->plot(x);
284
285    ss.str("");
286    ss << total.back() << " total";
287    gp->command("set key height 0");
288    gp->linetitle(ss.str());
289    gp->linestyle("steps 1");
290    gp->plot(total);
291
292    gp->command("unset multiplot");
293    gp->yrange();
294  }
295
296
297  void Stats::print(std::ostream& os) const
298  {
299    os << last_changed_rev_ << " ";
300    os << authors_.size() << "\n";
301
302    std::copy(authors_.begin(), authors_.end(), 
303              std::ostream_iterator<std::string>(os, "\n"));
304    do_print(os);
305  }
306
307
308  void Stats::reset(void)
309  {
310    assert("implement me");
311  }
312
313
314  Stats& Stats::operator+=(const Stats& rhs)
315  {
316    revision_ = std::max(revision_, rhs.revision_);
317    last_changed_rev_ = std::max(last_changed_rev_, rhs.last_changed_rev_);
318    add_authors(rhs.authors().begin(), rhs.authors().end());
319    map_add(rhs.code_.begin(), rhs.code_.end(), code_);
320    map_add(rhs.comments_.begin(), rhs.comments_.end(), comments_);
321    map_add(rhs.other_.begin(), rhs.other_.end(), other_);
322    map_add(rhs.total_.begin(), rhs.total_.end(), total_);
323    assert(rhs.other_.size());
324    assert(other_.size());
325   
326    return *this;
327  }
328
329
330}} // end of namespace svndigest and namespace theplu
Note: See TracBrowser for help on using the repository browser.