26#define ZTH_STRINGIFY_(x) #x
30#define ZTH_STRINGIFY(x) ZTH_STRINGIFY_(x)
40# define likely(expr) \
41 __builtin_expect(!!(expr) , 1)
43# define likely(expr) (expr)
55# define unlikely(expr) \
56 __builtin_expect(!!(expr) , 0)
58# define unlikely(expr) (expr)
65#define ZTH_GET_MACRO_ARGN( \
66 _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, NAME, ...) \
70# define FOREACH_0(WHAT)
71# define FOREACH_1(WHAT, X) WHAT(X)
72# define FOREACH_2(WHAT, X, ...) \
73 WHAT(X) FOREACH_1(WHAT, __VA_ARGS__)
74# define FOREACH_3(WHAT, X, ...) \
75 WHAT(X) FOREACH_2(WHAT, __VA_ARGS__)
76# define FOREACH_4(WHAT, X, ...) \
77 WHAT(X) FOREACH_3(WHAT, __VA_ARGS__)
78# define FOREACH_5(WHAT, X, ...) \
79 WHAT(X) FOREACH_4(WHAT, __VA_ARGS__)
80# define FOREACH_6(WHAT, X, ...) \
81 WHAT(X) FOREACH_5(WHAT, __VA_ARGS__)
82# define FOREACH_7(WHAT, X, ...) \
83 WHAT(X) FOREACH_6(WHAT, __VA_ARGS__)
84# define FOREACH_8(WHAT, X, ...) \
85 WHAT(X) FOREACH_7(WHAT, __VA_ARGS__)
86# define FOREACH_9(WHAT, X, ...) \
87 WHAT(X) FOREACH_8(WHAT, __VA_ARGS__)
88# define FOREACH_10(WHAT, X, ...) \
89 WHAT(X) FOREACH_9(WHAT, __VA_ARGS__)
90# define FOREACH_11(WHAT, X, ...) \
91 WHAT(X) FOREACH_10(WHAT, __VA_ARGS__)
92# define FOREACH_12(WHAT, X, ...) \
93 WHAT(X) FOREACH_11(WHAT, __VA_ARGS__)
94# define FOREACH_13(WHAT, X, ...) \
95 WHAT(X) FOREACH_12(WHAT, __VA_ARGS__)
96# define FOREACH_14(WHAT, X, ...) \
97 WHAT(X) FOREACH_13(WHAT, __VA_ARGS__)
98# define FOREACH_15(WHAT, X, ...) \
99 WHAT(X) FOREACH_14(WHAT, __VA_ARGS__)
100# define FOREACH_16(WHAT, X, ...) \
101 WHAT(X) FOREACH_15(WHAT, __VA_ARGS__)
107# define FOREACH(action, ...) \
108 ZTH_GET_MACRO_ARGN( \
109 0, ##__VA_ARGS__, FOREACH_16, FOREACH_15, FOREACH_14, FOREACH_13, FOREACH_12, \
110 FOREACH_11, FOREACH_10, FOREACH_9, FOREACH_8, FOREACH_7, FOREACH_6, FOREACH_5, \
111 FOREACH_4, FOREACH_3, FOREACH_2, FOREACH_1, FOREACH_0) \
112 (action, ##__VA_ARGS__)
117# define REVERSE_1(a) a
118# define REVERSE_2(a, ...) REVERSE_1(__VA_ARGS__), a
119# define REVERSE_3(a, ...) REVERSE_2(__VA_ARGS__), a
120# define REVERSE_4(a, ...) REVERSE_3(__VA_ARGS__), a
121# define REVERSE_5(a, ...) REVERSE_4(__VA_ARGS__), a
122# define REVERSE_6(a, ...) REVERSE_5(__VA_ARGS__), a
123# define REVERSE_7(a, ...) REVERSE_6(__VA_ARGS__), a
124# define REVERSE_8(a, ...) REVERSE_7(__VA_ARGS__), a
125# define REVERSE_9(a, ...) REVERSE_8(__VA_ARGS__), a
126# define REVERSE_10(a, ...) REVERSE_9(__VA_ARGS__), a
127# define REVERSE_11(a, ...) REVERSE_10(__VA_ARGS__), a
128# define REVERSE_12(a, ...) REVERSE_11(__VA_ARGS__), a
129# define REVERSE_13(a, ...) REVERSE_12(__VA_ARGS__), a
130# define REVERSE_14(a, ...) REVERSE_13(__VA_ARGS__), a
131# define REVERSE_15(a, ...) REVERSE_14(__VA_ARGS__), a
132# define REVERSE_16(a, ...) REVERSE_15(__VA_ARGS__), a
133# define REVERSE(...) \
134 ZTH_GET_MACRO_ARGN( \
135 0, ##__VA_ARGS__, REVERSE_16, REVERSE_15, REVERSE_14, REVERSE_13, REVERSE_12, \
136 REVERSE_11, REVERSE_10, REVERSE_9, REVERSE_8, REVERSE_7, REVERSE_6, REVERSE_5, \
137 REVERSE_4, REVERSE_3, REVERSE_2, REVERSE_1, REVERSE_0) \
152# if __cplusplus >= 201103L
155# include <inttypes.h>
158# ifdef ZTH_HAVE_PTHREAD
162# ifdef ZTH_OS_WINDOWS
165# include <sys/types.h>
170zth_logv(
char const* fmt, va_list arg);
177# define ZTH_DBG_PREFIX " > "
189# define zth_dbg(group, fmt, a...) \
191 if(::zth::Config::SupportDebugPrint && ::zth::Config::Print_##group > 0 \
192 && zth_config(EnableDebugPrint)) { \
193 if(::zth::Config::EnableColorLog) \
195 ::zth::Config::Print_##group, \
196 ZTH_DBG_PREFIX "zth::" ZTH_STRINGIFY(group) ": " fmt \
201 ZTH_DBG_PREFIX "zth::" ZTH_STRINGIFY(group) ": " fmt \
212# define zth_assert(expr) \
214 if(unlikely(::zth::Config::EnableAssert && !(expr))) \
215 ::zth::assert_handler( \
216 __FILE__, __LINE__, \
217 ::zth::Config::EnableFullAssert ? ZTH_STRINGIFY(expr) \
221# define zth_assert(...) \
227# ifndef ZTH_CLASS_NOCOPY
228# if __cplusplus >= 201103L
229# define ZTH_CLASS_NOCOPY(Class) \
231 Class(Class const&) = delete; \
235 Class& operator=(Class const&) noexcept = delete; \
236 Class& operator=(Class&&) noexcept = \
241# define ZTH_CLASS_NOCOPY(Class) \
243 Class(Class const&); \
244 Class& operator=(Class const&);
252ZTH_EXPORT
char const* banner()
noexcept;
254ZTH_EXPORT __attribute__((format(
ZTH_ATTR_PRINTF, 1, 2), noreturn))
void
255abort(
char const* fmt, ...)
noexcept;
257ZTH_EXPORT __attribute__((format(
ZTH_ATTR_PRINTF, 1, 0), noreturn))
void
258abortv(
char const* fmt, va_list args)
noexcept;
260ZTH_EXPORT __attribute__((noreturn))
void
261assert_handler(
char const* file,
int line,
char const* expr);
263ZTH_EXPORT
bool log_supports_ansi_colors()
noexcept;
266log_colorv(
int color,
char const* fmt, va_list args);
274log_color(
int color,
char const* fmt, ...)
278 log_colorv(color, fmt, args);
289logv(
char const* fmt, va_list arg)
300ZTH_EXPORT __attribute__((format(
ZTH_ATTR_PRINTF, 1, 2)))
inline void log(
char const* fmt, ...)
312typedef std::basic_string<char, std::char_traits<char>, Config::Allocator<char>::type> string;
364# if __cplusplus >= 201103L
371 , m_str(
std::move(s))
377 m_str = std::move(s);
384 return std::move(
local());
393 char const*
c_str()
const
395 return m_cstr ? m_cstr : m_str.c_str();
398 operator string const&()
const
403 char const&
at(
size_t pos)
const
405 return str().at(pos);
410 return m_cstr ? m_cstr[pos] :
str()[pos];
418 char const*
data()
const
423 bool empty() const noexcept
425 return m_cstr ? *m_cstr == 0 : m_str.empty();
428 size_t size() const noexcept
433 size_t length() const noexcept
435 return str().length();
438 void clear() noexcept
446 return m_cstr !=
nullptr;
451 return m_cstr ==
nullptr;
455 string const&
local()
const
471 mutable char const* m_cstr;
472 mutable string m_str;
480__attribute__((format(
ZTH_ATTR_PRINTF, 1, 2))) inline
string format(
char const* fmt, ...)
484 string res =
formatv(fmt, args);
494inline cow_string
str(T value)
496 return cow_string(value);
502 return format(
"%c", value);
506inline cow_string str<signed char>(
signed char value)
508 if(Config::UseLimitedFormatSpecifiers)
509 return format(
"%d", (
int)value);
511 return format(
"%hhd", value);
515inline cow_string str<unsigned char>(
unsigned char value)
517 if(Config::UseLimitedFormatSpecifiers)
518 return format(
"%u", (
unsigned int)value);
520 return format(
"%hhu", value);
526 if(Config::UseLimitedFormatSpecifiers)
527 return format(
"%d", (
int)value);
529 return format(
"%hd", value);
533inline cow_string str<unsigned short>(
unsigned short value)
535 if(Config::UseLimitedFormatSpecifiers)
536 return format(
"%u", (
unsigned int)value);
538 return format(
"%hu", value);
544 return format(
"%d", value);
548inline cow_string str<unsigned int>(
unsigned int value)
550 return format(
"%u", value);
554ZTH_EXPORT
ZTH_INLINE cow_string strull(
unsigned long long value)
557 if(value > (
unsigned long long)std::numeric_limits<int>::max())
559 "0x%x%08x", (
unsigned)(value >> 32U),
560 (
unsigned)(value & 0xFFFFFFFFU));
562 return format(
"%d", (
int)value);
564 return format(
"%llu", value);
572 if(Config::UseLimitedFormatSpecifiers) {
573 if(
sizeof(
long) ==
sizeof(
int)
574 || (value <= std::numeric_limits<int>::max()
575 && value >= std::numeric_limits<int>::min()))
576 return format(
"%d", (
int)value);
578 return impl::strull((
unsigned long long)value);
580 return format(
"%ld", value);
585inline cow_string str<unsigned long>(
unsigned long value)
587 if(Config::UseLimitedFormatSpecifiers) {
588 if(
sizeof(
unsigned long) ==
sizeof(
unsigned int)
589 || value <= std::numeric_limits<unsigned int>::max())
590 return format(
"%u", (
unsigned int)value);
592 return impl::strull((
unsigned long long)value);
594 return format(
"%lu", value);
599inline cow_string str<long long>(
long long value)
601 if(Config::UseLimitedFormatSpecifiers) {
602 if(value > std::numeric_limits<int>::max()
603 || value < std::numeric_limits<int>::min())
604 return impl::strull((
unsigned long long)value);
606 return format(
"%d", (
int)value);
608 return format(
"%lld", value);
613inline cow_string str<unsigned long long>(
unsigned long long value)
615 return impl::strull(value);
619ZTH_EXPORT
ZTH_INLINE cow_string strf(
float value)
622 if(!(value < (
float)std::numeric_limits<int>::max()
623 && value > (
float)-std::numeric_limits<int>::max()))
628 if(std::abs(fi - value) < 0.0005F)
631 int f = std::min(std::abs((
int)((value - fi) * 1000.0F + 0.5F)), 999);
632 return format(
"%d.%03d", i, f);
634 return format(
"%g", (
double)value);
642 if(Config::UseLimitedFormatSpecifiers)
643 return impl::strf(value);
645 return format(
"%g", (
double)value);
651 if(Config::UseLimitedFormatSpecifiers)
652 return impl::strf((
float)value);
654 return format(
"%g", value);
658inline cow_string str<long double>(
long double value)
660 if(Config::UseLimitedFormatSpecifiers)
661 return impl::strf((
float)value);
663 return format(
"%Lg", value);
666# if __cplusplus >= 201103L
668inline cow_string str<string&&>(
string&& value)
677inline string err(
int e)
679# ifdef ZTH_OS_BAREMETAL
681 return format(
"error %d", e);
682# elif defined(ZTH_HAVE_LIBZMQ)
683 return format(
"%s (error %d)", zmq_strerror(e), e);
684# elif ZTH_THREADS && !defined(ZTH_OS_WINDOWS)
686# if !defined(ZTH_OS_LINUX) || (_POSIX_C_SOURCE >= 200112L) && !defined(_GNU_SOURCE)
688 return format(
"%s (error %d)", strerror_r(e, buf,
sizeof(buf)) ?
"Unknown error" : buf, e);
691 return format(
"%s (error %d)", strerror_r(e, buf,
sizeof(buf)), e);
695 return format(
"%s (error %d)", strerror(e), e);
716template <
typename T,
bool ThreadSafe = Config::EnableThreads>
717class UniqueID :
public UniqueIDBase {
718# if __cplusplus < 201103L
728 *
this = std::move(u);
734 m_name = std::move(u.m_name);
735 m_id_str = std::move(u.m_id_str);
743 static uint64_t getID() noexcept
746# if GCC_VERSION < 40802L
747 __sync_add_and_fetch(&m_nextId, 1)
749 __atomic_add_fetch(&m_nextId, 1, __ATOMIC_RELAXED)
754 explicit UniqueID(
string const& name)
759# if __cplusplus >= 201103L
762 , m_name(
std::move(name))
766 explicit UniqueID(
char const* name =
nullptr)
775 void const* normptr() const noexcept
780 __attribute__((pure)) uint64_t id() const noexcept
785 string const& name() const noexcept
790 void setName(
string const& name)
799 changedName(this->name());
802# if __cplusplus >= 201103L
805 m_name = std::move(name);
807 changedName(this->name());
811 virtual char const* id_str()
const override
815# ifdef ZTH_OS_BAREMETAL
818 format(
"%s #%u", name().empty() ?
"Object" : name().c_str(),
822 name().empty() ?
"Object" : name().c_str(),
823# ifdef ZTH_OS_WINDOWS
824 (
unsigned int)_getpid(),
826 (
unsigned int)getpid(),
835 return m_id_str.c_str();
839 virtual void changedName(
string const&
UNUSED_PAR(name)) {}
844 string mutable m_id_str;
847 static uint64_t m_nextId;
850template <
typename T,
bool ThreadSafe>
851uint64_t UniqueID<T, ThreadSafe>::m_nextId = 0;
853template <
typename T,
typename WhenTIsVo
id>
858template <
typename WhenTIsVo
id>
860 typedef WhenTIsVoid
type;
863# if __cplusplus >= 201103L
867template <
size_t N,
size_t... S>
868struct SequenceGenerator : SequenceGenerator<N - 1, N - 1, S...> {};
870template <
size_t... S>
871struct SequenceGenerator<0, S...> {
872 typedef Sequence<S...> type;
891 constexpr operator pointer_type*()
const noexcept
896 constexpr operator bool() const noexcept
901 constexpr14 pointer_type* operator->() const noexcept
907 constexpr14 pointer_type& operator*() const noexcept
981 if(m_instance ==
static_cast<singleton_type*
>(
this))
982 m_instance =
nullptr;
990 __attribute__((pure))
constexpr14 static typename safe_ptr<singleton_type>::type
998 static singleton_type* m_instance;
1001template <
typename T>
1013template <
typename T>
1014class ThreadLocalSingleton {
1040 if(
ZTH_TLS_GET(m_instance) ==
static_cast<singleton_type*
>(
this))
1049 __attribute__((pure))
static typename safe_ptr<singleton_type>::type instance() noexcept
1059template <
typename T>
1080template <typename T, int8_t Prealloc = 1, typename Allocator = typename Config::Allocator<T>::type>
1085 typedef std::vector<value_type, allocator_type>
vector_type;
1088 prealloc_request = Prealloc > 0 ? Prealloc : 0,
1089 prealloc_request_size = prealloc_request *
sizeof(
value_type),
1092 prealloc_request_size > vector_size ? prealloc_request_size : vector_size,
1103 static_assert(prealloc < std::numeric_limits<uint8_t>::max(),
"");
1114 vector().~vector_type();
1120 value_type& operator[](
size_t index)
noexcept
1123 return data()[index];
1129 value_type
const& operator[](
size_t index)
const noexcept
1132 return data()[index];
1140 value_type& front() noexcept
1150 value_type
const& front() const noexcept
1160 value_type& back() noexcept
1163 return (*
this)[size() - 1U];
1171 value_type
const& back() const noexcept
1174 return (*
this)[size() - 1U];
1180 value_type* data() noexcept
1182 return is_small() ? array() : vector().data();
1188 value_type
const* data() const noexcept
1190 return is_small() ? array() : vector().data();
1196 bool empty() const noexcept
1198 return is_small() ? m_size == 0 : vector().empty();
1204 size_t size() const noexcept
1206 return is_small() ? m_size : vector().size();
1214 void reserve(
size_t new_cap)
1216 if(is_small() && new_cap <= prealloc)
1220 make_vector(new_cap);
1222 vector().reserve(new_cap);
1229 size_t capacity() const noexcept
1231 return is_small() ? (size_t)prealloc : vector().capacity();
1239 void clear() noexcept
1250 void clear_and_release() noexcept
1264 void push_back(value_type
const& v)
1266 reserve(size() + 1U);
1268 if(m_size < prealloc) {
1269 new(&array()[m_size]) value_type(v);
1272 vector().push_back(v);
1275# if __cplusplus >= 201103L
1280 template <
class... Args>
1281 void emplace_back(Args&&... args)
1283 reserve(size() + 1U);
1285 if(m_size < prealloc) {
1286 new(&array()[m_size]) value_type(std::forward<Args>(args)...);
1289 vector().emplace_back(std::forward<Args>(args)...);
1298 void pop_back() noexcept
1302 array()[--m_size].~value_type();
1304 vector().pop_back();
1312 void resize(
size_t count, value_type
const& x = value_type())
1315 while(count < m_size)
1316 array()[--m_size].~value_type();
1318 if(count <= prealloc) {
1319 while(count > m_size) {
1320 new(&array()[m_size]) value_type(x);
1325 vector().resize(count, x);
1328 vector().resize(count, x);
1335 bool is_small() const noexcept
1337 return m_size <= prealloc;
1343 value_type* array() noexcept
1346 return reinterpret_cast<value_type*
>(m_buffer);
1352 value_type
const* array() const noexcept
1355 return reinterpret_cast<value_type const*
>(m_buffer);
1361 vector_type& vector() noexcept
1364 void* buffer = m_buffer;
1365 return *
reinterpret_cast<vector_type*
>(buffer);
1371 vector_type
const& vector() const noexcept
1374 void const* buffer = m_buffer;
1375 return *
reinterpret_cast<vector_type const*
>(buffer);
1381 void make_vector(
size_t new_cap)
1387 v.reserve(std::max(new_cap, (
size_t)m_size));
1389 for(
size_t i = 0; i < m_size; i++) {
1390# if __cplusplus >= 201103L
1391 v.emplace_back(std::move(array()[i]));
1393 v.push_back(array()[i]);
1395 array()[i].~value_type();
1398 m_size = prealloc + 1U;
1399 new(m_buffer) vector_type;
1408 alignas(vector_type)
alignas(value_type)
char m_buffer[buffer_size];
1420template <
size_t size>
1425 x >= 0x100000000ULL ? 8U
1426 : x >= 0x10000U ? 4U
1429struct smallest_uint {
1430 typedef uint64_t
type;
1433template <u
int64_t x>
1435 typedef uint8_t
type;
1438template <u
int64_t x>
1440 typedef uint16_t
type;
1443template <u
int64_t x>
1445 typedef uint32_t
type;
1484 va_start(args, fmt);
1503 va_start(args, fmt);
1511#ifdef ZTH_OS_BAREMETAL
1514EXTERN_C __attribute__((
format(gnu_printf, 2, 0))) int asprintf(
char** strp, const
char* fmt, ...);
1515EXTERN_C __attribute__((format(gnu_printf, 2, 0)))
int
1516vasprintf(
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.
char operator[](size_t pos) const
bool isConst() const noexcept
string const & local() const
char const & at(size_t pos) const
char const * c_str() const
size_t length() const noexcept
cow_string & operator=(cow_string const &s)
size_t size() const noexcept
char const * data() const
bool empty() const noexcept
bool isLocal() const noexcept
Wrapper for a pointer, which checks validity of the pointer upon dereference.
Change the name of a fiber returned by zth_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_colorv(int color, char const *fmt, va_list args)
Logs a given printf()-like formatted string using an ANSI color code.
char const * banner() noexcept
Prints a banner line with version and configuration information.
void logv(char const *fmt, va_list arg)
Logs a given printf()-like formatted string.
#define ZTH_TLS_DEFINE(type, var, init)
#define ZTH_TLS_MEMBER(type, var)
#define ZTH_TLS_SET(var, value)
cow_string str(T value)
Returns an zth::string representation of the given value.
string formatv(char const *fmt, va_list args)
Format like vsprintf(), but save the result in an zth::string.
string format(char const *fmt,...)
Format like sprintf(), but save the result in an zth::string.
static bool const UseLimitedFormatSpecifiers
Use limited formatting specifiers.
#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.