// // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #pragma once #include "td/utils/common.h" #include "td/utils/misc.h" #include #include #include namespace td { template class FastSetWithPosition { public: std::vector get_some_elements() const { std::vector res; res.reserve(4); if (!checked_.empty()) { res.push_back(*checked_.begin()); res.push_back(*checked_.rbegin()); } if (!not_checked_.empty()) { res.push_back(*not_checked_.begin()); res.push_back(*not_checked_.rbegin()); } std::sort(res.begin(), res.end()); res.erase(std::unique(res.begin(), res.end()), res.end()); if (res.size() > 2) { res.erase(res.begin() + 1, res.end() - 1); } return res; } bool add(T x) { if (checked_.count(x) != 0) { return false; } return not_checked_.insert(x).second; } bool remove(T x) { return checked_.erase(x) != 0 || not_checked_.erase(x) != 0; } bool has_next() const { return !not_checked_.empty(); } void reset_position() { if (not_checked_.empty()) { not_checked_ = std::move(checked_); } else { not_checked_.insert(checked_.begin(), checked_.end()); } reset_to_empty(checked_); } T next() { CHECK(has_next()); auto it = not_checked_.begin(); auto res = *it; not_checked_.erase(it); checked_.insert(res); return res; } void merge(FastSetWithPosition &&other) { if (this == &other) { return; } if (size() < other.size()) { std::swap(*this, other); } for (auto x : other.checked_) { not_checked_.erase(x); checked_.insert(x); } for (auto x : other.not_checked_) { if (checked_.count(x) != 0) { continue; } not_checked_.insert(x); } } size_t size() const { return checked_.size() + not_checked_.size(); } bool empty() const { return size() == 0; } private: std::set checked_; std::set not_checked_; }; template class SetWithPosition { public: std::vector get_some_elements() const { if (fast_) { return fast_->get_some_elements(); } if (has_value_) { return {value_}; } return {}; } bool add(T x) { if (fast_) { return fast_->add(x); } if (!has_value_) { value_ = x; has_value_ = true; is_checked_ = false; return true; } if (value_ == x) { return false; } make_fast(); return fast_->add(x); } bool remove(T x) { if (fast_) { return fast_->remove(x); } if (has_value_ && value_ == x) { has_value_ = false; is_checked_ = false; return true; } return false; } bool has_next() const { if (fast_) { return fast_->has_next(); } return has_value_ && !is_checked_; } void reset_position() { if (fast_) { fast_->reset_position(); return; } is_checked_ = false; } T next() { CHECK(has_next()); if (fast_) { return fast_->next(); } is_checked_ = true; return value_; } void merge(SetWithPosition &&other) { if (this == &other) { return; } if (size() < other.size()) { std::swap(*this, other); } if (other.size() == 0) { return; } if (other.fast_ == nullptr && fast_ == nullptr && value_ == other.value_) { is_checked_ |= other.is_checked_; other.value_ = T(); other.has_value_ = false; other.is_checked_ = false; return; } make_fast(); other.make_fast(); fast_->merge(std::move(*other.fast_)); reset_to_empty(other); } size_t size() const { if (fast_) { return fast_->size(); } return static_cast(has_value_); } bool empty() const { if (fast_) { return false; } return !has_value_; } private: T value_{}; bool has_value_{false}; bool is_checked_{false}; unique_ptr> fast_; void make_fast() { if (fast_) { return; } fast_ = make_unique>(); CHECK(has_value_); fast_->add(value_); if (is_checked_) { fast_->next(); } } }; } // namespace td