diff --git a/persistent-data/space-maps/subtracting_span_iterator.h b/persistent-data/space-maps/subtracting_span_iterator.h new file mode 100644 index 0000000..3b0ca65 --- /dev/null +++ b/persistent-data/space-maps/subtracting_span_iterator.h @@ -0,0 +1,101 @@ +#ifndef SPAN_ITERATOR_H +#define SPAN_ITERATOR_H + +#include "persistent-data/space_map.h" + +#include + +//---------------------------------------------------------------- + +namespace persistent_data { + // FIXME: rewrite with tests using the run_list stuff. + class subtracting_span_iterator : public space_map::span_iterator { + public: + typedef set block_set; + typedef space_map::span span; + + subtracting_span_iterator(span_iterator &sub_it, + block_set const &forbidden_blocks) + : sub_it_(sub_it), + forbidden_blocks_(forbidden_blocks), + current_begin_() { + } + + virtual maybe_span first() { + current_span_ = sub_it_.first(); + + if (current_span_) + current_begin_ = current_span_->first; + + return next(); + } + + virtual maybe_span next() { + maybe_span r; + + while (more_spans()) { + r = next_(); + if (r) + break; + } + + return r; + } + + private: + bool more_spans() const { + return current_span_; + } + + bool span_consumed() const { + return current_begin_ == current_span_->second; + } + + bool forbidden_block(block_address b) const { + return forbidden_blocks_.count(b) > 0; + } + + void skip_forbidden_blocks() { + while (!span_consumed() && forbidden_block(current_begin_)) + current_begin_++; + } + + span get_span() { + block_address b = current_begin_; + + while (!span_consumed() && !forbidden_block(current_begin_)) + current_begin_++; + + return span(b, current_begin_); + } + + void get_current_span_from_sub_it() { + current_span_ = sub_it_.next(); + current_begin_ = current_span_->first; + } + + maybe_span next_() { + if (span_consumed()) + get_current_span_from_sub_it(); + + if (!more_spans()) + return maybe_span(); + + skip_forbidden_blocks(); + + if (!span_consumed()) + return maybe_span(get_span()); + else + return maybe_span(); + } + + span_iterator &sub_it_; + block_set const &forbidden_blocks_; + maybe_span current_span_; + block_address current_begin_; + }; +} + +//---------------------------------------------------------------- + +#endif diff --git a/unit-tests/span_iterator_t.cc b/unit-tests/span_iterator_t.cc new file mode 100644 index 0000000..8c6a188 --- /dev/null +++ b/unit-tests/span_iterator_t.cc @@ -0,0 +1,183 @@ +#include "gmock/gmock.h" + +#include "persistent-data/space-maps/subtracting_span_iterator.h" + +using namespace std; +using namespace persistent_data; +using namespace testing; + +//---------------------------------------------------------------- + +namespace { + typedef space_map::span span; + typedef space_map::maybe_span maybe_span; + + class regular_span_iterator : public space_map::span_iterator { + public: + regular_span_iterator(block_address span_length, + block_address gap_length, + unsigned span_count) + : span_length_(span_length), + gap_length_(gap_length), + span_count_(span_count), + current_span_(0) { + } + + virtual maybe_span first() { + current_span_ = 0; + return current_span(); + } + + + virtual maybe_span next() { + current_span_++; + return current_span(); + } + + private: + maybe_span current_span() const { + if (current_span_ >= span_count_) + return maybe_span(); + + block_address begin = (span_length_ + gap_length_) * current_span_; + block_address end = begin + span_length_; + return maybe_span(space_map::span(begin, end)); + } + + block_address span_length_; + block_address gap_length_; + unsigned span_count_; + + unsigned current_span_; + }; + + class span_iterator_mock : public space_map::span_iterator { + public: + MOCK_METHOD0(first, maybe_span()); + MOCK_METHOD0(next, maybe_span()); + }; + + class SpanItTests : public Test { + public: + SpanItTests() + : it(mock_it, forbidden) { + + EXPECT_CALL(mock_it, first()). + Times(1). + WillOnce(Return(maybe_span(span(23, 47)))); + EXPECT_CALL(mock_it, next()). + Times(1). + WillOnce(Return(maybe_span(span(59, 103)))); + } + + span_iterator_mock mock_it; + set forbidden; + subtracting_span_iterator it; + }; +} + +//---------------------------------------------------------------- + +TEST(RegularSpanItTests, regular_span_iterator) +{ + regular_span_iterator it(5, 3, 5); + + static struct { + block_address b; + block_address e; + } expected[] = { + {0, 5}, + {8, 13}, + {16, 21}, + {24, 29}, + {32, 37} + }; + + ASSERT_THAT(it.first(), Eq(maybe_span(span(expected[0].b, expected[0].e)))); + + for (unsigned count = 1; count < 5; count++) + ASSERT_THAT(it.next(), Eq(maybe_span(span(expected[count].b, expected[count].e)))); + + ASSERT_THAT(it.next(), Eq(maybe_span())); +} + +TEST_F(SpanItTests, sub_it_with_no_removed_blocks) +{ + ASSERT_THAT(it.first(), Eq(maybe_span(span(23, 47)))); + ASSERT_THAT(it.next(), Eq(maybe_span(span(59, 103)))); +} + +TEST_F(SpanItTests, sub_it_with_removed_first_block) +{ + forbidden.insert(23); + + ASSERT_THAT(it.first(), Eq(maybe_span(span(24, 47)))); + ASSERT_THAT(it.next(), Eq(maybe_span(span(59, 103)))); +} + +TEST_F(SpanItTests, sub_it_with_removed_run_overlapping_front_of_first_block) +{ + for (block_address i = 19; i < 26; i++) + forbidden.insert(i); + + ASSERT_THAT(it.first(), Eq(maybe_span(span(26, 47)))); + ASSERT_THAT(it.next(), Eq(maybe_span(span(59, 103)))); +} + +TEST_F(SpanItTests, sub_it_with_removed_mid_block) +{ + forbidden.insert(40); + + ASSERT_THAT(it.first(), Eq(maybe_span(span(23, 40)))); + ASSERT_THAT(it.next(), Eq(maybe_span(span(41, 47)))); + ASSERT_THAT(it.next(), Eq(maybe_span(span(59, 103)))); +} + +TEST_F(SpanItTests, sub_it_with_removed_run_mid_block) +{ + for (block_address i = 26; i < 36; i++) + forbidden.insert(i); + + ASSERT_THAT(it.first(), Eq(maybe_span(span(23, 26)))); + ASSERT_THAT(it.next(), Eq(maybe_span(span(36, 47)))); + ASSERT_THAT(it.next(), Eq(maybe_span(span(59, 103)))); +} + +TEST_F(SpanItTests, sub_it_with_removed_end_block) +{ + forbidden.insert(46); + + ASSERT_THAT(it.first(), Eq(maybe_span(span(23, 46)))); + ASSERT_THAT(it.next(), Eq(maybe_span(span(59, 103)))); +} + +TEST_F(SpanItTests, sub_it_with_removed_run_end_block) +{ + for (block_address i = 26; i < 50; i++) + forbidden.insert(i); + + ASSERT_THAT(it.first(), Eq(maybe_span(span(23, 26)))); + ASSERT_THAT(it.next(), Eq(maybe_span(span(59, 103)))); +} + +TEST_F(SpanItTests, sub_it_with_removed_run_overlapping_2_blocks) +{ + for (block_address i = 26; i < 70; i++) + forbidden.insert(i); + + ASSERT_THAT(it.first(), Eq(maybe_span(span(23, 26)))); + ASSERT_THAT(it.next(), Eq(maybe_span(span(70, 103)))); +} + +TEST_F(SpanItTests, sub_it_with_removed_intermediate_blocks) +{ + forbidden.insert(53); + forbidden.insert(54); + forbidden.insert(57); + forbidden.insert(58); + + ASSERT_THAT(it.first(), Eq(maybe_span(span(23, 47)))); + ASSERT_THAT(it.next(), Eq(maybe_span(span(59, 103)))); +} + +//----------------------------------------------------------------