AK+Userland: Add generic AK::abs() function and use it

Previously, in LibGFX's `Point` class, calculated distances were passed
to the integer `abs` function, even if the stored type was a float. This
caused the value to unexpectedly be truncated. Luckily, this API was not
used with floating point types, but that can change in the future, so
why not fix it now :^)

Since we are in C++, we can use function overloading to make things
easy, and to automatically use the right version.

This is even better than the LibC/LibM functions, as using a bit of
hackery, they are able to be constant-evaluated. They use compiler
intrinsics, so they do not depend on external code and the compiler can
emit the most optimized code by default.

Since we aren't using the C++ standard library's trick of importing
everything into the `AK` namespace, this `abs` function cannot be
exported to the global namespace, as the names would clash.
This commit is contained in:
Daniel Bertalan 2021-07-05 18:38:17 +02:00 committed by Gunnar Beutner
parent 62f84e94c8
commit c6fafd3e90
Notes: sideshowbarker 2024-07-18 10:06:28 +09:00
5 changed files with 29 additions and 9 deletions

View file

@ -125,6 +125,26 @@ constexpr bool is_constant_evaluated()
#endif #endif
} }
// These can't be exported into the global namespace as they would clash with the C standard library.
#define __DEFINE_GENERIC_ABS(type, zero, intrinsic) \
constexpr type abs(type num) \
{ \
if (is_constant_evaluated()) \
return num < zero ? -num : num; \
else \
return __builtin_##intrinsic(num); \
}
__DEFINE_GENERIC_ABS(int, 0, abs);
__DEFINE_GENERIC_ABS(long, 0l, labs);
__DEFINE_GENERIC_ABS(long long, 0ll, llabs);
#ifndef KERNEL
__DEFINE_GENERIC_ABS(float, 0.0f, fabsf);
__DEFINE_GENERIC_ABS(double, 0.0, fabs);
__DEFINE_GENERIC_ABS(long double, 0.0l, fabsl);
#endif
} }
using AK::array_size; using AK::array_size;

View file

@ -5,6 +5,7 @@
*/ */
#include "EyesWidget.h" #include "EyesWidget.h"
#include <AK/StdLibExtraDetails.h>
#include <LibGUI/Painter.h> #include <LibGUI/Painter.h>
#include <LibGUI/Window.h> #include <LibGUI/Window.h>
#include <LibGUI/WindowServerConnection.h> #include <LibGUI/WindowServerConnection.h>
@ -89,14 +90,14 @@ Gfx::IntPoint EyesWidget::pupil_center(Gfx::IntRect& eyeball_bounds) const
double max_distance_along_this_direction; double max_distance_along_this_direction;
// clang-format off // clang-format off
if (dx != 0 && abs(dx) >= abs(dy)) { if (dx != 0 && AK::abs(dx) >= AK::abs(dy)) {
double slope = dy / dx; double slope = dy / dx;
double slope_squared = slope * slope; double slope_squared = slope * slope;
max_distance_along_this_direction = 0.25 * sqrt( max_distance_along_this_direction = 0.25 * sqrt(
(slope_squared + 1) / (slope_squared + 1) /
(1 / width_squared + slope_squared / height_squared) (1 / width_squared + slope_squared / height_squared)
); );
} else if (dy != 0 && abs(dy) >= abs(dx)) { } else if (dy != 0 && AK::abs(dy) >= AK::abs(dx)) {
double slope = dx / dy; double slope = dx / dy;
double slope_squared = slope * slope; double slope_squared = slope * slope;
max_distance_along_this_direction = 0.25 * sqrt( max_distance_along_this_direction = 0.25 * sqrt(

View file

@ -13,7 +13,6 @@
#include <LibGfx/Orientation.h> #include <LibGfx/Orientation.h>
#include <LibIPC/Forward.h> #include <LibIPC/Forward.h>
#include <math.h> #include <math.h>
#include <stdlib.h>
namespace Gfx { namespace Gfx {
@ -217,7 +216,7 @@ public:
// Returns pixels moved from other in either direction // Returns pixels moved from other in either direction
[[nodiscard]] T pixels_moved(Point<T> const& other) const [[nodiscard]] T pixels_moved(Point<T> const& other) const
{ {
return max(abs(dx_relative_to(other)), abs(dy_relative_to(other))); return max(AK::abs(dx_relative_to(other)), AK::abs(dy_relative_to(other)));
} }
[[nodiscard]] float distance_from(Point<T> const& other) const [[nodiscard]] float distance_from(Point<T> const& other) const
@ -229,7 +228,7 @@ public:
[[nodiscard]] Point absolute_relative_distance_to(Point const& other) const [[nodiscard]] Point absolute_relative_distance_to(Point const& other) const
{ {
return { abs(dx_relative_to(other)), abs(dy_relative_to(other)) }; return { AK::abs(dx_relative_to(other)), AK::abs(dy_relative_to(other)) };
} }
template<typename U> template<typename U>

View file

@ -179,7 +179,7 @@ static String double_to_string(double d)
else else
builder.append('-'); builder.append('-');
builder.append(String::number(fabs(exponent - 1))); builder.append(String::number(AK::abs(exponent - 1)));
return builder.to_string(); return builder.to_string();
} }
@ -193,7 +193,7 @@ static String double_to_string(double d)
else else
builder.append('-'); builder.append('-');
builder.append(String::number(fabs(exponent - 1))); builder.append(String::number(AK::abs(exponent - 1)));
return builder.to_string(); return builder.to_string();
} }

View file

@ -482,7 +482,7 @@ void FlexFormattingContext::run(Box& box, LayoutMode)
if (sum_of_unfrozen_flex_items_flex_factors < 1) { if (sum_of_unfrozen_flex_items_flex_factors < 1) {
auto intermediate_free_space = initial_free_space * sum_of_unfrozen_flex_items_flex_factors; auto intermediate_free_space = initial_free_space * sum_of_unfrozen_flex_items_flex_factors;
if (abs(intermediate_free_space) < abs(remaining_free_space)) if (AK::abs(intermediate_free_space) < AK::abs(remaining_free_space))
remaining_free_space = intermediate_free_space; remaining_free_space = intermediate_free_space;
} }
@ -503,7 +503,7 @@ void FlexFormattingContext::run(Box& box, LayoutMode)
for_each_unfrozen_item([&](FlexItem* flex_item) { for_each_unfrozen_item([&](FlexItem* flex_item) {
float ratio = flex_item->scaled_flex_shrink_factor / sum_of_scaled_flex_shrink_factor_of_unfrozen_items; float ratio = flex_item->scaled_flex_shrink_factor / sum_of_scaled_flex_shrink_factor_of_unfrozen_items;
flex_item->target_main_size = flex_item->flex_base_size - (abs(remaining_free_space) * ratio); flex_item->target_main_size = flex_item->flex_base_size - (AK::abs(remaining_free_space) * ratio);
}); });
} }
} else { } else {