Make status implementation more correct wrt type punning

This commit is contained in:
2025-03-18 22:31:59 +01:00
parent a7475b6af2
commit 4884b59433
5 changed files with 26 additions and 18 deletions

View File

@ -35,6 +35,13 @@ template<typename T, typename U>
return static_cast<return_type>(x); return static_cast<return_type>(x);
} }
template<typename T>
[[nodiscard]] constexpr T* launder(T* ptr) noexcept // NOLINT
requires (!asl::is_func<T> && !asl::is_void<T>)
{
return __builtin_launder(ptr);
}
} // namespace std } // namespace std
namespace asl namespace asl

View File

@ -110,7 +110,9 @@ private:
constexpr void set_size_inline(isize_t new_size) constexpr void set_size_inline(isize_t new_size)
{ {
ASL_ASSERT(new_size >= 0 && new_size <= kInlineCapacity); ASL_ASSERT(new_size >= 0 && new_size <= kInlineCapacity);
const size_t size_encoded = (load_size_encoded() & size_t{0x00ff'ffff'ffff'ffff}) | (bit_cast<size_t>(new_size) << 56U); const size_t size_encoded =
(load_size_encoded() & size_t{0x00ff'ffff'ffff'ffff})
| (bit_cast<size_t>(new_size) << 56U);
store_size_encoded(size_encoded); store_size_encoded(size_encoded);
} }

View File

@ -15,7 +15,7 @@ using Allocator = asl::DefaultAllocator;
// NOLINTNEXTLINE(*-non-const-global-variables) // NOLINTNEXTLINE(*-non-const-global-variables)
static Allocator g_allocator{}; static Allocator g_allocator{};
namespace namespace asl
{ {
struct StatusInternal struct StatusInternal
@ -33,7 +33,7 @@ struct StatusInternal
} }
}; };
} // anonymous namespace } // namespace asl
asl::status::status(status_code code, string_view msg) asl::status::status(status_code code, string_view msg)
: m_payload{alloc_new<StatusInternal>(g_allocator, msg, code)} : m_payload{alloc_new<StatusInternal>(g_allocator, msg, code)}
@ -49,34 +49,29 @@ asl::status::status(status_code code, string_view fmt, span<format_internals::ty
asl::status_code asl::status::code_internal() const asl::status_code asl::status::code_internal() const
{ {
ASL_ASSERT(!is_inline()); ASL_ASSERT(!is_inline());
// NOLINTNEXTLINE(*-reinterpret-cast) return m_payload->code;
return reinterpret_cast<const StatusInternal*>(m_payload)->code;
} }
asl::string_view asl::status::message_internal() const asl::string_view asl::status::message_internal() const
{ {
ASL_ASSERT(!is_inline()); ASL_ASSERT(!is_inline());
// NOLINTNEXTLINE(*-reinterpret-cast) return m_payload->msg;
return reinterpret_cast<const StatusInternal*>(m_payload)->msg;
} }
void asl::status::ref() void asl::status::ref()
{ {
ASL_ASSERT(!is_inline()); ASL_ASSERT(!is_inline());
// NOLINTNEXTLINE(*-reinterpret-cast) atomic_fetch_increment(&m_payload->ref_count, memory_order::relaxed);
auto* internal = reinterpret_cast<StatusInternal*>(m_payload);
atomic_fetch_increment(&internal->ref_count, memory_order::relaxed);
} }
void asl::status::unref() void asl::status::unref()
{ {
ASL_ASSERT(!is_inline()); ASL_ASSERT(!is_inline());
// NOLINTNEXTLINE(*-reinterpret-cast) if (atomic_fetch_decrement(&m_payload->ref_count, memory_order::release) == 1)
auto* internal = reinterpret_cast<StatusInternal*>(m_payload);
if (atomic_fetch_decrement(&internal->ref_count, memory_order::release) == 1)
{ {
atomic_fence(memory_order::acquire); atomic_fence(memory_order::acquire);
alloc_delete(g_allocator, internal); alloc_delete(g_allocator, m_payload);
m_payload = nullptr;
} }
} }

View File

@ -22,15 +22,17 @@ enum class status_code : uint8_t
invalid_argument = 4, invalid_argument = 4,
}; };
struct StatusInternal;
class status class status
{ {
void* m_payload{}; StatusInternal* m_payload{};
static constexpr void* status_to_payload(status_code code) static constexpr StatusInternal* status_to_payload(status_code code)
{ {
return code == status_code::ok return code == status_code::ok
? nullptr ? nullptr
: bit_cast<void*>((static_cast<uintptr_t>(code) << 1) | 1); : bit_cast<StatusInternal*>((static_cast<uintptr_t>(code) << 1) | 1);
} }
static constexpr status_code payload_to_status(void* payload) static constexpr status_code payload_to_status(void* payload)

View File

@ -1 +1,3 @@
review unions
review reinterpret_cast
review as_bytes & static_cast in general