blob: de304fcda2e155500c13312095337dacc5b2df72 [file] [log] [blame]
// Copyright 2024 The Fuchsia 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 "src/developer/debug/zxdb/symbols/address_range_map_builder.h"
#include "src/developer/debug/shared/largest_less_or_equal.h"
namespace zxdb {
void AddressRangeMapBuilder::AddRange(const AddressRange& range,
AddressRangeMap::Value die_offset) {
if (map_.empty()) {
map_.emplace(range, die_offset);
return;
}
// The first existing range beginning at or after the new one (computes >=).
auto lower = map_.lower_bound(range);
// We actually want to find the LAST range less than or equal to.
if (lower == map_.end()) {
// Past the beginning of the last range.
--lower;
} else if (lower->first.begin() > range.begin()) {
// Past the beginning of the found range.
if (lower == map_.begin()) {
// Input is before the first existing range, just insert it.
map_.emplace(range, die_offset);
return;
}
--lower;
}
AddressRange found_range = lower->first; // Need copy because we will invalidate "lower" below.
if (range.begin() >= found_range.end()) {
// Input is past the end, just insert it.
map_.emplace(range, die_offset);
return;
}
// If we get here, the existing range needs splitting.
AddressRangeMap::Value found_value = lower->second;
// Save the insert position before deleting the existing range. |lower| IS INVALIDATED.
auto insert_hint = lower;
++insert_hint;
map_.erase(lower);
// Any range before the new one gets the existing value.
if (found_range.begin() < range.begin()) {
map_.emplace_hint(insert_hint, AddressRange(found_range.begin(), range.begin()), found_value);
}
// Always followed by the new range.
map_.emplace_hint(insert_hint, range, die_offset);
// Any range after the new one gets the existing value.
if (found_range.end() > range.end()) {
map_.emplace_hint(insert_hint, AddressRange(range.end(), found_range.end()), found_value);
}
}
void AddressRangeMapBuilder::AddRanges(const AddressRanges& ranges,
AddressRangeMap::Value die_offset) {
for (const auto& r : ranges) {
AddRange(r, die_offset);
}
}
AddressRangeMap AddressRangeMapBuilder::GetMap() const {
if (map_.empty()) {
return AddressRangeMap();
}
std::vector<AddressRangeMap::Record> output;
// Reserve extra space because there will be gaps.
output.reserve(map_.size() + map_.size() / 2);
// Flatten the map.
uint64_t prev_end = std::numeric_limits<uint64_t>::max();
for (auto [range, value] : map_) {
if (range.begin() > prev_end) {
// Mark the blank space between the previous range and this one.
output.emplace_back(prev_end, AddressRangeMap::kNullValue);
}
output.emplace_back(range.begin(), value);
prev_end = range.end();
}
// Mark the end of the last range.
output.emplace_back(prev_end, AddressRangeMap::kNullValue);
return AddressRangeMap(std::move(output));
}
} // namespace zxdb