#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_
|