#ifndef BASE_METRICS_SAMPLE_MAP_ITERATOR_H_
#define BASE_METRICS_SAMPLE_MAP_ITERATOR_H_
#include <stdint.h>
#include <atomic>
#include <type_traits>
#include <utility>
#include "base/check.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/histogram_base.h"
#include "base/metrics/histogram_samples.h"
#include "base/types/to_address.h"
namespace base {
template <typename MapT, bool support_extraction>
class SampleMapIterator : public SampleCountIterator {
private:
using T = std::conditional_t<support_extraction, MapT, const MapT>;
public:
explicit SampleMapIterator(T& sample_counts)
: iter_(sample_counts.begin()), end_(sample_counts.end()) {
SkipEmptyBuckets();
}
~SampleMapIterator() override {
if constexpr (support_extraction) {
DCHECK(Done());
}
}
bool Done() const override { return iter_ == end_; }
void Next() override {
DCHECK(!Done());
++iter_;
SkipEmptyBuckets();
}
void Get(HistogramBase::Sample32* min,
int64_t* max,
HistogramBase::Count32* count) override {
DCHECK(!Done());
*min = iter_->first;
*max = int64_t{iter_->first} + 1;
if constexpr (support_extraction) {
*count = Exchange();
} else {
*count = Load();
}
}
private:
using I = std::conditional_t<support_extraction,
typename T::iterator,
typename T::const_iterator>;
static constexpr bool kUseAtomicOps =
IsPointerOrRawPtr<typename T::mapped_type>;
void SkipEmptyBuckets() {
while (!Done() && Load() == 0) {
++iter_;
}
}
HistogramBase::Count32 Load() const {
if constexpr (kUseAtomicOps) {
return iter_->second->load(std::memory_order_relaxed);
} else {
return iter_->second;
}
}
HistogramBase::Count32 Exchange() const
requires support_extraction
{
if constexpr (kUseAtomicOps) {
return iter_->second->exchange(0, std::memory_order_relaxed);
} else {
return std::exchange(iter_->second, 0);
}
}
I iter_;
const I end_;
};
}
#endif