mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-08-05 17:52:29 +00:00
00ef7d4be2
Given the change to the README I thought it might be a good idea to also update the copyright notices which had an address too.
200 lines
7.2 KiB
C++
200 lines
7.2 KiB
C++
// rTorrent - BitTorrent client
|
|
// Copyright (C) 2005-2008, Jari Sundell
|
|
//
|
|
// This program 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 2 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program 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 this program; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
//
|
|
// In addition, as a special exception, the copyright holders give
|
|
// permission to link the code of portions of this program with the
|
|
// OpenSSL library under certain conditions as described in each
|
|
// individual source file, and distribute linked combinations
|
|
// including the two.
|
|
//
|
|
// You must obey the GNU General Public License in all respects for
|
|
// all of the code used other than OpenSSL. If you modify file(s)
|
|
// with this exception, you may extend this exception to your version
|
|
// of the file(s), but you are not obligated to do so. If you do not
|
|
// wish to do so, delete this exception statement from your version.
|
|
// If you delete this exception statement from all source files in the
|
|
// program, then also delete it here.
|
|
//
|
|
// Contact: Jari Sundell <sundell.software@gmail.com>
|
|
|
|
|
|
#ifndef RTORRENT_CORE_RANGE_MAP_H
|
|
#define RTORRENT_CORE_RANGE_MAP_H
|
|
|
|
#include <map>
|
|
#include <stdexcept>
|
|
|
|
namespace core {
|
|
|
|
// Associate values with a range of keys, and retrieve for any key in the range.
|
|
|
|
// The template arguments have the same semantics as std::map.
|
|
// Exception: if set_merge is used, the value type must have a defined operator ==.
|
|
template<typename Key, typename T, typename Compare = std::less<Key>,
|
|
typename Alloc = std::allocator<std::pair<const Key, T> > >
|
|
class RangeMap : private std::map<Key, std::pair<Key, T>, Compare,
|
|
typename std::allocator_traits<Alloc>::template rebind_alloc<std::pair<const Key, std::pair<Key, T>>>> {
|
|
|
|
typedef std::map<Key, std::pair<Key, T>, Compare,
|
|
typename std::allocator_traits<Alloc>::template rebind_alloc<std::pair<const Key, std::pair<Key, T>>>> base_type;
|
|
|
|
//std::allocator_traits<Alloc>::template rebind_alloc<std::pair<const Key, std::pair<Key, T>>>
|
|
|
|
public:
|
|
RangeMap() = default;
|
|
RangeMap(const Compare& c) : base_type(c) {}
|
|
|
|
typedef typename base_type::iterator iterator;
|
|
typedef typename base_type::reverse_iterator reverse_iterator;
|
|
typedef typename base_type::const_iterator const_iterator;
|
|
typedef typename base_type::const_reverse_iterator const_reverse_iterator;
|
|
|
|
// using typename base_type::const_iterator;
|
|
// using typename base_type::const_reverse_iterator;
|
|
|
|
using base_type::clear;
|
|
using base_type::swap;
|
|
|
|
using base_type::size;
|
|
using base_type::empty;
|
|
|
|
using base_type::begin;
|
|
using base_type::end;
|
|
using base_type::rbegin;
|
|
using base_type::rend;
|
|
|
|
using base_type::key_comp;
|
|
using base_type::value_comp;
|
|
|
|
// Store a value for the range [begin, end). Returns iterator for the range.
|
|
const_iterator set_range(const Key& begin, const Key& end, const T& value);
|
|
|
|
// Same, but merge adjacent ranges having the same value. Returns iterator for the merged range.
|
|
const_iterator set_merge(Key begin, const Key& end, const T& value);
|
|
|
|
// Find range containing the given key, or end().
|
|
const_iterator find(const Key& key) const;
|
|
|
|
// Retrieve value for key in a range, throw std::out_of_range if range does not exist.
|
|
const T& get(const Key& key) const;
|
|
|
|
// Retrieve value for key in a range, return def if range does not exist.
|
|
T get(const Key& key, T def) const;
|
|
|
|
private:
|
|
iterator crop_overlap(const Key& begin, const Key& end);
|
|
};
|
|
|
|
// Semantics of an entry:
|
|
// .first End of range (exclusive), map key.
|
|
// .second.first Beginning of range.
|
|
// .second.second Value.
|
|
|
|
template<typename Key, typename T, typename C, typename A>
|
|
inline typename RangeMap<Key,T,C,A>::iterator
|
|
RangeMap<Key,T,C,A>::crop_overlap(const Key& _begin, const Key& _end) {
|
|
typename RangeMap::iterator itr = base_type::upper_bound(_begin);
|
|
|
|
while (itr != end() && key_comp()(itr->second.first, _end)) {
|
|
// There's a subrange before the new begin: need new entry (new range end means new key).
|
|
if (key_comp()(itr->second.first, _begin))
|
|
base_type::insert(itr, typename RangeMap::value_type(_begin, itr->second));
|
|
|
|
// Old end is within our range: erase entry.
|
|
if (!key_comp()(_end, itr->first)) {
|
|
base_type::erase(itr++);
|
|
|
|
// Otherwise simply set the new begin of the old range.
|
|
} else {
|
|
itr->second.first = _end;
|
|
++itr;
|
|
}
|
|
}
|
|
|
|
return itr;
|
|
}
|
|
|
|
template<typename Key, typename T, typename C, typename A>
|
|
inline typename RangeMap<Key,T,C,A>::const_iterator
|
|
RangeMap<Key,T,C,A>::set_merge(Key _begin, const Key& _end, const T& value) {
|
|
if (!key_comp()(_begin, _end))
|
|
return end();
|
|
|
|
// Crop overlapping ranges and return iterator to first range after the one we're inserting.
|
|
typename RangeMap::iterator itr = crop_overlap(_begin, _end);
|
|
|
|
// Check if range before new one is adjacent and has same value: if so erase it and use its beginning.
|
|
if (itr != begin()) {
|
|
typename RangeMap::iterator prev = itr;
|
|
if (!key_comp()((--prev)->first, _begin) && prev->second.second == value) {
|
|
_begin = prev->second.first;
|
|
base_type::erase(prev);
|
|
}
|
|
}
|
|
|
|
// Range after new one is adjacent and has same value: set new beginning.
|
|
if (itr != end() && !key_comp()(_end, itr->second.first) && itr->second.second == value) {
|
|
itr->second.first = _begin;
|
|
return itr;
|
|
}
|
|
|
|
// Otherwise, this range isn't mergeable, make new entry.
|
|
return base_type::insert(itr, typename RangeMap::value_type(_end, typename RangeMap::mapped_type(_begin, value)));
|
|
}
|
|
|
|
template<typename Key, typename T, typename C, typename A>
|
|
inline typename RangeMap<Key,T,C,A>::const_iterator
|
|
RangeMap<Key,T,C,A>::set_range(const Key& _begin, const Key& _end, const T& value) {
|
|
if (!key_comp()(_begin, _end))
|
|
return end();
|
|
|
|
return base_type::insert(crop_overlap(_begin, _end), typename RangeMap::value_type(_end, typename RangeMap::mapped_type(_begin, value)));
|
|
}
|
|
|
|
template<typename Key, typename T, typename C, typename A>
|
|
inline typename RangeMap<Key,T,C,A>::const_iterator
|
|
RangeMap<Key,T,C,A>::find(const Key& key) const {
|
|
typename RangeMap::const_iterator itr = base_type::upper_bound(key);
|
|
|
|
if (itr != end() && key_comp()(key, itr->second.first))
|
|
itr = end();
|
|
|
|
return itr;
|
|
}
|
|
|
|
template<typename Key, typename T, typename C, typename A>
|
|
inline const T&
|
|
RangeMap<Key,T,C,A>::get(const Key& key) const {
|
|
typename RangeMap::const_iterator itr = find(key);
|
|
|
|
if (itr == end())
|
|
throw std::out_of_range("RangeMap::get");
|
|
|
|
return itr->second.second;
|
|
}
|
|
|
|
template<typename Key, typename T, typename C, typename A>
|
|
inline T
|
|
RangeMap<Key,T,C,A>::get(const Key& key, T def) const {
|
|
typename RangeMap::const_iterator itr = find(key);
|
|
return (itr == end() ? def : itr->second.second);
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|