23#include <system_error>
27#if defined(__has_feature)
28#if __has_feature(thread_sanitizer)
29#include <sanitizer/tsan_interface.h>
30#define tsan_acquire(addr) __tsan_acquire(addr)
31#define tsan_release(addr) __tsan_release(addr)
33#define tsan_acquire(addr) static_cast<void>(0)
34#define tsan_release(addr) static_cast<void>(0)
37#define tsan_acquire(addr) static_cast<void>(0)
38#define tsan_release(addr) static_cast<void>(0)
43class [[nodiscard]] Defer {
45 template <
typename Func>
46 Defer(Func &&func) : func_(std::forward<Func>(func)) {}
49 Defer(
const Defer &) =
delete;
50 Defer &operator=(
const Defer &) =
delete;
51 Defer(Defer &&) =
delete;
52 Defer &operator=(Defer &&) =
delete;
55 std::function<void()> func_;
64template <
typename Func> Defer
defer(Func &&func) {
65 return Defer(std::forward<Func>(func));
68[[noreturn]]
inline void panic_on(std::string_view msg)
noexcept {
69 std::cerr << std::format(
"Panic: {}\n", msg);
74 std::exit(EXIT_FAILURE);
78template <
typename T>
class RawStorage {
80 template <
typename... Args>
81 void construct(Args &&...args)
noexcept(
82 std::is_nothrow_constructible_v<T, Args...>) {
83 new (&storage_) T(std::forward<Args>(args)...);
86 T &get() noexcept {
return *
reinterpret_cast<T *
>(&storage_); }
88 const T &get() const noexcept {
89 return *
reinterpret_cast<const T *
>(&storage_);
92 void destroy() noexcept { get().~T(); }
95 alignas(T)
unsigned char storage_[
sizeof(T)];
98template <
typename T,
size_t N>
class SmallArray {
100 SmallArray(
size_t capacity) : capacity_(capacity) {
102 large_ =
new T[capacity];
112 T &operator[](
size_t index)
noexcept {
113 return is_small_() ? small_[index] : large_[index];
116 const T &operator[](
size_t index)
const noexcept {
117 return is_small_() ? small_[index] : large_[index];
120 size_t capacity() const noexcept {
return capacity_; }
123 bool is_small_() const noexcept {
return capacity_ <= N; }
133inline auto make_system_error(std::string_view msg,
int ec) {
134 return std::system_error(ec, std::generic_category(), std::string(msg));
137inline auto make_system_error(std::string_view msg) {
138 return make_system_error(msg, errno);
141template <
typename M,
typename T>
142constexpr ptrdiff_t offset_of(M T::*member)
noexcept {
143 constexpr T *dummy =
nullptr;
144 return reinterpret_cast<ptrdiff_t
>(&(dummy->*member));
147template <
typename M,
typename T>
148T *container_of(M T::*member, M *ptr)
noexcept {
149 auto offset = offset_of(member);
151 return reinterpret_cast<T *
>(
reinterpret_cast<intptr_t
>(ptr) - offset);
154template <typename T, T From = 0, T To = std::numeric_limits<T>::max()>
157 static_assert(From < To,
"Invalid ID range");
160 if (!recycled_ids_.empty()) {
161 T
id = recycled_ids_.top();
168 throw std::runtime_error(
"ID pool exhausted");
171 void recycle(T
id)
noexcept {
172 assert(From <=
id &&
id < next_id_ &&
id < To);
173 recycled_ids_.push(
id);
176 void reset() noexcept {
178 while (!recycled_ids_.empty()) {
185 std::stack<T> recycled_ids_;
190 void lock() noexcept {
191 bool expected =
false;
192 while (!lock_.compare_exchange_weak(expected,
true,
193 std::memory_order_acquire,
194 std::memory_order_relaxed)) {
196 lock_.wait(
true, std::memory_order_relaxed);
200 void unlock() noexcept {
201 lock_.store(
false, std::memory_order_release);
206 std::atomic_bool lock_ =
false;
The main namespace for the Condy library.
Defer defer(Func &&func)
Defer the execution of a function until the current scope ends.