Files
rtorrent/src/core/range_map.h
T
Bryant Eadon 00ef7d4be2 cleanup of personal information
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.
2025-09-02 20:10:38 +02:00

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