diff options
author | aunsane <aunsane@gmail.com> | 2018-04-27 21:33:17 +0300 |
---|---|---|
committer | aunsane <aunsane@gmail.com> | 2018-04-27 21:33:17 +0300 |
commit | e1ec72eab6d00b3ba38e5932bc88920f103b6e4a (patch) | |
tree | 999de2725a83e30fbbf6576200525d4ef0c5fe38 /protocols/Telegram/tdlib/td/tdutils/td/utils/SharedObjectPool.h | |
parent | b9ce1d4d98525490ca1a38e2d9fd4f3369adb3e0 (diff) |
Telegram: initial commit
- tdlib moved to telegram dir
Diffstat (limited to 'protocols/Telegram/tdlib/td/tdutils/td/utils/SharedObjectPool.h')
-rw-r--r-- | protocols/Telegram/tdlib/td/tdutils/td/utils/SharedObjectPool.h | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/protocols/Telegram/tdlib/td/tdutils/td/utils/SharedObjectPool.h b/protocols/Telegram/tdlib/td/tdutils/td/utils/SharedObjectPool.h new file mode 100644 index 0000000000..dc8512b268 --- /dev/null +++ b/protocols/Telegram/tdlib/td/tdutils/td/utils/SharedObjectPool.h @@ -0,0 +1,276 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018 +// +// 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/logging.h" +#include "td/utils/MpscLinkQueue.h" + +#include <atomic> +#include <memory> +#include <new> +#include <utility> + +namespace td { + +namespace detail { +class AtomicRefCnt { + public: + explicit AtomicRefCnt(uint64 cnt) : cnt_(cnt) { + } + void inc() { + cnt_.fetch_add(1, std::memory_order_relaxed); + } + bool dec() { + return cnt_.fetch_sub(1, std::memory_order_acq_rel) == 1; + } + uint64 value() const { + return cnt_.load(std::memory_order_relaxed); + } + + private: + std::atomic<uint64> cnt_; +}; + +template <class DataT, class DeleterT> +class SharedPtrRaw + : public DeleterT + , private MpscLinkQueueImpl::Node { + public: + explicit SharedPtrRaw(DeleterT deleter) : DeleterT(std::move(deleter)), ref_cnt_{0}, option_magic_(Magic) { + } + + ~SharedPtrRaw() { + CHECK(use_cnt() == 0); + CHECK(option_magic_ == Magic); + } + template <class... ArgsT> + void init_data(ArgsT &&... args) { + new (&option_data_) DataT(std::forward<ArgsT>(args)...); + } + void destroy_data() { + option_data_.~DataT(); + option_magic_ = Magic; + } + uint64 use_cnt() const { + return ref_cnt_.value(); + } + void inc() { + ref_cnt_.inc(); + } + bool dec() { + return ref_cnt_.dec(); + } + DataT &data() { + return option_data_; + } + static SharedPtrRaw *from_mpsc_link_queue_node(MpscLinkQueueImpl::Node *node) { + return static_cast<SharedPtrRaw<DataT, DeleterT> *>(node); + } + MpscLinkQueueImpl::Node *to_mpsc_link_queue_node() { + return static_cast<MpscLinkQueueImpl::Node *>(this); + } + + private: + AtomicRefCnt ref_cnt_; + enum { Magic = 0x732817a2 }; + union { + DataT option_data_; + uint32 option_magic_; + }; +}; + +template <class T, class DeleterT = std::default_delete<T>> +class SharedPtr { + public: + using Raw = detail::SharedPtrRaw<T, DeleterT>; + SharedPtr() = default; + ~SharedPtr() { + if (!raw_) { + return; + } + reset(); + } + explicit SharedPtr(Raw *raw) : raw_(raw) { + raw_->inc(); + } + SharedPtr(const SharedPtr &other) : SharedPtr(other.raw_) { + } + SharedPtr &operator=(const SharedPtr &other) { + other.raw_->inc(); + reset(other.raw_); + return *this; + } + SharedPtr(SharedPtr &&other) : raw_(other.raw_) { + other.raw_ = nullptr; + } + SharedPtr &operator=(SharedPtr &&other) { + reset(other.raw_); + other.raw_ = nullptr; + return *this; + } + bool empty() const { + return raw_ == nullptr; + } + explicit operator bool() const { + return !empty(); + } + uint64 use_cnt() const { + if (!raw_) { + return 0; + } + return raw_->use_cnt(); + } + T &operator*() const { + return raw_->data(); + } + T *operator->() const { + return &raw_->data(); + } + + Raw *release() { + auto res = raw_; + raw_ = nullptr; + return res; + } + + void reset(Raw *new_raw = nullptr) { + if (raw_ && raw_->dec()) { + raw_->destroy_data(); + auto deleter = std::move(static_cast<DeleterT &>(*raw_)); + deleter(raw_); + } + raw_ = new_raw; + } + + template <class... ArgsT> + static SharedPtr<T, DeleterT> create(ArgsT &&... args) { + auto raw = std::make_unique<Raw>(DeleterT()); + raw->init_data(std::forward<ArgsT>(args)...); + return SharedPtr<T, DeleterT>(raw.release()); + } + template <class D, class... ArgsT> + static SharedPtr<T, DeleterT> create_with_deleter(D &&d, ArgsT &&... args) { + auto raw = std::make_unique<Raw>(std::forward<D>(d)); + raw->init_data(std::forward<ArgsT>(args)...); + return SharedPtr<T, DeleterT>(raw.release()); + } + + private: + Raw *raw_{nullptr}; +}; + +} // namespace detail + +template <class DataT> +class SharedObjectPool { + class Deleter; + + public: + using Ptr = detail::SharedPtr<DataT, Deleter>; + + SharedObjectPool() = default; + SharedObjectPool(const SharedObjectPool &other) = delete; + SharedObjectPool &operator=(const SharedObjectPool &other) = delete; + SharedObjectPool(SharedObjectPool &&other) = delete; + SharedObjectPool &operator=(SharedObjectPool &&other) = delete; + ~SharedObjectPool() { + free_queue_.pop_all(free_queue_reader_); + size_t free_cnt = 0; + while (free_queue_reader_.read()) { + free_cnt++; + } + CHECK(free_cnt == allocated_.size()) << free_cnt << " " << allocated_.size(); + } + + template <class... ArgsT> + Ptr alloc(ArgsT &&... args) { + auto *raw = alloc_raw(); + raw->init_data(std::forward<ArgsT>(args)...); + return Ptr(raw); + } + size_t total_size() const { + return allocated_.size(); + } + uint64 calc_free_size() { + free_queue_.pop_all(free_queue_reader_); + return free_queue_reader_.calc_size(); + } + + //non thread safe + template <class F> + void for_each(F &&f) { + for (auto &raw : allocated_) { + if (raw->use_cnt() > 0) { + f(raw->data()); + } + } + } + + private: + using Raw = typename Ptr::Raw; + Raw *alloc_raw() { + free_queue_.pop_all(free_queue_reader_); + auto *raw = free_queue_reader_.read().get(); + if (raw) { + return raw; + } + allocated_.push_back(std::make_unique<Raw>(deleter())); + return allocated_.back().get(); + } + + void free_raw(Raw *raw) { + free_queue_.push(Node{raw}); + } + + class Node { + public: + Node() = default; + explicit Node(Raw *raw) : raw_(raw) { + } + + MpscLinkQueueImpl::Node *to_mpsc_link_queue_node() { + return raw_->to_mpsc_link_queue_node(); + } + static Node from_mpsc_link_queue_node(MpscLinkQueueImpl::Node *node) { + return Node{Raw::from_mpsc_link_queue_node(node)}; + } + Raw *get() const { + return raw_; + } + explicit operator bool() const { + return raw_ != nullptr; + } + + private: + Raw *raw_{nullptr}; + }; + + class Deleter { + public: + explicit Deleter(SharedObjectPool<DataT> *pool) : pool_(pool) { + } + void operator()(Raw *raw) { + pool_->free_raw(raw); + }; + + private: + SharedObjectPool<DataT> *pool_; + }; + friend class Deleter; + + Deleter deleter() { + return Deleter(this); + } + + std::vector<std::unique_ptr<Raw>> allocated_; + MpscLinkQueue<Node> free_queue_; + typename MpscLinkQueue<Node>::Reader free_queue_reader_; +}; + +} // namespace td |