From 01ba6cf610641f1937092b469843b14ebc2a5962 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 4 Feb 2024 14:44:17 +0100 Subject: Common: Introduce Range Sets --- src/common/range_sets.inc | 279 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 279 insertions(+) create mode 100644 src/common/range_sets.inc (limited to 'src/common/range_sets.inc') diff --git a/src/common/range_sets.inc b/src/common/range_sets.inc new file mode 100644 index 000000000..fa55a68fb --- /dev/null +++ b/src/common/range_sets.inc @@ -0,0 +1,279 @@ +// SPDX-FileCopyrightText: 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include + +#define BOOST_NO_MT +#include +#undef BOOST_NO_MT +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common/range_sets.h" + +namespace boost { +template +class fast_pool_allocator; +} + +namespace Common { + +template +struct RangeSet::RangeSetImpl { + using IntervalSet = boost::icl::interval_set< + AddressType, std::less, ICL_INTERVAL_INSTANCE(ICL_INTERVAL_DEFAULT, AddressType, std::less), + boost::fast_pool_allocator>; + 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); + } + + IntervalSet m_ranges_set; +}; + +template +struct SplitRangeSet::SplitRangeSetImpl { + + using IntervalSet = + boost::icl::split_interval_map; + 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) { + 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); + } + + 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 { + if (m_impl->m_ranges_set.empty()) { + return; + } + auto it = m_impl->m_ranges_set.begin(); + auto end_it = m_impl->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 +template +void RangeSet::ForEachInRange(AddressType base_addr, size_t size, Func&& func) const { + auto& range_set = m_impl->m_ranges_set; + const AddressType start_address = base_addr; + const AddressType end_address = start_address + size; + const RangeSetImpl::IntervalType search_interval{start_address, end_address}; + auto it = range_set.lower_bound(search_interval); + if (it == range_set.end()) { + return; + } + auto end_it = range_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); + } +} + +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->Subtract(base_address, size, 1, [](AddressType, AddressType) {}); +} + +template +template +void SplitRangeSet::Subtract(AddressType base_address, size_t size, Func&& on_delete) { + m_impl->Subtract(base_address, size, 1, on_delete); +} + +template +void SplitRangeSet::DeleteAll(AddressType base_address, size_t size) { + m_impl->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 { + if (m_impl->m_split_ranges_set.empty()) { + return; + } + auto it = m_impl->m_split_ranges_set.begin(); + auto end_it = m_impl->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 +template +void SplitRangeSet::ForEachInRange(AddressType base_address, size_t size, + Func&& func) const { + auto& range_set = m_impl->m_split_ranges_set; + const AddressType start_address = base_address; + const AddressType end_address = start_address + size; + const SplitRangeSetImpl::IntervalType search_interval{start_address, end_address}; + auto it = range_set.lower_bound(search_interval); + if (it == range_set.end()) { + return; + } + auto end_it = range_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); + } +} + +} // namespace Common \ No newline at end of file -- cgit v1.2.3 From 0d5a3abeaefd3a1682c48a59c5a9170cfb0a39d0 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 4 Feb 2024 19:16:07 +0100 Subject: Buffer Cache: Refactor to use Range sets instead --- src/common/range_sets.inc | 184 ++++++++++++++++++++++++++-------------------- 1 file changed, 103 insertions(+), 81 deletions(-) (limited to 'src/common/range_sets.inc') diff --git a/src/common/range_sets.inc b/src/common/range_sets.inc index fa55a68fb..705ebd4a1 100644 --- a/src/common/range_sets.inc +++ b/src/common/range_sets.inc @@ -6,9 +6,6 @@ #include #include -#define BOOST_NO_MT -#include -#undef BOOST_NO_MT #include #include #include @@ -20,18 +17,16 @@ #include "common/range_sets.h" -namespace boost { -template -class fast_pool_allocator; -} - 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), - boost::fast_pool_allocator>; + MyAllocator>; using IntervalType = typename IntervalSet::interval_type; RangeSetImpl() = default; @@ -49,18 +44,58 @@ struct RangeSet::RangeSetImpl { 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 { - - using IntervalSet = - boost::icl::split_interval_map; + 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; @@ -75,6 +110,9 @@ struct SplitRangeSet::SplitRangeSetImpl { 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; @@ -101,6 +139,47 @@ struct SplitRangeSet::SplitRangeSetImpl { } 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; }; @@ -146,41 +225,13 @@ bool RangeSet::Empty() const { template template void RangeSet::ForEach(Func&& func) const { - if (m_impl->m_ranges_set.empty()) { - return; - } - auto it = m_impl->m_ranges_set.begin(); - auto end_it = m_impl->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); - } + m_impl->ForEach(std::move(func)); } template template -void RangeSet::ForEachInRange(AddressType base_addr, size_t size, Func&& func) const { - auto& range_set = m_impl->m_ranges_set; - const AddressType start_address = base_addr; - const AddressType end_address = start_address + size; - const RangeSetImpl::IntervalType search_interval{start_address, end_address}; - auto it = range_set.lower_bound(search_interval); - if (it == range_set.end()) { - return; - } - auto end_it = range_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); - } +void RangeSet::ForEachInRange(AddressType base_address, size_t size, Func&& func) const { + m_impl->ForEachInRange(base_address, size, std::move(func)); } template @@ -209,18 +260,18 @@ void SplitRangeSet::Add(AddressType base_address, size_t size) { template void SplitRangeSet::Subtract(AddressType base_address, size_t size) { - m_impl->Subtract(base_address, size, 1, [](AddressType, AddressType) {}); + 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->Subtract(base_address, size, 1, 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->Subtract(base_address, size, std::numeric_limits::max(), + m_impl->template Subtract(base_address, size, std::numeric_limits::max(), [](AddressType, AddressType) {}); } @@ -237,43 +288,14 @@ bool SplitRangeSet::Empty() const { template template void SplitRangeSet::ForEach(Func&& func) const { - if (m_impl->m_split_ranges_set.empty()) { - return; - } - auto it = m_impl->m_split_ranges_set.begin(); - auto end_it = m_impl->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); - } + m_impl->ForEach(func); } template template void SplitRangeSet::ForEachInRange(AddressType base_address, size_t size, Func&& func) const { - auto& range_set = m_impl->m_split_ranges_set; - const AddressType start_address = base_address; - const AddressType end_address = start_address + size; - const SplitRangeSetImpl::IntervalType search_interval{start_address, end_address}; - auto it = range_set.lower_bound(search_interval); - if (it == range_set.end()) { - return; - } - auto end_it = range_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); - } + m_impl->ForEachInRange(base_address, size, std::move(func)); } } // namespace Common \ No newline at end of file -- cgit v1.2.3 From fa47ac1c9f8b117d556c7c18ac9dcb062af5cefc Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 5 Feb 2024 12:46:49 +0100 Subject: Common: Rename SplitRangeSet to OverlapRangeSet --- src/common/range_sets.inc | 63 +++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 30 deletions(-) (limited to 'src/common/range_sets.inc') diff --git a/src/common/range_sets.inc b/src/common/range_sets.inc index 705ebd4a1..b83eceb7b 100644 --- a/src/common/range_sets.inc +++ b/src/common/range_sets.inc @@ -19,14 +19,18 @@ namespace Common { +namespace { +template +using RangeSetsAllocator = + boost::fast_pool_allocator; +} + 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>; + RangeSetsAllocator>; using IntervalType = typename IntervalSet::interval_type; RangeSetImpl() = default; @@ -88,18 +92,15 @@ struct RangeSet::RangeSetImpl { }; template -struct SplitRangeSet::SplitRangeSetImpl { - template - using MyAllocator = boost::fast_pool_allocator; +struct OverlapRangeSet::OverlapRangeSetImpl { 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>; + ICL_INTERVAL_INSTANCE(ICL_INTERVAL_DEFAULT, AddressType, std::less), RangeSetsAllocator>; using IntervalType = typename IntervalSet::interval_type; - SplitRangeSetImpl() = default; - ~SplitRangeSetImpl() = default; + OverlapRangeSetImpl() = default; + ~OverlapRangeSetImpl() = default; void Add(AddressType base_address, size_t size) { AddressType end_address = base_address + static_cast(size); @@ -160,7 +161,7 @@ struct SplitRangeSet::SplitRangeSetImpl { } const AddressType start_address = base_address; const AddressType end_address = start_address + size; - const SplitRangeSetImpl::IntervalType search_interval{start_address, end_address}; + const OverlapRangeSetImpl::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; @@ -230,72 +231,74 @@ void RangeSet::ForEach(Func&& func) const { template template -void RangeSet::ForEachInRange(AddressType base_address, size_t size, Func&& func) const { +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>(); +OverlapRangeSet::OverlapRangeSet() { + m_impl = std::make_unique::OverlapRangeSetImpl>(); } template -SplitRangeSet::~SplitRangeSet() = default; +OverlapRangeSet::~OverlapRangeSet() = default; template -SplitRangeSet::SplitRangeSet(SplitRangeSet&& other) { - m_impl = std::make_unique::SplitRangeSetImpl>(); +OverlapRangeSet::OverlapRangeSet(OverlapRangeSet&& other) { + m_impl = std::make_unique::OverlapRangeSetImpl>(); m_impl->m_split_ranges_set = std::move(other.m_impl->m_split_ranges_set); } template -SplitRangeSet& SplitRangeSet::operator=(SplitRangeSet&& other) { +OverlapRangeSet& OverlapRangeSet::operator=(OverlapRangeSet&& 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) { +void OverlapRangeSet::Add(AddressType base_address, size_t size) { m_impl->Add(base_address, size); } template -void SplitRangeSet::Subtract(AddressType base_address, size_t size) { +void OverlapRangeSet::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) { +void OverlapRangeSet::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) { +void OverlapRangeSet::DeleteAll(AddressType base_address, size_t size) { m_impl->template Subtract(base_address, size, std::numeric_limits::max(), - [](AddressType, AddressType) {}); + [](AddressType, AddressType) {}); } template -void SplitRangeSet::Clear() { +void OverlapRangeSet::Clear() { m_impl->m_split_ranges_set.clear(); } template -bool SplitRangeSet::Empty() const { +bool OverlapRangeSet::Empty() const { return m_impl->m_split_ranges_set.empty(); } template template -void SplitRangeSet::ForEach(Func&& func) const { +void OverlapRangeSet::ForEach(Func&& func) const { m_impl->ForEach(func); } template template -void SplitRangeSet::ForEachInRange(AddressType base_address, size_t size, - Func&& func) const { +void OverlapRangeSet::ForEachInRange(AddressType base_address, size_t size, + Func&& func) const { m_impl->ForEachInRange(base_address, size, std::move(func)); } -} // namespace Common \ No newline at end of file +} // namespace Common -- cgit v1.2.3