build: Switch to better interval tree implementation

This commit is contained in:
WerWolv
2023-05-07 23:27:43 +02:00
parent 82111617a4
commit 5a6e5d2255
13 changed files with 308 additions and 430 deletions

View File

@@ -2,7 +2,7 @@
#include <hex/providers/provider.hpp>
#include <IntervalTree.h>
#include <IITree.h>
namespace hex::plugin::builtin {
@@ -44,7 +44,7 @@ namespace hex::plugin::builtin {
protected:
bool m_dataValid = false;
size_t m_dataSize = 0x00;
interval_tree::IntervalTree<u64, std::vector<u8>> m_data;
IITree<u64, std::vector<u8>> m_data;
std::fs::path m_sourceFilePath;
};

View File

@@ -12,7 +12,7 @@
#include "ui/hex_editor.hpp"
#include <IntervalTree.h>
#include <IITree.h>
namespace hex::plugin::builtin {

View File

@@ -9,7 +9,7 @@
#include <atomic>
#include <vector>
#include <IntervalTree.h>
#include <IITree.h>
namespace hex::plugin::builtin {
@@ -94,11 +94,11 @@ namespace hex::plugin::builtin {
} m_searchSettings, m_decodeSettings;
using OccurrenceTree = interval_tree::IntervalTree<u64, Occurrence>;
using OccurrenceTree = IITree<u64, Occurrence>;
std::map<prv::Provider*, std::vector<Occurrence>> m_foundOccurrences, m_sortedOccurrences;
std::map<prv::Provider*, OccurrenceTree> m_occurrenceTree;
std::map<prv::Provider*, std::string> m_currFilter;
PerProvider<std::vector<Occurrence>> m_foundOccurrences, m_sortedOccurrences;
PerProvider<OccurrenceTree> m_occurrenceTree;
PerProvider<std::string> m_currFilter;
TaskHolder m_searchTask, m_filterTask;
bool m_settingsValid = false;

View File

@@ -161,26 +161,37 @@ namespace hex::plugin::builtin {
void IntelHexProvider::setBaseAddress(u64 address) {
auto oldBase = this->getBaseAddress();
auto intervals = this->m_data.findOverlapping(oldBase, oldBase + this->getActualSize());
std::vector<size_t> indices;
this->m_data.overlap(oldBase, oldBase + this->getActualSize(), indices);
for (auto &interval : intervals) {
interval.start = (interval.start - oldBase) + address;
interval.stop = (interval.stop - oldBase) + address;
IITree<u64, std::vector<u8>> intervals;
for (auto &index : indices) {
intervals.add(
(this->m_data.start(index) - oldBase) + address,
(this->m_data.end(index) - oldBase) + address,
this->m_data.data(index)
);
}
this->m_data = std::move(intervals);
this->m_data.index();
Provider::setBaseAddress(address);
}
void IntelHexProvider::readRaw(u64 offset, void *buffer, size_t size) {
auto intervals = this->m_data.findOverlapping(offset, (offset + size) - 1);
std::vector<size_t> indices;
this->m_data.overlap(offset, (offset + size) - 1, indices);
std::memset(buffer, 0x00, size);
auto bytes = reinterpret_cast<u8*>(buffer);
for (const auto &interval : intervals) {
for (u32 i = std::max(interval.start, offset); i <= interval.stop && (i - offset) < size; i++) {
bytes[i - offset] = interval.value[i - interval.start];
for (const auto &index : indices) {
auto start = this->m_data.start(index);
auto end = this->m_data.end(index);
auto data = this->m_data.data(index);
for (u32 i = std::max(start, offset); i <= end && (i - offset) < size; i++) {
bytes[i - offset] = data[i - start];
}
}
}
@@ -203,15 +214,15 @@ namespace hex::plugin::builtin {
return false;
u64 maxAddress = 0x00;
decltype(this->m_data)::interval_vector intervals;
for (auto &[address, bytes] : data) {
auto endAddress = (address + bytes.size()) - 1;
intervals.emplace_back(address, endAddress, std::move(bytes));
this->m_data.add(address, endAddress, std::move(bytes));
if (endAddress > maxAddress)
maxAddress = endAddress;
}
this->m_data = std::move(intervals);
this->m_data.index();
this->m_dataSize = maxAddress + 1;
this->m_dataValid = true;
@@ -254,17 +265,22 @@ namespace hex::plugin::builtin {
}
std::pair<Region, bool> IntelHexProvider::getRegionValidity(u64 address) const {
auto intervals = this->m_data.findOverlapping(address, address);
if (intervals.empty()) {
std::vector<size_t> indices;
this->m_data.overlap(address, address, indices);
if (indices.empty()) {
return Provider::getRegionValidity(address);
}
auto closestInterval = intervals.front();
for (const auto &interval : intervals) {
if (interval.start < closestInterval.start)
closestInterval = interval;
auto closestIndex = indices.front();
for (const auto &index : indices) {
if (this->m_data.start(index) < this->m_data.start(closestIndex))
closestIndex = index;
}
return { Region { closestInterval.start, (closestInterval.stop - closestInterval.start) + 1}, true };
auto start = this->m_data.start(closestIndex);
auto end = this->m_data.end(closestIndex);
return { Region { start, (end - start) + 1 }, true };
}
void IntelHexProvider::loadSettings(const nlohmann::json &settings) {

View File

@@ -180,15 +180,15 @@ namespace hex::plugin::builtin {
return false;
u64 maxAddress = 0x00;
decltype(this->m_data)::interval_vector intervals;
for (auto &[address, bytes] : data) {
auto endAddress = (address + bytes.size()) - 1;
intervals.emplace_back(address, endAddress, std::move(bytes));
this->m_data.add(address, endAddress, std::move(bytes));
if (endAddress > maxAddress)
maxAddress = endAddress;
}
this->m_data = std::move(intervals);
this->m_data.index();
this->m_dataSize = maxAddress + 1;
this->m_dataValid = true;

View File

@@ -22,9 +22,8 @@ namespace hex::plugin::builtin {
if (this->m_searchTask.isRunning())
return { };
auto provider = ImHexApi::Provider::get();
if (!this->m_occurrenceTree[provider].findOverlapping(address, address).empty())
std::vector<size_t> occurrences;
if (this->m_occurrenceTree->overlap(address, address, occurrences))
return HighlightColor();
else
return std::nullopt;
@@ -36,10 +35,8 @@ namespace hex::plugin::builtin {
if (this->m_searchTask.isRunning())
return;
auto provider = ImHexApi::Provider::get();
auto occurrences = this->m_occurrenceTree[provider].findOverlapping(address, address);
if (occurrences.empty())
std::vector<size_t> occurrences;
if (!this->m_occurrenceTree->overlap(address, address, occurrences))
return;
ImGui::BeginTooltip();
@@ -51,7 +48,10 @@ namespace hex::plugin::builtin {
ImGui::TableNextColumn();
{
const auto value = this->decodeValue(ImHexApi::Provider::get(), occurrence.value, 256);
auto start = this->m_occurrenceTree->start(occurrence);
auto end = this->m_occurrenceTree->end(occurrence) - 1;
const auto &bytes = this->m_occurrenceTree->data(occurrence);
const auto value = this->decodeValue(ImHexApi::Provider::get(), bytes, 256);
ImGui::ColorButton("##color", ImColor(HighlightColor()));
ImGui::SameLine(0, 10);
@@ -65,7 +65,7 @@ namespace hex::plugin::builtin {
ImGui::TableNextColumn();
ImGui::TextFormatted("{}: ", "hex.builtin.common.region"_lang);
ImGui::TableNextColumn();
ImGui::TextFormatted("[ 0x{:08X} - 0x{:08X} ]", occurrence.value.region.getStartAddress(), occurrence.value.region.getEndAddress());
ImGui::TextFormatted("[ 0x{:08X} - 0x{:08X} ]", start, end);
auto demangledValue = llvm::demangle(value);
@@ -494,28 +494,27 @@ namespace hex::plugin::builtin {
switch (settings.mode) {
using enum SearchSettings::Mode;
case Strings:
this->m_foundOccurrences[provider] = searchStrings(task, provider, searchRegion, settings.strings);
this->m_foundOccurrences.get(provider) = searchStrings(task, provider, searchRegion, settings.strings);
break;
case Sequence:
this->m_foundOccurrences[provider] = searchSequence(task, provider, searchRegion, settings.bytes);
this->m_foundOccurrences.get(provider) = searchSequence(task, provider, searchRegion, settings.bytes);
break;
case Regex:
this->m_foundOccurrences[provider] = searchRegex(task, provider, searchRegion, settings.regex);
this->m_foundOccurrences.get(provider) = searchRegex(task, provider, searchRegion, settings.regex);
break;
case BinaryPattern:
this->m_foundOccurrences[provider] = searchBinaryPattern(task, provider, searchRegion, settings.binaryPattern);
this->m_foundOccurrences.get(provider) = searchBinaryPattern(task, provider, searchRegion, settings.binaryPattern);
break;
case Value:
this->m_foundOccurrences[provider] = searchValue(task, provider, searchRegion, settings.value);
this->m_foundOccurrences.get(provider) = searchValue(task, provider, searchRegion, settings.value);
break;
}
this->m_sortedOccurrences[provider] = this->m_foundOccurrences[provider];
this->m_sortedOccurrences.get(provider) = this->m_foundOccurrences.get(provider);
OccurrenceTree::interval_vector intervals;
for (const auto &occurrence : this->m_foundOccurrences[provider])
intervals.emplace_back(occurrence.region.getStartAddress(), occurrence.region.getEndAddress(), occurrence);
this->m_occurrenceTree[provider] = std::move(intervals);
for (const auto &occurrence : this->m_foundOccurrences.get(provider))
this->m_occurrenceTree->add(occurrence.region.getStartAddress(), occurrence.region.getEndAddress() + 1, occurrence);
this->m_occurrenceTree->index();
});
}
@@ -800,14 +799,14 @@ namespace hex::plugin::builtin {
ImGui::EndDisabled();
ImGui::SameLine();
ImGui::TextFormatted("hex.builtin.view.find.search.entries"_lang, this->m_foundOccurrences[provider].size());
ImGui::TextFormatted("hex.builtin.view.find.search.entries"_lang, this->m_foundOccurrences->size());
ImGui::BeginDisabled(this->m_foundOccurrences[provider].empty());
ImGui::BeginDisabled(this->m_foundOccurrences->empty());
{
if (ImGui::Button("hex.builtin.view.find.search.reset"_lang)) {
this->m_foundOccurrences[provider].clear();
this->m_sortedOccurrences[provider].clear();
this->m_occurrenceTree[provider].clear();
this->m_foundOccurrences->clear();
this->m_sortedOccurrences->clear();
*this->m_occurrenceTree = {};
}
}
ImGui::EndDisabled();
@@ -818,25 +817,25 @@ namespace hex::plugin::builtin {
ImGui::Separator();
ImGui::NewLine();
auto &currOccurrences = this->m_sortedOccurrences[provider];
auto &currOccurrences = *this->m_sortedOccurrences;
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
auto prevFilterLength = this->m_currFilter[provider].length();
if (ImGui::InputTextWithHint("##filter", "hex.builtin.common.filter"_lang, this->m_currFilter[provider])) {
if (prevFilterLength > this->m_currFilter[provider].length())
this->m_sortedOccurrences[provider] = this->m_foundOccurrences[provider];
auto prevFilterLength = this->m_currFilter->length();
if (ImGui::InputTextWithHint("##filter", "hex.builtin.common.filter"_lang, *this->m_currFilter)) {
if (prevFilterLength > this->m_currFilter->length())
*this->m_sortedOccurrences = *this->m_foundOccurrences;
if (this->m_filterTask.isRunning())
this->m_filterTask.interrupt();
if (!this->m_currFilter[provider].empty()) {
if (!this->m_currFilter->empty()) {
this->m_filterTask = TaskManager::createTask("Filtering", currOccurrences.size(), [this, provider, &currOccurrences](Task &task) {
u64 progress = 0;
currOccurrences.erase(std::remove_if(currOccurrences.begin(), currOccurrences.end(), [this, provider, &task, &progress](const auto &region) {
task.update(progress);
progress += 1;
return !hex::containsIgnoreCase(this->decodeValue(provider, region), this->m_currFilter[provider]);
return !hex::containsIgnoreCase(this->decodeValue(provider, region), this->m_currFilter.get(provider));
}), currOccurrences.end());
});
}

View File

@@ -18,7 +18,7 @@ namespace hex::plugin::builtin {
auto selection = ImHexApi::HexEditor::getSelection();
if (ImGui::GetIO().KeyShift) {
if (selection.has_value() && ImGui::GetIO().KeyShift) {
auto &hashFunctions = this->m_hashFunctions.get(selection->getProvider());
if (!hashFunctions.empty() && selection.has_value() && selection->overlaps(Region { address, size })) {
ImGui::BeginTooltip();