run_set
This commit is contained in:
parent
e701b96642
commit
3be8376256
113
persistent-data/run_set.h
Normal file
113
persistent-data/run_set.h
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
#ifndef PERSISTENT_DATA_H
|
||||||
|
#define PERSISTENT_DATA_H
|
||||||
|
|
||||||
|
#include "persistent-data/run.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace base {
|
||||||
|
template <typename T>
|
||||||
|
class run_set {
|
||||||
|
public:
|
||||||
|
void add(T const &b) {
|
||||||
|
add(run<T>(b, b + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(T const &b, T const &e) {
|
||||||
|
add(run<T>(b, e));
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(run<T> const &r_) {
|
||||||
|
run<T> r(r_);
|
||||||
|
|
||||||
|
if (runs_.size()) {
|
||||||
|
// Correct but slow
|
||||||
|
const_iterator it = runs_.cbegin();
|
||||||
|
|
||||||
|
// Skip all blocks that end before r
|
||||||
|
while (it != runs_.end() && it->end_ <= r.begin_)
|
||||||
|
++it;
|
||||||
|
|
||||||
|
// work out which runs overlap
|
||||||
|
if (it != runs_.end()) {
|
||||||
|
r.begin_ = min_maybe(it->begin_, r.begin_);
|
||||||
|
const_iterator first = it;
|
||||||
|
while (it != runs_.end() && it->begin_ < r.end_) {
|
||||||
|
r.end_ = max_maybe(it->end_, r.end_);
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove overlapping runs
|
||||||
|
runs_.erase(first, it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
runs_.insert(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
void merge(run_set<T> const &rhs) {
|
||||||
|
for (const_iterator it = rhs.begin(); it != rhs.end(); ++it)
|
||||||
|
add(*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool member(T const &v) const {
|
||||||
|
if (!runs_.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto it = runs_.lower_bound(run<T>(v));
|
||||||
|
|
||||||
|
if (it->begin_ == v)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
it--;
|
||||||
|
|
||||||
|
if (it != runs_.end())
|
||||||
|
return it->contains(v);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct compare_begin {
|
||||||
|
bool operator ()(run<T> const &r1, run<T> const &r2) const {
|
||||||
|
return r1.begin_ < r2.begin_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::set<run<T>, compare_begin> rset;
|
||||||
|
typedef typename rset::const_iterator const_iterator;
|
||||||
|
|
||||||
|
const_iterator begin() const {
|
||||||
|
return runs_.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator end() const {
|
||||||
|
return runs_.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef typename run<T>::maybe maybe;
|
||||||
|
|
||||||
|
static maybe min_maybe(maybe const &m1, maybe const &m2) {
|
||||||
|
if (!m1 || !m2)
|
||||||
|
return maybe();
|
||||||
|
|
||||||
|
return maybe(std::min<T>(*m1, *m2));
|
||||||
|
}
|
||||||
|
|
||||||
|
static maybe max_maybe(maybe const &m1, maybe const &m2) {
|
||||||
|
if (!m1 || !m2)
|
||||||
|
return maybe();
|
||||||
|
|
||||||
|
return maybe(std::max<T>(*m1, *m2));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<run<T>, compare_begin> runs_;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
#endif
|
@ -56,6 +56,7 @@ TEST_SOURCE=\
|
|||||||
unit-tests/damage_tracker_t.cc \
|
unit-tests/damage_tracker_t.cc \
|
||||||
unit-tests/endian_t.cc \
|
unit-tests/endian_t.cc \
|
||||||
unit-tests/rmap_visitor_t.cc \
|
unit-tests/rmap_visitor_t.cc \
|
||||||
|
unit-tests/run_set_t.cc \
|
||||||
unit-tests/space_map_t.cc \
|
unit-tests/space_map_t.cc \
|
||||||
unit-tests/span_iterator_t.cc \
|
unit-tests/span_iterator_t.cc \
|
||||||
unit-tests/transaction_manager_t.cc
|
unit-tests/transaction_manager_t.cc
|
||||||
|
179
unit-tests/run_set_t.cc
Normal file
179
unit-tests/run_set_t.cc
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
#include "gmock/gmock.h"
|
||||||
|
|
||||||
|
#include "persistent-data/run_set.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
using namespace base;
|
||||||
|
using namespace std;
|
||||||
|
using namespace testing;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
MATCHER_P2(EqRun, b, e, "") {
|
||||||
|
return (arg.begin_ == static_cast<unsigned>(b)) &&
|
||||||
|
(arg.end_ == static_cast<unsigned>(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
class RunSetTests : public Test {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
TEST_F(RunSetTests, create)
|
||||||
|
{
|
||||||
|
auto_ptr<run_set<unsigned> > rs(new run_set<unsigned>());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RunSetTests, add_single_blocks)
|
||||||
|
{
|
||||||
|
run_set<unsigned> rs;
|
||||||
|
|
||||||
|
rs.add(3u);
|
||||||
|
rs.add(8u);
|
||||||
|
rs.add(9u);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RunSetTests, add_runs)
|
||||||
|
{
|
||||||
|
run_set<unsigned> rs;
|
||||||
|
|
||||||
|
rs.add(run<unsigned>(3, 8));
|
||||||
|
rs.add(run<unsigned>(23, 55));
|
||||||
|
rs.add(run<unsigned>(78, 190));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RunSetTests, member_empty_set)
|
||||||
|
{
|
||||||
|
run_set<unsigned> rs;
|
||||||
|
ASSERT_THAT(rs.begin(), Eq(rs.end()));
|
||||||
|
ASSERT_FALSE(rs.member(5));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RunSetTests, member_many_runs)
|
||||||
|
{
|
||||||
|
run_set<unsigned> rs;
|
||||||
|
|
||||||
|
rs.add(3);
|
||||||
|
rs.add(7, 15);
|
||||||
|
rs.add(23, 28);
|
||||||
|
rs.add(25, 50);
|
||||||
|
|
||||||
|
rs.add(101, 105);
|
||||||
|
rs.add(105, 110);
|
||||||
|
|
||||||
|
rs.add(201, 205);
|
||||||
|
rs.add(206, 210);
|
||||||
|
|
||||||
|
ASSERT_TRUE(rs.member(3));
|
||||||
|
|
||||||
|
ASSERT_FALSE(rs.member(6));
|
||||||
|
for (unsigned i = 7; i < 15; i++)
|
||||||
|
ASSERT_TRUE(rs.member(i));
|
||||||
|
ASSERT_FALSE(rs.member(15));
|
||||||
|
|
||||||
|
ASSERT_FALSE(rs.member(22));
|
||||||
|
for (unsigned i = 23; i < 50; i++)
|
||||||
|
ASSERT_TRUE(rs.member(i));
|
||||||
|
ASSERT_FALSE(rs.member(50));
|
||||||
|
|
||||||
|
ASSERT_FALSE(rs.member(100));
|
||||||
|
for (unsigned i = 101; i < 110; i++)
|
||||||
|
ASSERT_TRUE(rs.member(i));
|
||||||
|
ASSERT_FALSE(rs.member(110));
|
||||||
|
|
||||||
|
ASSERT_FALSE(rs.member(200));
|
||||||
|
for (unsigned i = 201; i < 205; i++)
|
||||||
|
ASSERT_TRUE(rs.member(i));
|
||||||
|
ASSERT_FALSE(rs.member(205));
|
||||||
|
for (unsigned i = 206; i < 210; i++)
|
||||||
|
ASSERT_TRUE(rs.member(i));
|
||||||
|
ASSERT_FALSE(rs.member(210));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RunSetTests, iterate_empty)
|
||||||
|
{
|
||||||
|
run_set<unsigned> rs;
|
||||||
|
ASSERT_THAT(rs.begin(), Eq(rs.end()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RunSetTests, iterate_single)
|
||||||
|
{
|
||||||
|
run_set<unsigned> rs;
|
||||||
|
rs.add(5, 10);
|
||||||
|
ASSERT_THAT(*rs.begin(), EqRun(5, 10));
|
||||||
|
ASSERT_THAT(++rs.begin(), Eq(rs.end()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RunSetTests, iterate_overlapping_runs)
|
||||||
|
{
|
||||||
|
run_set<unsigned> rs;
|
||||||
|
rs.add(5, 10);
|
||||||
|
rs.add(8, 15);
|
||||||
|
ASSERT_THAT(*rs.begin(), EqRun(5, 15));
|
||||||
|
ASSERT_THAT(++rs.begin(), Eq(rs.end()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RunSetTests, iterate_overlapping_runs_other_way)
|
||||||
|
{
|
||||||
|
run_set<unsigned> rs;
|
||||||
|
rs.add(8, 15);
|
||||||
|
rs.add(5, 10);
|
||||||
|
ASSERT_THAT(*rs.begin(), EqRun(5, 15));
|
||||||
|
ASSERT_THAT(++rs.begin(), Eq(rs.end()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RunSetTests, iterate_covered_runs)
|
||||||
|
{
|
||||||
|
run_set<unsigned> rs;
|
||||||
|
rs.add(8, 15);
|
||||||
|
rs.add(5, 20);
|
||||||
|
ASSERT_THAT(*rs.begin(), EqRun(5, 20));
|
||||||
|
ASSERT_THAT(++rs.begin(), Eq(rs.end()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RunSetTests, iterate_covered_runs2)
|
||||||
|
{
|
||||||
|
run_set<unsigned> rs;
|
||||||
|
rs.add(8, 10);
|
||||||
|
rs.add(12, 20);
|
||||||
|
rs.add(5, 30);
|
||||||
|
ASSERT_THAT(*rs.begin(), EqRun(5, 30));
|
||||||
|
ASSERT_THAT(++rs.begin(), Eq(rs.end()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RunSetTests, iterate_non_overlapping_runs)
|
||||||
|
{
|
||||||
|
run_set<unsigned> rs;
|
||||||
|
rs.add(5, 10);
|
||||||
|
rs.add(15, 20);
|
||||||
|
ASSERT_THAT(*rs.begin(), EqRun(5, 10));
|
||||||
|
ASSERT_THAT(*(++rs.begin()), EqRun(15, 20));
|
||||||
|
ASSERT_THAT(++(++(rs.begin())), Eq(rs.end()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RunSetTests, merge_empty_sets)
|
||||||
|
{
|
||||||
|
run_set<unsigned> rs1;
|
||||||
|
run_set<unsigned> rs2;
|
||||||
|
|
||||||
|
rs1.merge(rs2);
|
||||||
|
ASSERT_THAT(rs1.begin(), Eq(rs1.end()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RunSetTests, merge_discrete_sets)
|
||||||
|
{
|
||||||
|
run_set<unsigned> rs1;
|
||||||
|
run_set<unsigned> rs2;
|
||||||
|
|
||||||
|
rs1.add(5, 10);
|
||||||
|
rs2.add(15, 20);
|
||||||
|
rs1.merge(rs2);
|
||||||
|
ASSERT_THAT(*rs1.begin(), EqRun(5, 10));
|
||||||
|
ASSERT_THAT(*(++rs1.begin()), EqRun(15, 20));
|
||||||
|
ASSERT_THAT(++(++(rs1.begin())), Eq(rs1.end()));
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
Loading…
x
Reference in New Issue
Block a user