Fix a bunch of warnings

This commit is contained in:
2025-07-06 14:34:21 +02:00
parent bcdad5b876
commit 00ea14788f
13 changed files with 118 additions and 39 deletions

View File

@ -12,9 +12,36 @@ using float64_t = double;
namespace asl namespace asl
{ {
template<is_floating_point T> constexpr T infinity() { return __builtin_inf(); } template<typename T> struct float_traits {};
template<is_floating_point T> constexpr T nan() { return static_cast<T>(__builtin_nanf("")); } #define ASL_FLOAT_TRAITS(T, INF, NAN, EPS, SMALLEST) \
template<> struct float_traits<T> \
{ \
static constexpr T kInfinity{__builtin_bit_cast(T, INF)}; \
static constexpr T kNaN{__builtin_bit_cast(T, NAN)}; \
static constexpr T kEpsilon{EPS}; \
static constexpr T kSmallest{__builtin_bit_cast(T, SMALLEST)}; \
};
ASL_FLOAT_TRAITS(
float32_t,
0x7F800000,
0x7FC00000,
__builtin_bit_cast(float32_t, 0x3F800001) - float32_t{1},
0x00800000
);
ASL_FLOAT_TRAITS(
float64_t,
0x7FF0000000000000,
0x7FF8000000000000,
__builtin_bit_cast(float64_t, 0x3FF0000000000001) - float64_t{1},
0x0010000000000000
);
template<is_floating_point T> constexpr T infinity() { return float_traits<T>::kInfinity; }
template<is_floating_point T> constexpr T nan() { return float_traits<T>::kNaN; }
template<is_floating_point T> constexpr bool is_infinity(T f) { return __builtin_isinf(f); } template<is_floating_point T> constexpr bool is_infinity(T f) { return __builtin_isinf(f); }

View File

@ -45,8 +45,8 @@ template<typename T> struct integer_traits {};
#define ASL_INTEGER_TRAITS(T, MIN, MAX) \ #define ASL_INTEGER_TRAITS(T, MIN, MAX) \
template<> struct integer_traits<T> \ template<> struct integer_traits<T> \
{ \ { \
static constexpr T kMin = MIN; \ static constexpr T kMin{static_cast<T>(MIN)}; \
static constexpr T kMax = MAX; \ static constexpr T kMax{static_cast<T>(MAX)}; \
} }
ASL_INTEGER_TRAITS(uint8_t, 0, 0xff); ASL_INTEGER_TRAITS(uint8_t, 0, 0xff);

View File

@ -5,6 +5,7 @@
#pragma once #pragma once
#include "asl/base/integers.hpp" #include "asl/base/integers.hpp"
#include "asl/base/float.hpp"
#include "asl/base/bit.hpp" #include "asl/base/bit.hpp"
#include "asl/base/meta.hpp" #include "asl/base/meta.hpp"
#include "asl/base/assert.hpp" #include "asl/base/assert.hpp"
@ -54,5 +55,47 @@ constexpr T clamp(T x, T a, T b)
return min(max(x, a), b); return min(max(x, a), b);
} }
constexpr float32_t abs(float32_t x) { return __builtin_fabsf(x); }
constexpr float64_t abs(float64_t x) { return __builtin_fabs(x); }
template<is_floating_point T>
bool are_nearly_equal(T a, T b)
{
// This is a fast path for identical values and correctly handles
// the case where +0.0 == -0.0.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wfloat-equal"
if (a == b) { return true; }
#pragma clang diagnostic pop
// NaNs are never equal to anything, including themselves.
if (is_nan(a) || is_nan(b)) { return false; }
// Infinities are only equal if they are identical (which is handled by the
// `a == b` check above). If one is infinity and the other is not, they
// are not equal. The relative comparison below would fail with infinities.
if (is_infinity(a) || is_infinity(b)) { return false; }
static constexpr T kMin = float_traits<T>::kSmallest;
static constexpr T kEps = float_traits<T>::kEpsilon;
const T abs_a = abs(a);
const T abs_b = abs(b);
const T abs_diff = abs(a - b);
// The relative error comparison (`|a-b| <= ε * max(|a|, |b|)`) breaks
// down when `a` and `b` are near zero. In this case, we switch to an
// absolute error comparison. `DBL_MIN` is the smallest positive
// normalized double, so it's a good threshold for this check.
if (abs_a < kMin || abs_b < kMin)
{
return abs_diff < kEps;
}
// For all other cases, we use the standard relative error formula.
// The error is scaled by the magnitude of the numbers.
return abs_diff <= kEps * max(abs_a, abs_b);
}
} // namespace asl } // namespace asl

