286 lines
9.1 KiB
C++
286 lines
9.1 KiB
C++
/*
|
|
* RangeMap.h
|
|
*
|
|
* This source file is part of the FoundationDB open source project
|
|
*
|
|
* Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
|
|
*
|
|
* 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
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* 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) {}
|
|
};
|
|
|
|
template <class Key>
|
|
RangeMapRange<Key> rangeMapRange( Key const& begin, Key const& end ) { return RangeMapRange<Key>(begin,end); }
|
|
|
|
template <class Metric>
|
|
struct ConstantMetric {
|
|
template<typename pair_type>
|
|
Metric operator()(pair_type const& p) const { return Metric(1); }
|
|
};
|
|
|
|
template <class Metric>
|
|
struct KeyBytesMetric {
|
|
template<typename pair_type>
|
|
Metric operator()(pair_type const& p) const { return Metric(p.key.size() + sizeof(pair_type)); }
|
|
};
|
|
|
|
template <class Metric>
|
|
struct ValueBytesMetric {
|
|
template<typename pair_type>
|
|
Metric operator()(pair_type const& p) const { return Metric(p.value.size() + sizeof(pair_type)); }
|
|
};
|
|
|
|
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)); }
|
|
};
|
|
|
|
template <class Key, class Val, class Range = RangeMapRange<Key>, class Metric = int, class MetricFunc = ConstantMetric<Metric>>
|
|
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
|
|
template <bool isConst>
|
|
class IteratorImpl {
|
|
using self_t = IteratorImpl<isConst>;
|
|
|
|
public:
|
|
using value_type = std::conditional_t<isConst, typename Map<Key, Val, pair_type, Metric>::const_iterator,
|
|
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) {}
|
|
|
|
Key const& begin() { return it->key; }
|
|
Key const& end() { auto j = it; ++j; return j->key; }
|
|
|
|
Range range() { return Range(begin(),end()); }
|
|
|
|
std::conditional_t<isConst, const Val&, Val&> value() {
|
|
//ASSERT( it->key != allKeys.end );
|
|
return it->value;
|
|
}
|
|
const Val& cvalue() const { return it->value; }
|
|
|
|
void operator ++() { ++it; }
|
|
void operator --() { it.decrementNonEnd(); }
|
|
bool operator==(self_t const& r) const { return it == r.it; }
|
|
bool operator!=(self_t const& r) const { return it != r.it; }
|
|
|
|
// operator* and -> return this
|
|
self_t& operator*() { return *this; }
|
|
self_t* operator->() { return this; }
|
|
|
|
private:
|
|
value_type it;
|
|
};
|
|
|
|
public:
|
|
using iterator = IteratorImpl<false>;
|
|
using const_iterator = IteratorImpl<true>;
|
|
using Ranges = iterator_range<iterator>;
|
|
using ConstRanges = iterator_range<const_iterator>;
|
|
|
|
explicit RangeMap(Key endKey, Val v=Val(), MetricFunc m = MetricFunc()) : mf(m) {
|
|
Key beginKey = Key();
|
|
pair_type beginPair(beginKey, v);
|
|
map.insert(beginPair, true, mf(beginPair));
|
|
pair_type endPair(endKey, Val());
|
|
map.insert(endPair, true, mf(endPair));
|
|
}
|
|
Val const& operator[]( const Key& k ) { return rangeContaining(k).value(); }
|
|
|
|
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
|
|
Ranges intersectingRanges(const Range& r) {
|
|
return Ranges(rangeContaining(r.begin), iterator(map.lower_bound(r.end)));
|
|
}
|
|
ConstRanges intersectingRanges(const Range& r) const {
|
|
return ConstRanges(rangeContaining(r.begin), const_iterator(map.lower_bound(r.end)));
|
|
}
|
|
// containedRanges() will return all ranges that are fully contained by the passed range (note that a range fully contains itself)
|
|
Ranges containedRanges(const Range& r) {
|
|
iterator s(map.lower_bound(r.begin));
|
|
if (s.begin() >= r.end) return Ranges(s, s);
|
|
return Ranges(s, rangeContaining(r.end));
|
|
}
|
|
template <class ComparableToKey>
|
|
iterator rangeContaining(const ComparableToKey& k) {
|
|
return iterator(map.lastLessOrEqual(k));
|
|
}
|
|
template <class ComparableToKey>
|
|
const_iterator rangeContaining(const ComparableToKey& k) const {
|
|
return const_iterator(map.lastLessOrEqual(k));
|
|
}
|
|
// Returns the range containing a key infinitesimally before k, or the first range if k==Key()
|
|
template <class ComparableToKey>
|
|
iterator rangeContainingKeyBefore(const ComparableToKey& k) {
|
|
iterator i(map.lower_bound(k));
|
|
if (!i->begin().size()) return i;
|
|
--i;
|
|
return i;
|
|
}
|
|
template <class ComparableToKey>
|
|
const_iterator rangeContainingKeyBefore(const ComparableToKey& k) const {
|
|
const_iterator i(map.lower_bound(k));
|
|
if ( !i->begin().size() ) return i;
|
|
--i;
|
|
return i;
|
|
}
|
|
iterator lastItem() {
|
|
auto i(map.lastItem());
|
|
i.decrementNonEnd();
|
|
return iterator(i);
|
|
}
|
|
const_iterator lastItem() const {
|
|
auto i(map.lastItem());
|
|
i.decrementNonEnd();
|
|
return const_iterator(i);
|
|
}
|
|
int size() const { return map.size() - 1; } // We always have one range bounded by two entries
|
|
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)); }
|
|
|
|
bool allEqual( const Range& r, const Val& v );
|
|
|
|
template <class ComparableToKey>
|
|
void coalesce( const ComparableToKey& k );
|
|
void coalesce( const Range& k );
|
|
void validateCoalesced();
|
|
|
|
void operator=(RangeMap&& r) noexcept { map = std::move(r.map); }
|
|
//void clear( const Val& value ) { ranges.clear(); ranges.insert(std::make_pair(Key(),value)); }
|
|
|
|
void insert( const Range& keys, const Val& value );
|
|
|
|
Future<Void> clearAsync() { return map.clearAsync(); }
|
|
|
|
protected:
|
|
Map<Key,Val,pair_type,Metric> map;
|
|
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 ) {
|
|
auto begin = map.lastLessOrEqual(k);
|
|
auto end = begin;
|
|
const Val& compareVal = begin->value;
|
|
ASSERT( begin != map.end() );
|
|
while( begin != map.begin() && begin->value == compareVal )
|
|
begin.decrementNonEnd();
|
|
while( end != map.lastItem() && end->value == compareVal )
|
|
++end;
|
|
if( begin->value != compareVal ) {
|
|
++begin;
|
|
if( begin == end ) return;
|
|
}
|
|
++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 ) {
|
|
coalesce(k.begin);
|
|
auto it = map.lastLessOrEqual(k.begin);
|
|
Val* lastVal = &it->value;
|
|
++it;
|
|
if( it == map.end() )
|
|
return;
|
|
bool doCheck = true;
|
|
while( it != map.lastItem() && doCheck ) {
|
|
doCheck = it->key < k.end;
|
|
if( it->value == *lastVal ) {
|
|
doCheck = true;
|
|
auto begin = it;
|
|
++it;
|
|
map.erase(begin, it);
|
|
}
|
|
else {
|
|
lastVal = &it->value;
|
|
++it;
|
|
}
|
|
}
|
|
if( EXPENSIVE_VALIDATION )
|
|
validateCoalesced();
|
|
}
|
|
|
|
template <class Key, class Val, class Range, class Metric, class MetricFunc>
|
|
void RangeMap<Key,Val,Range,Metric,MetricFunc>::validateCoalesced() {
|
|
auto it = map.begin();
|
|
Val* lastVal = &it->value;
|
|
++it;
|
|
auto end = map.lastItem();
|
|
for( ; it != end; ++it ) {
|
|
ASSERT( it->value != *lastVal );
|
|
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 ) {
|
|
auto r = intersectingRanges(keys);
|
|
for(auto i=r.begin(); i!=r.end(); ++i)
|
|
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)
|
|
return;
|
|
|
|
auto end = map.lower_bound( keys.end );
|
|
if( end->key != keys.end ) {
|
|
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 );
|
|
|
|
map.erase(begin, end);
|
|
pair_type beginPair(keys.begin, value);
|
|
map.insert(beginPair, true, mf(beginPair));
|
|
}
|
|
|
|
#endif
|