1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/metrics/sample_map.h"
6 
7 #include "base/logging.h"
8 #include "base/memory/ptr_util.h"
9 #include "base/numerics/safe_conversions.h"
10 #include "base/stl_util.h"
11 
12 namespace base {
13 
14 typedef HistogramBase::Count Count;
15 typedef HistogramBase::Sample Sample;
16 
17 namespace {
18 
19 // An iterator for going through a SampleMap. The logic here is identical
20 // to that of PersistentSampleMapIterator but with different data structures.
21 // Changes here likely need to be duplicated there.
22 class SampleMapIterator : public SampleCountIterator {
23  public:
24   typedef std::map<HistogramBase::Sample, HistogramBase::Count>
25       SampleToCountMap;
26 
27   explicit SampleMapIterator(const SampleToCountMap& sample_counts);
28   ~SampleMapIterator() override;
29 
30   // SampleCountIterator:
31   bool Done() const override;
32   void Next() override;
33   void Get(HistogramBase::Sample* min,
34            int64_t* max,
35            HistogramBase::Count* count) const override;
36 
37  private:
38   void SkipEmptyBuckets();
39 
40   SampleToCountMap::const_iterator iter_;
41   const SampleToCountMap::const_iterator end_;
42 };
43 
SampleMapIterator(const SampleToCountMap & sample_counts)44 SampleMapIterator::SampleMapIterator(const SampleToCountMap& sample_counts)
45     : iter_(sample_counts.begin()),
46       end_(sample_counts.end()) {
47   SkipEmptyBuckets();
48 }
49 
50 SampleMapIterator::~SampleMapIterator() = default;
51 
Done() const52 bool SampleMapIterator::Done() const {
53   return iter_ == end_;
54 }
55 
Next()56 void SampleMapIterator::Next() {
57   DCHECK(!Done());
58   ++iter_;
59   SkipEmptyBuckets();
60 }
61 
Get(Sample * min,int64_t * max,Count * count) const62 void SampleMapIterator::Get(Sample* min, int64_t* max, Count* count) const {
63   DCHECK(!Done());
64   if (min)
65     *min = iter_->first;
66   if (max)
67     *max = strict_cast<int64_t>(iter_->first) + 1;
68   if (count)
69     *count = iter_->second;
70 }
71 
SkipEmptyBuckets()72 void SampleMapIterator::SkipEmptyBuckets() {
73   while (!Done() && iter_->second == 0) {
74     ++iter_;
75   }
76 }
77 
78 }  // namespace
79 
SampleMap()80 SampleMap::SampleMap() : SampleMap(0) {}
81 
SampleMap(uint64_t id)82 SampleMap::SampleMap(uint64_t id) : HistogramSamples(id, new LocalMetadata()) {}
83 
~SampleMap()84 SampleMap::~SampleMap() {
85   delete static_cast<LocalMetadata*>(meta());
86 }
87 
Accumulate(Sample value,Count count)88 void SampleMap::Accumulate(Sample value, Count count) {
89   sample_counts_[value] += count;
90   IncreaseSumAndCount(strict_cast<int64_t>(count) * value, count);
91 }
92 
GetCount(Sample value) const93 Count SampleMap::GetCount(Sample value) const {
94   std::map<Sample, Count>::const_iterator it = sample_counts_.find(value);
95   if (it == sample_counts_.end())
96     return 0;
97   return it->second;
98 }
99 
TotalCount() const100 Count SampleMap::TotalCount() const {
101   Count count = 0;
102   for (const auto& entry : sample_counts_) {
103     count += entry.second;
104   }
105   return count;
106 }
107 
Iterator() const108 std::unique_ptr<SampleCountIterator> SampleMap::Iterator() const {
109   return WrapUnique(new SampleMapIterator(sample_counts_));
110 }
111 
AddSubtractImpl(SampleCountIterator * iter,Operator op)112 bool SampleMap::AddSubtractImpl(SampleCountIterator* iter, Operator op) {
113   Sample min;
114   int64_t max;
115   Count count;
116   for (; !iter->Done(); iter->Next()) {
117     iter->Get(&min, &max, &count);
118     if (strict_cast<int64_t>(min) + 1 != max)
119       return false;  // SparseHistogram only supports bucket with size 1.
120 
121     sample_counts_[min] += (op == HistogramSamples::ADD) ? count : -count;
122   }
123   return true;
124 }
125 
126 }  // namespace base
127