View File

@ -155,8 +155,8 @@ ASL_TEST(pop)
ASL_TEST(pop_destruct) ASL_TEST(pop_destruct)
{ {
bool d[3]{};
asl::chunked_buffer<DestructorObserver, 16> b; asl::chunked_buffer<DestructorObserver, 16> b;
bool d[3];
b.push(&d[0]); b.push(&d[0]);
b.push(&d[1]); b.push(&d[1]);

View File

@ -5,6 +5,7 @@
#pragma once #pragma once
#include "asl/base/integers.hpp" #include "asl/base/integers.hpp"
#include "asl/base/float.hpp"
#include "asl/base/meta.hpp" #include "asl/base/meta.hpp"
#include "asl/io/writer.hpp" #include "asl/io/writer.hpp"
#include "asl/types/span.hpp" #include "asl/types/span.hpp"
@ -93,8 +94,8 @@ inline void AslFormat(Formatter& f, string_view sv)
f.write(sv); f.write(sv);
} }
void AslFormat(Formatter& f, float); void AslFormat(Formatter& f, float32_t);
void AslFormat(Formatter& f, double); void AslFormat(Formatter& f, float64_t);
void AslFormat(Formatter& f, bool); void AslFormat(Formatter& f, bool);

View File

@ -6,9 +6,12 @@
#include "asl/base/float.hpp" #include "asl/base/float.hpp"
#include "asl/base/numeric.hpp" #include "asl/base/numeric.hpp"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Weverything"
#define JKJ_STD_REPLACEMENT_NAMESPACE_DEFINED 0 #define JKJ_STD_REPLACEMENT_NAMESPACE_DEFINED 0
#define JKJ_STATIC_DATA_SECTION_DEFINED 0 #define JKJ_STATIC_DATA_SECTION_DEFINED 0
#include <dragonbox.h> #include <dragonbox.h>
#pragma clang diagnostic pop
static constexpr isize_t kZeroCount = 100; static constexpr isize_t kZeroCount = 100;
static constexpr char kZeros[kZeroCount] = { static constexpr char kZeros[kZeroCount] = {
@ -24,12 +27,12 @@ static constexpr char kZeros[kZeroCount] = {
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
}; };
static constexpr bool is_zero(float x) static constexpr bool is_zero(float32_t x)
{ {
return (asl::bit_cast<uint32_t>(x) & 0x7fff'ffffU) == 0; return (asl::bit_cast<uint32_t>(x) & 0x7fff'ffffU) == 0;
} }
static constexpr bool is_zero(double x) static constexpr bool is_zero(float64_t x)
{ {
return (asl::bit_cast<uint64_t>(x) & 0x7fff'ffff'ffff'ffffULL) == 0; return (asl::bit_cast<uint64_t>(x) & 0x7fff'ffff'ffff'ffffULL) == 0;
} }
@ -102,12 +105,12 @@ static void format_float(asl::Formatter& f, T value)
} }
} }
void asl::AslFormat(Formatter& f, float value) void asl::AslFormat(Formatter& f, float32_t value)
{ {
format_float(f, value); format_float(f, value);
} }
void asl::AslFormat(Formatter& f, double value) void asl::AslFormat(Formatter& f, float64_t value)
{ {
format_float(f, value); format_float(f, value);
} }

View File

@ -79,7 +79,7 @@ ASL_TEST(format_floats)
s = asl::format_to_string("{}", 123e-8); s = asl::format_to_string("{}", 123e-8);
ASL_TEST_EXPECT(s == "0.00000123"_sv); ASL_TEST_EXPECT(s == "0.00000123"_sv);
s = asl::format_to_string("{} {}", asl::infinity<float>(), -asl::infinity<double>()); s = asl::format_to_string("{} {}", asl::infinity<float32_t>(), -asl::infinity<float64_t>());
ASL_TEST_EXPECT(s == "Infinity -Infinity"_sv); ASL_TEST_EXPECT(s == "Infinity -Infinity"_sv);
s = asl::format_to_string("{}", asl::nan<float>()); s = asl::format_to_string("{}", asl::nan<float>());

View File

