22#include <system_error>
26#if defined(__has_feature)
27#if __has_feature(thread_sanitizer)
28#include <sanitizer/tsan_interface.h>
29#define tsan_acquire(addr) __tsan_acquire(addr)
30#define tsan_release(addr) __tsan_release(addr)
32#define tsan_acquire(addr) static_cast<void>(0)
33#define tsan_release(addr) static_cast<void>(0)
36#define tsan_acquire(addr) static_cast<void>(0)
37#define tsan_release(addr) static_cast<void>(0)
42template <
typename Func>
class [[nodiscard]] Defer {
44 Defer(Func func) : func_(std::move(func)) {}
50 Defer(
const Defer &) =
delete;
51 Defer &operator=(
const Defer &) =
delete;
52 Defer(Defer &&) =
delete;
53 Defer &operator=(Defer &&) =
delete;
56 void dismiss() noexcept { active_ =
false; }
69template <
typename Func>
auto defer(Func &&func) {
70 return Defer<std::decay_t<Func>>(std::forward<Func>(func));
73[[noreturn]]
inline void panic_on(std::string_view msg)
noexcept {
74 std::cerr << std::format(
"Panic: {}\n", msg);
79 std::exit(EXIT_FAILURE);
83template <
typename T>
class RawStorage {
85 template <
typename... Args>
86 void construct(Args &&...args)
noexcept(
87 std::is_nothrow_constructible_v<T, Args...>) {
88 new (&storage_) T(std::forward<Args>(args)...);
91 T &get() noexcept {
return *
reinterpret_cast<T *
>(&storage_); }
93 const T &get() const noexcept {
94 return *
reinterpret_cast<const T *
>(&storage_);
97 void destroy() noexcept { get().~T(); }
100 alignas(T)
unsigned char storage_[
sizeof(T)];
103template <
typename T,
size_t N>
class SmallArray {
105 SmallArray(
size_t capacity) : capacity_(capacity) {
107 large_ =
new T[capacity];
117 T &operator[](
size_t index)
noexcept {
118 return is_small_() ? small_[index] : large_[index];
121 const T &operator[](
size_t index)
const noexcept {
122 return is_small_() ? small_[index] : large_[index];
125 size_t capacity() const noexcept {
return capacity_; }
128 bool is_small_() const noexcept {
return capacity_ <= N; }
138inline auto make_system_error(std::string_view msg,
int ec) {
139 return std::system_error(ec, std::generic_category(), std::string(msg));
142inline auto make_system_error(std::string_view msg) {
143 return make_system_error(msg, errno);
146template <
typename M,
typename T>
147constexpr ptrdiff_t offset_of(M T::*member)
noexcept {
148 constexpr T *dummy =
nullptr;
149 return reinterpret_cast<ptrdiff_t
>(&(dummy->*member));
152template <
typename M,
typename T>
153T *container_of(M T::*member, M *ptr)
noexcept {
154 auto offset = offset_of(member);
156 return reinterpret_cast<T *
>(
reinterpret_cast<intptr_t
>(ptr) - offset);
159template <typename T, T From = 0, T To = std::numeric_limits<T>::max()>
162 static_assert(From < To,
"Invalid ID range");
165 if (!recycled_ids_.empty()) {
166 T
id = recycled_ids_.top();
173 throw std::runtime_error(
"ID pool exhausted");
176 void recycle(T
id)
noexcept {
177 assert(From <=
id &&
id < next_id_ &&
id < To);
178 recycled_ids_.push(
id);
181 void reset() noexcept {
183 while (!recycled_ids_.empty()) {
190 std::stack<T> recycled_ids_;
195 void lock() noexcept {
196 bool expected =
false;
197 while (!lock_.compare_exchange_weak(expected,
true,
198 std::memory_order_acquire,
199 std::memory_order_relaxed)) {
201 lock_.wait(
true, std::memory_order_relaxed);
205 void unlock() noexcept {
206 lock_.store(
false, std::memory_order_release);
211 std::atomic_bool lock_ =
false;
214#if __cplusplus >= 202302L
215[[noreturn]]
inline void unreachable() { std::unreachable(); }
217[[noreturn]]
inline void unreachable() { __builtin_unreachable(); }
The main namespace for the Condy library.
auto defer(Func &&func)
Defer the execution of a function until the current scope ends.