22#include <system_error>
28#if defined(__has_feature)
29#if __has_feature(thread_sanitizer)
30#define CONDY_DETAIL_HAS_TSAN
34#if defined(__SANITIZE_THREAD__)
35#define CONDY_DETAIL_HAS_TSAN
38#if defined(CONDY_DETAIL_HAS_TSAN)
40void __tsan_acquire(
void *addr);
41void __tsan_release(
void *addr);
47inline void tsan_acquire([[maybe_unused]]
void *addr)
noexcept {
48#if defined(CONDY_DETAIL_HAS_TSAN)
53inline void tsan_release([[maybe_unused]]
void *addr)
noexcept {
54#if defined(CONDY_DETAIL_HAS_TSAN)
61#undef CONDY_DETAIL_HAS_TSAN
65template <
typename Func>
class [[nodiscard]] Defer {
67 Defer(Func func) : func_(std::move(func)) {}
73 Defer(
const Defer &) =
delete;
74 Defer &operator=(
const Defer &) =
delete;
75 Defer(Defer &&) =
delete;
76 Defer &operator=(Defer &&) =
delete;
79 void dismiss() noexcept { active_ =
false; }
92template <
typename Func>
auto defer(Func &&func) {
93 return Defer<std::decay_t<Func>>(std::forward<Func>(func));
96[[noreturn]]
inline void panic_on(std::string_view msg)
noexcept {
97 std::cerr << std::format(
"Panic: {}\n", msg);
102 std::exit(EXIT_FAILURE);
106template <
typename T>
class RawStorage {
108 template <
typename Factory>
109 void accept(Factory &&factory)
noexcept(
110 noexcept(T(std::forward<Factory>(factory)()))) {
111 new (&storage_) T(std::forward<Factory>(factory)());
114 template <
typename... Args>
115 void construct(Args &&...args)
noexcept(
116 std::is_nothrow_constructible_v<T, Args...>) {
117 accept([&]() {
return T(std::forward<Args>(args)...); });
120 T &get() noexcept {
return *std::launder(
reinterpret_cast<T *
>(storage_)); }
122 const T &get() const noexcept {
123 return *std::launder(
reinterpret_cast<const T *
>(storage_));
126 void destroy() noexcept { get().~T(); }
129 alignas(T)
unsigned char storage_[
sizeof(T)];
132template <
typename T,
size_t N>
class SmallArray {
134 SmallArray(
size_t capacity) : capacity_(capacity) {
136 large_ =
new T[capacity];
146 T &operator[](
size_t index)
noexcept {
147 return is_small_() ? small_[index] : large_[index];
150 const T &operator[](
size_t index)
const noexcept {
151 return is_small_() ? small_[index] : large_[index];
154 size_t capacity() const noexcept {
return capacity_; }
157 bool is_small_() const noexcept {
return capacity_ <= N; }
167inline auto make_system_error(std::string_view msg,
int ec) {
168 return std::system_error(ec, std::generic_category(), std::string(msg));
171inline auto make_system_error(std::string_view msg) {
172 return make_system_error(msg, errno);
175template <
typename M,
typename T>
176constexpr ptrdiff_t offset_of(M T::*member)
noexcept {
177 constexpr T *dummy =
nullptr;
178 return reinterpret_cast<ptrdiff_t
>(&(dummy->*member));
181template <
typename M,
typename T>
182T *container_of(M T::*member, M *ptr)
noexcept {
183 auto offset = offset_of(member);
185 return reinterpret_cast<T *
>(
reinterpret_cast<uintptr_t
>(ptr) - offset);
188template <typename T, T From = 0, T To = std::numeric_limits<T>::max()>
191 static_assert(From < To,
"Invalid ID range");
194 if (!recycled_ids_.empty()) {
195 T
id = recycled_ids_.top();
202 throw std::runtime_error(
"ID pool exhausted");
205 void recycle(T
id)
noexcept {
206 assert(From <=
id &&
id < next_id_ &&
id < To);
207 recycled_ids_.push(
id);
210 void reset() noexcept {
212 while (!recycled_ids_.empty()) {
219 std::stack<T> recycled_ids_;
222#if __cplusplus >= 202302L
223[[noreturn]]
inline void unreachable() { std::unreachable(); }
225[[noreturn]]
inline void unreachable() { __builtin_unreachable(); }
228template <
size_t Idx = 0,
typename... Ts>
229std::variant<Ts...> tuple_at(std::tuple<Ts...> &results,
size_t idx) {
230 if constexpr (Idx <
sizeof...(Ts)) {
232 return std::variant<Ts...>{std::in_place_index<Idx>,
233 std::move(std::get<Idx>(results))};
235 return tuple_at<Idx + 1, Ts...>(results, idx);
242 assert(
false &&
"Index out of bounds");
243 return std::variant<Ts...>{std::in_place_index<0>,
244 std::move(std::get<0>(results))};
246 panic_on(
"Index out of bounds in tuple_at");
The main namespace for the Condy library.
auto defer(Func &&func)
Defer the execution of a function until the current scope ends.