@ -35,8 +35,8 @@ class DenseHandlePool
T obj; T obj;
template<typename... Args> template<typename... Args>
explicit Slot(ThisIndexPool::handle h, Args&&... args) explicit Slot(ThisIndexPool::handle h_, Args&&... args)
: h{h} : h{h_}
, obj(std::forward<Args>(args)...) , obj(std::forward<Args>(args)...)
{} {}
}; };

View File

@ -252,7 +252,8 @@ public:
[[nodiscard]] bool is_full() const [[nodiscard]] bool is_full() const
{ {
return m_first_available.is_null() && m_slots.size() > config::kMaxIndex; return m_first_available.is_null()
&& static_cast<uint64_t>(m_slots.size()) > config::kMaxIndex;
} }
option<handle> acquire() option<handle> acquire()

View File

@ -12,14 +12,14 @@ bool parse_double_impl(const char** begin, const char* end, double*);
} // namespace asl } // namespace asl
asl::status_or<asl::parse_number_result<float>> asl::parse_float(asl::string_view sv) asl::status_or<asl::parse_number_result<float32_t>> asl::parse_float32(asl::string_view sv)
{ {
const auto* begin = sv.data(); const auto* begin = sv.data();
// NOLINTNEXTLINE(*-pointer-arithmetic) // NOLINTNEXTLINE(*-pointer-arithmetic)
const auto* end = begin + sv.size(); const auto* end = begin + sv.size();
if (float value{}; parse_float_impl(&begin, end, &value)) if (float32_t value{}; parse_float_impl(&begin, end, &value))
{ {
return parse_number_result<float>{ return parse_number_result<float32_t>{
.value = value, .value = value,
.remaining = string_view{begin, end}, .remaining = string_view{begin, end},
}; };
@ -27,14 +27,14 @@ asl::status_or<asl::parse_number_result<float>> asl::parse_float(asl::string_vie
return invalid_argument_error(); return invalid_argument_error();
} }
asl::status_or<asl::parse_number_result<double>> asl::parse_double(asl::string_view sv) asl::status_or<asl::parse_number_result<float64_t>> asl::parse_float64(asl::string_view sv)
{ {
const auto* begin = sv.data(); const auto* begin = sv.data();
// NOLINTNEXTLINE(*-pointer-arithmetic) // NOLINTNEXTLINE(*-pointer-arithmetic)
const auto* end = begin + sv.size(); const auto* end = begin + sv.size();
if (float value{}; parse_float_impl(&begin, end, &value)) if (float64_t value{}; parse_double_impl(&begin, end, &value))
{ {
return parse_number_result<double>{ return parse_number_result<float64_t>{
.value = value, .value = value,
.remaining = string_view{begin, end}, .remaining = string_view{begin, end},
}; };
@ -96,7 +96,7 @@ asl::status_or<asl::parse_number_result<T>> parse_integer(asl::string_view sv, i
if (asl::is_signed_integer<T> && is_negative) if (asl::is_signed_integer<T> && is_negative)
{ {
digit = static_cast<T>(-digit); digit = static_cast<int8_t>(-digit);
} }
if (__builtin_add_overflow(value, static_cast<T>(digit), &value)) if (__builtin_add_overflow(value, static_cast<T>(digit), &value))

View File

@ -6,6 +6,7 @@
#include "asl/types/status_or.hpp" #include "asl/types/status_or.hpp"
#include "asl/strings/string_view.hpp" #include "asl/strings/string_view.hpp"
#include "asl/base/float.hpp"
namespace asl namespace asl
{ {
@ -17,8 +18,8 @@ struct parse_number_result
string_view remaining; string_view remaining;
}; };
status_or<parse_number_result<float>> parse_float(string_view); status_or<parse_number_result<float32_t>> parse_float32(string_view);
status_or<parse_number_result<double>> parse_double(string_view); status_or<parse_number_result<float64_t>> parse_float64(string_view);
status_or<parse_number_result<uint8_t>> parse_uint8(string_view, int base = 10); status_or<parse_number_result<uint8_t>> parse_uint8(string_view, int base = 10);
status_or<parse_number_result<uint16_t>> parse_uint16(string_view, int base = 10); status_or<parse_number_result<uint16_t>> parse_uint16(string_view, int base = 10);

View File

@ -2,13 +2,18 @@
// //
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Weverything"
#include <fast_float.h> #include <fast_float.h>
#pragma clang diagnostic pop
// We need to isolate fast_float.h completely from asl // We need to isolate fast_float.h completely from asl
// because it conflicts with our redefinitions of things // because it conflicts with our redefinitions of things
// from the STL. In this case it's operator new, but there // from the STL. In this case it's operator new, but there
// might be other conflicts. // might be other conflicts.
#pragma clang diagnostic ignored "-Wmissing-prototypes"
namespace asl namespace asl
{ {

View File

@ -3,38 +3,36 @@
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
#include "asl/strings/parse_number.hpp" #include "asl/strings/parse_number.hpp"
#include "asl/base/numeric.hpp"
#include "asl/testing/testing.hpp" #include "asl/testing/testing.hpp"
// @Todo Once we have an equivalent of std::numeric_limits,
// properly compare floating point values in these tests.
ASL_TEST(parse_float_error) ASL_TEST(parse_float_error)
{ {
const asl::string_view sv = "this is not a number lmao"; const asl::string_view sv = "this is not a number lmao";
auto res = asl::parse_float(sv); auto res = asl::parse_float32(sv);
ASL_TEST_EXPECT(!res.ok()); ASL_TEST_EXPECT(!res.ok());
} }
ASL_TEST(parse_float_empty) ASL_TEST(parse_float_empty)
{ {
const asl::string_view sv = ""; const asl::string_view sv = "";
auto res = asl::parse_float(sv); auto res = asl::parse_float32(sv);
ASL_TEST_EXPECT(!res.ok()); ASL_TEST_EXPECT(!res.ok());
} }
ASL_TEST(parse_float_simple) ASL_TEST(parse_float_simple)
{ {
const asl::string_view sv = "3.1415"; const asl::string_view sv = "3.1415";
auto res = asl::parse_float(sv); auto res = asl::parse_float32(sv);
ASL_TEST_EXPECT(res.ok()); ASL_TEST_EXPECT(res.ok());
ASL_TEST_EXPECT(res.value().value == 3.1415F); ASL_TEST_EXPECT(asl::are_nearly_equal(res.value().value, 3.1415F));
ASL_TEST_EXPECT(res.value().remaining.size() == 0); ASL_TEST_EXPECT(res.value().remaining.size() == 0);
} }
ASL_TEST(parse_float_integer) ASL_TEST(parse_float_integer)
{ {
const asl::string_view sv = "31415"; const asl::string_view sv = "31415";
auto res = asl::parse_float(sv); auto res = asl::parse_float32(sv);
ASL_TEST_EXPECT(res.ok()); ASL_TEST_EXPECT(res.ok());
ASL_TEST_EXPECT(res.value().value == 31415.0F); ASL_TEST_EXPECT(res.value().value == 31415.0F);
ASL_TEST_EXPECT(res.value().remaining.size() == 0); ASL_TEST_EXPECT(res.value().remaining.size() == 0);
@ -43,18 +41,18 @@ ASL_TEST(parse_float_integer)
ASL_TEST(parse_float_scientific) ASL_TEST(parse_float_scientific)
{ {
const asl::string_view sv = "314.15e-2"; const asl::string_view sv = "314.15e-2";
auto res = asl::parse_float(sv); auto res = asl::parse_float32(sv);
ASL_TEST_EXPECT(res.ok()); ASL_TEST_EXPECT(res.ok());
ASL_TEST_EXPECT(res.value().value == 3.1415F); ASL_TEST_EXPECT(asl::are_nearly_equal(res.value().value, 3.1415F));
ASL_TEST_EXPECT(res.value().remaining.size() == 0); ASL_TEST_EXPECT(res.value().remaining.size() == 0);
} }
ASL_TEST(parse_float_suffix) ASL_TEST(parse_float_suffix)
{ {
const asl::string_view sv = "3.1415 yoyoyo"; const asl::string_view sv = "3.1415 yoyoyo";
auto res = asl::parse_float(sv); auto res = asl::parse_float32(sv);
ASL_TEST_EXPECT(res.ok()); ASL_TEST_EXPECT(res.ok());
ASL_TEST_EXPECT(res.value().value == 3.1415F); ASL_TEST_EXPECT(asl::are_nearly_equal(res.value().value, 3.1415F));
ASL_TEST_EXPECT(res.value().remaining == " yoyoyo"); ASL_TEST_EXPECT(res.value().remaining == " yoyoyo");
} }