[libcxx-commits] [libcxx] [libc++] Add __pointer_int_pair (PR #94324)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Thu Jun 6 09:15:27 PDT 2024


================
@@ -0,0 +1,154 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___UTILITY_POINTER_INT_PAIR_H
+#define _LIBCPP___UTILITY_POINTER_INT_PAIR_H
+
+#include <__assert>
+#include <__bit/bit_log2.h>
+#include <__concepts/derived_from.h>
+#include <__config>
+#include <__tuple/tuple_element.h>
+#include <__tuple/tuple_size.h>
+#include <__type_traits/is_pointer.h>
+#include <__type_traits/is_unsigned.h>
+#include <__type_traits/is_void.h>
+#include <__type_traits/remove_pointer.h>
+#include <__utility/swap.h>
+#include <cstddef>
+#include <cstdint>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+#if _LIBCPP_STD_VER >= 23
+
+// A __pointer_int_pair is a pair of a pointer and an integral type. The lower bits of the pointer that are free
+// due to the alignment requirement of the pointee are used to store the integral type.
+//
+// This imposes a constraint on the number of bits available for the integral type -- the integral type can use
+// at most log2(alignof(T)) bits. This technique allows storing the integral type without additional storage
+// beyond that of the pointer itself, at the cost of some bit twiddling.
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class>
+struct _PointerLikeTraits;
+
+template <class _Tp>
+  requires(!is_void_v<_Tp>)
+struct _PointerLikeTraits<_Tp*> {
+  static constexpr size_t __low_bits_available = std::__bit_log2(alignof(_Tp));
+
+  static _LIBCPP_HIDE_FROM_ABI uintptr_t __to_uintptr(_Tp* __ptr) { return reinterpret_cast<uintptr_t>(__ptr); }
+  static _LIBCPP_HIDE_FROM_ABI _Tp* __to_pointer(uintptr_t __ptr) { return reinterpret_cast<_Tp*>(__ptr); }
+};
+
+template <class _Tp>
+  requires is_void_v<_Tp>
+struct _PointerLikeTraits<_Tp*> {
+  static constexpr size_t __low_bits_available = 0;
+
+  static _LIBCPP_HIDE_FROM_ABI uintptr_t __to_uintptr(_Tp* __ptr) { return reinterpret_cast<uintptr_t>(__ptr); }
+  static _LIBCPP_HIDE_FROM_ABI _Tp* __to_pointer(uintptr_t __ptr) { return reinterpret_cast<_Tp*>(__ptr); }
+};
+
+enum class __integer_width : size_t {};
+
+template <class _Pointer, class _IntType, __integer_width __int_bit_count>
+class __pointer_int_pair {
+  using _PointerTraits = _PointerLikeTraits<_Pointer>;
+
+  static constexpr auto __int_width = static_cast<size_t>(__int_bit_count);
+
+  static_assert(__int_width <= _PointerTraits::__low_bits_available,
+                "Not enough bits available for requested bit count");
+  static_assert(is_integral_v<_IntType>, "_IntType has to be an integral type");
+  static_assert(is_unsigned_v<_IntType>, "__pointer_int_pair doesn't work for signed types");
----------------
ldionne wrote:

```suggestion
  static_assert(is_unsigned_v<_IntType>, "__pointer_int_pair doesn't work for signed types since that would require handling the sign bit");
```

This will do the same job as a comment explaining why we don't bother support them.

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


More information about the libcxx-commits mailing list