foundationdb/fdbrpc/RangeMap.h

310 lines
9.2 KiB
C
Raw Normal View History

2017-05-26 04:48:44 +08:00
/*
* RangeMap.h
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
*
2017-05-26 04:48:44 +08:00
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
2017-05-26 04:48:44 +08:00
* http://www.apache.org/licenses/LICENSE-2.0
*
2017-05-26 04:48:44 +08:00
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLOW_RANGEMAP_H
#define FLOW_RANGEMAP_H
#pragma once
#include "flow/flow.h"
#include <boost/range.hpp>
#include "flow/IndexedSet.h"
using boost::iterator_range;
template <class Key>
class RangeMapRange {
public:
Key begin, end;
RangeMapRange(Key const& begin, Key const& end) : begin(begin), end(end) {}
2017-05-26 04:48:44 +08:00
};
template <class Key>
RangeMapRange<Key> rangeMapRange(Key const& begin, Key const& end) {
return RangeMapRange<Key>(begin, end);
}
2017-05-26 04:48:44 +08:00
template <class Metric>
struct ConstantMetric {
template <typename pair_type>
Metric operator()(pair_type const& p) const {
return Metric(1);
}
2017-05-26 04:48:44 +08:00
};
template <class Metric>
struct KeyBytesMetric {
template <typename pair_type>
Metric operator()(pair_type const& p) const {
return Metric(p.key.size() + sizeof(pair_type));
}
2017-05-26 04:48:44 +08:00
};
template <class Metric>
struct ValueBytesMetric {
template <typename pair_type>
Metric operator()(pair_type const& p) const {
return Metric(p.value.size() + sizeof(pair_type));
}
2017-05-26 04:48:44 +08:00
};
template <class Metric>
struct KeyValueBytesMetric {
template <typename pair_type>
Metric operator()(pair_type const& p) const {
return Metric(p.key.size() + p.value.size() + sizeof(pair_type));
}
2017-05-26 04:48:44 +08:00
};
template <class Key,
class Val,
class Range = RangeMapRange<Key>,
class Metric = int,
class MetricFunc = ConstantMetric<Metric>>
2017-05-26 04:48:44 +08:00
class RangeMap {
private:
typedef MapPair<Key, Val> pair_type;
// Applications may decrement an iterator before ranges begin, or increment after ranges end, but once in this state
// cannot do further incrementing or decrementing
2020-07-10 13:05:37 +08:00
template <bool isConst>
class IteratorImpl {
using self_t = IteratorImpl<isConst>;
2017-05-26 04:48:44 +08:00
public:
using value_type = std::conditional_t<isConst,
typename Map<Key, Val, pair_type, Metric>::const_iterator,
2020-07-10 13:05:37 +08:00
typename Map<Key, Val, pair_type, Metric>::iterator>;
typedef std::forward_iterator_tag iterator_category;
using difference_type = int;
using pointer = self_t*;
using reference = self_t&;
IteratorImpl() {} // singular
explicit IteratorImpl<isConst>(const value_type it) : it(it) {}
2017-05-26 04:48:44 +08:00
Key const& begin() { return it->key; }
Key const& end() {
auto j = it;
++j;
return j->key;
}
2017-05-26 04:48:44 +08:00
Range range() { return Range(begin(), end()); }
2017-05-26 04:48:44 +08:00
2020-07-11 10:04:35 +08:00
std::conditional_t<isConst, const Val&, Val&> value() {
// ASSERT( it->key != allKeys.end );
return it->value;
2017-05-26 04:48:44 +08:00
}
2020-07-11 10:04:35 +08:00
const Val& cvalue() const { return it->value; }
2017-05-26 04:48:44 +08:00
void operator++() { ++it; }
void operator--() { it.decrementNonEnd(); }
2020-07-10 13:05:37 +08:00
bool operator==(self_t const& r) const { return it == r.it; }
bool operator!=(self_t const& r) const { return it != r.it; }
2017-05-26 04:48:44 +08:00
// operator* and -> return this
2020-07-10 13:05:37 +08:00
self_t& operator*() { return *this; }
self_t* operator->() { return this; }
2017-05-26 04:48:44 +08:00
private:
2020-07-10 13:05:37 +08:00
value_type it;
2017-05-26 04:48:44 +08:00
};
2020-07-11 10:04:35 +08:00
public:
2020-07-11 01:43:33 +08:00
using iterator = IteratorImpl<false>;
using const_iterator = IteratorImpl<true>;
using Ranges = iterator_range<iterator>;
using ConstRanges = iterator_range<const_iterator>;
2017-05-26 04:48:44 +08:00
explicit RangeMap(Key endKey, Val v = Val(), MetricFunc m = MetricFunc()) : mf(m) {
2017-05-26 04:48:44 +08:00
Key beginKey = Key();
pair_type beginPair(beginKey, v);
map.insert(beginPair, true, mf(beginPair));
2017-05-26 04:48:44 +08:00
pair_type endPair(endKey, Val());
map.insert(endPair, true, mf(endPair));
2017-05-26 04:48:44 +08:00
}
Val const& operator[](const Key& k) { return rangeContaining(k).value(); }
2017-05-26 04:48:44 +08:00
2020-07-11 01:43:33 +08:00
Ranges ranges() { return Ranges(iterator(map.begin()), iterator(map.lastItem())); }
ConstRanges ranges() const { return ConstRanges(const_iterator(map.begin()), const_iterator(map.lastItem())); }
// intersectingRanges returns [begin, end] where begin <= r.begin and end >= r.end
2020-07-10 13:05:37 +08:00
Ranges intersectingRanges(const Range& r) {
2020-07-11 01:43:33 +08:00
return Ranges(rangeContaining(r.begin), iterator(map.lower_bound(r.end)));
2020-07-10 13:05:37 +08:00
}
ConstRanges intersectingRanges(const Range& r) const {
2020-07-11 01:43:33 +08:00
return ConstRanges(rangeContaining(r.begin), const_iterator(map.lower_bound(r.end)));
2020-07-10 13:05:37 +08:00
}
// containedRanges() will return all ranges that are fully contained by the passed range (note that a range fully
// contains itself)
2020-07-10 13:05:37 +08:00
Ranges containedRanges(const Range& r) {
2020-07-11 01:43:33 +08:00
iterator s(map.lower_bound(r.begin));
if (s.begin() >= r.end)
return Ranges(s, s);
2017-05-26 04:48:44 +08:00
return Ranges(s, rangeContaining(r.end));
}
template <class ComparableToKey>
2020-07-11 01:43:33 +08:00
iterator rangeContaining(const ComparableToKey& k) {
return iterator(map.lastLessOrEqual(k));
2020-07-10 13:05:37 +08:00
}
template <class ComparableToKey>
2020-07-11 01:43:33 +08:00
const_iterator rangeContaining(const ComparableToKey& k) const {
return const_iterator(map.lastLessOrEqual(k));
2017-05-26 04:48:44 +08:00
}
// Returns the range containing a key infinitesimally before k, or the first range if k==Key()
template <class ComparableToKey>
2020-07-11 01:43:33 +08:00
iterator rangeContainingKeyBefore(const ComparableToKey& k) {
iterator i(map.lower_bound(k));
if (!i->begin().size())
return i;
2020-07-10 13:05:37 +08:00
--i;
return i;
}
template <class ComparableToKey>
2020-07-11 01:43:33 +08:00
const_iterator rangeContainingKeyBefore(const ComparableToKey& k) const {
const_iterator i(map.lower_bound(k));
if (!i->begin().size())
return i;
2017-05-26 04:48:44 +08:00
--i;
return i;
}
2020-07-11 01:43:33 +08:00
iterator lastItem() {
2020-07-10 13:05:37 +08:00
auto i(map.lastItem());
2017-05-26 04:48:44 +08:00
i.decrementNonEnd();
2020-07-11 01:43:33 +08:00
return iterator(i);
2017-05-26 04:48:44 +08:00
}
2020-08-20 08:32:11 +08:00
const_iterator lastItem() const {
auto i(map.lastItem());
i.decrementNonEnd();
return const_iterator(i);
}
2017-05-26 04:48:44 +08:00
int size() const { return map.size() - 1; } // We always have one range bounded by two entries
2020-07-11 01:43:33 +08:00
iterator randomRange() { return iterator(map.index(deterministicRandom()->randomInt(0, map.size() - 1))); }
const_iterator randomRange() const {
return const_iterator(map.index(deterministicRandom()->randomInt(0, map.size() - 1)));
}
iterator nthRange(int n) { return iterator(map.index(n)); }
const_iterator nthRange(int n) const { return const_iterator(map.index(n)); }
2017-05-26 04:48:44 +08:00
bool allEqual(const Range& r, const Val& v);
2017-05-26 04:48:44 +08:00
template <class ComparableToKey>
void coalesce(const ComparableToKey& k);
void coalesce(const Range& k);
2017-05-26 04:48:44 +08:00
void validateCoalesced();
2020-06-10 08:33:41 +08:00
void operator=(RangeMap&& r) noexcept { map = std::move(r.map); }
// void clear( const Val& value ) { ranges.clear(); ranges.insert(std::make_pair(Key(),value)); }
2017-05-26 04:48:44 +08:00
void insert(const Range& keys, const Val& value);
2017-05-26 04:48:44 +08:00
Future<Void> clearAsync() { return map.clearAsync(); }
2017-05-26 04:48:44 +08:00
protected:
Map<Key, Val, pair_type, Metric> map;
2017-05-26 04:48:44 +08:00
const MetricFunc mf;
};
template <class Key, class Val, class Range, class Metric, class MetricFunc>
template <class ComparableToKey>
void RangeMap<Key, Val, Range, Metric, MetricFunc>::coalesce(const ComparableToKey& k) {
2017-05-26 04:48:44 +08:00
auto begin = map.lastLessOrEqual(k);
auto end = begin;
const Val& compareVal = begin->value;
ASSERT(begin != map.end());
while (begin != map.begin() && begin->value == compareVal)
2017-05-26 04:48:44 +08:00
begin.decrementNonEnd();
while (end != map.lastItem() && end->value == compareVal)
2017-05-26 04:48:44 +08:00
++end;
if (begin->value != compareVal) {
2017-05-26 04:48:44 +08:00
++begin;
if (begin == end)
return;
2017-05-26 04:48:44 +08:00
}
++begin;
map.erase(begin, end);
}
template <class Key, class Val, class Range, class Metric, class MetricFunc>
void RangeMap<Key, Val, Range, Metric, MetricFunc>::coalesce(const Range& k) {
2017-05-26 04:48:44 +08:00
coalesce(k.begin);
auto it = map.lastLessOrEqual(k.begin);
Val* lastVal = &it->value;
++it;
if (it == map.end())
2017-05-26 04:48:44 +08:00
return;
bool doCheck = true;
while (it != map.lastItem() && doCheck) {
2017-05-26 04:48:44 +08:00
doCheck = it->key < k.end;
if (it->value == *lastVal) {
2017-05-26 04:48:44 +08:00
doCheck = true;
auto begin = it;
++it;
map.erase(begin, it);
} else {
2017-05-26 04:48:44 +08:00
lastVal = &it->value;
++it;
}
}
if (EXPENSIVE_VALIDATION)
2017-05-26 04:48:44 +08:00
validateCoalesced();
}
template <class Key, class Val, class Range, class Metric, class MetricFunc>
void RangeMap<Key, Val, Range, Metric, MetricFunc>::validateCoalesced() {
2017-05-26 04:48:44 +08:00
auto it = map.begin();
Val* lastVal = &it->value;
++it;
auto end = map.lastItem();
for (; it != end; ++it) {
ASSERT(it->value != *lastVal);
2017-05-26 04:48:44 +08:00
lastVal = &it->value;
}
}
template <class Key, class Val, class Range, class Metric, class MetricFunc>
bool RangeMap<Key, Val, Range, Metric, MetricFunc>::allEqual(const Range& keys, const Val& val) {
2017-05-26 04:48:44 +08:00
auto r = intersectingRanges(keys);
for (auto i = r.begin(); i != r.end(); ++i)
2017-05-26 04:48:44 +08:00
if (i.value() != val)
return false;
return true;
}
template <class Key, class Val, class Range, class Metric, class MetricFunc>
void RangeMap<Key, Val, Range, Metric, MetricFunc>::insert(const Range& keys, const Val& value) {
if (keys.begin == keys.end)
2017-05-26 04:48:44 +08:00
return;
auto end = map.lower_bound(keys.end);
if (end->key != keys.end) {
2017-05-26 04:48:44 +08:00
end.decrementNonEnd();
const Val& valueAfterRange = end->value;
pair_type endPair(keys.end, valueAfterRange);
end = map.insert(endPair, true, mf(endPair));
}
auto begin = map.lower_bound(keys.begin);
2017-05-26 04:48:44 +08:00
map.erase(begin, end);
pair_type beginPair(keys.begin, value);
map.insert(beginPair, true, mf(beginPair));
}
2020-08-20 08:32:11 +08:00
#endif