diff options
Diffstat (limited to 'quickcheck/flat_segment_tree.cpp')
-rw-r--r-- | quickcheck/flat_segment_tree.cpp | 512 |
1 files changed, 512 insertions, 0 deletions
diff --git a/quickcheck/flat_segment_tree.cpp b/quickcheck/flat_segment_tree.cpp new file mode 100644 index 0000000..a7d3168 --- /dev/null +++ b/quickcheck/flat_segment_tree.cpp @@ -0,0 +1,512 @@ +#include <algorithm> +#include <cassert> +#include <iterator> +#include <memory> +#include <ostream> +#include <set> +#include <string> +#include <sstream> + +#include <mdds/flat_segment_tree.hpp> + +#include <quickcheck/quickcheck.hh> + +namespace +{ + +using quickcheck::Property; + +using std::ostream; +using std::pair; +using std::string; + +typedef mdds::flat_segment_tree<unsigned, unsigned> fst_type; +typedef fst_type::key_type key_type; +typedef fst_type::value_type value_type; + +class fst_wrapper +{ +public: + fst_type* get() const + { + return m_pimpl.get(); + } + fst_type& operator*() const + { + assert(initialized()); + return *get(); + } + fst_type* operator->() const + { + assert(initialized()); + return get(); + } + + bool initialized() const + { + return m_pimpl.get(); + } + + void initialize(key_type low_, key_type high_, value_type value_) + { + assert(!initialized()); + m_pimpl.reset(new fst_type(low_, high_, value_)); + } + +private: + std::shared_ptr<fst_type> m_pimpl; +}; + +template<typename Key, typename Value> +ostream& +operator<<(ostream& out_, mdds::flat_segment_tree<Key, Value> const& fst_) +{ + out_ << "["; + bool first(true); + typedef typename mdds::flat_segment_tree<Key, Value>::const_iterator + iterator_type; + iterator_type cur(fst_.begin()); + for (iterator_type end(fst_.end()); cur != end; ++cur) + { + if (first) + first = false; + else + out_ << ", "; + out_ << cur->first << ": " << cur->second; + } + out_ << ", " << cur->first << "), default = " << fst_.default_value(); + return out_; +} + +ostream& operator<<(ostream& out_, fst_wrapper const& fst_) +{ + return fst_.initialized() ? out_ << *fst_ : out_; +} + +template<typename T> +struct generator +{ + generator(size_t n_) + : m_n(n_) + { + } + + T operator()() const + { + using quickcheck::generate; + T val; + generate(m_n, val); + return val; + } + +private: + size_t m_n; +}; + +void generate(size_t n_, fst_wrapper& fst_) +{ + using quickcheck::generate; + value_type default_value; + generate(n_, default_value); + + // generate a number of segments + size_t segments(0); + generate(n_, segments); + segments = std::max<size_t>(segments, 1); + + using std::set; + set<key_type> points; + { + size_t count(segments + 1); + while (count > 0) + { + generator<key_type> gen(n_); + if (points.insert(gen()).second) + --count; + } + } + + using std::vector; + vector<value_type> values; + values.reserve(segments); + std::generate_n( + std::back_inserter(values), segments, generator<value_type>(n_)); + + fst_.initialize(*points.begin(), *points.rbegin(), default_value); + + // insert segments + if (segments >= 2) + { + assert(points.size() == values.size() + 1); + + typedef set<key_type>::const_iterator points_iterator; + points_iterator last(points.begin()); + points_iterator cur(points.begin()); + points_iterator end(points.end()); + typedef vector<value_type>::const_iterator values_iterator; + values_iterator cur_val(values.begin()); + values_iterator end_val(values.end()); + ++cur; + while (cur != end && cur_val != end_val) + { + fst_->insert_back(*last, *cur, *cur_val); + last = cur; + ++cur; + ++cur_val; + } + } +} + +bool is_valid_key(fst_type const& fst_, key_type const& key_) +{ + return key_ >= fst_.begin()->first && key_ < fst_.rbegin()->first; +} + +bool is_valid_range(fst_type const& fst_, key_type const& low_, key_type const& high_) +{ + return low_ < high_ && is_valid_key(fst_, low_) && is_valid_key(fst_, high_); +} + +bool is_empty_tree(fst_type const& fst_) +{ + return fst_.rbegin()->first - fst_.begin()->first == 1; +} + +bool is_single_segment(fst_type const& fst_) +{ + fst_type::const_iterator begin(fst_.begin()); + ++begin; + return begin == fst_.end(); +} + +class FlatSegmentTreeInsertProperty + : public Property<fst_wrapper, key_type, key_type, key_type> +{ +public: + typedef fst_type::const_iterator const_iterator; + + virtual bool + accepts( + fst_wrapper const& fst_, key_type const& low_, key_type const& high_, + value_type const&) + { + return is_valid_range(*fst_, low_, high_); + } +}; + +class FlatSegmentTreeChangeProperty + : public FlatSegmentTreeInsertProperty +{ +public: + virtual bool + isTrivialFor( + fst_wrapper const& fst_, key_type const& low_, key_type const& high_, + value_type const&) + { + return is_empty_tree(*fst_); + } +}; + +class PInsertFrontIsSameAsInsertBack : public FlatSegmentTreeChangeProperty +{ + virtual bool + holdsFor( + fst_wrapper const& fst_, key_type const& low_, key_type const& high_, + value_type const& value_) + { + fst_type insert_front(*fst_); + fst_type insert_back(*fst_); + insert_front.insert_front(low_, high_, value_); + insert_back.insert_back(low_, high_, value_); + return insert_front == insert_back; + } +}; + +class PInsertIsSameAsInsertBack : public FlatSegmentTreeChangeProperty +{ + virtual bool + holdsFor( + fst_wrapper const& fst_, key_type const& low_, key_type const& high_, + value_type const& value_) + { + fst_type insert(*fst_); + fst_type insert_back(*fst_); + insert.insert(insert.begin(), low_, high_, value_); + insert_back.insert_back(low_, high_, value_); + return insert == insert_back; + } +}; + +class PRepeatedInsertDoesNothing : public FlatSegmentTreeChangeProperty +{ + virtual bool + holdsFor( + fst_wrapper const& fst_, key_type const& low_, key_type const& high_, + value_type const& value_) + { + fst_type fst(*fst_); + const_iterator const pos(fst.insert_front(low_, high_, value_).first); + fst_type orig(fst); + fst.build_tree(); + pair<const_iterator, bool> result(fst.insert(pos, low_, high_, value_)); + return !result.second && result.first == pos && fst == orig; + } +}; + +class PKeyInLimitsIsFound : public FlatSegmentTreeInsertProperty +{ + virtual bool + holdsFor( + fst_wrapper const& fst_, key_type const& low_, key_type const& high_, + value_type const& value_) + { + fst_type fst(*fst_); + value_type dummy; + pair<const_iterator, bool> result(fst.search(low_, dummy)); + + return result.second && result.first != fst.end() && + result.first->first <= low_; + } +}; + +class PKeyInInsertedSegmentIsFound : public FlatSegmentTreeChangeProperty +{ + virtual bool + holdsFor( + fst_wrapper const& fst_, key_type const& low_, key_type const& high_, + value_type const& value_) + { + fst_type fst(*fst_); + pair<const_iterator, bool> + insert(fst.insert_front(low_, high_, value_)); + value_type value; + pair<const_iterator, bool> search(fst.search(insert.first, low_, value)); + return search.second && search.first == insert.first && value == value_; + } +}; + +class PSearchTreeIsSameAsSearch : public Property<fst_wrapper, key_type> +{ + virtual bool holdsFor(fst_wrapper const& fst_, key_type const& key_) + { + fst_type fst(*fst_); + value_type value; + key_type low; + key_type high; + pair<fst_type::const_iterator, bool> search(fst.search(key_, value, &low, &high)); + + if (!fst.is_tree_valid()) + fst.build_tree(); + value_type value_tree; + key_type low_tree; + key_type high_tree; + bool const search_tree(fst.search_tree(key_, value_tree, &low_tree, &high_tree)); + return search.second == search_tree && low == low_tree + && high == high_tree && value == value_tree; + } + + virtual bool accepts(fst_wrapper const& fst_, key_type const& key_) + { + return is_valid_key(*fst_, key_); + } +}; + +class PSearchDoesNotChangeTree : public Property<fst_wrapper, key_type> +{ + virtual bool holdsFor(fst_wrapper const& fst_, key_type const& key_) + { + fst_type& orig(*fst_); + fst_type fst(orig); + value_type dummy; + fst.search(key_, dummy); + return fst == orig; + } + + virtual bool accepts(fst_wrapper const& fst_, key_type const& key_) + { + return is_valid_key(*fst_, key_); + } +}; + +class PBuildTreeDoesNotChangeTree : public Property<fst_wrapper> +{ + virtual bool holdsFor(fst_wrapper const& fst_) + { + fst_type& orig(*fst_); + fst_type& fst(orig); + fst.build_tree(); + return fst == orig; + } + + virtual bool isTrivialFor(fst_wrapper const& fst_) + { + return fst_->is_tree_valid(); + } +}; + +class PShiftLeftRemovesSomething : public Property<fst_wrapper, key_type, key_type> +{ + virtual bool + holdsFor(fst_wrapper const& fst_, key_type const& low_, key_type const& high_) + { + fst_type& orig(*fst_); + fst_type fst(orig); + fst.shift_left(low_, high_); + return fst != orig; + } + + virtual bool + accepts(fst_wrapper const& fst_, key_type const& low_, key_type const& high_) + { + return is_valid_range(*fst_, low_, high_) && !is_single_segment(*fst_); + } +}; + +class PShiftRightWorks : public Property<fst_wrapper, key_type, key_type, bool> +{ + virtual bool + holdsFor( + fst_wrapper const& fst_, key_type const& key_, key_type const& size_, + bool const& skip_start_) + { + fst_type& orig(*fst_); + fst_type fst(orig); + fst.shift_right(key_, size_, skip_start_); + return isTrivialFor(fst_, key_, size_, skip_start_) ? fst == orig : fst != orig; + } + + virtual bool + accepts( + fst_wrapper const& fst_, key_type const& key_, key_type const& size_, + bool const&) + { + return is_valid_key(*fst_, key_); + } + + virtual bool + isTrivialFor( + fst_wrapper const& fst_, key_type const& key_, key_type const& size_, + bool const& skip_start_) + { + return + (is_single_segment(*fst_) && fst_->begin()->second == fst_->default_value()) + || size_ == 0 + || (skip_start_ && key_ == fst_->max_key() - 1); + } +}; + +bool keys_ordered(fst_type const& fst_) +{ + fst_type::const_iterator cur(fst_.begin()); + fst_type::const_iterator end(fst_.end()); + fst_type::const_iterator last(cur); + ++cur; + while (cur != end) + { + if (last->first >= cur->first) + return false; + ++cur; + } + return last->first < cur->first; +} + +class PKeysOrderedAfterInsert : public FlatSegmentTreeInsertProperty +{ + virtual bool + holdsFor( + fst_wrapper const& fst_, key_type const& low_, key_type const& high_, + value_type const& value_) + { + fst_type fst(*fst_); + fst.insert_front(low_, high_, value_); + return keys_ordered(fst); + } + + virtual bool + isTrivialFor( + fst_wrapper const& fst_, key_type const& low_, key_type const& high_, + value_type const& value_) + { + fst_type fst(*fst_); + return !fst.insert_front(low_, high_, value_).second; + } +}; + +class PKeysOrderedAfterShiftLeft : public Property<fst_wrapper, key_type, key_type> +{ + virtual bool + holdsFor(fst_wrapper const& fst_, key_type const& low_, key_type const& high_) + { + fst_type fst(*fst_); + fst.shift_left(low_, high_); + return keys_ordered(fst); + } + + virtual bool + accepts(fst_wrapper const& fst_, key_type const& low_, key_type const& high_) + { + return is_valid_range(*fst_, low_, high_); + } + + virtual bool + isTrivialFor(fst_wrapper const& fst_, key_type const& low_, key_type const& high_) + { + fst_type& fst(*fst_); + return is_single_segment(fst) && fst.begin()->second == fst.default_value(); + } +}; + +class PKeysOrderedAfterShiftRight : public Property<fst_wrapper, key_type, key_type, bool> +{ + virtual bool + holdsFor( + fst_wrapper const& fst_, key_type const& key_, key_type const& size_, + bool const& skip_start_) + { + fst_type fst(*fst_); + fst.shift_right(key_, size_, skip_start_); + return keys_ordered(fst); + } + + virtual bool + accepts( + fst_wrapper const& fst_, key_type const& key_, key_type const& size_, + bool const&) + { + return is_valid_key(*fst_, key_); + } + + virtual bool + isTrivialFor( + fst_wrapper const& fst_, key_type const& low_, key_type const& high_, + bool const&) + { + fst_type& fst(*fst_); + return is_single_segment(fst) && fst.begin()->second == fst.default_value(); + } +}; + +} + +int main() +{ + size_t const tests(200); + using quickcheck::check; + check<PInsertFrontIsSameAsInsertBack>( + "insert_front is the same as insert_back", tests); + check<PInsertIsSameAsInsertBack>("insert is same as insert_back", tests); + check<PRepeatedInsertDoesNothing>("repeated insert does nothing", tests); + check<PKeyInLimitsIsFound>("key in tree limits is found", tests); + check<PKeyInInsertedSegmentIsFound>( + "key in just inserted segment is found at the right pos", tests); + check<PSearchTreeIsSameAsSearch>("search_tree is the same as search", tests); + check<PSearchDoesNotChangeTree>("search does not change tree", tests); + check<PBuildTreeDoesNotChangeTree>("build_tree does not change tree", tests); + check<PShiftLeftRemovesSomething>("shift_left removes something", tests); + // check<PShiftRightWorks>("shift_right works", tests); + check<PKeysOrderedAfterInsert>("keys remain ordered after insert", tests); + check<PKeysOrderedAfterShiftLeft>("keys remain ordered after shift_left", tests); + check<PKeysOrderedAfterShiftRight>("keys remain ordered after shift_right", tests); +} + +// vim: set ts=4 sw=4 et: |