diff --git a/mjpc/utilities.cc b/mjpc/utilities.cc index 5c87cbf62..6f67c27e5 100644 --- a/mjpc/utilities.cc +++ b/mjpc/utilities.cc @@ -15,6 +15,7 @@ #include "mjpc/utilities.h" #include +#include #include #include #include @@ -115,12 +116,28 @@ void Clamp(double* x, const double* bounds, int n) { } } -int ReinterpretAsInt(double value) { - return *std::launder(reinterpret_cast(&value)); +int64_t ReinterpretAsInt(double value) { + static_assert(sizeof(double) == sizeof(int64_t), + "double and int64_t must have same size"); +#if defined(__cpp_lib_bit_cast) + return std::bit_cast(value); +#else + int64_t dst; + std::memcpy(&dst, &value, sizeof(int64_t)); + return dst; +#endif } double ReinterpretAsDouble(int64_t value) { - return *std::launder(reinterpret_cast(&value)); + static_assert(sizeof(double) == sizeof(int64_t), + "double and int64_t must have same size"); +#if defined(__cpp_lib_bit_cast) + return std::bit_cast(value); +#else + double dst; + std::memcpy(&dst, &value, sizeof(double)); + return dst; +#endif } absl::flat_hash_map> @@ -225,7 +242,7 @@ int ParameterIndex(const mjModel* model, std::string_view name) { double DefaultResidualSelection(const mjModel* m, int numeric_index) { // list selections are stored as ints, but numeric values are doubles. int64_t value = m->numeric_data[m->numeric_adr[numeric_index]]; - return *std::launder(reinterpret_cast(&value)); + return ReinterpretAsDouble(value); } int CostTermByName(const mjModel* m, const std::string& name) { diff --git a/mjpc/utilities.h b/mjpc/utilities.h index f3eb5c8a0..f5c88cd54 100644 --- a/mjpc/utilities.h +++ b/mjpc/utilities.h @@ -66,8 +66,8 @@ T GetNumberOrDefault(T default_value, const mjModel* m, std::string_view name) { return GetNumber(m, name).value_or(default_value); } -// reinterpret double as int -int ReinterpretAsInt(double value); +// reinterpret double as int64_t +int64_t ReinterpretAsInt(double value); // reinterpret int64_t as double double ReinterpretAsDouble(int64_t value);