#ifndef SYSTEM_EXTRAS_PERFPROFD_MAP_UTILS_H_
#define SYSTEM_EXTRAS_PERFPROFD_MAP_UTILS_H_
#include <map>
#include <set>
#include <android-base/logging.h>
namespace android {
namespace perfprofd {
template <typename T, typename U>
decltype(static_cast<T*>(nullptr)->begin()) GetLeqIterator(T& map, U key) {
if (map.empty()) {
return map.end();
}
auto it = map.upper_bound(key);
if (it == map.begin()) {
return map.end();
}
--it;
return it;
}
template <typename SymType, typename ValType>
class RangeMap {
public:
struct AggregatedSymbol {
SymType symbol;
std::set<ValType> offsets;
AggregatedSymbol(const SymType& sym, const ValType& offset) : symbol(sym) {
offsets.insert(offset);
}
};
public:
void Insert(const SymType& sym, const ValType& val) {
auto aggr_it = GetLeqIterator(map_, val);
if (aggr_it == map_.end()) {
// Maybe we need to extend the first one.
if (!map_.empty()) {
AggregatedSymbol& first = map_.begin()->second;
CHECK_LT(val, map_.begin()->first);
if (first.symbol == sym) {
ExtendLeft(map_.begin(), val);
return;
}
}
// Nope, new entry needed.
map_.emplace(val, AggregatedSymbol(sym, val));
return;
}
AggregatedSymbol& maybe_match = aggr_it->second;
if (maybe_match.symbol == sym) {
// Same symbol, just insert. This is true for overlap as well as extension.
maybe_match.offsets.insert(val);
return;
}
// Is there overlap?
if (*maybe_match.offsets.rbegin() < val) {
// No. See if it can be merged with the next one.
++aggr_it;
if (aggr_it != map_.end() && aggr_it->second.symbol == sym) {
ExtendLeft(aggr_it, val);
return;
}
// Just add a new symbol entry.
map_.emplace(val, AggregatedSymbol(sym, val));
return;
}
// OK, we have an overlapping non-symbol-equal AggregatedSymbol. Need to break
// things up.
AggregatedSymbol left(maybe_match.symbol, *maybe_match.offsets.begin());
auto offset_it = maybe_match.offsets.begin();
for (; *offset_it < val; ++offset_it) {
left.offsets.insert(*offset_it);
}
if (*offset_it == val) {
// This should not happen.
LOG(ERROR) << "Unexpected overlap!";
return;
}
AggregatedSymbol right(maybe_match.symbol, *offset_it);
for (; offset_it != maybe_match.offsets.end(); ++offset_it) {
right.offsets.insert(*offset_it);
}
map_.erase(aggr_it);
map_.emplace(*left.offsets.begin(), std::move(left));
map_.emplace(val, AggregatedSymbol(sym, val));
map_.emplace(*right.offsets.begin(), std::move(right));
}
using RangeMapType = std::map<ValType, AggregatedSymbol>;
typename RangeMapType::const_iterator begin() const {
return map_.begin();
}
typename RangeMapType::const_iterator end() const {
return map_.end();
}
bool empty() const {
return map_.empty();
}
private:
void ExtendLeft(typename RangeMapType::iterator it, const ValType& val) {
CHECK(val < *it->second.offsets.begin());
AggregatedSymbol copy = std::move(it->second);
map_.erase(it);
copy.offsets.insert(val);
map_.emplace(val, std::move(copy));
}
RangeMapType map_;
};
} // namespace perfprofd
} // namespace android
#endif // SYSTEM_EXTRAS_PERFPROFD_MAP_UTILS_H_