/** * \file libconcur/queue.h * \author mutouyun (orz@orzz.org) * \brief Define concurrent queue. * \date 2022-11-19 */ #pragma once #include #include "libimp/construct.h" #include "libimp/detect_plat.h" #include "libpmr/allocator.h" #include "libpmr/memory_resource.h" #include "libconcur/def.h" #include "libconcur/concurrent.h" LIBCONCUR_NAMESPACE_BEG_ template class queue { public: using producer_relation_t = PRelationT; using consumer_relation_t = CRelationT; using model_type = prod_cons; using value_type = T; private: struct data { model_type model_; typename concur::traits::header header_; element elements_start_; template data(U &&model) noexcept : header_(std::forward(model)) {} /// \brief element elements[0]; ::LIBIMP::span> elements() noexcept { return {&elements_start_, header_.circ_size}; } }; data *init(index_t circ_size) noexcept { if (!data_allocator_) { return nullptr; } LIBIMP_TRY { auto data_ptr = data_allocator_.allocate(sizeof(data) + (circ_size - 1) * sizeof(element)); if (data_ptr == nullptr) { return nullptr; } return ::LIBIMP::construct(data_ptr, circ_size); } LIBIMP_CATCH(...) { return nullptr; } } ::LIBPMR::allocator data_allocator_; data *data_; typename concur::traits::context context_; public: queue() = default; queue(queue const &) = delete; queue(queue &&) = delete; queue &operator=(queue const &) = delete; queue &operator=(queue &&) = delete; template = true> explicit queue(index_t circ_size = default_circle_buffer_size, MR *memory_resource = ::LIBPMR::new_delete_resource::get()) noexcept : data_allocator_(memory_resource) , data_(init(circ_size)) {} template = true> explicit queue(MR *memory_resource) noexcept : queue(default_circle_buffer_size, memory_resource) {} bool valid() const noexcept { return data_ != nullptr; } explicit operator bool() const noexcept { return valid(); } template bool push(U &&value) noexcept { if (!valid()) return false; return data_->model_.enqueue(data_->elements(), data_->header_, context_, std::forward(value)); } bool pop(value_type &value) noexcept { if (!valid()) return false; return data_->model_.dequeue(data_->elements(), data_->header_, context_, value); } }; LIBCONCUR_NAMESPACE_END_