Zth (libzth)
util.h
Go to the documentation of this file.
1 #ifndef ZTH_UTIL_H
2 #define ZTH_UTIL_H
3 /*
4  * Zth (libzth), a cooperative userspace multitasking library.
5  * Copyright (C) 2019-2022 Jochem Rutgers
6  *
7  * This Source Code Form is subject to the terms of the Mozilla Public
8  * License, v. 2.0. If a copy of the MPL was not distributed with this
9  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
10  */
11 
21 #include <libzth/macros.h>
22 #include <libzth/config.h>
23 
28 #define ZTH_STRINGIFY_(x) #x
32 #define ZTH_STRINGIFY(x) ZTH_STRINGIFY_(x)
33 
40 #ifndef likely
41 # ifdef __GNUC__
42 # define likely(expr) __builtin_expect(!!(expr), 1)
43 # else
44 # define likely(expr) (expr)
45 # endif
46 #endif
47 
54 #ifndef unlikely
55 # ifdef __GNUC__
56 # define unlikely(expr) __builtin_expect(!!(expr), 0)
57 # else
58 # define unlikely(expr) (expr)
59 # endif
60 #endif
61 
62 #include <assert.h>
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]
66 #endif
67 
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, ...) \
71  NAME
72 
73 #ifndef FOREACH
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__)
106 //... repeat as needed
107 
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, \
116  FOREACH_0) \
117  (action, ##__VA_ARGS__)
118 #endif
119 
120 #ifndef REVERSE
121 # define REVERSE_0()
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, \
143  REVERSE_0) \
144  (__VA_ARGS__)
145 #endif
146 
147 #include <stdarg.h>
148 
149 #ifdef __cplusplus
150 # include <cstdio>
151 # include <cstdlib>
152 # include <cstring>
153 # include <limits>
154 # include <memory>
155 # include <string>
156 # include <vector>
157 
158 # if __cplusplus >= 201103L
159 # include <cinttypes>
160 # else
161 # include <inttypes.h>
162 # endif
163 
164 # ifdef ZTH_HAVE_PTHREAD
165 # include <pthread.h>
166 # endif
167 
168 # ifdef ZTH_OS_WINDOWS
169 # include <process.h>
170 # else
171 # include <sys/types.h>
172 # include <unistd.h>
173 # endif
174 
175 EXTERN_C ZTH_EXPORT __attribute__((format(ZTH_ATTR_PRINTF, 1, 0))) void
176 zth_logv(char const* fmt, va_list arg);
177 
178 # ifdef __cplusplus
183 # define ZTH_DBG_PREFIX " > "
184 
195 # define zth_dbg(group, fmt, a...) \
196  do { \
197  if(::zth::Config::SupportDebugPrint \
198  && ::zth::Config::Print_##group > 0 \
199  && zth_config(EnableDebugPrint)) { \
200  if(::zth::Config::EnableColorLog) \
201  ::zth::log_color( \
202  ::zth::Config::Print_##group, \
203  ZTH_DBG_PREFIX \
204  "zth::" ZTH_STRINGIFY(group) ": " fmt \
205  "\n", \
206  ##a); \
207  else \
208  ::zth::log( \
209  ZTH_DBG_PREFIX \
210  "zth::" ZTH_STRINGIFY(group) ": " fmt \
211  "\n", \
212  ##a); \
213  } \
214  } while(0)
215 
220 # ifndef NDEBUG
221 # define zth_assert(expr) \
222  do { \
223  if(unlikely(::zth::Config::EnableAssert && !(expr))) \
224  ::zth::assert_handler( \
225  __FILE__, __LINE__, \
226  ::zth::Config::EnableFullAssert \
227  ? ZTH_STRINGIFY(expr) \
228  : nullptr); \
229  } while(false)
230 # else
231 # define zth_assert(...) \
232  do { \
233  } while(0)
234 # endif
235 # endif
236 
237 # ifndef ZTH_CLASS_NOCOPY
238 # if __cplusplus >= 201103L
239 # define ZTH_CLASS_NOCOPY(Class) \
240  public: \
241  Class(Class const&) = delete; \
242  Class(Class&&) = \
243  delete; /* NOLINT(misc-macro-parentheses,bugprone-macro-parentheses) \
244  */ \
245  Class& operator=(Class const&) noexcept = delete; \
246  Class& operator=(Class&&) noexcept = \
247  delete; /* NOLINT(misc-macro-parentheses,bugprone-macro-parentheses) \
248  */ \
249  private:
250 # else
251 # define ZTH_CLASS_NOCOPY(Class) \
252  private: \
253  Class(Class const&); \
254  Class& operator=(Class const&);
255 # endif
256 # endif
257 
258 # include <libzth/zmq.h>
259 
260 namespace zth {
261 
262 ZTH_EXPORT char const* banner() noexcept;
263 
264 ZTH_EXPORT __attribute__((format(ZTH_ATTR_PRINTF, 1, 2), noreturn)) void
265 abort(char const* fmt, ...) noexcept;
266 
267 ZTH_EXPORT __attribute__((format(ZTH_ATTR_PRINTF, 1, 0), noreturn)) void
268 abortv(char const* fmt, va_list args) noexcept;
269 
270 ZTH_EXPORT __attribute__((noreturn)) void
271 assert_handler(char const* file, int line, char const* expr);
272 
273 ZTH_EXPORT bool log_supports_ansi_colors() noexcept;
274 
275 ZTH_EXPORT __attribute__((format(ZTH_ATTR_PRINTF, 2, 0))) void
276 log_colorv(int color, char const* fmt, va_list args);
277 
283 ZTH_EXPORT __attribute__((format(ZTH_ATTR_PRINTF, 2, 3))) inline void
284 log_color(int color, char const* fmt, ...)
285 {
286  va_list args;
287  va_start(args, fmt);
288  log_colorv(color, fmt, args);
289  va_end(args);
290 }
291 
298 ZTH_EXPORT __attribute__((format(ZTH_ATTR_PRINTF, 1, 0))) inline void
299 logv(char const* fmt, va_list arg)
300 {
301  ::zth_logv(fmt, arg);
302 }
303 
310 ZTH_EXPORT __attribute__((format(ZTH_ATTR_PRINTF, 1, 2))) inline void log(char const* fmt, ...)
311 {
312  va_list args;
313  va_start(args, fmt);
314  logv(fmt, args);
315  va_end(args);
316 }
317 
322 typedef std::basic_string<char, std::char_traits<char>, Config::Allocator<char>::type> string;
323 
331 class cow_string {
332 public:
333  cow_string()
334  : m_cstr()
335  {}
336 
337  // cppcheck-suppress noExplicitConstructor
338  cow_string(char const* s)
339  : m_cstr(s)
340  {}
341 
342  // cppcheck-suppress noExplicitConstructor
343  cow_string(string const& s)
344  : m_cstr()
345  , m_str(s)
346  {}
347 
348  cow_string(cow_string const& s)
349  {
350  *this = s;
351  }
352 
353  cow_string& operator=(cow_string const& s)
354  {
355  m_cstr = s.m_cstr;
356  m_str = s.m_str;
357  return *this;
358  }
359 
360  cow_string& operator=(char const* s)
361  {
362  m_cstr = s;
363  m_str.clear();
364  return *this;
365  }
366 
367  cow_string& operator=(string const& s)
368  {
369  m_cstr = nullptr;
370  m_str = s;
371  return *this;
372  }
373 
374 # if __cplusplus >= 201103L
375  cow_string(cow_string&& s) = default;
376  cow_string& operator=(cow_string&& s) = default;
377 
378  // cppcheck-suppress noExplicitConstructor
379  cow_string(string&& s)
380  : m_cstr()
381  , m_str(std::move(s))
382  {}
383 
384  cow_string& operator=(string&& s)
385  {
386  m_cstr = nullptr;
387  m_str = std::move(s);
388  return *this;
389  }
390 
391  string str() &&
392  {
393  // cppcheck-suppress returnStdMoveLocal
394  return std::move(local());
395  }
396 # endif
397 
398  string const& str() const LREF_QUALIFIED
399  {
400  return local();
401  }
402 
403  char const* c_str() const
404  {
405  return m_cstr ? m_cstr : m_str.c_str();
406  }
407 
408  operator string const &() const
409  {
410  return str();
411  }
412 
413  char const& at(size_t pos) const
414  {
415  return str().at(pos);
416  }
417 
418  char operator[](size_t pos) const
419  {
420  return m_cstr ? m_cstr[pos] : str()[pos];
421  }
422 
423  char& operator[](size_t pos)
424  {
425  return local()[pos];
426  }
427 
428  char const* data() const
429  {
430  return c_str();
431  }
432 
433  bool empty() const noexcept
434  {
435  return m_cstr ? *m_cstr == 0 : m_str.empty();
436  }
437 
438  size_t size() const noexcept
439  {
440  return str().size();
441  }
442 
443  size_t length() const noexcept
444  {
445  return str().length();
446  }
447 
448  void clear() noexcept
449  {
450  m_cstr = nullptr;
451  m_str.clear();
452  }
453 
454  bool isConst() const noexcept
455  {
456  return m_cstr != nullptr;
457  }
458 
459  bool isLocal() const noexcept
460  {
461  return m_cstr == nullptr;
462  }
463 
464 protected:
465  string const& local() const
466  {
467  if(unlikely(m_cstr)) {
468  m_str = m_cstr;
469  m_cstr = nullptr;
470  }
471  return m_str;
472  }
473 
474  string& local()
475  {
476  const_cast<cow_string const*>(this)->local();
477  return m_str;
478  }
479 
480 private:
481  mutable char const* m_cstr;
482  mutable string m_str;
483 };
484 
485 __attribute__((format(ZTH_ATTR_PRINTF, 1, 0))) string formatv(char const* fmt, va_list args);
486 
490 __attribute__((format(ZTH_ATTR_PRINTF, 1, 2))) inline string format(char const* fmt, ...)
491 {
492  va_list args;
493  va_start(args, fmt);
494  string res = formatv(fmt, args);
495  va_end(args);
496  return res;
497 }
498 
503 template <typename T>
504 inline cow_string str(T value)
505 {
506  return cow_string(value);
507 }
508 
509 template <>
510 inline cow_string str<char>(char value)
511 {
512  return format("%c", value);
513 }
514 
515 template <>
516 inline cow_string str<signed char>(signed char value)
517 {
518  return format("%hhd", value);
519 }
520 
521 template <>
522 inline cow_string str<unsigned char>(unsigned char value)
523 {
524  return format("%hhu", value);
525 }
526 
527 template <>
528 inline cow_string str<short>(short value)
529 {
530  return format("%hd", value);
531 }
532 
533 template <>
534 inline cow_string str<unsigned short>(unsigned short value)
535 {
536  return format("%hu", value);
537 }
538 
539 template <>
540 inline cow_string str<int>(int value)
541 {
542  return format("%d", value);
543 }
544 
545 template <>
546 inline cow_string str<unsigned int>(unsigned int value)
547 {
548  return format("%u", value);
549 }
550 
551 template <>
552 inline cow_string str<long>(long value)
553 {
554  return format("%ld", value);
555 }
556 
557 template <>
558 inline cow_string str<unsigned long>(unsigned long value)
559 {
560  return format("%lu", value);
561 }
562 
563 template <>
564 inline cow_string str<long long>(long long value)
565 {
566  return format("%lld", value);
567 }
568 
569 template <>
570 inline cow_string str<unsigned long long>(unsigned long long value)
571 {
572  return format("%llu", value);
573 }
574 
575 template <>
576 inline cow_string str<float>(float value)
577 {
578  return format("%g", (double)value);
579 }
580 
581 template <>
582 inline cow_string str<double>(double value)
583 {
584  return format("%g", value);
585 }
586 
587 template <>
588 inline cow_string str<long double>(long double value)
589 {
590  return format("%Lg", value);
591 }
592 
593 # if __cplusplus >= 201103L
594 template <>
595 inline cow_string str<string&&>(string&& value)
596 {
597  return cow_string(std::move(value));
598 }
599 # endif
600 
604 inline string err(int e)
605 {
606 # ifdef ZTH_OS_BAREMETAL
607  // You are probably low on memory. Don't include all strerror strings in the binary.
608  return format("error %d", e);
609 # elif defined(ZTH_HAVE_LIBZMQ)
610  return format("%s (error %d)", zmq_strerror(e), e);
611 # elif ZTH_THREADS && !defined(ZTH_OS_WINDOWS)
612  char buf[128];
613 # if !defined(ZTH_OS_LINUX) || (_POSIX_C_SOURCE >= 200112L) && !defined(_GNU_SOURCE)
614  // XSI-compatible
615  return format("%s (error %d)", strerror_r(e, buf, sizeof(buf)) ? "Unknown error" : buf, e);
616 # else
617  // GNU-specific
618  return format("%s (error %d)", strerror_r(e, buf, sizeof(buf)), e);
619 # endif
620 # else
621  // Not thread-safe
622  return format("%s (error %d)", strerror(e), e);
623 # endif
624 }
625 
626 class UniqueIDBase {
627 protected:
628  virtual char const* id_str() const = 0;
629  virtual ~UniqueIDBase() is_default
630  friend cow_string str<UniqueIDBase const&>(UniqueIDBase const&);
631 };
632 
633 template <>
634 inline cow_string str<UniqueIDBase const&>(UniqueIDBase const& value)
635 {
636  return cow_string(value.id_str());
637 }
638 
643 template <typename T, bool ThreadSafe = Config::EnableThreads>
644 class UniqueID : public UniqueIDBase {
645 # if __cplusplus < 201103L
647 # else
648 public:
649  UniqueID(UniqueID const&) = delete;
650  UniqueID& operator=(UniqueID const&) = delete;
651 
652  UniqueID(UniqueID&& u) noexcept
653  : m_id{}
654  {
655  *this = std::move(u);
656  }
657 
658  UniqueID& operator=(UniqueID&& u) noexcept
659  {
660  m_id = u.m_id;
661  m_name = std::move(u.m_name);
662  m_id_str = std::move(u.m_id_str);
663 
664  u.m_id = 0;
665 
666  return *this;
667  }
668 # endif
669 public:
670  static uint64_t getID() noexcept
671  {
672  return ThreadSafe ?
673 # if GCC_VERSION < 40802L
674  __sync_add_and_fetch(&m_nextId, 1)
675 # else
676  __atomic_add_fetch(&m_nextId, 1, __ATOMIC_RELAXED)
677 # endif
678  : ++m_nextId;
679  }
680 
681  explicit UniqueID(string const& name)
682  : m_id(getID())
683  , m_name(name)
684  {}
685 
686 # if __cplusplus >= 201103L
687  explicit UniqueID(string&& name)
688  : m_id(getID())
689  , m_name(std::move(name))
690  {}
691 # endif
692 
693  explicit UniqueID(char const* name = nullptr)
694  : m_id(getID())
695  {
696  if(name)
697  m_name = name;
698  }
699 
700  virtual ~UniqueID() is_default
701 
702  void const* normptr() const noexcept
703  {
704  return this;
705  }
706 
707  __attribute__((pure)) uint64_t id() const noexcept
708  {
709  return m_id;
710  }
711 
712  string const& name() const noexcept
713  {
714  return m_name;
715  }
716 
717  void setName(string const& name)
718  {
719  setName(name.c_str());
720  }
721 
722  void setName(char const* name)
723  {
724  m_name = name;
725  m_id_str.clear();
726  changedName(this->name());
727  }
728 
729 # if __cplusplus >= 201103L
730  void setName(string&& name)
731  {
732  m_name = std::move(name);
733  m_id_str.clear();
734  changedName(this->name());
735  }
736 # endif
737 
738  virtual char const* id_str() const override
739  {
740  if(unlikely(m_id_str.empty())) {
741  m_id_str =
742 # ifdef ZTH_OS_BAREMETAL
743  // No OS, no pid. And if newlib is used, don't try to format 64-bit
744  // ints.
745  format("%s #%u", name().empty() ? "Object" : name().c_str(),
746  (unsigned int)id());
747 # else
748  format("%s #%u:%" PRIu64,
749  name().empty() ? "Object" : name().c_str(),
750 # ifdef ZTH_OS_WINDOWS
751  (unsigned int)_getpid(),
752 # else
753  (unsigned int)getpid(),
754 # endif
755  id());
756 # endif
757  if(unlikely(m_id_str.empty()))
758  // Should not happen, but make sure the string is not empty.
759  m_id_str = "?";
760  }
761 
762  return m_id_str.c_str();
763  }
764 
765 private:
766  virtual void changedName(string const& UNUSED_PAR(name)) {}
767 
768 private:
769  uint64_t m_id;
770  string m_name;
771  string mutable m_id_str;
772  // If allocating once every ns, it takes more than 500 years until we run out of
773  // identifiers.
774  static uint64_t m_nextId;
775 };
776 
777 template <typename T, bool ThreadSafe>
778 uint64_t UniqueID<T, ThreadSafe>::m_nextId = 0;
779 
780 template <typename T, typename WhenTIsVoid>
781 struct choose_type {
782  typedef T type;
783 };
784 
785 template <typename WhenTIsVoid>
786 struct choose_type<void, WhenTIsVoid> {
787  typedef WhenTIsVoid type;
788 };
789 
790 # if __cplusplus >= 201103L
791 template <size_t...>
792 struct Sequence {};
793 # ifndef DOXYGEN
794 template <size_t N, size_t... S>
795 struct SequenceGenerator : SequenceGenerator<N - 1, N - 1, S...> {};
796 
797 template <size_t... S>
798 struct SequenceGenerator<0, S...> {
799  typedef Sequence<S...> type;
800 };
801 # endif
802 # endif
806 # ifdef _DEBUG
807 template <typename T>
808 class safe_ptr {
809 public:
810  typedef safe_ptr type;
811  typedef T pointer_type;
812 
813  // cppcheck-suppress noExplicitConstructor
814  constexpr safe_ptr(pointer_type* p) noexcept
815  : m_p(p)
816  {}
817 
818  constexpr operator pointer_type*() const noexcept
819  {
820  return ptr();
821  }
822 
823  constexpr operator bool() const noexcept
824  {
825  return ptr();
826  }
827 
828  constexpr14 pointer_type* operator->() const noexcept
829  {
830  zth_assert(ptr());
831  return ptr();
832  }
833 
834  constexpr14 pointer_type& operator*() const noexcept
835  {
836  zth_assert(ptr());
837  // cppcheck-suppress nullPointerRedundantCheck
838  return *ptr();
839  }
840 
841 protected:
842  constexpr pointer_type* ptr() const noexcept
843  {
844  return m_p;
845  }
846 
847 private:
848  pointer_type* m_p;
849 };
850 # else // _DEBUG
851 
852 // No checking, use use the pointer.
853 template <typename T>
854 class safe_ptr {
855 public:
856  typedef T* type;
857 };
858 # endif // !_DEBUG
859 
882 template <typename T>
883 class Singleton {
884 public:
886  typedef T singleton_type;
887 
888 protected:
893  constexpr14 Singleton() noexcept
894  {
895  // Do not enforce construction of only one Singleton, only register the first one
896  // as 'the' instance.
897 
898  if(!m_instance)
899  m_instance = static_cast<singleton_type*>(this);
900  }
901 
907  {
908  if(m_instance == static_cast<singleton_type*>(this))
909  m_instance = nullptr;
910  }
911 
912 public:
917  __attribute__((pure)) constexpr14 static typename safe_ptr<singleton_type>::type
918  instance() noexcept
919  {
920  return m_instance;
921  }
922 
923 private:
925  static singleton_type* m_instance;
926 };
927 
928 template <typename T>
929 typename Singleton<T>::singleton_type* Singleton<T>::m_instance = nullptr;
930 
940 template <typename T>
941 class ThreadLocalSingleton {
942 public:
944  typedef T singleton_type;
945 
946 protected:
952  __attribute__((no_sanitize_undefined)) ThreadLocalSingleton()
953  {
954  // Do not enforce construction of only one Singleton, only register the first one
955  // as 'the' instance.
956 
957  if(!ZTH_TLS_GET(m_instance))
958  ZTH_TLS_SET(m_instance, static_cast<singleton_type*>(this));
959  }
960 
965  __attribute__((no_sanitize_undefined)) ~ThreadLocalSingleton()
966  {
967  if(ZTH_TLS_GET(m_instance) == static_cast<singleton_type*>(this))
968  ZTH_TLS_SET(m_instance, nullptr);
969  }
970 
971 public:
976  __attribute__((pure)) static typename safe_ptr<singleton_type>::type instance() noexcept
977  {
978  return ZTH_TLS_GET(m_instance);
979  }
980 
981 private:
983  ZTH_TLS_MEMBER(singleton_type*, m_instance)
984 };
985 
986 template <typename T>
988  typename ThreadLocalSingleton<T>::singleton_type*, ThreadLocalSingleton<T>::m_instance,
989  nullptr)
990 
991 
1007 template <typename T, int8_t Prealloc = 1, typename Allocator = typename Config::Allocator<T>::type>
1008 class small_vector {
1009 public:
1010  typedef T value_type;
1011  typedef Allocator allocator_type;
1012  typedef std::vector<value_type, allocator_type> vector_type;
1013 
1014  enum { prealloc_request = Prealloc > 0 ? Prealloc : 0,
1015  prealloc_request_size = prealloc_request * sizeof(value_type),
1016  vector_size = sizeof(vector_type),
1017  buffer_size =
1018  prealloc_request_size > vector_size ? prealloc_request_size : vector_size,
1019  prealloc = buffer_size / sizeof(value_type),
1020  };
1025  // cppcheck-suppress uninitMemberVar
1026  constexpr small_vector() noexcept
1027  : m_size()
1028  {
1029  static_assert(prealloc < std::numeric_limits<uint8_t>::max(), "");
1030  }
1031 
1035  ~small_vector()
1036  {
1037  if(is_small())
1038  resize(0);
1039  else
1040  vector().~vector_type();
1041  }
1042 
1046  value_type& operator[](size_t index) noexcept
1047  {
1048  zth_assert(index < size());
1049  return data()[index];
1050  }
1051 
1055  value_type const& operator[](size_t index) const noexcept
1056  {
1057  zth_assert(index < size());
1058  return data()[index];
1059  }
1060 
1066  value_type& front() noexcept
1067  {
1068  return (*this)[0];
1069  }
1070 
1076  value_type const& front() const noexcept
1077  {
1078  return (*this)[0];
1079  }
1080 
1086  value_type& back() noexcept
1087  {
1088  zth_assert(!empty());
1089  return (*this)[size() - 1u];
1090  }
1091 
1097  value_type const& back() const noexcept
1098  {
1099  zth_assert(!empty());
1100  return (*this)[size() - 1u];
1101  }
1102 
1106  value_type* data() noexcept
1107  {
1108  return is_small() ? array() : vector().data();
1109  }
1114  value_type const* data() const noexcept
1115  {
1116  return is_small() ? array() : vector().data();
1117  }
1118 
1122  bool empty() const noexcept
1123  {
1124  return is_small() ? m_size == 0 : vector().empty();
1125  }
1126 
1130  size_t size() const noexcept
1131  {
1132  return is_small() ? m_size : vector().size();
1133  }
1134 
1140  void reserve(size_t new_cap)
1141  {
1142  if(is_small() && new_cap <= prealloc)
1143  return;
1144 
1145  if(is_small())
1146  make_vector(new_cap);
1147 
1148  vector().reserve(new_cap);
1149  }
1150 
1155  size_t capacity() const noexcept
1156  {
1157  return is_small() ? (size_t)prealloc : vector().capacity();
1158  }
1159 
1165  void clear() noexcept
1166  {
1167  if(is_small())
1168  resize(0);
1169  else
1170  vector().clear();
1171  }
1172 
1176  void clear_and_release() noexcept
1177  {
1178  if(is_small()) {
1179  resize(0);
1180  } else {
1181  vector_type v;
1182  v.swap(vector());
1183  }
1184  }
1185 
1190  void push_back(value_type const& v)
1191  {
1192  reserve(size() + 1u);
1193 
1194  if(m_size < prealloc) {
1195  new(&array()[m_size]) value_type(v);
1196  m_size++;
1197  } else
1198  vector().push_back(v);
1199  }
1200 
1201 # if __cplusplus >= 201103L
1206  template <class... Args>
1207  void emplace_back(Args&&... args)
1208  {
1209  reserve(size() + 1u);
1210 
1211  if(m_size < prealloc) {
1212  new(&array()[m_size]) value_type(std::forward<Args>(args)...);
1213  m_size++;
1214  } else
1215  vector().emplace_back(std::forward<Args>(args)...);
1216  }
1217 # endif
1218 
1224  void pop_back() noexcept
1225  {
1226  zth_assert(!empty());
1227  if(is_small())
1228  array()[--m_size].~value_type();
1229  else
1230  vector().pop_back();
1231  }
1232 
1238  void resize(size_t count, value_type const& x = value_type())
1239  {
1240  if(is_small()) {
1241  while(count < m_size)
1242  array()[--m_size].~value_type();
1243 
1244  if(count <= prealloc) {
1245  while(count > m_size) {
1246  new(&array()[m_size]) value_type(x);
1247  m_size++;
1248  }
1249  } else {
1250  make_vector(count);
1251  vector().resize(count, x);
1252  }
1253  } else
1254  vector().resize(count, x);
1255  }
1256 
1257 protected:
1261  bool is_small() const noexcept
1262  {
1263  return m_size <= prealloc;
1264  }
1265 
1269  value_type* array() noexcept
1270  {
1271  zth_assert(is_small());
1272  return reinterpret_cast<value_type*>(m_buffer);
1273  }
1278  value_type const* array() const noexcept
1279  {
1280  zth_assert(is_small());
1281  return reinterpret_cast<value_type const*>(m_buffer);
1282  }
1283 
1287  vector_type& vector() noexcept
1288  {
1289  zth_assert(!is_small());
1290  void* buffer = m_buffer;
1291  return *reinterpret_cast<vector_type*>(buffer);
1292  }
1293 
1297  vector_type const& vector() const noexcept
1298  {
1299  zth_assert(!is_small());
1300  void const* buffer = m_buffer;
1301  return *reinterpret_cast<vector_type const*>(buffer);
1302  }
1303 
1307  void make_vector(size_t new_cap)
1308  {
1309  if(!is_small())
1310  return;
1311 
1312  vector_type v;
1313  v.reserve(std::max(new_cap, (size_t)m_size));
1314 
1315  for(size_t i = 0; i < m_size; i++) {
1316 # if __cplusplus >= 201103L
1317  v.emplace_back(std::move(array()[i]));
1318 # else
1319  v.push_back(array()[i]);
1320 # endif
1321  array()[i].~value_type();
1322  }
1323 
1324  m_size = prealloc + 1u;
1325  new(m_buffer) vector_type;
1326  vector().swap(v);
1327  }
1328 
1329 private:
1334  alignas(vector_type) alignas(value_type) char m_buffer[buffer_size];
1335 
1343  uint8_t m_size;
1344 };
1345 
1346 template <size_t size>
1347 struct smallest_uint_size {};
1348 
1349 template <
1350  uint64_t x,
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;
1355 };
1356 
1357 template <uint64_t x>
1358 struct smallest_uint<x, smallest_uint_size<1> > {
1359  typedef uint8_t type;
1360 };
1361 
1362 template <uint64_t x>
1363 struct smallest_uint<x, smallest_uint_size<2> > {
1364  typedef uint16_t type;
1365 };
1366 
1367 template <uint64_t x>
1368 struct smallest_uint<x, smallest_uint_size<4> > {
1369  typedef uint32_t type;
1370 };
1372 } // namespace zth
1373 
1374 #endif // __cplusplus
1375 
1381 #ifdef __cplusplus
1382 EXTERN_C ZTH_EXPORT ZTH_INLINE void zth_banner()
1383 {
1384  zth::banner();
1385 }
1386 #else
1387 ZTH_EXPORT void zth_banner();
1388 #endif
1389 
1395 ZTH_EXPORT __attribute__((format(ZTH_ATTR_PRINTF, 1, 2), noreturn)) void
1396 zth_abort(char const* fmt, ...);
1397 
1403 #ifdef __cplusplus
1404 EXTERN_C ZTH_EXPORT ZTH_INLINE __attribute__((format(ZTH_ATTR_PRINTF, 2, 3))) void
1405 zth_log_color(int color, char const* fmt, ...)
1406 {
1407  va_list args;
1408  va_start(args, fmt);
1409  zth::log_colorv(color, fmt, args);
1410  va_end(args);
1411 }
1412 #else
1413 ZTH_EXPORT __attribute__((format(ZTH_ATTR_PRINTF, 2, 3))) void
1414 zth_log_color(int color, char const* fmt, ...);
1415 #endif
1416 
1422 #ifdef __cplusplus
1423 EXTERN_C ZTH_EXPORT ZTH_INLINE __attribute__((format(ZTH_ATTR_PRINTF, 1, 2))) void
1424 zth_log(char const* fmt, ...)
1425 {
1426  va_list args;
1427  va_start(args, fmt);
1428  zth::logv(fmt, args);
1429  va_end(args);
1430 }
1431 #else
1432 ZTH_EXPORT __attribute__((format(ZTH_ATTR_PRINTF, 1, 2))) void zth_log(char const* fmt, ...);
1433 #endif
1434 
1435 #ifdef ZTH_OS_BAREMETAL
1436 // newlib probably doesn't have these. Provide some default implementation for
1437 // them.
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);
1441 #endif
1442 
1443 #endif // ZTH_UTIL_H
Singleton pattern.
Definition: util.h:896
T singleton_type
Alias of the T template parameter.
Definition: util.h:899
Singleton pattern, but only per-thread.
Definition: util.h:954
T singleton_type
Alias of the T template parameter.
Definition: util.h:957
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.
Definition: util.h:657
void setName(string const &name)
Definition: util.h:730
Copy-on-write string.
Definition: util.h:344
char operator[](size_t pos) const
Definition: util.h:431
string str() &&
Definition: util.h:404
bool isConst() const noexcept
Definition: util.h:467
char const * data() const
Definition: util.h:441
string const & local() const
Definition: util.h:478
cow_string & operator=(cow_string const &s)
Definition: util.h:366
size_t length() const noexcept
Definition: util.h:456
size_t size() const noexcept
Definition: util.h:451
char const * c_str() const
Definition: util.h:416
void clear() noexcept
Definition: util.h:461
bool empty() const noexcept
Definition: util.h:446
char const & at(size_t pos) const
Definition: util.h:426
bool isLocal() const noexcept
Definition: util.h:472
Wrapper for a pointer, which checks validity of the pointer upon dereference.
Definition: util.h:821
T pointer_type
Definition: util.h:824
Change the name of a fiber returned by async.
Definition: async.h:167
A simple std::vector, which can contain Prealloc without heap allocation.
Definition: util.h:1021
std::vector< value_type, allocator_type > vector_type
Definition: util.h:1025
void zth_banner()
Prints a banner line with version and configuration information.
Definition: util.h:1395
void zth_log(char const *fmt,...)
Logs a given printf()-like formatted string.
Definition: util.h:1437
void zth_abort(char const *fmt,...)
Aborts the process after printing the given printf() formatted message.
Definition: util.cpp:280
void zth_log_color(int color, char const *fmt,...)
Logs a given printf()-like formatted string using an ANSI color code.
Definition: util.h:1418
void zth_logv(char const *fmt, va_list arg)
Prints the given printf()-like formatted string to stdout.
Definition: zth_logv.cpp:20
void log_color(int color, char const *fmt,...)
Logs a given printf()-like formatted string using an ANSI color code.
Definition: util.h:297
void log_colorv(int color, char const *fmt, va_list args)
Logs a given printf()-like formatted string using an ANSI color code.
Definition: util.cpp:221
void abort(char const *fmt,...) noexcept
Aborts the process after printing the given printf() formatted message.
Definition: util.cpp:130
std::basic_string< char, std::char_traits< char >, Config::Allocator< char >::type > string
std::string type using Config::Allocator::type.
Definition: util.h:335
char const * banner() noexcept
Prints a banner line with version and configuration information.
Definition: util.cpp:34
void log(char const *fmt,...)
Logs a given printf()-like formatted string.
Definition: util.h:323
void logv(char const *fmt, va_list arg)
Logs a given printf()-like formatted string.
Definition: util.h:312
void abortv(char const *fmt, va_list args) noexcept
Aborts the process after printing the given printf() formatted message.
Definition: util.cpp:142
#define constexpr14
Definition: macros.h:201
#define ZTH_TLS_DEFINE(type, var, init)
Definition: macros.h:56
#define ZTH_TLS_GET(var)
Definition: macros.h:60
#define is_default
Definition: macros.h:205
#define ZTH_TLS_MEMBER(type, var)
Definition: macros.h:58
#define ZTH_TLS_SET(var, value)
Definition: macros.h:59
#define LREF_QUALIFIED
Definition: macros.h:208
#define ZTH_ATTR_PRINTF
Definition: macros.h:66
#define ZTH_INLINE
Definition: macros.h:130
#define UNUSED_PAR(name)
Definition: macros.h:79
Definition: allocator.h:23
cow_string str< string && >(string &&value)
Definition: util.h:608
cow_string str< char >(char value)
Definition: util.h:523
cow_string str< signed char >(signed char value)
Definition: util.h:529
cow_string str(T value)
Returns an zth::string representation of the given value.
Definition: util.h:517
cow_string str< unsigned int >(unsigned int value)
Definition: util.h:559
cow_string str< unsigned char >(unsigned char value)
Definition: util.h:535
cow_string str< int >(int value)
Definition: util.h:553
bool log_supports_ansi_colors() noexcept
Returns if the system supports ANSI colors.
Definition: util.cpp:179
cow_string str< long double >(long double value)
Definition: util.h:601
cow_string str< unsigned long >(unsigned long value)
Definition: util.h:571
string formatv(char const *fmt, va_list args)
Format like vsprintf(), but save the result in an zth::string.
Definition: util.cpp:238
cow_string str< long >(long value)
Definition: util.h:565
cow_string str< unsigned long long >(unsigned long long value)
Definition: util.h:583
string err(int e)
Return a string like strerror() does, but as a zth::string.
Definition: util.h:617
void assert_handler(char const *file, int line, char const *expr)
Definition: assert.cpp:17
cow_string str< short >(short value)
Definition: util.h:541
cow_string str< long long >(long long value)
Definition: util.h:577
cow_string str< double >(double value)
Definition: util.h:595
string format(char const *fmt,...)
Format like sprintf(), but save the result in an zth::string.
Definition: util.h:503
cow_string str< float >(float value)
Definition: util.h:589
cow_string str< unsigned short >(unsigned short value)
Definition: util.h:547
The configuration of Zth.
Definition: zth_config.h:22
std::allocator< T > type
Definition: config.h:193
std::vector type using Config::Allocator::type.
Definition: allocator.h:133
#define zth_assert(expr)
assert(), but better integrated in Zth.
Definition: util.h:236
#define ZTH_CLASS_NOCOPY(Class)
Definition: util.h:254
#define unlikely(expr)
Marks the given expression to likely be evaluated to true.
Definition: util.h:56