HumanRender/human_render/Ipc/libipc/circ/elem_array.h
2024-12-22 23:24:02 +08:00

142 lines
4.1 KiB
C++

#pragma once
#include <atomic> // std::atomic<?>
#include <limits>
#include <utility>
#include <type_traits>
#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 <typename Policy,
std::size_t DataSize,
std::size_t AlignSize = (ipc::detail::min)(DataSize, alignof(std::max_align_t))>
class elem_array : public ipc::circ::conn_head<Policy> {
public:
using base_t = ipc::circ::conn_head<Policy>;
using policy_t = Policy;
using cursor_t = decltype(std::declval<policy_t>().cursor());
using elem_t = typename policy_t::template elem_t<DataSize, AlignSize>;
enum : std::size_t {
head_size = sizeof(base_t) + sizeof(policy_t),
data_size = DataSize,
elem_max = (std::numeric_limits<uint_t<8>>::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 <typename P, bool/* = relat_trait<P>::is_multi_producer*/>
struct sender_checker;
template <typename P>
struct sender_checker<P, true> {
constexpr static bool connect() noexcept {
// always return true
return true;
}
constexpr static void disconnect() noexcept {}
};
template <typename P>
struct sender_checker<P, false> {
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 <typename P, bool/* = relat_trait<P>::is_multi_consumer*/>
struct receiver_checker;
template <typename P>
struct receiver_checker<P, true> {
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 <typename P>
struct receiver_checker<P, false> : protected sender_checker<P, false> {
cc_t connect(base_t &conn) noexcept {
return sender_checker<P, false>::connect() ? conn.connect() : 0;
}
cc_t disconnect(base_t &conn, cc_t cc_id) noexcept {
sender_checker<P, false>::disconnect();
return conn.disconnect(cc_id);
}
};
sender_checker <policy_t, relat_trait<policy_t>::is_multi_producer> s_ckr_;
receiver_checker<policy_t, relat_trait<policy_t>::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 <typename Q, typename F>
bool push(Q* que, F&& f) {
return head_.push(que, std::forward<F>(f), block_);
}
template <typename Q, typename F>
bool force_push(Q* que, F&& f) {
return head_.force_push(que, std::forward<F>(f), block_);
}
template <typename Q, typename F, typename R>
bool pop(Q* que, cursor_t* cur, F&& f, R&& out) {
if (cur == nullptr) return false;
return head_.pop(que, *cur, std::forward<F>(f), std::forward<R>(out), block_);
}
};
} // namespace circ
} // namespace ipc