Gav Wood
10 years ago
4 changed files with 213 additions and 349 deletions
@ -0,0 +1,5 @@ |
|||||
|
#include "RangeMask.h" |
||||
|
|
||||
|
RangeMask::RangeMask() |
||||
|
{ |
||||
|
} |
@ -0,0 +1,192 @@ |
|||||
|
/*
|
||||
|
This file is part of cpp-ethereum. |
||||
|
|
||||
|
cpp-ethereum is free software: you can redistribute it and/or modify |
||||
|
it under the terms of the GNU General Public License as published by |
||||
|
the Free Software Foundation, either version 3 of the License, or |
||||
|
(at your option) any later version. |
||||
|
|
||||
|
cpp-ethereum is distributed in the hope that it will be useful, |
||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
GNU General Public License for more details. |
||||
|
|
||||
|
You should have received a copy of the GNU General Public License |
||||
|
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
*/ |
||||
|
/** @file EthereumHost.h
|
||||
|
* @author Gav Wood <i@gavwood.com> |
||||
|
* @date 2014 |
||||
|
*/ |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <map> |
||||
|
#include <utility> |
||||
|
#include <vector> |
||||
|
|
||||
|
namespace dev |
||||
|
{ |
||||
|
|
||||
|
class RLPStream; |
||||
|
|
||||
|
using UnsignedRange = std::pair<unsigned, unsigned>; |
||||
|
using UnsignedRanges = std::vector<UnsignedRange>; |
||||
|
|
||||
|
template <class T> |
||||
|
class RangeMask |
||||
|
{ |
||||
|
template <class U> friend std::ostream& operator<<(std::ostream& _out, RangeMask<U> const& _r); |
||||
|
|
||||
|
public: |
||||
|
using Range = std::pair<T, T>; |
||||
|
using Ranges = std::vector<Range>; |
||||
|
|
||||
|
RangeMask() {} |
||||
|
RangeMask(T _begin, T _end): m_all(_begin, _end) {} |
||||
|
RangeMask(Range const& _c): m_all(_c) {} |
||||
|
|
||||
|
RangeMask operator+(RangeMask const& _m) const { return RangeMask(*this) += _m; } |
||||
|
|
||||
|
RangeMask lowest(T _items) const |
||||
|
{ |
||||
|
RangeMask ret(m_all); |
||||
|
for (auto i = m_ranges.begin(); i != m_ranges.end() && _items; ++i) |
||||
|
_items -= (ret.m_ranges[i->first] = std::min(i->first + _items, i->second)); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
RangeMask operator~() const |
||||
|
{ |
||||
|
RangeMask ret(m_all); |
||||
|
T last = m_all.first; |
||||
|
for (auto i: m_ranges) |
||||
|
{ |
||||
|
if (i.first != last) |
||||
|
ret.m_ranges[last] = i.first; |
||||
|
last = i.second; |
||||
|
} |
||||
|
if (last != m_all.second) |
||||
|
ret.m_ranges[last] = m_all.second; |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
RangeMask& operator+=(RangeMask const& _m) |
||||
|
{ |
||||
|
for (auto const& i: _m.m_ranges) |
||||
|
operator+=(i); |
||||
|
return *this; |
||||
|
} |
||||
|
RangeMask& operator+=(UnsignedRange const& _m) |
||||
|
{ |
||||
|
for (auto i = _m.first; i < _m.second;) |
||||
|
{ |
||||
|
// for each number, we find the element equal or next lower. this, if any, must contain the value.
|
||||
|
auto uit = m_ranges.upper_bound(i); |
||||
|
auto it = uit == m_ranges.begin() ? m_ranges.end() : std::prev(uit); |
||||
|
if (it == m_ranges.end() || it->second < i) |
||||
|
// lower range is too low to merge.
|
||||
|
// if the next higher range is too high.
|
||||
|
if (uit == m_ranges.end() || uit->first > _m.second) |
||||
|
{ |
||||
|
// just create a new range
|
||||
|
m_ranges[i] = _m.second; |
||||
|
break; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if (uit->first == i) |
||||
|
// move i to end of range
|
||||
|
i = uit->second; |
||||
|
else |
||||
|
{ |
||||
|
// merge with the next higher range
|
||||
|
// move i to end of range
|
||||
|
i = m_ranges[i] = uit->second; |
||||
|
i = uit->second; |
||||
|
m_ranges.erase(uit); |
||||
|
} |
||||
|
} |
||||
|
else if (it->second == i) |
||||
|
{ |
||||
|
// if the next higher range is too high.
|
||||
|
if (uit == m_ranges.end() || uit->first > _m.second) |
||||
|
{ |
||||
|
// merge with the next lower range
|
||||
|
m_ranges[it->first] = _m.second; |
||||
|
break; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
// merge with both next lower & next higher.
|
||||
|
i = m_ranges[it->first] = uit->second; |
||||
|
m_ranges.erase(uit); |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
i = it->second; |
||||
|
} |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
RangeMask& operator+=(T _i) |
||||
|
{ |
||||
|
return operator+=(Range(_i, _i + 1)); |
||||
|
} |
||||
|
|
||||
|
bool contains(T _i) const |
||||
|
{ |
||||
|
auto it = m_ranges.lower_bound(_i); |
||||
|
return it != m_ranges.end() && it->first <= _i && it->second > _i; |
||||
|
} |
||||
|
|
||||
|
class const_iterator |
||||
|
{ |
||||
|
friend class RangeMask; |
||||
|
|
||||
|
public: |
||||
|
const_iterator() {} |
||||
|
|
||||
|
T operator*() const { return m_value; } |
||||
|
const_iterator& operator++() { if (m_owner) m_value = m_owner->next(m_value); return *this; } |
||||
|
const_iterator operator++(int) { auto ret = *this; if (m_owner) m_value = m_owner->next(m_value); return ret; } |
||||
|
|
||||
|
bool operator==(const_iterator const& _i) const { return m_owner == _i.m_owner && m_value == _i.m_value; } |
||||
|
bool operator!=(const_iterator const& _i) const { return !operator==(_i); } |
||||
|
bool operator<(const_iterator const& _i) const { return m_value < _i.m_value; } |
||||
|
|
||||
|
private: |
||||
|
const_iterator(RangeMask const& _m, bool _end): m_owner(&_m), m_value(_m.m_ranges.empty() || _end ? _m.m_all.second : _m.m_ranges.begin()->first) {} |
||||
|
|
||||
|
RangeMask const* m_owner = nullptr; |
||||
|
T m_value = 0; |
||||
|
}; |
||||
|
|
||||
|
const_iterator begin() const { return const_iterator(*this, false); } |
||||
|
const_iterator end() const { return const_iterator(*this, true); } |
||||
|
T next(T _t) const |
||||
|
{ |
||||
|
_t++; |
||||
|
// find next item in range at least _t
|
||||
|
auto uit = m_ranges.upper_bound(_t); // > _t
|
||||
|
auto it = uit == m_ranges.begin() ? m_ranges.end() : std::prev(uit); |
||||
|
if (it != m_ranges.end() && it->first <= _t && it->second > _t) |
||||
|
return _t; |
||||
|
return uit == m_ranges.end() ? m_all.second : uit->first; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
UnsignedRange m_all; |
||||
|
std::map<T, T> m_ranges; |
||||
|
}; |
||||
|
|
||||
|
template <class T> inline std::ostream& operator<<(std::ostream& _out, RangeMask<T> const& _r) |
||||
|
{ |
||||
|
_out << _r.m_all.first << "{ "; |
||||
|
for (auto const& i: _r.m_ranges) |
||||
|
_out << "[" << i.first << ", " << i.second << ") "; |
||||
|
_out << "}" << _r.m_all.second; |
||||
|
return _out; |
||||
|
} |
||||
|
|
||||
|
} |
Loading…
Reference in new issue