add: [concur] utility template for extracting object type internal traits.

This commit is contained in:
mutouyun 2023-04-05 15:51:13 +08:00
parent bb67bd9ddc
commit 33768dd79d
2 changed files with 80 additions and 13 deletions

View File

@ -12,6 +12,7 @@
#include <cstdint> #include <cstdint>
#include "libimp/span.h" #include "libimp/span.h"
#include "libimp/generic.h"
#include "libconcur/def.h" #include "libconcur/def.h"
#include "libconcur/element.h" #include "libconcur/element.h"
@ -21,6 +22,71 @@ LIBCONCUR_NAMESPACE_BEG_
/// \typedef The queue index type. /// \typedef The queue index type.
using index_t = std::uint32_t; using index_t = std::uint32_t;
namespace detail_concurrent {
template <typename T, typename = void>
struct has_header : std::false_type {};
template <typename T>
struct has_header<T, ::LIBIMP::void_t<typename T::header>>
: std::true_type {};
template <typename T, typename = void>
struct has_header_impl : std::false_type {};
template <typename T>
struct has_header_impl<T, ::LIBIMP::void_t<typename T::header_impl>>
: std::true_type {};
template <typename T, typename = void>
struct has_context : std::false_type {};
template <typename T>
struct has_context<T, ::LIBIMP::void_t<typename T::context>>
: std::true_type {};
template <typename T, typename = void>
struct has_context_impl : std::false_type {};
template <typename T>
struct has_context_impl<T, ::LIBIMP::void_t<typename T::context_impl>>
: std::true_type {};
template <typename T, bool = has_header<T>{}
, bool = has_header_impl<T>{}>
struct traits_header {
struct header {};
};
template <typename T, bool HasH>
struct traits_header<T, true, HasH> {
using header = typename T::header;
};
template <typename T>
struct traits_header<T, false, true> {
using header = typename T::header_impl;
};
template <typename T, bool = has_context<T>{}
, bool = has_context_impl<T>{}>
struct traits_context {
struct context {};
};
template <typename T, bool HasH>
struct traits_context<T, true, HasH> {
using context = typename T::context;
};
template <typename T>
struct traits_context<T, false, true> {
using context = typename T::context_impl;
};
} // namespace detail_concurrent
/// \typedef Utility template for extracting object type internal traits.
template <typename T>
struct traits : detail_concurrent::traits_header<T>
, detail_concurrent::traits_context<T> {};
/// \brief Multiplicity of the relationship. /// \brief Multiplicity of the relationship.
namespace relation { namespace relation {
@ -91,10 +157,10 @@ struct producer<trans::unicast, relation::single> {
private: padding<decltype(w_idx)> ___; private: padding<decltype(w_idx)> ___;
}; };
template <typename T, typename H, typename U, template <typename T, typename H, typename C, typename U,
is_elems_header<H> = true, is_elems_header<H> = true,
is_convertible<H, header_impl> = true> is_convertible<H, header_impl> = true>
static bool enqueue(::LIBIMP::span<element<T>> elems, H &hdr, U &&src) noexcept { static bool enqueue(::LIBIMP::span<element<T>> elems, H &hdr, C &/*ctx*/, U &&src) noexcept {
auto w_idx = hdr.w_idx; auto w_idx = hdr.w_idx;
auto w_cur = trunc_index(hdr, w_idx); auto w_cur = trunc_index(hdr, w_idx);
auto &elem = elems[w_cur]; auto &elem = elems[w_cur];
@ -122,10 +188,10 @@ struct producer<trans::unicast, relation::multi> {
private: padding<decltype(w_idx)> ___; private: padding<decltype(w_idx)> ___;
}; };
template <typename T, typename H, typename U, template <typename T, typename H, typename C, typename U,
is_elems_header<H> = true, is_elems_header<H> = true,
is_convertible<H, header_impl> = true> is_convertible<H, header_impl> = true>
static bool enqueue(::LIBIMP::span<element<T>> elems, H &hdr, U &&src) noexcept { static bool enqueue(::LIBIMP::span<element<T>> elems, H &hdr, C &/*ctx*/, U &&src) noexcept {
auto w_idx = hdr.w_idx.load(std::memory_order_acquire); auto w_idx = hdr.w_idx.load(std::memory_order_acquire);
for (;;) { for (;;) {
auto w_cur = trunc_index(hdr, w_idx); auto w_cur = trunc_index(hdr, w_idx);
@ -157,10 +223,10 @@ struct consumer<trans::unicast, relation::single> {
private: padding<decltype(r_idx)> ___; private: padding<decltype(r_idx)> ___;
}; };
template <typename T, typename H, typename U, template <typename T, typename H, typename C, typename U,
is_elems_header<H> = true, is_elems_header<H> = true,
is_convertible<H, header_impl> = true> is_convertible<H, header_impl> = true>
static bool dequeue(::LIBIMP::span<element<T>> elems, H &hdr, U &des) noexcept { static bool dequeue(::LIBIMP::span<element<T>> elems, H &hdr, C &/*ctx*/, U &des) noexcept {
auto r_idx = hdr.r_idx; auto r_idx = hdr.r_idx;
auto r_cur = trunc_index(hdr, r_idx); auto r_cur = trunc_index(hdr, r_idx);
auto &elem = elems[r_cur]; auto &elem = elems[r_cur];
@ -187,10 +253,10 @@ struct consumer<trans::unicast, relation::multi> {
private: padding<decltype(r_idx)> ___; private: padding<decltype(r_idx)> ___;
}; };
template <typename T, typename H, typename U, template <typename T, typename H, typename C, typename U,
is_elems_header<H> = true, is_elems_header<H> = true,
is_convertible<H, header_impl> = true> is_convertible<H, header_impl> = true>
static bool dequeue(::LIBIMP::span<element<T>> elems, H &hdr, U &des) noexcept { static bool dequeue(::LIBIMP::span<element<T>> elems, H &hdr, C &/*ctx*/, U &des) noexcept {
auto r_idx = hdr.r_idx.load(std::memory_order_acquire); auto r_idx = hdr.r_idx.load(std::memory_order_acquire);
for (;;) { for (;;) {
auto r_cur = trunc_index(hdr, r_idx); auto r_cur = trunc_index(hdr, r_idx);
@ -252,7 +318,7 @@ struct prod_cons : producer<TransModT, ProdModT>
: circ_size(cs) {} : circ_size(cs) {}
template <typename T> template <typename T>
constexpr header(::LIBIMP::span<element<T>> elems) noexcept constexpr header(::LIBIMP::span<element<T>> const &elems) noexcept
: circ_size(static_cast<index_t>(elems.size())) {} : circ_size(static_cast<index_t>(elems.size())) {}
constexpr bool valid() const noexcept { constexpr bool valid() const noexcept {

View File

@ -99,8 +99,9 @@ void test_concur(std::size_t np, std::size_t nc, std::size_t k) {
concur::element<std::uint64_t> circ[32] {}; concur::element<std::uint64_t> circ[32] {};
PC pc; PC pc;
typename PC::header ctx {imp::make_span(circ)}; typename concur::traits<PC>::header hdr {imp::make_span(circ)};
ASSERT_TRUE(ctx.valid()); typename concur::traits<PC>::context ctx {};
ASSERT_TRUE(hdr.valid());
std::atomic<std::uint64_t> sum {0}; std::atomic<std::uint64_t> sum {0};
std::atomic<std::size_t> running {np}; std::atomic<std::size_t> running {np};
@ -108,7 +109,7 @@ void test_concur(std::size_t np, std::size_t nc, std::size_t k) {
auto prod_call = [&](std::size_t n) { auto prod_call = [&](std::size_t n) {
for (std::uint32_t i = 1; i <= loop_size; ++i) { for (std::uint32_t i = 1; i <= loop_size; ++i) {
std::this_thread::yield(); std::this_thread::yield();
while (!pc.enqueue(imp::make_span(circ), ctx, i)) { while (!pc.enqueue(imp::make_span(circ), hdr, ctx, i)) {
std::this_thread::yield(); std::this_thread::yield();
} }
if (i % (loop_size / 10) == 0) { if (i % (loop_size / 10) == 0) {
@ -121,7 +122,7 @@ void test_concur(std::size_t np, std::size_t nc, std::size_t k) {
for (;;) { for (;;) {
std::this_thread::yield(); std::this_thread::yield();
std::uint64_t i; std::uint64_t i;
while (!pc.dequeue(imp::make_span(circ), ctx, i)) { while (!pc.dequeue(imp::make_span(circ), hdr, ctx, i)) {
if (running == 0) return; if (running == 0) return;
std::this_thread::yield(); std::this_thread::yield();
} }