From 59f4535adf6f26c6f02ab7203e52893167b3ff53 Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Wed, 21 Oct 2020 16:44:54 -0400 Subject: [PATCH 1/4] This branch improves portability (under Windows). --- .github/workflows/alpine.yml | 27 ++++++++++++++++++ .github/workflows/msys2.yml | 44 +++++++++++++++++++++++++++++ .github/workflows/vs16-clang-ci.yml | 25 ++++++++++++++++ include/fast_float/float_common.h | 20 +++++++------ 4 files changed, 108 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/alpine.yml create mode 100644 .github/workflows/msys2.yml create mode 100644 .github/workflows/vs16-clang-ci.yml diff --git a/.github/workflows/alpine.yml b/.github/workflows/alpine.yml new file mode 100644 index 0000000..8259376 --- /dev/null +++ b/.github/workflows/alpine.yml @@ -0,0 +1,27 @@ +name: Alpine Linux +'on': + - push + - pull_request +jobs: + ubuntu-build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: start docker + run: | + docker run -w /src -dit --name alpine -v $PWD:/src alpine:latest + echo 'docker exec alpine "$@";' > ./alpine.sh + chmod +x ./alpine.sh + - name: install packages + run: | + ./alpine.sh apk update + ./alpine.sh apk add build-base cmake g++ linux-headers git bash + - name: cmake + run: | + ./alpine.sh cmake -DFASTFLOAT_TEST=ON -B build_for_alpine + - name: build + run: | + ./alpine.sh cmake --build build_for_alpine + - name: test + run: | + ./alpine.sh bash -c "cd build_for_alpine && ctest -R basictest" \ No newline at end of file diff --git a/.github/workflows/msys2.yml b/.github/workflows/msys2.yml new file mode 100644 index 0000000..b6177f4 --- /dev/null +++ b/.github/workflows/msys2.yml @@ -0,0 +1,44 @@ +name: MSYS2-CI + +on: [push, pull_request] + +jobs: + windows-mingw: + name: ${{ matrix.msystem }} + runs-on: windows-latest + defaults: + run: + shell: msys2 {0} + strategy: + fail-fast: false + matrix: + include: + - msystem: "MINGW64" + install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc + type: Release + - msystem: "MINGW32" + install: mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-gcc + type: Release + - msystem: "MINGW64" + install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc + type: Debug + - msystem: "MINGW32" + install: mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-gcc + type: Debug + env: + CMAKE_GENERATOR: Ninja + + steps: + - uses: actions/checkout@v2 + - uses: msys2/setup-msys2@v2 + with: + update: true + msystem: ${{ matrix.msystem }} + install: ${{ matrix.install }} + - name: Build and Test + run: | + mkdir build + cd build + cmake -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DFASTFLOAT_TEST=ON .. + cmake --build . --verbose + ctest --output-on-failure -R basictest \ No newline at end of file diff --git a/.github/workflows/vs16-clang-ci.yml b/.github/workflows/vs16-clang-ci.yml new file mode 100644 index 0000000..ba58239 --- /dev/null +++ b/.github/workflows/vs16-clang-ci.yml @@ -0,0 +1,25 @@ +ame: VS16-CLANG-CI + +on: [push, pull_request] + +jobs: + ci: + name: windows-vs16 + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + - name: 'Run CMake with VS16' + uses: lukka/run-cmake@v2 + with: + cmakeListsOrSettingsJson: CMakeListsTxtAdvanced + cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt' + buildDirectory: "${{ github.workspace }}/../../_temp/windows" + cmakeBuildType: Release + buildWithCMake: true + cmakeGenerator: VS16Win64 + cmakeAppendedArgs: -T ClangCL -DFASTFLOAT_TEST=ON + buildWithCMakeArgs: --config Release + + - name: 'Run CTest' + run: ctest -C Release -R basictest --output-on-failure + working-directory: "${{ github.workspace }}/../../_temp/windows" \ No newline at end of file diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index bc8a4f1..0dc487a 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -18,14 +18,17 @@ #define fastfloat_really_inline inline __attribute__((always_inline)) #endif -#ifdef _MSC_VER -#define fastfloat_strcasecmp _stricmp -#define fastfloat_strncasecmp _strnicmp -#else -#define fastfloat_strcasecmp strcasecmp -#define fastfloat_strncasecmp strncasecmp -#endif namespace fast_float { + +// Compares two ASCII strings in a case insensitive manner. +inline bool fastfloat_strncasecmp(const char * input1, const char * input2, size_t length) { + char running_diff{0}; + for(size_t i = 0; i < length; i++) { + running_diff |= (input1[i] ^ input2[i]); + } + return (running_diff == 0) || (running_diff == 32); +} + #ifndef FLT_EVAL_METHOD #error "FLT_EVAL_METHOD should be defined, please include cfloat." #endif @@ -72,7 +75,8 @@ int leading_zeroes(uint64_t input_num) { } -#ifdef FASTFLOAT_VISUAL_STUDIO +#if defined(_WIN32) && !defined(__clang__) +// Note MinGW falls here too #include #if !defined(_M_X64) && !defined(_M_ARM64)// _umul128 for x86, arm From 609c48c2a2181ac83ec4bd24549a6caec55e9da5 Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Wed, 21 Oct 2020 16:56:44 -0400 Subject: [PATCH 2/4] Another tweak. --- tests/exhaustive32_midpoint.cpp | 26 +++++++++++++++++++++++++- tests/random_string.cpp | 26 +++++++++++++++++++++++++- tests/string_test.cpp | 27 +++++++++++++++++++++++++-- 3 files changed, 75 insertions(+), 4 deletions(-) diff --git a/tests/exhaustive32_midpoint.cpp b/tests/exhaustive32_midpoint.cpp index 42afff3..377d456 100644 --- a/tests/exhaustive32_midpoint.cpp +++ b/tests/exhaustive32_midpoint.cpp @@ -4,6 +4,25 @@ #include #include +#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) +// Anything at all that is related to cygwin, msys and so forth will +// always use this fallback because we cannot rely on it behaving as normal +// gcc. +#include +#include +// workaround for CYGWIN +double cygwin_strtod_l(const char* start, char** end) { + double d; + std::stringstream ss; + ss.imbue(std::locale::classic()); + ss << start; + ss >> d; + size_t nread = ss.tellg(); + *end = const_cast(start) + nread; + return d; +} +#endif + template char *to_string(T d, char *buffer) { auto written = std::snprintf(buffer, 64, "%.*e", std::numeric_limits::max_digits10 - 1, d); @@ -12,7 +31,9 @@ template char *to_string(T d, char *buffer) { void strtod_from_string(const char * st, float& d) { char *pr = (char *)st; -#ifdef _WIN32 +#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) + d = cygwin_strtod_l(st, &pr, c_locale); +#elif defined(_WIN32) static _locale_t c_locale = _create_locale(LC_ALL, "C"); d = _strtof_l(st, &pr, c_locale); #else @@ -73,6 +94,9 @@ void allvalues() { } int main() { +#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) + std::cout << "Warning: msys/cygwin detected. This particular test is likely to generate false failures due to our reliance on the underlying runtime library." << std::endl; +#endif allvalues(); std::cout << std::endl; std::cout << "all ok" << std::endl; diff --git a/tests/random_string.cpp b/tests/random_string.cpp index b40eb07..88a8673 100644 --- a/tests/random_string.cpp +++ b/tests/random_string.cpp @@ -2,6 +2,25 @@ #include #include +#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) +// Anything at all that is related to cygwin, msys and so forth will +// always use this fallback because we cannot rely on it behaving as normal +// gcc. +#include +#include +// workaround for CYGWIN +double cygwin_strtod_l(const char* start, char** end) { + double d; + std::stringstream ss; + ss.imbue(std::locale::classic()); + ss << start; + ss >> d; + size_t nread = ss.tellg(); + *end = const_cast(start) + nread; + return d; +} +#endif + class RandomEngine { public: RandomEngine() = delete; @@ -103,7 +122,9 @@ std::pair strtod_from_string(char *st) { std::pair strtof_from_string(char *st) { float d; char *pr; -#ifdef _WIN32 +#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) + d = cygwin_strtod_l(st, &pr, c_locale); +#elif defined(_WIN32) static _locale_t c_locale = _create_locale(LC_ALL, "C"); d = _strtof_l(st, &pr, c_locale); #else @@ -178,6 +199,9 @@ bool tester(int seed, size_t volume) { } int main() { +#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) + std::cout << "Warning: msys/cygwin detected. This particular test is likely to generate false failures due to our reliance on the underlying runtime library." << std::endl; +#endif if (tester(1234344, 100000000)) { std::cout << "All tests ok." << std::endl; return EXIT_SUCCESS; diff --git a/tests/string_test.cpp b/tests/string_test.cpp index a7f9c54..3686def 100644 --- a/tests/string_test.cpp +++ b/tests/string_test.cpp @@ -2,6 +2,25 @@ #include +#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) +// Anything at all that is related to cygwin, msys and so forth will +// always use this fallback because we cannot rely on it behaving as normal +// gcc. +#include +#include +// workaround for CYGWIN +double cygwin_strtod_l(const char* start, char** end) { + double d; + std::stringstream ss; + ss.imbue(std::locale::classic()); + ss << start; + ss >> d; + size_t nread = ss.tellg(); + *end = const_cast(start) + nread; + return d; +} +#endif + inline void Assert(bool Assertion) { if (!Assertion) throw std::runtime_error("bug"); @@ -66,7 +85,9 @@ void strtod_from_string(const std::string &st, double& d) { template <> void strtod_from_string(const std::string &st, float& d) { char *pr = (char *)st.data(); -#ifdef _WIN32 +#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) + d = cygwin_strtod_l(st, &pr, c_locale); +#elif defined(_WIN32) static _locale_t c_locale = _create_locale(LC_ALL, "C"); d = _strtof_l(st.data(), &pr, c_locale); #else @@ -215,7 +236,9 @@ bool partow_test() { int main() { - +#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) + std::cout << "Warning: msys/cygwin detected. This particular test is likely to generate false failures due to our reliance on the underlying runtime library." << std::endl; +#endif std::cout << "32 bits checks" << std::endl; Assert(partow_test()); Assert(test()); From 903c1f1c31890b2ec285bc98e470285e10ca4390 Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Wed, 21 Oct 2020 17:10:06 -0400 Subject: [PATCH 3/4] Another tweak. --- tests/exhaustive32_midpoint.cpp | 2 +- tests/random_string.cpp | 2 +- tests/string_test.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/exhaustive32_midpoint.cpp b/tests/exhaustive32_midpoint.cpp index 377d456..f473577 100644 --- a/tests/exhaustive32_midpoint.cpp +++ b/tests/exhaustive32_midpoint.cpp @@ -32,7 +32,7 @@ template char *to_string(T d, char *buffer) { void strtod_from_string(const char * st, float& d) { char *pr = (char *)st; #if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) - d = cygwin_strtod_l(st, &pr, c_locale); + d = cygwin_strtod_l(st, &pr); #elif defined(_WIN32) static _locale_t c_locale = _create_locale(LC_ALL, "C"); d = _strtof_l(st, &pr, c_locale); diff --git a/tests/random_string.cpp b/tests/random_string.cpp index 88a8673..f5a8d51 100644 --- a/tests/random_string.cpp +++ b/tests/random_string.cpp @@ -123,7 +123,7 @@ std::pair strtof_from_string(char *st) { float d; char *pr; #if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) - d = cygwin_strtod_l(st, &pr, c_locale); + d = cygwin_strtod_l(st, &pr); #elif defined(_WIN32) static _locale_t c_locale = _create_locale(LC_ALL, "C"); d = _strtof_l(st, &pr, c_locale); diff --git a/tests/string_test.cpp b/tests/string_test.cpp index 3686def..22e16fe 100644 --- a/tests/string_test.cpp +++ b/tests/string_test.cpp @@ -86,7 +86,7 @@ template <> void strtod_from_string(const std::string &st, float& d) { char *pr = (char *)st.data(); #if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) - d = cygwin_strtod_l(st, &pr, c_locale); + d = cygwin_strtod_l(st, &pr); #elif defined(_WIN32) static _locale_t c_locale = _create_locale(LC_ALL, "C"); d = _strtof_l(st.data(), &pr, c_locale); From f6e1d938a81e07c6ed3646b8354bc46e345b44f1 Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Wed, 21 Oct 2020 18:04:08 -0400 Subject: [PATCH 4/4] Another tweak. --- tests/string_test.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/string_test.cpp b/tests/string_test.cpp index 22e16fe..e2d6b96 100644 --- a/tests/string_test.cpp +++ b/tests/string_test.cpp @@ -69,32 +69,32 @@ void strtod_from_string(const std::string &st, T& d); template <> void strtod_from_string(const std::string &st, double& d) { - char *pr = (char *)st.data(); + char *pr = (char *)st.c_str(); #ifdef _WIN32 static _locale_t c_locale = _create_locale(LC_ALL, "C"); - d = _strtod_l(st.data(), &pr, c_locale); + d = _strtod_l(st.c_str(), &pr, c_locale); #else static locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL); - d = strtod_l(st.data(), &pr, c_locale); + d = strtod_l(st.c_str(), &pr, c_locale); #endif - if (pr == st.data()) { + if (pr == st.c_str()) { throw std::runtime_error("bug in strtod_from_string"); } } template <> void strtod_from_string(const std::string &st, float& d) { - char *pr = (char *)st.data(); + char *pr = (char *)st.c_str(); #if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) - d = cygwin_strtod_l(st, &pr); + d = cygwin_strtod_l(st.c_str(), &pr); #elif defined(_WIN32) static _locale_t c_locale = _create_locale(LC_ALL, "C"); - d = _strtof_l(st.data(), &pr, c_locale); + d = _strtof_l(st.c_str(), &pr, c_locale); #else static locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL); - d = strtof_l(st.data(), &pr, c_locale); + d = strtof_l(st.c_str(), &pr, c_locale); #endif - if (pr == st.data()) { + if (pr == st.c_str()) { throw std::runtime_error("bug in strtod_from_string"); } }