// SPDX-FileCopyrightText: 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include #include #include #include #include #include #include #include #include #include #include "common/range_sets.h" namespace Common { template struct RangeSet::RangeSetImpl { template using MyAllocator = boost::fast_pool_allocator; using IntervalSet = boost::icl::interval_set< AddressType, std::less, ICL_INTERVAL_INSTANCE(ICL_INTERVAL_DEFAULT, AddressType, std::less), MyAllocator>; using IntervalType = typename IntervalSet::interval_type; RangeSetImpl() = default; ~RangeSetImpl() = default; void Add(AddressType base_address, size_t size) { AddressType end_address = base_address + static_cast(size); IntervalType interval{base_address, end_address}; m_ranges_set.add(interval); } void Subtract(AddressType base_address, size_t size) { AddressType end_address = base_address + static_cast(size); IntervalType interval{base_address, end_address}; m_ranges_set.subtract(interval); } template void ForEach(Func&& func) const { if (m_ranges_set.empty()) { return; } auto it = m_ranges_set.begin(); auto end_it = m_ranges_set.end(); for (; it != end_it; it++) { const AddressType inter_addr_end = it->upper(); const AddressType inter_addr = it->lower(); func(inter_addr, inter_addr_end); } } template void ForEachInRange(AddressType base_addr, size_t size, Func&& func) const { if (m_ranges_set.empty()) { return; } const AddressType start_address = base_addr; const AddressType end_address = start_address + size; const RangeSetImpl::IntervalType search_interval{start_address, end_address}; auto it = m_ranges_set.lower_bound(search_interval); if (it == m_ranges_set.end()) { return; } auto end_it = m_ranges_set.upper_bound(search_interval); for (; it != end_it; it++) { AddressType inter_addr_end = it->upper(); AddressType inter_addr = it->lower(); if (inter_addr_end > end_address) { inter_addr_end = end_address; } if (inter_addr < start_address) { inter_addr = start_address; } func(inter_addr, inter_addr_end); } } IntervalSet m_ranges_set; }; template struct SplitRangeSet::SplitRangeSetImpl { template using MyAllocator = boost::fast_pool_allocator; using IntervalSet = boost::icl::split_interval_map< AddressType, s32, boost::icl::partial_enricher, std::less, boost::icl::inplace_plus, boost::icl::inter_section, ICL_INTERVAL_INSTANCE(ICL_INTERVAL_DEFAULT, AddressType, std::less), MyAllocator>; using IntervalType = typename IntervalSet::interval_type; SplitRangeSetImpl() = default; ~SplitRangeSetImpl() = default; void Add(AddressType base_address, size_t size) { AddressType end_address = base_address + static_cast(size); IntervalType interval{base_address, end_address}; m_split_ranges_set += std::make_pair(interval, 1); } template void Subtract(AddressType base_address, size_t size, s32 amount, [[maybe_unused]] Func&& on_delete) { if (m_split_ranges_set.empty()) { return; } AddressType end_address = base_address + static_cast(size); IntervalType interval{base_address, end_address}; bool any_removals = false; m_split_ranges_set += std::make_pair(interval, -amount); do { any_removals = false; auto it = m_split_ranges_set.lower_bound(interval); if (it == m_split_ranges_set.end()) { return; } auto end_it = m_split_ranges_set.upper_bound(interval); for (; it != end_it; it++) { if (it->second <= 0) { if constexpr (has_on_delete) { if (it->second == 0) { on_delete(it->first.lower(), it->first.upper()); } } any_removals = true; m_split_ranges_set.erase(it); break; } } } while (any_removals); } template void ForEach(Func&& func) const { if (m_split_ranges_set.empty()) { return; } auto it = m_split_ranges_set.begin(); auto end_it = m_split_ranges_set.end(); for (; it != end_it; it++) { const AddressType inter_addr_end = it->first.upper(); const AddressType inter_addr = it->first.lower(); func(inter_addr, inter_addr_end, it->second); } } template void ForEachInRange(AddressType base_address, size_t size, Func&& func) const { if (m_split_ranges_set.empty()) { return; } const AddressType start_address = base_address; const AddressType end_address = start_address + size; const SplitRangeSetImpl::IntervalType search_interval{start_address, end_address}; auto it = m_split_ranges_set.lower_bound(search_interval); if (it == m_split_ranges_set.end()) { return; } auto end_it = m_split_ranges_set.upper_bound(search_interval); for (; it != end_it; it++) { auto& inter = it->first; AddressType inter_addr_end = inter.upper(); AddressType inter_addr = inter.lower(); if (inter_addr_end > end_address) { inter_addr_end = end_address; } if (inter_addr < start_address) { inter_addr = start_address; } func(inter_addr, inter_addr_end, it->second); } } IntervalSet m_split_ranges_set; }; template RangeSet::RangeSet() { m_impl = std::make_unique::RangeSetImpl>(); } template RangeSet::~RangeSet() = default; template RangeSet::RangeSet(RangeSet&& other) { m_impl = std::make_unique::RangeSetImpl>(); m_impl->m_ranges_set = std::move(other.m_impl->m_ranges_set); } template RangeSet& RangeSet::operator=(RangeSet&& other) { m_impl->m_ranges_set = std::move(other.m_impl->m_ranges_set); } template void RangeSet::Add(AddressType base_address, size_t size) { m_impl->Add(base_address, size); } template void RangeSet::Subtract(AddressType base_address, size_t size) { m_impl->Subtract(base_address, size); } template void RangeSet::Clear() { m_impl->m_ranges_set.clear(); } template bool RangeSet::Empty() const { return m_impl->m_ranges_set.empty(); } template template void RangeSet::ForEach(Func&& func) const { m_impl->ForEach(std::move(func)); } template template void RangeSet::ForEachInRange(AddressType base_address, size_t size, Func&& func) const { m_impl->ForEachInRange(base_address, size, std::move(func)); } template SplitRangeSet::SplitRangeSet() { m_impl = std::make_unique::SplitRangeSetImpl>(); } template SplitRangeSet::~SplitRangeSet() = default; template SplitRangeSet::SplitRangeSet(SplitRangeSet&& other) { m_impl = std::make_unique::SplitRangeSetImpl>(); m_impl->m_split_ranges_set = std::move(other.m_impl->m_split_ranges_set); } template SplitRangeSet& SplitRangeSet::operator=(SplitRangeSet&& other) { m_impl->m_split_ranges_set = std::move(other.m_impl->m_split_ranges_set); } template void SplitRangeSet::Add(AddressType base_address, size_t size) { m_impl->Add(base_address, size); } template void SplitRangeSet::Subtract(AddressType base_address, size_t size) { m_impl->template Subtract(base_address, size, 1, [](AddressType, AddressType) {}); } template template void SplitRangeSet::Subtract(AddressType base_address, size_t size, Func&& on_delete) { m_impl->template Subtract(base_address, size, 1, std::move(on_delete)); } template void SplitRangeSet::DeleteAll(AddressType base_address, size_t size) { m_impl->template Subtract(base_address, size, std::numeric_limits::max(), [](AddressType, AddressType) {}); } template void SplitRangeSet::Clear() { m_impl->m_split_ranges_set.clear(); } template bool SplitRangeSet::Empty() const { return m_impl->m_split_ranges_set.empty(); } template template void SplitRangeSet::ForEach(Func&& func) const { m_impl->ForEach(func); } template template void SplitRangeSet::ForEachInRange(AddressType base_address, size_t size, Func&& func) const { m_impl->ForEachInRange(base_address, size, std::move(func)); } } // namespace Common