#ifndef EMULATOR_SRC_GRAPHICS_HOST_GPU_RANGESET_H_ #define EMULATOR_SRC_GRAPHICS_HOST_GPU_RANGESET_H_ #include "common/assert.h" #include #include #include 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 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 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 m_ranges; }; } // namespace Libs::Graphics #endif // EMULATOR_SRC_GRAPHICS_HOST_GPU_RANGESET_H_