[libcxx-commits] [libcxx] [libc++] Consolidate ordering/hashing/formatting of std::thread::id. (PR #195763)

Petr Hosek via libcxx-commits libcxx-commits at lists.llvm.org
Tue May 5 00:20:56 PDT 2026


================
@@ -35,24 +39,70 @@ template <>
 struct hash<__thread_id>;
 
 class __thread_id {
-  // FIXME: pthread_t is a pointer on Darwin but a long on Linux.
-  // NULL is the no-thread value on Darwin.  Someone needs to check
-  // on other platforms.  We assume 0 works everywhere for now.
   __libcpp_thread_id __id_;
 
-  static _LIBCPP_HIDE_FROM_ABI bool
-  __lt_impl(__thread_id __x, __thread_id __y) _NOEXCEPT { // id==0 is always less than any other thread_id
+  // Even though __libcpp_thread_id is provided by underlying threading implementation
+  // (e.g. C11, pthreads, or Windows) its type may still be unspecified. E.g. for pthreads
+  // implementation __libcpp_thread_id is an alias for pthread_t, which is left unspecified
+  // in POSIX. Typically it's either an integral type (glibc) or a pointer (Apple systems),
+  // but it can also be an opaque type on some systems / libc implementations.
+  //
+  // Note that in order to satisfy standard requirements on std::thread::id, we need:
+  // * strong total order
+  // * formatter support
+  // * std::hash implementation
+  // Currently, we can implement all of the above only on pointer and integral types.
+  using _Tp = __libcpp_thread_id;
+  static_assert(is_pointer<_Tp>::value || is_integral<_Tp>::value,
+                "unsupported thread::id type, please file a bug report");
+
+  // Strong total order implementation.
+  // Here we provide a best-effort implementation of strong total order, comparing
+  // integral types as-is and routing pointers through uintptr_t for a well-defined comparison.
+  template <typename Thr, typename enable_if<is_pointer<typename Thr::_Tp>::value, int>::type = 0>
+  static _LIBCPP_HIDE_FROM_ABI bool __eq_impl(Thr __x, Thr __y) _NOEXCEPT {
+    return reinterpret_cast<uintptr_t>(__x.__id_) == reinterpret_cast<uintptr_t>(__y.__id_);
+  }
+  template <typename Thr, typename enable_if<is_integral<typename Thr::_Tp>::value, int>::type = 0>
+  static _LIBCPP_HIDE_FROM_ABI bool __eq_impl(Thr __x, Thr __y) _NOEXCEPT {
+    return __x.__id_ == __y.__id_;
+  }
+
+  template <typename Thr, typename enable_if<is_pointer<typename Thr::_Tp>::value, int>::type = 0>
+  static _LIBCPP_HIDE_FROM_ABI bool __lt_impl(Thr __x, Thr __y) _NOEXCEPT {
+    return reinterpret_cast<uintptr_t>(__x.__id_) < reinterpret_cast<uintptr_t>(__y.__id_);
+  }
+  template <typename Thr, typename enable_if<is_integral<typename Thr::_Tp>::value, int>::type = 0>
+  static _LIBCPP_HIDE_FROM_ABI bool __lt_impl(Thr __x, Thr __y) _NOEXCEPT {
+    // For integral thread IDs, assume 0 is always less than any other thread_id.
     if (__x.__id_ == 0)
       return __y.__id_ != 0;
     if (__y.__id_ == 0)
       return false;
----------------
petrhosek wrote:

Could we instead sink this logic into `__libcpp_thread_id_less` to avoid the assumption of `__libcpp_thread_id` being integral?

https://github.com/llvm/llvm-project/pull/195763


More information about the libcxx-commits mailing list