#pragma once #include // std::atomic #include #include #include #include "libipc/def.h" #include "libipc/rw_lock.h" #include "libipc/circ/elem_def.h" #include "libipc/platform/detail.h" namespace ipc { namespace circ { template class elem_array : public ipc::circ::conn_head { public: using base_t = ipc::circ::conn_head; using policy_t = Policy; using cursor_t = decltype(std::declval().cursor()); using elem_t = typename policy_t::template elem_t; enum : std::size_t { head_size = sizeof(base_t) + sizeof(policy_t), data_size = DataSize, elem_max = (std::numeric_limits>::max)() + 1, // default is 255 + 1 elem_size = sizeof(elem_t), block_size = elem_size * elem_max }; private: policy_t head_; elem_t block_[elem_max] {}; /** * \remarks 'warning C4348: redefinition of default parameter' with MSVC. * \see * - https://stackoverflow.com/questions/12656239/redefinition-of-default-template-parameter * - https://developercommunity.visualstudio.com/content/problem/425978/incorrect-c4348-warning-in-nested-template-declara.html */ template ::is_multi_producer*/> struct sender_checker; template struct sender_checker { constexpr static bool connect() noexcept { // always return true return true; } constexpr static void disconnect() noexcept {} }; template struct sender_checker { bool connect() noexcept { return !flag_.test_and_set(std::memory_order_acq_rel); } void disconnect() noexcept { flag_.clear(); } private: // in shm, it should be 0 whether it's initialized or not. std::atomic_flag flag_ = ATOMIC_FLAG_INIT; }; template ::is_multi_consumer*/> struct receiver_checker; template struct receiver_checker { constexpr static cc_t connect(base_t &conn) noexcept { return conn.connect(); } constexpr static cc_t disconnect(base_t &conn, cc_t cc_id) noexcept { return conn.disconnect(cc_id); } }; template struct receiver_checker : protected sender_checker { cc_t connect(base_t &conn) noexcept { return sender_checker::connect() ? conn.connect() : 0; } cc_t disconnect(base_t &conn, cc_t cc_id) noexcept { sender_checker::disconnect(); return conn.disconnect(cc_id); } }; sender_checker ::is_multi_producer> s_ckr_; receiver_checker::is_multi_consumer> r_ckr_; // make these be private using base_t::connect; using base_t::disconnect; public: bool connect_sender() noexcept { return s_ckr_.connect(); } void disconnect_sender() noexcept { return s_ckr_.disconnect(); } cc_t connect_receiver() noexcept { return r_ckr_.connect(*this); } cc_t disconnect_receiver(cc_t cc_id) noexcept { return r_ckr_.disconnect(*this, cc_id); } cursor_t cursor() const noexcept { return head_.cursor(); } template bool push(Q* que, F&& f) { return head_.push(que, std::forward(f), block_); } template bool force_push(Q* que, F&& f) { return head_.force_push(que, std::forward(f), block_); } template bool pop(Q* que, cursor_t* cur, F&& f, R&& out) { if (cur == nullptr) return false; return head_.pop(que, *cur, std::forward(f), std::forward(out), block_); } }; } // namespace circ } // namespace ipc