28 #define ZTH_STRINGIFY_(x) #x
32 #define ZTH_STRINGIFY(x) ZTH_STRINGIFY_(x)
42 # define likely(expr) __builtin_expect(!!(expr), 1)
44 # define likely(expr) (expr)
56 # define unlikely(expr) __builtin_expect(!!(expr), 0)
58 # define unlikely(expr) (expr)
63 #if defined(__cplusplus) && __cplusplus < 201103L && !defined(static_assert)
64 # pragma GCC diagnostic ignored "-Wunused-local-typedefs"
65 # define static_assert(expr, msg) typedef int static_assert_[(expr) ? 1 : -1]
69 #define ZTH_GET_MACRO_ARGN( \
70 _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, NAME, ...) \
74 # define FOREACH_0(WHAT)
75 # define FOREACH_1(WHAT, X) WHAT(X)
76 # define FOREACH_2(WHAT, X, ...) \
77 WHAT(X) FOREACH_1(WHAT, __VA_ARGS__)
78 # define FOREACH_3(WHAT, X, ...) \
79 WHAT(X) FOREACH_2(WHAT, __VA_ARGS__)
80 # define FOREACH_4(WHAT, X, ...) \
81 WHAT(X) FOREACH_3(WHAT, __VA_ARGS__)
82 # define FOREACH_5(WHAT, X, ...) \
83 WHAT(X) FOREACH_4(WHAT, __VA_ARGS__)
84 # define FOREACH_6(WHAT, X, ...) \
85 WHAT(X) FOREACH_5(WHAT, __VA_ARGS__)
86 # define FOREACH_7(WHAT, X, ...) \
87 WHAT(X) FOREACH_6(WHAT, __VA_ARGS__)
88 # define FOREACH_8(WHAT, X, ...) \
89 WHAT(X) FOREACH_7(WHAT, __VA_ARGS__)
90 # define FOREACH_9(WHAT, X, ...) \
91 WHAT(X) FOREACH_8(WHAT, __VA_ARGS__)
92 # define FOREACH_10(WHAT, X, ...) \
93 WHAT(X) FOREACH_9(WHAT, __VA_ARGS__)
94 # define FOREACH_11(WHAT, X, ...) \
95 WHAT(X) FOREACH_10(WHAT, __VA_ARGS__)
96 # define FOREACH_12(WHAT, X, ...) \
97 WHAT(X) FOREACH_11(WHAT, __VA_ARGS__)
98 # define FOREACH_13(WHAT, X, ...) \
99 WHAT(X) FOREACH_12(WHAT, __VA_ARGS__)
100 # define FOREACH_14(WHAT, X, ...) \
101 WHAT(X) FOREACH_13(WHAT, __VA_ARGS__)
102 # define FOREACH_15(WHAT, X, ...) \
103 WHAT(X) FOREACH_14(WHAT, __VA_ARGS__)
104 # define FOREACH_16(WHAT, X, ...) \
105 WHAT(X) FOREACH_15(WHAT, __VA_ARGS__)
111 # define FOREACH(action, ...) \
112 ZTH_GET_MACRO_ARGN( \
113 0, ##__VA_ARGS__, FOREACH_16, FOREACH_15, FOREACH_14, FOREACH_13, \
114 FOREACH_12, FOREACH_11, FOREACH_10, FOREACH_9, FOREACH_8, FOREACH_7, \
115 FOREACH_6, FOREACH_5, FOREACH_4, FOREACH_3, FOREACH_2, FOREACH_1, \
117 (action, ##__VA_ARGS__)
122 # define REVERSE_1(a) a
123 # define REVERSE_2(a, ...) REVERSE_1(__VA_ARGS__), a
124 # define REVERSE_3(a, ...) REVERSE_2(__VA_ARGS__), a
125 # define REVERSE_4(a, ...) REVERSE_3(__VA_ARGS__), a
126 # define REVERSE_5(a, ...) REVERSE_4(__VA_ARGS__), a
127 # define REVERSE_6(a, ...) REVERSE_5(__VA_ARGS__), a
128 # define REVERSE_7(a, ...) REVERSE_6(__VA_ARGS__), a
129 # define REVERSE_8(a, ...) REVERSE_7(__VA_ARGS__), a
130 # define REVERSE_9(a, ...) REVERSE_8(__VA_ARGS__), a
131 # define REVERSE_10(a, ...) REVERSE_9(__VA_ARGS__), a
132 # define REVERSE_11(a, ...) REVERSE_10(__VA_ARGS__), a
133 # define REVERSE_12(a, ...) REVERSE_11(__VA_ARGS__), a
134 # define REVERSE_13(a, ...) REVERSE_12(__VA_ARGS__), a
135 # define REVERSE_14(a, ...) REVERSE_13(__VA_ARGS__), a
136 # define REVERSE_15(a, ...) REVERSE_14(__VA_ARGS__), a
137 # define REVERSE_16(a, ...) REVERSE_15(__VA_ARGS__), a
138 # define REVERSE(...) \
139 ZTH_GET_MACRO_ARGN( \
140 0, ##__VA_ARGS__, REVERSE_16, REVERSE_15, REVERSE_14, REVERSE_13, \
141 REVERSE_12, REVERSE_11, REVERSE_10, REVERSE_9, REVERSE_8, REVERSE_7, \
142 REVERSE_6, REVERSE_5, REVERSE_4, REVERSE_3, REVERSE_2, REVERSE_1, \
158 # if __cplusplus >= 201103L
159 # include <cinttypes>
161 # include <inttypes.h>
164 # ifdef ZTH_HAVE_PTHREAD
165 # include <pthread.h>
168 # ifdef ZTH_OS_WINDOWS
169 # include <process.h>
171 # include <sys/types.h>
176 zth_logv(
char const* fmt, va_list arg);
183 # define ZTH_DBG_PREFIX " > "
195 # define zth_dbg(group, fmt, a...) \
197 if(::zth::Config::SupportDebugPrint \
198 && ::zth::Config::Print_##group > 0 \
199 && zth_config(EnableDebugPrint)) { \
200 if(::zth::Config::EnableColorLog) \
202 ::zth::Config::Print_##group, \
204 "zth::" ZTH_STRINGIFY(group) ": " fmt \
210 "zth::" ZTH_STRINGIFY(group) ": " fmt \
221 # define zth_assert(expr) \
223 if(unlikely(::zth::Config::EnableAssert && !(expr))) \
224 ::zth::assert_handler( \
225 __FILE__, __LINE__, \
226 ::zth::Config::EnableFullAssert \
227 ? ZTH_STRINGIFY(expr) \
231 # define zth_assert(...) \
237 # ifndef ZTH_CLASS_NOCOPY
238 # if __cplusplus >= 201103L
239 # define ZTH_CLASS_NOCOPY(Class) \
241 Class(Class const&) = delete; \
245 Class& operator=(Class const&) noexcept = delete; \
246 Class& operator=(Class&&) noexcept = \
251 # define ZTH_CLASS_NOCOPY(Class) \
253 Class(Class const&); \
254 Class& operator=(Class const&);
262 ZTH_EXPORT
char const*
banner() noexcept;
265 abort(
char const* fmt, ...) noexcept;
268 abortv(
char const* fmt, va_list args) noexcept;
270 ZTH_EXPORT __attribute__((noreturn))
void
276 log_colorv(
int color,
char const* fmt, va_list args);
284 log_color(
int color,
char const* fmt, ...)
299 logv(
char const* fmt, va_list arg)
374 # if __cplusplus >= 201103L
381 , m_str(std::move(s))
387 m_str = std::move(s);
394 return std::move(
local());
403 char const*
c_str()
const
405 return m_cstr ? m_cstr : m_str.c_str();
408 operator string const &()
const
413 char const&
at(
size_t pos)
const
415 return str().at(pos);
420 return m_cstr ? m_cstr[pos] :
str()[pos];
428 char const*
data()
const
433 bool empty() const noexcept
435 return m_cstr ? *m_cstr == 0 : m_str.empty();
438 size_t size() const noexcept
443 size_t length() const noexcept
445 return str().length();
448 void clear() noexcept
456 return m_cstr !=
nullptr;
461 return m_cstr ==
nullptr;
465 string const&
local()
const
481 mutable char const* m_cstr;
482 mutable string m_str;
494 string res =
formatv(fmt, args);
503 template <
typename T>
512 return format(
"%c", value);
518 return format(
"%hhd", value);
524 return format(
"%hhu", value);
530 return format(
"%hd", value);
536 return format(
"%hu", value);
540 inline cow_string
str<int>(
int value)
542 return format(
"%d", value);
548 return format(
"%u", value);
554 return format(
"%ld", value);
560 return format(
"%lu", value);
566 return format(
"%lld", value);
572 return format(
"%llu", value);
578 return format(
"%g", (
double)value);
584 return format(
"%g", value);
590 return format(
"%Lg", value);
593 # if __cplusplus >= 201103L
604 inline string err(
int e)
606 # ifdef ZTH_OS_BAREMETAL
609 # elif defined(ZTH_HAVE_LIBZMQ)
610 return format(
"%s (error %d)", zmq_strerror(e), e);
611 # elif ZTH_THREADS && !defined(ZTH_OS_WINDOWS)
613 # if !defined(ZTH_OS_LINUX) || (_POSIX_C_SOURCE >= 200112L) && !defined(_GNU_SOURCE)
615 return format(
"%s (error %d)", strerror_r(e, buf,
sizeof(buf)) ?
"Unknown error" : buf, e);
618 return format(
"%s (error %d)", strerror_r(e, buf,
sizeof(buf)), e);
622 return format(
"%s (error %d)", strerror(e), e);
628 virtual char const*
id_str()
const = 0;
630 friend cow_string
str<UniqueIDBase const&>(UniqueIDBase const&);
634 inline cow_string
str<UniqueIDBase const&>(UniqueIDBase const& value)
636 return cow_string(value.id_str());
643 template <
typename T,
bool ThreadSafe = Config::EnableThreads>
645 # if __cplusplus < 201103L
655 *
this = std::move(u);
661 m_name = std::move(u.m_name);
662 m_id_str = std::move(u.m_id_str);
670 static uint64_t getID() noexcept
673 # if GCC_VERSION < 40802L
674 __sync_add_and_fetch(&m_nextId, 1)
676 __atomic_add_fetch(&m_nextId, 1, __ATOMIC_RELAXED)
681 explicit UniqueID(
string const& name)
686 # if __cplusplus >= 201103L
689 , m_name(std::move(name))
693 explicit UniqueID(
char const* name =
nullptr)
702 void const* normptr() const noexcept
707 __attribute__((pure)) uint64_t id() const noexcept
712 string const& name() const noexcept
717 void setName(
string const& name)
726 changedName(this->name());
729 # if __cplusplus >= 201103L
732 m_name = std::move(name);
734 changedName(this->name());
738 virtual char const*
id_str()
const override
742 # ifdef ZTH_OS_BAREMETAL
745 format(
"%s #%u", name().empty() ?
"Object" : name().c_str(),
749 name().empty() ?
"Object" : name().c_str(),
750 # ifdef ZTH_OS_WINDOWS
751 (
unsigned int)_getpid(),
753 (
unsigned int)getpid(),
762 return m_id_str.c_str();
766 virtual void changedName(
string const&
UNUSED_PAR(name)) {}
771 string mutable m_id_str;
774 static uint64_t m_nextId;
777 template <
typename T,
bool ThreadSafe>
778 uint64_t UniqueID<T, ThreadSafe>::m_nextId = 0;
780 template <
typename T,
typename WhenTIsVo
id>
785 template <
typename WhenTIsVo
id>
786 struct choose_type<void, WhenTIsVoid> {
787 typedef WhenTIsVoid type;
790 # if __cplusplus >= 201103L
794 template <
size_t N,
size_t... S>
795 struct SequenceGenerator : SequenceGenerator<N - 1, N - 1, S...> {};
797 template <
size_t... S>
798 struct SequenceGenerator<0, S...> {
807 template <
typename T>
811 typedef T pointer_type;
814 constexpr
safe_ptr(pointer_type* p) noexcept
818 constexpr
operator pointer_type*()
const noexcept
823 constexpr
operator bool() const noexcept
834 constexpr14 pointer_type& operator*() const noexcept
853 template <
typename T>
882 template <
typename T>
886 typedef T singleton_type;
909 m_instance =
nullptr;
925 static singleton_type* m_instance;
928 template <
typename T>
940 template <
typename T>
941 class ThreadLocalSingleton {
944 typedef T singleton_type;
952 __attribute__((no_sanitize_undefined)) ThreadLocalSingleton()
986 template <
typename T>
1007 template <typename T, int8_t Prealloc = 1, typename Allocator = typename
Config::Allocator<T>::type>
1010 typedef T value_type;
1011 typedef Allocator allocator_type;
1012 typedef std::vector<value_type, allocator_type>
vector_type;
1014 enum { prealloc_request = Prealloc > 0 ? Prealloc : 0,
1015 prealloc_request_size = prealloc_request *
sizeof(value_type),
1018 prealloc_request_size > vector_size ? prealloc_request_size : vector_size,
1019 prealloc = buffer_size /
sizeof(value_type),
1029 static_assert(prealloc < std::numeric_limits<uint8_t>::max(),
"");
1040 vector().~vector_type();
1046 value_type& operator[](
size_t index) noexcept
1049 return data()[index];
1055 value_type
const& operator[](
size_t index)
const noexcept
1058 return data()[index];
1066 value_type& front() noexcept
1076 value_type
const& front() const noexcept
1086 value_type& back() noexcept
1089 return (*
this)[size() - 1u];
1097 value_type
const& back() const noexcept
1100 return (*
this)[size() - 1u];
1106 value_type* data() noexcept
1108 return is_small() ? array() : vector().data();
1116 return is_small() ? array() : vector().data();
1122 bool empty() const noexcept
1124 return is_small() ? m_size == 0 : vector().empty();
1130 size_t size() const noexcept
1132 return is_small() ? m_size : vector().size();
1140 void reserve(
size_t new_cap)
1142 if(is_small() && new_cap <= prealloc)
1146 make_vector(new_cap);
1148 vector().reserve(new_cap);
1155 size_t capacity() const noexcept
1157 return is_small() ? (size_t)prealloc : vector().capacity();
1165 void clear() noexcept
1176 void clear_and_release() noexcept
1190 void push_back(value_type
const& v)
1192 reserve(size() + 1u);
1194 if(m_size < prealloc) {
1195 new(&array()[m_size]) value_type(v);
1198 vector().push_back(v);
1201 # if __cplusplus >= 201103L
1206 template <
class... Args>
1207 void emplace_back(Args&&... args)
1209 reserve(size() + 1u);
1211 if(m_size < prealloc) {
1212 new(&array()[m_size]) value_type(std::forward<Args>(args)...);
1215 vector().emplace_back(std::forward<Args>(args)...);
1224 void pop_back() noexcept
1228 array()[--m_size].~value_type();
1230 vector().pop_back();
1238 void resize(
size_t count, value_type
const& x = value_type())
1241 while(count < m_size)
1242 array()[--m_size].~value_type();
1244 if(count <= prealloc) {
1245 while(count > m_size) {
1246 new(&array()[m_size]) value_type(x);
1251 vector().resize(count, x);
1254 vector().resize(count, x);
1261 bool is_small() const noexcept
1263 return m_size <= prealloc;
1269 value_type* array() noexcept
1272 return reinterpret_cast<value_type*
>(m_buffer);
1281 return reinterpret_cast<value_type const*
>(m_buffer);
1290 void* buffer = m_buffer;
1300 void const* buffer = m_buffer;
1301 return *
reinterpret_cast<vector_type const*
>(buffer);
1307 void make_vector(
size_t new_cap)
1313 v.reserve(std::max(new_cap, (
size_t)m_size));
1315 for(
size_t i = 0; i < m_size; i++) {
1316 # if __cplusplus >= 201103L
1317 v.emplace_back(std::move(array()[i]));
1319 v.push_back(array()[i]);
1321 array()[i].~value_type();
1324 m_size = prealloc + 1u;
1334 alignas(vector_type)
alignas(value_type)
char m_buffer[buffer_size];
1346 template <
size_t size>
1347 struct smallest_uint_size {};
1351 typename size = smallest_uint_size<
1352 x >= 0x100000000ULL ? 8U : x >= 0x10000U ? 4U : x >= 0x100U ? 2U : 1U> >
1353 struct smallest_uint {
1354 typedef uint64_t type;
1357 template <u
int64_t x>
1358 struct smallest_uint<x, smallest_uint_size<1> > {
1359 typedef uint8_t type;
1362 template <u
int64_t x>
1364 typedef uint16_t type;
1367 template <u
int64_t x>
1368 struct smallest_uint<x, smallest_uint_size<4> > {
1369 typedef uint32_t type;
1408 va_start(args, fmt);
1427 va_start(args, fmt);
1435 #ifdef ZTH_OS_BAREMETAL
1438 EXTERN_C __attribute__((
format(gnu_printf, 2, 0))) int asprintf(
char** strp, const
char* fmt, ...);
1439 EXTERN_C __attribute__((
format(gnu_printf, 2, 0)))
int
1440 vasprintf(
char** strp, const
char* fmt, va_list ap);
T singleton_type
Alias of the T template parameter.
Singleton pattern, but only per-thread.
T singleton_type
Alias of the T template parameter.
virtual char const * id_str() const =0
friend cow_string str(UniqueIDBase const &)
virtual ~UniqueIDBase()=default
Keeps track of a process-wide unique ID within the type T.
void setName(string const &name)
char operator[](size_t pos) const
bool isConst() const noexcept
char const * data() const
string const & local() const
cow_string & operator=(cow_string const &s)
size_t length() const noexcept
size_t size() const noexcept
char const * c_str() const
bool empty() const noexcept
char const & at(size_t pos) const
bool isLocal() const noexcept
Wrapper for a pointer, which checks validity of the pointer upon dereference.
Change the name of a fiber returned by async.
A simple std::vector, which can contain Prealloc without heap allocation.
std::vector< value_type, allocator_type > vector_type
void zth_banner()
Prints a banner line with version and configuration information.
void zth_log(char const *fmt,...)
Logs a given printf()-like formatted string.
void zth_abort(char const *fmt,...)
Aborts the process after printing the given printf() formatted message.
void zth_log_color(int color, char const *fmt,...)
Logs a given printf()-like formatted string using an ANSI color code.
void zth_logv(char const *fmt, va_list arg)
Prints the given printf()-like formatted string to stdout.
void log_color(int color, char const *fmt,...)
Logs a given printf()-like formatted string using an ANSI color code.
void log_colorv(int color, char const *fmt, va_list args)
Logs a given printf()-like formatted string using an ANSI color code.
void abort(char const *fmt,...) noexcept
Aborts the process after printing the given printf() formatted message.
std::basic_string< char, std::char_traits< char >, Config::Allocator< char >::type > string
std::string type using Config::Allocator::type.
char const * banner() noexcept
Prints a banner line with version and configuration information.
void log(char const *fmt,...)
Logs a given printf()-like formatted string.
void logv(char const *fmt, va_list arg)
Logs a given printf()-like formatted string.
void abortv(char const *fmt, va_list args) noexcept
Aborts the process after printing the given printf() formatted message.
#define ZTH_TLS_DEFINE(type, var, init)
#define ZTH_TLS_MEMBER(type, var)
#define ZTH_TLS_SET(var, value)
cow_string str< string && >(string &&value)
cow_string str< char >(char value)
cow_string str< signed char >(signed char value)
cow_string str(T value)
Returns an zth::string representation of the given value.
cow_string str< unsigned int >(unsigned int value)
cow_string str< unsigned char >(unsigned char value)
cow_string str< int >(int value)
bool log_supports_ansi_colors() noexcept
Returns if the system supports ANSI colors.
cow_string str< long double >(long double value)
cow_string str< unsigned long >(unsigned long value)
string formatv(char const *fmt, va_list args)
Format like vsprintf(), but save the result in an zth::string.
cow_string str< long >(long value)
cow_string str< unsigned long long >(unsigned long long value)
string err(int e)
Return a string like strerror() does, but as a zth::string.
void assert_handler(char const *file, int line, char const *expr)
cow_string str< short >(short value)
cow_string str< long long >(long long value)
cow_string str< double >(double value)
string format(char const *fmt,...)
Format like sprintf(), but save the result in an zth::string.
cow_string str< float >(float value)
cow_string str< unsigned short >(unsigned short value)
The configuration of Zth.
std::vector type using Config::Allocator::type.
#define zth_assert(expr)
assert(), but better integrated in Zth.
#define ZTH_CLASS_NOCOPY(Class)
#define unlikely(expr)
Marks the given expression to likely be evaluated to true.