diff --git a/base/CMakeLists.txt b/base/CMakeLists.txt index 70cdbd399..493b83e8a 100644 --- a/base/CMakeLists.txt +++ b/base/CMakeLists.txt @@ -28,6 +28,7 @@ set(SRC dfa_helpers.hpp exception.cpp exception.hpp + fast_math.cpp fifo_cache.hpp file_name_utils.cpp file_name_utils.hpp @@ -105,6 +106,10 @@ set(SRC omim_add_library(${PROJECT_NAME} ${SRC}) +# Exception for some of our math to work reliably. +# Ubuntu x86_64 gcc 14.2.0 ignores -fno-finite-math-only in debug builds without -O1 +set_source_files_properties(fast_math.cpp PROPERTIES COMPILE_OPTIONS "-fno-finite-math-only;$<$:-O1>") + set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) target_link_libraries(${PROJECT_NAME} INTERFACE Threads::Threads) diff --git a/base/base_tests/math_test.cpp b/base/base_tests/math_test.cpp index e3c614901..8fb1513a4 100644 --- a/base/base_tests/math_test.cpp +++ b/base/base_tests/math_test.cpp @@ -172,3 +172,22 @@ UNIT_TEST(Sign) TEST_EQUAL(-1, base::Sign(-11), ()); TEST_EQUAL(-1, base::Sign(-10.4), ()); } + +UNIT_TEST(is_finite) +{ + static_assert(std::numeric_limits::has_infinity); + static_assert(std::numeric_limits::has_quiet_NaN); + + using math::is_finite, math::Nan, math::Infinity; + + TEST(!is_finite(Nan()), ()); + TEST(!is_finite(Infinity()), ()); + TEST(!is_finite(DBL_MAX*2.0), ()); + + TEST(is_finite(0.0), ()); + TEST(is_finite(1.0), ()); + TEST(is_finite(-2.0), ()); + TEST(is_finite(DBL_MIN), ()); + TEST(is_finite(DBL_MAX), ()); + TEST(is_finite(DBL_MIN/2.0), ("As in cppreference example")); +} diff --git a/base/base_tests/string_utils_test.cpp b/base/base_tests/string_utils_test.cpp index 1df5cf608..391419034 100644 --- a/base/base_tests/string_utils_test.cpp +++ b/base/base_tests/string_utils_test.cpp @@ -131,22 +131,6 @@ UNIT_TEST(EqualNoCase) TEST(strings::EqualNoCase("HaHaHa", "hahaha"), ()); } -UNIT_TEST(is_finite) -{ - using namespace strings; - - TEST(!is_finite(NAN), ()); - TEST(!is_finite(INFINITY), ()); - //TEST(!is_finite(DBL_MIN/2.0), ()); - TEST(!is_finite(DBL_MAX*2.0), ()); - - TEST(is_finite(0.0), ()); - TEST(is_finite(1.0), ()); - TEST(is_finite(-2.0), ()); - TEST(is_finite(DBL_MIN), ()); - TEST(is_finite(DBL_MAX), ()); -} - UNIT_TEST(to_double) { std::string s; diff --git a/base/fast_math.cpp b/base/fast_math.cpp new file mode 100644 index 000000000..ca8d4b623 --- /dev/null +++ b/base/fast_math.cpp @@ -0,0 +1,19 @@ +// Separate cpp for different compiler flags. +#include +#include + +namespace math +{ +double Nan() +{ + return std::numeric_limits::quiet_NaN(); +} +double Infinity() +{ + return std::numeric_limits::infinity(); +} +bool is_finite(double t) +{ + return std::isfinite(t); +} +} // namespace base diff --git a/base/math.hpp b/base/math.hpp index 357f6f7a1..d817e3e2d 100644 --- a/base/math.hpp +++ b/base/math.hpp @@ -12,6 +12,11 @@ namespace math double constexpr pi = 3.14159265358979323846; double constexpr pi2 = pi / 2.0; double constexpr pi4 = pi / 4.0; + +// Defined in fast_math.cpp +double Nan(); +double Infinity(); +bool is_finite(double d); } // namespace math namespace base diff --git a/base/string_utils.cpp b/base/string_utils.cpp index 670b125b3..c79529165 100644 --- a/base/string_utils.cpp +++ b/base/string_utils.cpp @@ -1,6 +1,7 @@ #include "base/string_utils.hpp" #include "base/assert.hpp" +#include "base/math.hpp" #include "base/stl_helpers.hpp" #include @@ -10,7 +11,6 @@ #include #include -#include #include namespace strings @@ -34,27 +34,22 @@ double RealConverter(char const * start, char ** stop) return std::strtod(start, stop); } -template -bool IsFinite(T t) -{ - return boost::math::isfinite(t); -} - template bool ToReal(char const * start, T & result) { // Try faster implementation first. double d; + // TODO(AB): replace with more robust dependency that doesn't use std::is_finite in the implementation. char const * endptr = fast_double_parser::parse_number(start, &d); if (endptr == nullptr) { // Fallback to our implementation, it supports numbers like "1." char * stop; result = RealConverter(start, &stop); - if (*stop == 0 && start != stop && IsFinite(result)) + if (*stop == 0 && start != stop && math::is_finite(result)) return true; } - else if (*endptr == 0 && IsFinite(d)) + else if (*endptr == 0 && math::is_finite(d)) { result = static_cast(d); return true; @@ -116,11 +111,6 @@ bool to_double(char const * start, double & d) return ToReal(start, d); } -bool is_finite(double d) -{ - return IsFinite(d); -} - UniString MakeLowerCase(UniString s) { MakeLowerCaseInplace(s); diff --git a/generator/osm2meta.cpp b/generator/osm2meta.cpp index 7ad81cb71..d54322cf9 100644 --- a/generator/osm2meta.cpp +++ b/generator/osm2meta.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include namespace @@ -36,7 +35,7 @@ void RemoveDuplicatesAndKeepOrder(std::vector & vec) std::unordered_set seen; auto const predicate = [&seen](T const & value) { - if (seen.find(value) != seen.end()) + if (seen.contains(value)) return true; seen.insert(value); return false; @@ -79,7 +78,7 @@ bool Prefix2Double(std::string const & str, double & d) char const * s = str.c_str(); // TODO: Replace with a faster and locale-ignored double conversion. d = std::strtod(s, &stop); - return (s != stop && strings::is_finite(d)); + return (s != stop && math::is_finite(d)); } } // namespace @@ -466,8 +465,7 @@ std::string MetadataTagProcessorImpl::ValidateAndFormat_duration(std::string con return {}; char const type = v[pos]; - auto const addHours = convert(type, *op); - if (addHours) + if (auto const addHours = convert(type, *op)) hours += *addHours; else return {}; diff --git a/platform/measurement_utils.cpp b/platform/measurement_utils.cpp index 2794cfe31..72971144d 100644 --- a/platform/measurement_utils.cpp +++ b/platform/measurement_utils.cpp @@ -7,7 +7,6 @@ #include "base/assert.hpp" #include "base/bits.hpp" #include "base/logging.hpp" -#include "base/macros.hpp" #include "base/math.hpp" #include "base/string_utils.hpp" @@ -193,8 +192,8 @@ double MpsToUnits(double metersPerSecond, Units units) { switch (units) { - case Units::Imperial: return KmphToMiph(MpsToKmph(metersPerSecond)); break; - case Units::Metric: return MpsToKmph(metersPerSecond); break; + case Units::Imperial: return KmphToMiph(MpsToKmph(metersPerSecond)); + case Units::Metric: return MpsToKmph(metersPerSecond); } UNREACHABLE(); } @@ -235,8 +234,6 @@ std::string FormatOsmLink(double lat, double lon, int zoom) bool OSMDistanceToMeters(std::string const & osmRawValue, double & outMeters) { - using strings::is_finite; - char * stop; char const * s = osmRawValue.c_str(); outMeters = strtod(s, &stop); @@ -245,7 +242,7 @@ bool OSMDistanceToMeters(std::string const & osmRawValue, double & outMeters) if (s == stop) return false; - if (!is_finite(outMeters)) + if (!math::is_finite(outMeters)) return false; switch (*stop) @@ -259,7 +256,7 @@ bool OSMDistanceToMeters(std::string const & osmRawValue, double & outMeters) outMeters = FeetToMeters(outMeters); s = stop + 1; double const inches = strtod(s, &stop); - if (s != stop && *stop == '"' && is_finite(inches)) + if (s != stop && *stop == '"' && math::is_finite(inches)) outMeters += InchesToMeters(inches); return true; @@ -273,7 +270,7 @@ bool OSMDistanceToMeters(std::string const & osmRawValue, double & outMeters) { s = stop + 1; double const newValue = strtod(s, &stop); - if (s != stop && is_finite(newValue)) + if (s != stop && math::is_finite(newValue)) outMeters = newValue; } break; diff --git a/platform/measurement_utils.hpp b/platform/measurement_utils.hpp index 7329351ab..8f5d6db0d 100644 --- a/platform/measurement_utils.hpp +++ b/platform/measurement_utils.hpp @@ -31,7 +31,7 @@ inline double NauticalMilesToMeters(double nmi) { return nmi * 1852; } inline double constexpr KmphToMps(double kmph) { return kmph * 1000 / 3600; } double ToSpeedKmPH(double speed, Units units); -double MpsToUnits(double mps, Units units); +double MpsToUnits(double metersPerSecond, Units units); /// @return Speed value in km/h for Metric and in mph for Imperial. int FormatSpeed(double metersPerSecond, Units units); diff --git a/platform/settings.cpp b/platform/settings.cpp index 3d1fdf8f9..5d02572a9 100644 --- a/platform/settings.cpp +++ b/platform/settings.cpp @@ -11,7 +11,7 @@ #include "geometry/any_rect2d.hpp" #include "geometry/rect2d.hpp" -#include "base/string_utils.hpp" +#include "base/math.hpp" #include #include @@ -58,7 +58,7 @@ bool FromStringArray(string const & s, T(&arr)[N]) size_t count = 0; while (count < N && in >> arr[count]) { - if (!strings::is_finite(arr[count])) + if (!math::is_finite(arr[count])) return false; ++count; } diff --git a/xcode/base/base.xcodeproj/project.pbxproj b/xcode/base/base.xcodeproj/project.pbxproj index a45ef8ffe..570062965 100644 --- a/xcode/base/base.xcodeproj/project.pbxproj +++ b/xcode/base/base.xcodeproj/project.pbxproj @@ -145,6 +145,8 @@ E1B7FFC221FA19FE00F094DC /* thread_pool_delayed.hpp in Headers */ = {isa = PBXBuildFile; fileRef = E1B7FFBE21FA19FD00F094DC /* thread_pool_delayed.hpp */; }; E1B7FFC321FA19FE00F094DC /* thread_utils.hpp in Headers */ = {isa = PBXBuildFile; fileRef = E1B7FFBF21FA19FD00F094DC /* thread_utils.hpp */; }; E1B7FFC421FA19FE00F094DC /* thread_pool_delayed.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E1B7FFC021FA19FE00F094DC /* thread_pool_delayed.cpp */; }; + FAB54F592E053C17007B540E /* fast_math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAB54F582E053C17007B540E /* fast_math.cpp */; }; + FAB54F5A2E053C17007B540E /* fast_math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAB54F582E053C17007B540E /* fast_math.cpp */; settings = {COMPILER_FLAGS = "-fno-finite-math-only"; }; }; FACB768326B8738F00810C9C /* linked_map_tests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D08987A24810A1300837783 /* linked_map_tests.cpp */; }; FACB768426B8739300810C9C /* checked_cast_tests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DBD7B94240FB11200ED9FE8 /* checked_cast_tests.cpp */; }; FACB768526B873A000810C9C /* lru_cache_tests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56290B8B206D0937003892E0 /* lru_cache_tests.cpp */; }; @@ -298,6 +300,7 @@ E1B7FFC521FA1A2100F094DC /* thread_pool_computational_tests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = thread_pool_computational_tests.cpp; sourceTree = ""; }; E1B7FFC621FA1A2200F094DC /* thread_pool_delayed_tests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = thread_pool_delayed_tests.cpp; sourceTree = ""; }; F61B9796229BFDF1000E878B /* non_intersecting_intervals_tests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = non_intersecting_intervals_tests.cpp; sourceTree = ""; }; + FAB54F582E053C17007B540E /* fast_math.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = fast_math.cpp; sourceTree = ""; }; FAF23E20274E3F1000684735 /* exception_tests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = exception_tests.cpp; sourceTree = ""; }; /* End PBXFileReference section */ @@ -403,95 +406,96 @@ 675341851A3F57E400A0A8C3 /* array_adapters.hpp */, 675341861A3F57E400A0A8C3 /* assert.hpp */, 3D1BE645212D775500ACD94A /* atomic_shared_ptr.hpp */, - 675341871A3F57E400A0A8C3 /* base.cpp */, 675341881A3F57E400A0A8C3 /* base.hpp */, + 675341871A3F57E400A0A8C3 /* base.cpp */, 39F1E52E21C961A800D961DC /* beam.hpp */, 397DC50B22BB8EBF007126DB /* bidirectional_map.hpp */, 675341891A3F57E400A0A8C3 /* bits.hpp */, 6753418A1A3F57E400A0A8C3 /* buffer_vector.hpp */, 6753418B1A3F57E400A0A8C3 /* cache.hpp */, - 3901B744235F02B2006ABD43 /* cancellable.cpp */, 672DD4B01E04255F0078E13C /* cancellable.hpp */, + 3901B744235F02B2006ABD43 /* cancellable.cpp */, 67C79B9E1E2929DB00C40034 /* checked_cast.hpp */, 3917FA52211E008C00937DF4 /* clustering_map.hpp */, 672DD4B11E04255F0078E13C /* collection_cast.hpp */, 39BC0FCF1FD057F900B6C276 /* control_flow.hpp */, - 67A609AC1C88642E001E641A /* deferred_task.cpp */, 67A609AD1C88642E001E641A /* deferred_task.hpp */, + 67A609AC1C88642E001E641A /* deferred_task.cpp */, 3446C66C1DDCA96300146687 /* dfa_helpers.hpp */, - 675341941A3F57E400A0A8C3 /* exception.cpp */, 675341951A3F57E400A0A8C3 /* exception.hpp */, + 675341941A3F57E400A0A8C3 /* exception.cpp */, + FAB54F582E053C17007B540E /* fast_math.cpp */, 564BB444206E89ED00BDD211 /* fifo_cache.hpp */, - 390F1C0C2294298E00EA58E3 /* file_name_utils.cpp */, 390F1C0B2294298E00EA58E3 /* file_name_utils.hpp */, - 3917FA54211E009700937DF4 /* geo_object_id.cpp */, + 390F1C0C2294298E00EA58E3 /* file_name_utils.cpp */, 3917FA55211E009700937DF4 /* geo_object_id.hpp */, - 671182EE1C807C0A00CB8177 /* gmtime.cpp */, + 3917FA54211E009700937DF4 /* geo_object_id.cpp */, 671182EF1C807C0A00CB8177 /* gmtime.hpp */, + 671182EE1C807C0A00CB8177 /* gmtime.cpp */, 675345381A3F6F5E00A0A8C3 /* internal */, - 3446C66D1DDCA96300146687 /* levenshtein_dfa.cpp */, 3446C66E1DDCA96300146687 /* levenshtein_dfa.hpp */, + 3446C66D1DDCA96300146687 /* levenshtein_dfa.cpp */, 675341991A3F57E400A0A8C3 /* limited_priority_queue.hpp */, 3D08987824810A0B00837783 /* linked_map.hpp */, - 6753419A1A3F57E400A0A8C3 /* logging.cpp */, 6753419B1A3F57E400A0A8C3 /* logging.hpp */, + 6753419A1A3F57E400A0A8C3 /* logging.cpp */, 6753419C1A3F57E400A0A8C3 /* lower_case.cpp */, 56290B89206D0887003892E0 /* lru_cache.hpp */, 6753419D1A3F57E400A0A8C3 /* macros.hpp */, - ACB634A2274D65F000F91940 /* math.cpp */, 6753419E1A3F57E400A0A8C3 /* math.hpp */, + ACB634A2274D65F000F91940 /* math.cpp */, 6753419F1A3F57E400A0A8C3 /* matrix.hpp */, 672DD4B51E04255F0078E13C /* mem_trie.hpp */, 672DD4B61E04255F0078E13C /* newtype.hpp */, 397DC50C22BB8EBF007126DB /* non_intersecting_intervals.hpp */, 675341A21A3F57E400A0A8C3 /* normalize_unicode.cpp */, 672DD4B71E04255F0078E13C /* observer_list.hpp */, - 3917FA5A211E00BA00937DF4 /* pprof.cpp */, 3917FA5B211E00BB00937DF4 /* pprof.hpp */, + 3917FA5A211E00BA00937DF4 /* pprof.cpp */, 56B1A0721E69DE4D00395022 /* random.hpp */, 672DD4B81E0425600078E13C /* range_iterator.hpp */, 672DD4B91E0425600078E13C /* ref_counted.hpp */, 675341AA1A3F57E400A0A8C3 /* rolling_hash.hpp */, 675341AF1A3F57E400A0A8C3 /* scope_guard.hpp */, 675341B01A3F57E400A0A8C3 /* set_operations.hpp */, - 675341B11A3F57E400A0A8C3 /* shared_buffer_manager.cpp */, 675341B21A3F57E400A0A8C3 /* shared_buffer_manager.hpp */, + 675341B11A3F57E400A0A8C3 /* shared_buffer_manager.cpp */, 56B1A0731E69DE4D00395022 /* small_set.hpp */, - 675341B41A3F57E400A0A8C3 /* src_point.cpp */, 675341B51A3F57E400A0A8C3 /* src_point.hpp */, + 675341B41A3F57E400A0A8C3 /* src_point.cpp */, 675341B61A3F57E400A0A8C3 /* stats.hpp */, 675341B71A3F57E400A0A8C3 /* std_serialization.hpp */, 672DD4BA1E0425600078E13C /* stl_helpers.hpp */, 675341B91A3F57E400A0A8C3 /* stl_iterator.hpp */, - 675341BC1A3F57E400A0A8C3 /* string_utils.cpp */, 675341BD1A3F57E400A0A8C3 /* string_utils.hpp */, - 675341BE1A3F57E400A0A8C3 /* strings_bundle.cpp */, + 675341BC1A3F57E400A0A8C3 /* string_utils.cpp */, 675341BF1A3F57E400A0A8C3 /* strings_bundle.hpp */, - 3D74EF0B1F8B902B0081202C /* suffix_array.cpp */, + 675341BE1A3F57E400A0A8C3 /* strings_bundle.cpp */, 3917FA5E211E00C300937DF4 /* suffix_array.hpp */, - 670E39421C46C76900E9C0A6 /* sunrise_sunset.cpp */, + 3D74EF0B1F8B902B0081202C /* suffix_array.cpp */, 670E39431C46C76900E9C0A6 /* sunrise_sunset.hpp */, + 670E39421C46C76900E9C0A6 /* sunrise_sunset.cpp */, 3D7815711F3A145F0068B6AC /* task_loop.hpp */, - 67B52B5E1AD3C84E00664C17 /* thread_checker.cpp */, + 675341C41A3F57E400A0A8C3 /* thread.hpp */, + 675341C31A3F57E400A0A8C3 /* thread.cpp */, 67B52B5F1AD3C84E00664C17 /* thread_checker.hpp */, - E1B7FFBD21FA19FD00F094DC /* thread_pool_computational.hpp */, - E1B7FFC021FA19FE00F094DC /* thread_pool_delayed.cpp */, - E1B7FFBE21FA19FD00F094DC /* thread_pool_delayed.hpp */, - 675341C11A3F57E400A0A8C3 /* thread_pool.cpp */, + 67B52B5E1AD3C84E00664C17 /* thread_checker.cpp */, 675341C21A3F57E400A0A8C3 /* thread_pool.hpp */, + 675341C11A3F57E400A0A8C3 /* thread_pool.cpp */, + E1B7FFBD21FA19FD00F094DC /* thread_pool_computational.hpp */, + E1B7FFBE21FA19FD00F094DC /* thread_pool_delayed.hpp */, + E1B7FFC021FA19FE00F094DC /* thread_pool_delayed.cpp */, 3989E363230302EA00D63F84 /* thread_safe_queue.hpp */, E1B7FFBF21FA19FD00F094DC /* thread_utils.hpp */, - 675341C31A3F57E400A0A8C3 /* thread.cpp */, - 675341C41A3F57E400A0A8C3 /* thread.hpp */, - 675341C51A3F57E400A0A8C3 /* threaded_container.cpp */, 675341C61A3F57E400A0A8C3 /* threaded_container.hpp */, + 675341C51A3F57E400A0A8C3 /* threaded_container.cpp */, 675341C71A3F57E400A0A8C3 /* threaded_list.hpp */, - 674A7E2C1C0DB03D003D48E1 /* timegm.cpp */, 674A7E2D1C0DB03D003D48E1 /* timegm.hpp */, - 675341C91A3F57E400A0A8C3 /* timer.cpp */, + 674A7E2C1C0DB03D003D48E1 /* timegm.cpp */, 675341CA1A3F57E400A0A8C3 /* timer.hpp */, - 3446C66F1DDCA96300146687 /* uni_string_dfa.cpp */, + 675341C91A3F57E400A0A8C3 /* timer.cpp */, 3446C6701DDCA96300146687 /* uni_string_dfa.hpp */, + 3446C66F1DDCA96300146687 /* uni_string_dfa.cpp */, 3D74EF0C1F8B902B0081202C /* visitor.hpp */, 3D78157A1F3D89EC0068B6AC /* waiter.hpp */, ); @@ -695,6 +699,7 @@ 3975D20B235F2738004D84D3 /* cancellable_tests.cpp in Sources */, 39FD27381CC65AD000AFF551 /* timegm_test.cpp in Sources */, 39FD272C1CC65AD000AFF551 /* range_iterator_test.cpp in Sources */, + FAB54F592E053C17007B540E /* fast_math.cpp in Sources */, FAF23E21274E3F1000684735 /* exception_tests.cpp in Sources */, 39FD27261CC65AD000AFF551 /* containers_test.cpp in Sources */, 397DC51122BB8ED2007126DB /* bidirectional_map_tests.cpp in Sources */, @@ -748,6 +753,7 @@ 675342011A3F57E400A0A8C3 /* string_utils.cpp in Sources */, 674A7E2E1C0DB03D003D48E1 /* timegm.cpp in Sources */, E1B7FFC421FA19FE00F094DC /* thread_pool_delayed.cpp in Sources */, + FAB54F5A2E053C17007B540E /* fast_math.cpp in Sources */, 6753420A1A3F57E400A0A8C3 /* threaded_container.cpp in Sources */, 3917FA5C211E00BB00937DF4 /* pprof.cpp in Sources */, 67A609AE1C88642E001E641A /* deferred_task.cpp in Sources */,