althreads.h 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. #ifndef AL_THREADS_H
  2. #define AL_THREADS_H
  3. #include <cstdint>
  4. #include <stdexcept>
  5. #include <type_traits>
  6. #ifdef _WIN32
  7. #define WIN32_LEAN_AND_MEAN
  8. #include <windows.h>
  9. #elif defined(__STDC_NO_THREADS__) || !__has_include(<threads.h>)
  10. #include <pthread.h>
  11. #else
  12. #include <threads.h>
  13. #endif
  14. #include "albit.h"
  15. namespace al {
  16. template<typename T>
  17. class tss {
  18. static_assert(sizeof(T) <= sizeof(void*));
  19. static_assert(std::is_trivially_destructible_v<T> && std::is_trivially_copy_constructible_v<T>);
  20. [[nodiscard]]
  21. static auto to_ptr(const T &value) noexcept -> void*
  22. {
  23. if constexpr(std::is_pointer_v<T>)
  24. {
  25. if constexpr(std::is_const_v<std::remove_pointer_t<T>>)
  26. return const_cast<void*>(static_cast<const void*>(value)); /* NOLINT(*-const-cast) */
  27. else
  28. return static_cast<void*>(value);
  29. }
  30. else if constexpr(sizeof(T) == sizeof(void*))
  31. return al::bit_cast<void*>(value);
  32. else if constexpr(std::is_integral_v<T>)
  33. return al::bit_cast<void*>(static_cast<std::uintptr_t>(value));
  34. }
  35. [[nodiscard]]
  36. static auto from_ptr(void *ptr) noexcept -> T
  37. {
  38. if constexpr(std::is_pointer_v<T>)
  39. return static_cast<T>(ptr);
  40. else if constexpr(sizeof(T) == sizeof(void*))
  41. return al::bit_cast<T>(ptr);
  42. else if constexpr(std::is_integral_v<T>)
  43. return static_cast<T>(al::bit_cast<std::uintptr_t>(ptr));
  44. }
  45. #ifdef _WIN32
  46. DWORD mTss{TLS_OUT_OF_INDEXES};
  47. public:
  48. tss() : mTss{TlsAlloc()}
  49. {
  50. if(mTss == TLS_OUT_OF_INDEXES)
  51. throw std::runtime_error{"al::tss::tss()"};
  52. }
  53. explicit tss(const T &init) : tss{}
  54. {
  55. if(TlsSetValue(mTss, to_ptr(init)) == FALSE)
  56. throw std::runtime_error{"al::tss::tss(T)"};
  57. }
  58. ~tss() { TlsFree(mTss); }
  59. void set(const T &value) const
  60. {
  61. if(TlsSetValue(mTss, to_ptr(value)) == FALSE)
  62. throw std::runtime_error{"al::tss::set(T)"};
  63. }
  64. [[nodiscard]]
  65. auto get() const noexcept -> T { return from_ptr(TlsGetValue(mTss)); }
  66. #elif defined(__STDC_NO_THREADS__) || !__has_include(<threads.h>)
  67. pthread_key_t mTss{};
  68. public:
  69. tss()
  70. {
  71. if(int res{pthread_key_create(&mTss, nullptr)}; res != 0)
  72. throw std::runtime_error{"al::tss::tss()"};
  73. }
  74. explicit tss(const T &init) : tss{}
  75. {
  76. if(int res{pthread_setspecific(mTss, to_ptr(init))}; res != 0)
  77. throw std::runtime_error{"al::tss::tss(T)"};
  78. }
  79. ~tss() { pthread_key_delete(mTss); }
  80. void set(const T &value) const
  81. {
  82. if(int res{pthread_setspecific(mTss, to_ptr(value))}; res != 0)
  83. throw std::runtime_error{"al::tss::set(T)"};
  84. }
  85. [[nodiscard]]
  86. auto get() const noexcept -> T { return from_ptr(pthread_getspecific(mTss)); }
  87. #else
  88. tss_t mTss{};
  89. public:
  90. tss()
  91. {
  92. if(int res{tss_create(&mTss, nullptr)}; res != thrd_success)
  93. throw std::runtime_error{"al::tss::tss()"};
  94. }
  95. explicit tss(const T &init) : tss{}
  96. {
  97. if(int res{tss_set(mTss, to_ptr(init))}; res != thrd_success)
  98. throw std::runtime_error{"al::tss::tss(T)"};
  99. }
  100. ~tss() { tss_delete(mTss); }
  101. void set(const T &value) const
  102. {
  103. if(int res{tss_set(mTss, to_ptr(value))}; res != thrd_success)
  104. throw std::runtime_error{"al::tss::set(T)"};
  105. }
  106. [[nodiscard]]
  107. auto get() const noexcept -> T { return from_ptr(tss_get(mTss)); }
  108. #endif /* _WIN32 */
  109. tss(const tss&) = delete;
  110. tss(tss&&) = delete;
  111. void operator=(const tss&) = delete;
  112. void operator=(tss&&) = delete;
  113. };
  114. } // namespace al
  115. #endif /* AL_THREADS_H */