#ifndef EMULATOR_SRC_GRAPHICS_HOST_GPU_RANGESET_H_ #define EMULATOR_SRC_GRAPHICS_HOST_GPU_RANGESET_H_ #include "common/assert.h" #include #include #include #include namespace Libs::Graphics { class RangeSet final { public: struct Range { uint64_t address = 0; uint64_t size = 0; }; 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]] std::vector Intersections(uint64_t address, uint64_t size) const { std::vector result; ForEachIntersection(address, size, [&result](Range range) { result.push_back(range); }); return result; } [[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 ForEachIntersection(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(Range {begin, last - begin}); } } } [[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_