|  | // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "base/metrics/sample_map.h" | 
|  |  | 
|  | #include "base/logging.h" | 
|  | #include "base/memory/ptr_util.h" | 
|  | #include "base/numerics/safe_conversions.h" | 
|  | #include "base/stl_util.h" | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | typedef HistogramBase::Count Count; | 
|  | typedef HistogramBase::Sample Sample; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // An iterator for going through a SampleMap. The logic here is identical | 
|  | // to that of PersistentSampleMapIterator but with different data structures. | 
|  | // Changes here likely need to be duplicated there. | 
|  | class SampleMapIterator : public SampleCountIterator { | 
|  | public: | 
|  | typedef std::map<HistogramBase::Sample, HistogramBase::Count> | 
|  | SampleToCountMap; | 
|  |  | 
|  | explicit SampleMapIterator(const SampleToCountMap& sample_counts); | 
|  | ~SampleMapIterator() override; | 
|  |  | 
|  | // SampleCountIterator: | 
|  | bool Done() const override; | 
|  | void Next() override; | 
|  | void Get(HistogramBase::Sample* min, | 
|  | int64_t* max, | 
|  | HistogramBase::Count* count) const override; | 
|  |  | 
|  | private: | 
|  | void SkipEmptyBuckets(); | 
|  |  | 
|  | SampleToCountMap::const_iterator iter_; | 
|  | const SampleToCountMap::const_iterator end_; | 
|  | }; | 
|  |  | 
|  | SampleMapIterator::SampleMapIterator(const SampleToCountMap& sample_counts) | 
|  | : iter_(sample_counts.begin()), | 
|  | end_(sample_counts.end()) { | 
|  | SkipEmptyBuckets(); | 
|  | } | 
|  |  | 
|  | SampleMapIterator::~SampleMapIterator() = default; | 
|  |  | 
|  | bool SampleMapIterator::Done() const { | 
|  | return iter_ == end_; | 
|  | } | 
|  |  | 
|  | void SampleMapIterator::Next() { | 
|  | DCHECK(!Done()); | 
|  | ++iter_; | 
|  | SkipEmptyBuckets(); | 
|  | } | 
|  |  | 
|  | void SampleMapIterator::Get(Sample* min, int64_t* max, Count* count) const { | 
|  | DCHECK(!Done()); | 
|  | if (min) | 
|  | *min = iter_->first; | 
|  | if (max) | 
|  | *max = strict_cast<int64_t>(iter_->first) + 1; | 
|  | if (count) | 
|  | *count = iter_->second; | 
|  | } | 
|  |  | 
|  | void SampleMapIterator::SkipEmptyBuckets() { | 
|  | while (!Done() && iter_->second == 0) { | 
|  | ++iter_; | 
|  | } | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | SampleMap::SampleMap() : SampleMap(0) {} | 
|  |  | 
|  | SampleMap::SampleMap(uint64_t id) : HistogramSamples(id, new LocalMetadata()) {} | 
|  |  | 
|  | SampleMap::~SampleMap() { | 
|  | delete static_cast<LocalMetadata*>(meta()); | 
|  | } | 
|  |  | 
|  | void SampleMap::Accumulate(Sample value, Count count) { | 
|  | sample_counts_[value] += count; | 
|  | IncreaseSumAndCount(strict_cast<int64_t>(count) * value, count); | 
|  | } | 
|  |  | 
|  | Count SampleMap::GetCount(Sample value) const { | 
|  | auto it = sample_counts_.find(value); | 
|  | if (it == sample_counts_.end()) | 
|  | return 0; | 
|  | return it->second; | 
|  | } | 
|  |  | 
|  | Count SampleMap::TotalCount() const { | 
|  | Count count = 0; | 
|  | for (const auto& entry : sample_counts_) { | 
|  | count += entry.second; | 
|  | } | 
|  | return count; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<SampleCountIterator> SampleMap::Iterator() const { | 
|  | return WrapUnique(new SampleMapIterator(sample_counts_)); | 
|  | } | 
|  |  | 
|  | bool SampleMap::AddSubtractImpl(SampleCountIterator* iter, Operator op) { | 
|  | Sample min; | 
|  | int64_t max; | 
|  | Count count; | 
|  | for (; !iter->Done(); iter->Next()) { | 
|  | iter->Get(&min, &max, &count); | 
|  | if (strict_cast<int64_t>(min) + 1 != max) | 
|  | return false;  // SparseHistogram only supports bucket with size 1. | 
|  |  | 
|  | sample_counts_[min] += (op == HistogramSamples::ADD) ? count : -count; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | }  // namespace base |