110 lines
2.8 KiB
C++
110 lines
2.8 KiB
C++
#ifndef EMULATOR_SRC_GRAPHICS_HOST_GPU_RANGESET_H_
|
|
#define EMULATOR_SRC_GRAPHICS_HOST_GPU_RANGESET_H_
|
|
|
|
#include "common/assert.h"
|
|
|
|
#include <algorithm>
|
|
#include <cstdint>
|
|
#include <map>
|
|
|
|
namespace Libs::Graphics {
|
|
|
|
class RangeSet final {
|
|
public:
|
|
void Add(uint64_t address, uint64_t size) {
|
|
const auto end = End(address, size);
|
|
auto it = m_ranges.lower_bound(address);
|
|
if (it != m_ranges.begin() && std::prev(it)->second >= address) {
|
|
it = std::prev(it);
|
|
}
|
|
uint64_t begin = address;
|
|
uint64_t last = end;
|
|
while (it != m_ranges.end() && it->first <= last) {
|
|
begin = std::min(begin, it->first);
|
|
last = std::max(last, it->second);
|
|
it = m_ranges.erase(it);
|
|
}
|
|
m_ranges.emplace(begin, last);
|
|
}
|
|
|
|
void Subtract(uint64_t address, uint64_t size) {
|
|
const auto end = End(address, size);
|
|
auto it = m_ranges.lower_bound(address);
|
|
if (it != m_ranges.begin() && std::prev(it)->second > address) {
|
|
it = std::prev(it);
|
|
}
|
|
while (it != m_ranges.end() && it->first < end) {
|
|
const auto begin = it->first;
|
|
const auto last = it->second;
|
|
it = m_ranges.erase(it);
|
|
if (begin < address) {
|
|
m_ranges.emplace(begin, address);
|
|
}
|
|
if (last > end) {
|
|
m_ranges.emplace(end, last);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Clear() { m_ranges.clear(); }
|
|
|
|
template <typename Func>
|
|
void ForEach(Func&& func) const {
|
|
for (const auto& [begin, end]: m_ranges) {
|
|
func(begin, end);
|
|
}
|
|
}
|
|
|
|
[[nodiscard]] bool Intersects(uint64_t address, uint64_t size) const {
|
|
const auto end = End(address, size);
|
|
auto it = m_ranges.lower_bound(address);
|
|
if (it != m_ranges.begin() && std::prev(it)->second > address) {
|
|
return true;
|
|
}
|
|
return it != m_ranges.end() && it->first < end;
|
|
}
|
|
|
|
[[nodiscard]] bool Contains(uint64_t address, uint64_t size) const {
|
|
const auto end = End(address, size);
|
|
auto it = m_ranges.upper_bound(address);
|
|
if (it == m_ranges.begin()) {
|
|
return false;
|
|
}
|
|
--it;
|
|
return it->first <= address && it->second >= end;
|
|
}
|
|
|
|
template <typename Func>
|
|
void ForEachInRange(uint64_t address, uint64_t size, Func&& func) const {
|
|
const auto end = End(address, size);
|
|
auto it = m_ranges.upper_bound(address);
|
|
if (it != m_ranges.begin()) {
|
|
--it;
|
|
}
|
|
for (; it != m_ranges.end() && it->first < end; ++it) {
|
|
const auto begin = std::max(address, it->first);
|
|
const auto last = std::min(end, it->second);
|
|
if (begin < last) {
|
|
func(begin, last);
|
|
}
|
|
}
|
|
}
|
|
|
|
[[nodiscard]] bool Empty() const { return m_ranges.empty(); }
|
|
|
|
private:
|
|
static uint64_t End(uint64_t address, uint64_t size) {
|
|
if (size == 0 || size > UINT64_MAX - address) {
|
|
EXIT("invalid range-set address or size\n");
|
|
}
|
|
return address + size;
|
|
}
|
|
|
|
std::map<uint64_t, uint64_t> m_ranges;
|
|
};
|
|
|
|
} // namespace Libs::Graphics
|
|
|
|
#endif // EMULATOR_SRC_GRAPHICS_HOST_GPU_RANGESET_H_
|