mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-06 16:56:45 +08:00
105 lines
2.5 KiB
C++
105 lines
2.5 KiB
C++
/**
|
|
* \file libconcur/element.h
|
|
* \author mutouyun (orz@orzz.org)
|
|
* \brief Define concurrent queue element abstraction.
|
|
* \date 2022-11-19
|
|
*/
|
|
#pragma once
|
|
|
|
#include <atomic>
|
|
#include <utility>
|
|
#include <cstdint>
|
|
#include <exception>
|
|
|
|
#include "libimp/detect_plat.h"
|
|
#include "libimp/log.h"
|
|
#include "libimp/byte.h"
|
|
#include "libimp/generic.h"
|
|
|
|
#include "libconcur/def.h"
|
|
|
|
LIBCONCUR_NAMESPACE_BEG_
|
|
namespace state {
|
|
|
|
/// \typedef The state flag type for the queue element.
|
|
using flag_t = std::uint64_t;
|
|
|
|
enum : flag_t {
|
|
invalid_value = ~flag_t(0),
|
|
enqueue_mask = invalid_value << 32,
|
|
commit_mask = ~flag_t(1) << 32,
|
|
};
|
|
|
|
} // namespace state
|
|
|
|
/// \brief Define the padding type.
|
|
template <typename T>
|
|
using padding = std::array<::LIBIMP::byte, (cache_line_size - sizeof(T))>;
|
|
|
|
/**
|
|
* \class template <typename T> element
|
|
* \brief User-defined type element wrapper.
|
|
* Wrapper for wrapping user-defined types as elements.
|
|
*
|
|
* @tparam T - User-defined type.
|
|
*/
|
|
template <typename T>
|
|
class element {
|
|
|
|
template <typename E>
|
|
friend auto get(E &&elem) noexcept;
|
|
|
|
/// \brief Committed flag.
|
|
std::atomic<state::flag_t> f_ct_;
|
|
padding<decltype(f_ct_)> ___;
|
|
|
|
/// \brief The user data segment.
|
|
T data_;
|
|
|
|
/// \brief Disable copy & move.
|
|
element(element const &) = delete;
|
|
element &operator=(element const &) = delete;
|
|
|
|
public:
|
|
using value_type = T;
|
|
|
|
template <typename... A>
|
|
element(A &&... args)
|
|
noexcept(noexcept(T{std::forward<A>(args)...}))
|
|
: f_ct_{state::invalid_value}
|
|
, data_{std::forward<A>(args)...} {}
|
|
|
|
template <typename U>
|
|
void set_data(U &&src) noexcept {
|
|
LIBIMP_LOG_();
|
|
LIBIMP_TRY {
|
|
data_ = std::forward<U>(src);
|
|
} LIBIMP_CATCH(std::exception const &e) {
|
|
log.error("failed: `data = std::forward<U>(src)`. error = ", e.what());
|
|
} LIBIMP_CATCH(...) {
|
|
log.error("failed: `data = std::forward<U>(src)`. error = unknown");
|
|
}
|
|
}
|
|
|
|
void set_flag(state::flag_t flag,
|
|
std::memory_order const order = std::memory_order_release) noexcept {
|
|
f_ct_.store(flag, order);
|
|
}
|
|
|
|
bool cas_flag(state::flag_t &expected, state::flag_t flag,
|
|
std::memory_order const order = std::memory_order_acq_rel) noexcept {
|
|
return f_ct_.compare_exchange_weak(expected, flag, order);
|
|
}
|
|
|
|
state::flag_t get_flag() const noexcept {
|
|
return f_ct_.load(std::memory_order_acquire);
|
|
}
|
|
};
|
|
|
|
template <typename E>
|
|
auto get(E &&elem) noexcept {
|
|
return static_cast<imp::copy_cvref_t<E, typename std::decay<E>::type::value_type>>(elem.data_);
|
|
}
|
|
|
|
LIBCONCUR_NAMESPACE_END_
|