Use std::bit_cast, document that gauge mutex is an implementation detail
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
//
|
||||
// PRECISION STRATEGY:
|
||||
// - Use atomic<uint64_t> for lock-free storage
|
||||
// - Store doubles by reinterpreting bits as uint64_t (preserves full IEEE 754
|
||||
// - Store doubles using std::bit_cast to uint64_t (preserves full IEEE 754
|
||||
// precision)
|
||||
// - Single writer assumption allows simple load/store without CAS loops
|
||||
//
|
||||
@@ -19,9 +19,9 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <bit>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
@@ -74,15 +74,7 @@ using AtomicWord = std::atomic<uint64_t>;
|
||||
// DESIGN: Store doubles in atomic<uint64_t> for lock-free operations
|
||||
// - Preserves full IEEE 754 double precision (no truncation)
|
||||
// - Allows atomic load/store without locks
|
||||
// - Safe bit-wise conversion between double and uint64_t
|
||||
template <class U, class V> U reinterpret(V v) {
|
||||
static_assert(sizeof(U) == sizeof(V));
|
||||
static_assert(std::is_arithmetic_v<U>);
|
||||
static_assert(std::is_arithmetic_v<V>);
|
||||
U u;
|
||||
memcpy(&u, &v, sizeof(u));
|
||||
return u;
|
||||
}
|
||||
// - Use std::bit_cast for safe conversion between double and uint64_t
|
||||
|
||||
// Family::State structures own the second-level maps (labels -> instances)
|
||||
template <> struct Family<Counter>::State {
|
||||
@@ -235,11 +227,13 @@ void Counter::inc(double x) {
|
||||
// DESIGN: Single writer per thread allows simple load-modify-store
|
||||
// No CAS loop needed since only one thread writes to this counter
|
||||
auto current_value =
|
||||
reinterpret<double>(p->value.load(std::memory_order_relaxed));
|
||||
p->value.store(reinterpret<uint64_t>(current_value + x),
|
||||
std::bit_cast<double>(p->value.load(std::memory_order_relaxed));
|
||||
p->value.store(std::bit_cast<uint64_t>(current_value + x),
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
void Gauge::inc(double x) {
|
||||
// IMPLEMENTATION DETAIL: Gauges currently support multiple writers via mutex,
|
||||
// though the public API documents single-writer semantics for consistency
|
||||
std::unique_lock<std::mutex> _{p->mutex};
|
||||
p->value += x;
|
||||
}
|
||||
@@ -263,8 +257,8 @@ void Histogram::observe(double x) {
|
||||
// DESIGN: Single writer per thread allows simple load-modify-store for sum
|
||||
// No CAS loop needed since only one thread writes to this histogram
|
||||
auto current_sum =
|
||||
reinterpret<double>(p->sum.load(std::memory_order_relaxed));
|
||||
p->sum.store(reinterpret<uint64_t>(current_sum + x),
|
||||
std::bit_cast<double>(p->sum.load(std::memory_order_relaxed));
|
||||
p->sum.store(std::bit_cast<uint64_t>(current_sum + x),
|
||||
std::memory_order_relaxed);
|
||||
|
||||
p->observations.fetch_add(1, std::memory_order_relaxed);
|
||||
|
||||
Reference in New Issue
Block a user