// // 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/List.h" #include namespace td { template class TsList; template class TsListNode : protected ListNode { public: TsListNode() { clear(); } explicit TsListNode(DataT &&data) : data_(std::move(data)) { clear(); } ~TsListNode() { remove(); } std::unique_lock lock() TD_WARN_UNUSED_RESULT; TsListNode(const TsListNode &) = delete; TsListNode &operator=(const TsListNode &) = delete; TsListNode(TsListNode &&other) { other.validate(); if (other.empty()) { data_ = std::move(other.data_); clear(); } else { auto guard = other.lock(); init_from(std::move(other)); } validate(); other.validate(); } TsListNode &operator=(TsListNode &&other) { validate(); if (this == &other) { return *this; } other.validate(); remove(); if (other.empty()) { data_ = std::move(other.data_); } else { auto guard = other.lock(); init_from(std::move(other)); } validate(); other.validate(); return *this; } void validate() { if (empty()) { CHECK(ListNode::empty()); } else { auto guard = lock(); CHECK(!ListNode::empty() || is_root); } } void remove() { validate(); if (is_root) { CHECK(ListNode::empty()); return; } if (empty()) { CHECK(ListNode::empty()); return; } { auto guard = lock(); ListNode::remove(); if (!is_root) { parent = nullptr; } } validate(); } void put(TsListNode *other) { validate(); other->validate(); DCHECK(other->empty()); DCHECK(!empty()); DCHECK(!other->is_root); { auto guard = lock(); ListNode::put(other); other->parent = parent; } validate(); other->validate(); } void put_back(TsListNode *other) { DCHECK(other->empty()); DCHECK(!empty()); DCHECK(!other->is_root); auto guard = lock(); ListNode::put_back(other); other->parent = parent; } bool empty() const { return parent == nullptr; } TsListNode *get_next() { return static_cast(next); } TsListNode *get_prev() { return static_cast(prev); } DataT &get_data_unsafe() { return data_; } private: TsList *parent; bool is_root{false}; DataT data_; friend class TsList; void clear() { ListNode::clear(); if (!is_root) { parent = nullptr; } } void init_from(TsListNode &&other) { ListNode::init_from(std::move(other)); parent = other.parent; other.parent = nullptr; data_ = std::move(other.data_); } }; template class TsList : public TsListNode { public: TsList() { this->parent = this; this->is_root = true; } TsList(const TsList &) = delete; TsList &operator=(const TsList &) = delete; TsList(TsList &&) = delete; TsList &operator=(TsList &&) = delete; ~TsList() { auto guard = lock(); while (true) { auto res = static_cast *>(ListNode::get()); if (!res) { break; } res->parent = nullptr; } this->parent = nullptr; } static std::unique_lock lock() TD_WARN_UNUSED_RESULT { static std::mutex mutex; return std::unique_lock(mutex); } TsListNode *begin() { return this->get_next(); } TsListNode *end() { return this; } TsListNode *get() { auto guard = lock(); auto res = static_cast *>(ListNode::get()); if (res) { res->parent = nullptr; } return res; } }; template std::unique_lock TsListNode::lock() { CHECK(parent != nullptr); return parent->lock(); } } // namespace td