mirror of
https://github.com/dashpay/dash.git
synced 2024-12-29 05:49:11 +01:00
99 lines
2.8 KiB
C++
99 lines
2.8 KiB
C++
|
// Copyright (c) 2023 The Dash Core developers
|
||
|
// Distributed under the MIT software license, see the accompanying
|
||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||
|
|
||
|
#include <util/ranges_set.h>
|
||
|
|
||
|
CRangesSet::Range::Range() : CRangesSet::Range::Range(0, 0) {}
|
||
|
|
||
|
CRangesSet::Range::Range(uint64_t begin, uint64_t end) :
|
||
|
begin(begin),
|
||
|
end(end)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
bool CRangesSet::Add(uint64_t value)
|
||
|
{
|
||
|
if (Contains(value)) return false;
|
||
|
|
||
|
// If element is not in CRangesSet, we need to add a new range [value, value + 1)
|
||
|
// But this operation can cause 2 operation of merge (total 3 cases):
|
||
|
// - if there're exist ranges [x, value) and [value + 1, y) than
|
||
|
// all 3 of them should be merged in one range [x, y)
|
||
|
// - if there's exist a range [x, value) - we need to replace it to new range [x, value + 1)
|
||
|
// - if there's exist a range [value + 1, y) - we need to replace it to new range [value, y)
|
||
|
Range new_range{value, value + 1};
|
||
|
auto it = ranges.lower_bound({value, value});
|
||
|
if (it != ranges.begin()) {
|
||
|
auto prev = it;
|
||
|
--prev;
|
||
|
|
||
|
if (prev->end == value) {
|
||
|
new_range.begin = prev->begin;
|
||
|
it = ranges.erase(prev);
|
||
|
}
|
||
|
}
|
||
|
const auto next = it;
|
||
|
if (next != ranges.end()) {
|
||
|
if (next->begin == value + 1) {
|
||
|
new_range.end = next->end;
|
||
|
it = ranges.erase(next);
|
||
|
}
|
||
|
}
|
||
|
const auto ret = ranges.insert(new_range);
|
||
|
assert(ret.second);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool CRangesSet::Remove(uint64_t value)
|
||
|
{
|
||
|
if (!Contains(value)) return false;
|
||
|
|
||
|
// If element is in CRangesSet, there's possible 2 cases:
|
||
|
// - value in the range that is lower-bound (if begin of that range equals to `value`)
|
||
|
// - value in the previous range (otherwise)
|
||
|
auto it = ranges.lower_bound({value, value});
|
||
|
|
||
|
if (it == ranges.end() || it->begin != value) {
|
||
|
assert(it != ranges.begin());
|
||
|
--it;
|
||
|
}
|
||
|
|
||
|
const Range current_range = *it;
|
||
|
ranges.erase(it);
|
||
|
if (current_range.begin != value) {
|
||
|
const auto ret = ranges.insert({current_range.begin, value});
|
||
|
assert(ret.second);
|
||
|
}
|
||
|
if (value + 1 != current_range.end) {
|
||
|
const auto ret = ranges.insert({value + 1, current_range.end});
|
||
|
assert(ret.second);
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool CRangesSet::IsEmpty() const noexcept
|
||
|
{
|
||
|
return ranges.empty();
|
||
|
}
|
||
|
|
||
|
size_t CRangesSet::Size() const noexcept
|
||
|
{
|
||
|
size_t result{0};
|
||
|
for (auto i : ranges) {
|
||
|
result += i.end - i.begin;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
bool CRangesSet::Contains(uint64_t value) const noexcept
|
||
|
{
|
||
|
const auto it = ranges.lower_bound({value, value});
|
||
|
if (it != ranges.end() && it->begin == value) return true;
|
||
|
if (it == ranges.begin()) return false;
|
||
|
auto prev = it;
|
||
|
--prev;
|
||
|
return prev->begin <= value && prev->end > value;
|
||
|
}
|
||
|
|