source: trunk/lib/Stats.cc @ 493

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

fixed bug in summary plot on first page

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 7.6 KB
Line 
1// $Id: Stats.cc 493 2007-10-14 01:17:42Z 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/trac/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    : valid_(true)
54  {
55    // Make sure latest revision is set properly
56    SVNinfo svn_info(path);
57    revision_=svn_info.rev();
58    last_changed_rev_=svn_info.last_changed_rev();
59  }
60
61
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      }
89    }
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  }
160
161  bool Stats::load_cache(std::istream& is)
162  {
163
164    svn_revnum_t rev;
165    is >> rev;
166    if (rev<last_changed_rev_){
167      return false; // cache is not up to date
168    }
169    size_t a_size=0;
170    authors_.clear();
171    is >> a_size;
172    std::string str;
173    getline(is, str);
174    while (authors_.size()<a_size){
175      getline(is, str);
176      assert(str.size());
177      authors_.insert(str);
178    }
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();
192  }
193
194
195  void Stats::parse(const std::string& path)
196  {
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  }
204
205  std::string Stats::plot(const std::string& filename,
206                          const std::string& linetype) const
207  {
208    return do_plot(filename, linetype);
209  }
210
211
212  void Stats::plot_init(const std::string& filename) const
213  {
214    GnuplotFE* gp=GnuplotFE::instance();
215    gp->command("set term png");
216    gp->command("set output '"+filename+"'");
217    gp->command("set xtics nomirror");
218    gp->command("set ytics nomirror");
219    gp->command("set key default");
220    gp->command("set key left Left reverse");
221    gp->command("set multiplot");
222  }
223
224
225  void Stats::plot_summary(const std::string& filename) const
226  {
227    assert(valid());
228    plot_init(filename);
229    GnuplotFE* gp=GnuplotFE::instance();
230    std::vector<u_int> total = get_vector(total_, "all");
231    double yrange_max=1.03*total.back()+1;
232    gp->yrange(yrange_max);
233    std::stringstream ss;
234   
235    ss.str("");
236    std::vector<u_int> x(get_vector(code_, "all"));
237    ss << x.back() << " code";
238    gp->command("set key height 2");
239    gp->linetitle(ss.str());
240    gp->linestyle("steps 2");
241    gp->plot(x);
242
243    ss.str("");
244    x = get_vector(comments_, "all");
245    ss << x.back() << " comment";
246    gp->command("set key height 4");
247    gp->linetitle(ss.str());
248    gp->linestyle("steps 3");
249    gp->plot(x);
250
251    ss.str("");
252    x = get_vector(other_, "all");
253    ss << x.back() << " other";
254    gp->command("set key height 6");
255    gp->linetitle(ss.str());
256    gp->linestyle("steps 4");
257    gp->plot(x);
258
259    ss.str("");
260    ss << total.back() << " total";
261    gp->command("set key height 0");
262    gp->linetitle(ss.str());
263    gp->linestyle("steps 1");
264    gp->plot(total);
265
266    gp->command("unset multiplot");
267    gp->yrange();
268  }
269
270
271  void Stats::print(std::ostream& os) const
272  {
273    os << last_changed_rev_ << " ";
274    os << authors_.size() << "\n";
275
276    std::copy(authors_.begin(), authors_.end(), 
277              std::ostream_iterator<std::string>(os, "\n"));
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);
300    }
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
313
314}} // end of namespace svndigest and namespace theplu
Note: See TracBrowser for help on using the repository browser.