Condy v1.1.0
C++ Asynchronous System Call Layer for Linux
Loading...
Searching...
No Matches
utils.hpp
Go to the documentation of this file.
1
5
6#pragma once
7
8#include <cassert>
9#include <cstddef>
10#include <cstdint>
11#include <cstdlib>
12#include <cstring>
13#include <exception>
14#include <functional>
15#include <iostream>
16#include <system_error>
17#include <utility>
18
19#if defined(__has_feature)
20#if __has_feature(thread_sanitizer)
21#include <sanitizer/tsan_interface.h>
22#define tsan_acquire(addr) __tsan_acquire(addr)
23#define tsan_release(addr) __tsan_release(addr)
24#else
25#define tsan_acquire(addr) static_cast<void>(0)
26#define tsan_release(addr) static_cast<void>(0)
27#endif
28#else
29#define tsan_acquire(addr) static_cast<void>(0)
30#define tsan_release(addr) static_cast<void>(0)
31#endif
32
33namespace condy {
34
35class [[nodiscard]] Defer {
36public:
37 template <typename Func>
38 Defer(Func &&func) : func_(std::forward<Func>(func)) {}
39 ~Defer() { func_(); }
40
41 Defer(const Defer &) = delete;
42 Defer &operator=(const Defer &) = delete;
43 Defer(Defer &&) = delete;
44 Defer &operator=(Defer &&) = delete;
45
46private:
47 std::function<void()> func_;
48};
49
56template <typename Func> Defer defer(Func &&func) {
57 return Defer(std::forward<Func>(func));
58}
59
60template <typename BaseMutex> class MaybeMutex : public BaseMutex {
61public:
62 using Base = BaseMutex;
63 using Base::Base;
64
65 void lock() noexcept {
66 if (use_mutex_) {
67 Base::lock();
68 }
69 }
70
71 void unlock() noexcept {
72 if (use_mutex_) {
73 Base::unlock();
74 }
75 }
76
77 bool try_lock() noexcept {
78 if (use_mutex_) {
79 return Base::try_lock();
80 }
81 return true;
82 }
83
84 void set_use_mutex(bool use_mutex) noexcept { use_mutex_ = use_mutex; }
85
86private:
87 bool use_mutex_ = false;
88};
89
90[[noreturn]] inline void panic_on(const char *msg) noexcept {
91 std::cerr << "Panic: " << msg << '\n';
92#ifndef CRASH_TEST
93 std::terminate();
94#else
95 // Ctest cannot handle SIGABRT, so we use exit here
96 std::exit(EXIT_FAILURE);
97#endif
98}
99
100template <typename T> class RawStorage {
101public:
102 template <typename... Args> void construct(Args &&...args) {
103 new (&storage_) T(std::forward<Args>(args)...);
104 }
105
106 T &get() { return *reinterpret_cast<T *>(&storage_); }
107
108 const T &get() const { return *reinterpret_cast<const T *>(&storage_); }
109
110 void destroy() { get().~T(); }
111
112private:
113 alignas(T) unsigned char storage_[sizeof(T)];
114};
115
116template <typename T, size_t N> class SmallArray {
117public:
118 SmallArray(size_t capacity) : capacity_(capacity) {
119 if (!is_small_()) {
120 large_ = new T[capacity];
121 }
122 }
123
124 ~SmallArray() {
125 if (!is_small_()) {
126 delete[] large_;
127 }
128 }
129
130 T &operator[](size_t index) {
131 return is_small_() ? small_[index] : large_[index];
132 }
133
134 const T &operator[](size_t index) const {
135 return is_small_() ? small_[index] : large_[index];
136 }
137
138 size_t capacity() const { return capacity_; }
139
140private:
141 bool is_small_() const { return capacity_ <= N; }
142
143private:
144 size_t capacity_;
145 union {
146 T small_[N];
147 T *large_;
148 };
149};
150
151inline auto make_system_error(const char *msg, int ec) {
152 return std::system_error(ec, std::generic_category(), msg);
153}
154
155template <typename M, typename T> constexpr ptrdiff_t offset_of(M T::*member) {
156 constexpr T *dummy = nullptr;
157 return reinterpret_cast<ptrdiff_t>(&(dummy->*member));
158}
159
160template <typename M, typename T> T *container_of(M T::*member, M *ptr) {
161 auto offset = offset_of(member);
162 // NOLINTNEXTLINE(performance-no-int-to-ptr)
163 return reinterpret_cast<T *>(reinterpret_cast<intptr_t>(ptr) - offset);
164}
165
166} // namespace condy
The main namespace for the Condy library.
Definition condy.hpp:28
Defer defer(Func &&func)
Defer the execution of a function until the current scope ends.
Definition utils.hpp:56