22#include <system_error>
29#define CONDY_DELETE_COPY(cls) \
30 cls(const cls &) = delete; \
31 cls &operator=(const cls &) = delete
33#define CONDY_DELETE_MOVE(cls) \
34 cls(cls &&) = delete; \
35 cls &operator=(cls &&) = delete
38#define CONDY_DELETE_COPY_MOVE(cls) \
39 CONDY_DELETE_COPY(cls); \
40 CONDY_DELETE_MOVE(cls)
42#if defined(__has_feature)
43#if __has_feature(thread_sanitizer)
44#define CONDY_DETAIL_HAS_TSAN
48#if defined(__SANITIZE_THREAD__)
49#define CONDY_DETAIL_HAS_TSAN
52#if defined(CONDY_DETAIL_HAS_TSAN)
54void __tsan_acquire(
void *addr);
55void __tsan_release(
void *addr);
62inline void tsan_acquire([[maybe_unused]]
void *addr)
noexcept {
63#if defined(CONDY_DETAIL_HAS_TSAN)
68inline void tsan_release([[maybe_unused]]
void *addr)
noexcept {
69#if defined(CONDY_DETAIL_HAS_TSAN)
74template <
typename Func>
class [[nodiscard]] Defer {
76 Defer(Func func) : func_(std::move(func)) {}
82 CONDY_DELETE_COPY_MOVE(Defer);
85 void dismiss() noexcept { active_ =
false; }
92template <
typename Func>
auto defer(Func &&func) {
93 return Defer<std::decay_t<Func>>(std::forward<Func>(func));
96template <typename T, T From = 0, T To = std::numeric_limits<T>::max()>
99 static_assert(From < To,
"Invalid ID range");
102 if (!recycled_ids_.empty()) {
103 T
id = recycled_ids_.top();
110 throw std::runtime_error(
"ID pool exhausted");
113 void recycle(T
id)
noexcept {
114 assert(From <=
id &&
id < next_id_ &&
id < To);
115 recycled_ids_.push(
id);
118 void reset() noexcept {
120 while (!recycled_ids_.empty()) {
127 std::stack<T> recycled_ids_;
130[[noreturn]]
inline void panic_on(std::string_view msg)
noexcept {
131 std::cerr << std::format(
"Panic: {}\n", msg);
136 std::exit(EXIT_FAILURE);
140template <
typename T>
class RawStorage {
142 template <
typename Factory>
143 void accept(Factory &&factory)
noexcept(
144 noexcept(T(std::forward<Factory>(factory)()))) {
145 new (&storage_) T(std::forward<Factory>(factory)());
148 template <
typename... Args>
149 void construct(Args &&...args)
noexcept(
150 std::is_nothrow_constructible_v<T, Args...>) {
151 accept([&]() {
return T(std::forward<Args>(args)...); });
154 T &get() noexcept {
return *std::launder(
reinterpret_cast<T *
>(storage_)); }
156 const T &get() const noexcept {
157 return *std::launder(
reinterpret_cast<const T *
>(storage_));
160 void destroy() noexcept { get().~T(); }
163 alignas(T)
unsigned char storage_[
sizeof(T)];
166template <
typename T,
size_t N>
class SmallArray {
168 SmallArray(
size_t capacity) : capacity_(capacity) {
170 large_ =
new T[capacity];
180 T &operator[](
size_t index)
noexcept {
181 return is_small_() ? small_[index] : large_[index];
184 const T &operator[](
size_t index)
const noexcept {
185 return is_small_() ? small_[index] : large_[index];
188 size_t capacity() const noexcept {
return capacity_; }
191 bool is_small_() const noexcept {
return capacity_ <= N; }
201inline auto make_system_error(std::string_view msg,
int ec) {
202 return std::system_error(ec, std::generic_category(), std::string(msg));
205inline auto make_system_error(std::string_view msg) {
206 return make_system_error(msg, errno);
209#if __cplusplus >= 202302L
210[[noreturn]]
inline void unreachable() { std::unreachable(); }
212[[noreturn]]
inline void unreachable() { __builtin_unreachable(); }
215template <
size_t Idx = 0,
typename... Ts>
216std::variant<Ts...> tuple_at(std::tuple<Ts...> &results,
size_t idx) {
217 if constexpr (Idx <
sizeof...(Ts)) {
219 return std::variant<Ts...>{std::in_place_index<Idx>,
220 std::move(std::get<Idx>(results))};
222 return tuple_at<Idx + 1, Ts...>(results, idx);
229 assert(
false &&
"Index out of bounds");
230 return std::variant<Ts...>{std::in_place_index<0>,
231 std::move(std::get<0>(results))};
233 panic_on(
"Index out of bounds in tuple_at");
238template <
typename T>
inline T align_up(T value, T alignment)
noexcept {
240 assert(alignment > 0 && (alignment & (alignment - 1)) == 0);
241 return (value + alignment - 1) & ~(alignment - 1);
247#undef CONDY_DETAIL_HAS_TSAN
The main namespace for the Condy library.