source: trunk/lib/ClassicStats.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.9 KB
Line 
1// $Id: ClassicStats.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 "ClassicStats.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  ClassicStats::ClassicStats(const std::string& path)
53    : Stats(path)
54  {
55  }
56
57  ClassicStats::ClassicStats(const ClassicStats& other)
58  : Stats(other)
59  {
60  }
61
62  /*
63  std::vector<u_int> ClassicStats::accumulated(const Map_& map) const
64  {
65    // sum of all users
66    std::vector<u_int> sum(revision()+1);
67    sum=std::accumulate(map.begin(), map.end(), sum,
68                        PairValuePlus<std::string,u_int>());
69
70    // calculate accumulated sum
71    std::vector<u_int> accum(sum.size());
72    std::partial_sum(sum.begin(),sum.end(),accum.begin());
73    assert(sum.size()==accum.size());
74    return accum;
75  }
76
77  std::vector<u_int> ClassicStats::accumulated(const Map_& map,
78                                        const std::string& user) const
79  {
80    if (!map.count(user))
81      return std::vector<u_int>(last_changed_rev(),0);
82    std::vector<u_int> vec=(map.find(user))->second;
83
84    // static_cast to remove annoying compiler warning
85    if (vec.size() < static_cast<size_t>(revision()+1))
86      vec.insert(vec.end(), revision()+1-vec.size(), 0);
87
88    std::vector<u_int> accum(vec.size());
89    std::partial_sum(vec.begin(),vec.end(),accum.begin());
90    return accum;
91  }
92  */
93
94
95  void ClassicStats::add(const std::string& user, const u_int& rev, 
96                         const Parser::line_type& lt)
97  {
98    assert(user.size());
99    add_author(user);
100
101    std::vector<u_int>* total = &(total_[user]);
102    assert(total);
103    if (total->size() < rev+1){
104      total->reserve(revision() + 1);
105      total->insert(total->end(), rev - total->size(), 0);
106      total->push_back(1);
107    }
108    else
109      ++(*total)[rev];
110
111    std::vector<u_int>* code = &(code_[user]);
112    assert(code);
113    if (code->size() < rev+1){
114      code->reserve(revision() + 1);
115      code->insert(code->end(), rev - code->size(), 0);
116      if (lt == Parser::code)
117        code->push_back(1);
118      else 
119        code->push_back(0);
120    }
121    else if (lt == Parser::code)
122      ++(*code)[rev];
123
124    std::vector<u_int>* comments = &(comments_[user]);
125    assert(comments);
126    if (comments->size() < rev+1){
127      comments->reserve(revision() + 1);
128      comments->insert(comments->end(), rev - comments->size(), 0);
129      if (lt == Parser::comment)
130        comments->push_back(1);
131      else 
132        comments->push_back(0);
133    }
134    else if (lt == Parser::comment)
135      ++(*comments)[rev];
136
137    std::vector<u_int>* other = &(other_[user]);
138    assert(other);
139    if (other->size() < rev+1){
140      other->reserve(revision() + 1);
141      other->insert(other->end(), rev - other->size(), 0);
142      if (lt == Parser::other)
143        other->push_back(1);
144      else 
145        other->push_back(0);
146    }
147    else if (lt == Parser::other)
148      ++(*other)[rev];
149  }
150
151
152  bool ClassicStats::do_load_cache(std::istream& is)
153  {
154    svn_revnum_t rev;
155    is >> rev;
156    if (rev<last_changed_rev()){
157      return false; // cache is not up to date
158    }
159    reset();
160    size_t a_size=0;
161    is >> a_size;
162    std::string str;
163    while (authors().size()<a_size){
164      getline(is, str);
165      assert(str.size());
166      add_author(str);
167    }
168    getline(is, str);
169    if (str!=code_cache()){
170      return false;
171    }
172    load(is, code_);
173    getline(is, str);
174    getline(is, str);
175    if (str!=comments_cache()){
176      return false;
177    }
178    load(is, comments_);
179    getline(is, str);
180    getline(is, str);
181    if (str!=other_cache()){
182      return false;
183    }
184    load(is, other_);
185    getline(is, str);
186    getline(is, str);
187    if (str!=total_cache()){
188      return false;
189    }
190    load(is, total_);
191    getline(is,str);
192    getline(is,str);
193    return str==end_of_cache();
194  }
195
196
197  void ClassicStats::load(std::istream& is, Author2Vector& m)
198  {
199    while (m.size() < authors().size() && is.good()) {
200      std::string name;
201      std::getline(is, name);
202      assert(name.size());
203      std::vector<u_int>& vec=m[name];
204      size_t revs=0;
205      is >> revs;
206      vec.reserve(revs);
207      while (vec.size() < revs) {
208        u_int tmp;
209        is >> tmp;
210        vec.push_back(tmp);
211      }
212    }
213  }
214
215
216  void ClassicStats::do_parse(const std::string& path)
217  {
218    Parser parser(path);
219    std::vector<Parser::line_type>::const_iterator count=parser.type().begin();
220
221    SVNblame svn_blame(path);
222    while (svn_blame.valid()) {
223      add(svn_blame.author(), svn_blame.revision(), *count);
224      svn_blame.next_line();
225      ++count;
226    }
227  }
228
229
230  std::string ClassicStats::do_plot(const std::string& filename,
231                                    const std::string& linetype) const
232  {
233    plot_init(filename);
234    GnuplotFE* gp=GnuplotFE::instance();
235    const Author2Vector* stat=NULL;
236    if (linetype=="total")
237      stat = &total_;
238    else if (linetype=="code")
239      stat = &code_;
240    else if (linetype=="comments")
241      stat = &comments_;
242    else if (linetype=="empty")
243      stat = &other_;
244    assert(stat);
245    assert(stat->size());
246    std::vector<u_int> total=get_vector(*stat, "all");   
247    double yrange_max=1.03*total.back()+1;
248    gp->yrange(yrange_max);
249
250    typedef std::vector<std::pair<std::string, std::vector<u_int> > > vec_type;
251    vec_type author_cont;
252    author_cont.reserve(stat->size());
253    for (A2VConstIter i= stat->begin(); i != stat->end(); ++i) {
254      author_cont.push_back(std::make_pair(i->first,
255                                           get_vector(*stat,i->first)));
256    }
257
258    LessReversed<std::vector<u_int> > lr;
259    PairSecondCompare<std::string, std::vector<u_int>, 
260      LessReversed<std::vector<u_int> > > compare(lr);
261    std::sort(author_cont.begin(), author_cont.end(), compare);
262
263    size_t plotno=author_cont.size();
264    std::stringstream ss;
265    vec_type::iterator end(author_cont.end());
266    for (vec_type::iterator i(author_cont.begin()); i!=end; ++i) {
267      ss.str("");
268      ss << "set key height " << 2*plotno;
269      gp->command(ss.str());
270      ss.str("");
271      ss << i->second.back() << " " << i->first;
272      gp->yrange(yrange_max);
273      gp->linetitle(ss.str());
274      ss.str("");
275      ss << "steps " << --plotno+2;
276      gp->linestyle(ss.str());
277      gp->plot(i->second);
278    }
279    ss.str("");
280    ss << total.back() << " total";
281    gp->command("set key height 0");
282    gp->linetitle(ss.str());
283    gp->linestyle("steps 1");
284    gp->plot(total);
285
286    gp->command("unset multiplot");
287    gp->yrange();
288
289    return filename;
290  }
291
292
293  void ClassicStats::do_print(std::ostream& os) const
294  {
295    os << last_changed_rev() << " ";
296    os << authors().size() << " ";
297
298    std::copy(authors().begin(), authors().end(), 
299              std::ostream_iterator<std::string>(os, "\n"));
300    os << code_cache() << "\n";
301    do_print(os, code_);
302    os << "\n" << comments_cache() << "\n";
303    do_print(os, comments_);
304    os << "\n" << other_cache() << "\n";
305    do_print(os, other_);
306    os << "\n" << total_cache() << "\n";
307    do_print(os, total_);
308    os << "\n" << end_of_cache() << "\n";
309  }
310
311
312  void ClassicStats::do_print(std::ostream& os, const Author2Vector& m) const
313  {
314    for (A2VConstIter i(m.begin()); i!=m.end(); ++i){
315      os << i->first << "\n";
316      os << i->second.size() << " ";
317      std::copy(i->second.begin(), i->second.end(),
318                std::ostream_iterator<u_int>(os, " "));
319    }
320  }
321
322 
323}} // end of namespace svndigest and namespace theplu
Note: See TracBrowser for help on using the repository browser.