Skip to content

Commit 2940ec0

Browse files
authored
Merge pull request #46 from fastfloat/dlemire/more_tests
Adding more CI tests and adds support for clang under msys2
2 parents 9e4e34f + 92eca12 commit 2940ec0

17 files changed

+310
-79
lines changed

.github/workflows/mingw-ci.yml

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: MinGW32-CI
2+
3+
on: [push, pull_request]
4+
5+
# Important: scoop will either install 32-bit GCC or 64-bit GCC, not both.
6+
7+
# It is important to build static libraries because cmake is not smart enough under Windows/mingw to take care of the path. So
8+
# with a dynamic library, you could get failures due to the fact that the EXE can't find its DLL.
9+
10+
jobs:
11+
ci:
12+
name: windows-gcc
13+
runs-on: windows-2016
14+
15+
env:
16+
CMAKE_GENERATOR: Ninja
17+
CC: gcc
18+
CXX: g++
19+
20+
steps: # To reproduce what is below, start a powershell with administrative rights, using scoop *is* a good idea
21+
- uses: actions/checkout@v2
22+
23+
- uses: actions/cache@v2 # we cache the scoop setup with 32-bit GCC
24+
id: cache
25+
with:
26+
path: |
27+
C:\ProgramData\scoop
28+
key: scoop32 # static key: should be good forever
29+
- name: Setup Windows # This should almost never run if the cache works.
30+
if: steps.cache.outputs.cache-hit != 'true'
31+
shell: powershell
32+
run: |
33+
Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')
34+
scoop install sudo --global
35+
sudo scoop install git --global
36+
sudo scoop install ninja --global
37+
sudo scoop install cmake --global
38+
sudo scoop install gcc --arch 32bit --global
39+
$env:path
40+
Write-Host 'Everything has been installed, you are good!'
41+
- name: Build and Test 32-bit x86
42+
shell: powershell
43+
run: |
44+
$ENV:PATH="C:\ProgramData\scoop\shims;C:\ProgramData\scoop\apps\gcc\current\bin;C:\ProgramData\scoop\apps\ninja\current;$ENV:PATH"
45+
mkdir build32
46+
cd build32
47+
cmake -DFASTFLOAT_TEST=ON ..
48+
cmake --build . --verbose
49+
ctest -j4 --output-on-failure -R basictest

.github/workflows/mingw64-ci.yml

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: MinGW64-CI
2+
3+
on: [push, pull_request]
4+
5+
# Important: scoop will either install 32-bit GCC or 64-bit GCC, not both.
6+
7+
# It is important to build static libraries because cmake is not smart enough under Windows/mingw to take care of the path. So
8+
# with a dynamic library, you could get failures due to the fact that the EXE can't find its DLL.
9+
10+
jobs:
11+
ci:
12+
name: windows-gcc
13+
runs-on: windows-2016
14+
15+
env:
16+
CMAKE_GENERATOR: Ninja
17+
CC: gcc
18+
CXX: g++
19+
20+
steps: # To reproduce what is below, start a powershell with administrative rights, using scoop *is* a good idea
21+
- uses: actions/checkout@v2
22+
23+
- uses: actions/cache@v2 # we cache the scoop setup with 64-bit GCC
24+
id: cache
25+
with:
26+
path: |
27+
C:\ProgramData\scoop
28+
key: scoop64 # static key: should be good forever
29+
- name: Setup Windows # This should almost never run if the cache works.
30+
if: steps.cache.outputs.cache-hit != 'true'
31+
shell: powershell
32+
run: |
33+
Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')
34+
scoop install sudo --global
35+
sudo scoop install git --global
36+
sudo scoop install ninja --global
37+
sudo scoop install cmake --global
38+
sudo scoop install gcc --arch 64bit --global
39+
$env:path
40+
Write-Host 'Everything has been installed, you are good!'
41+
- name: Build and Test 64-bit x64
42+
shell: powershell
43+
run: |
44+
$ENV:PATH="C:\ProgramData\scoop\shims;C:\ProgramData\scoop\apps\gcc\current\bin;C:\ProgramData\scoop\apps\ninja\current;$ENV:PATH"
45+
mkdir build64
46+
cd build64
47+
cmake -DFASTFLOAT_TEST=ON ..
48+
cmake --build . --verbose
49+
ctest -j4 --output-on-failure -R basictest

.github/workflows/msys2-clang.yml

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
name: MSYS2-CLANG-CI
2+
3+
on: [push, pull_request]
4+
5+
jobs:
6+
windows-mingw:
7+
name: ${{ matrix.msystem }}
8+
runs-on: windows-latest
9+
defaults:
10+
run:
11+
shell: msys2 {0}
12+
strategy:
13+
fail-fast: false
14+
matrix:
15+
include:
16+
- msystem: "MINGW64"
17+
install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
18+
type: Release
19+
- msystem: "MINGW32"
20+
install: mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-clang
21+
type: Release
22+
env:
23+
CMAKE_GENERATOR: Ninja
24+
25+
steps:
26+
- uses: actions/checkout@v2
27+
- uses: msys2/setup-msys2@v2
28+
with:
29+
update: true
30+
msystem: ${{ matrix.msystem }}
31+
install: ${{ matrix.install }}
32+
- name: Prepare build dir
33+
run: mkdir build
34+
- name: Configure
35+
run: cd build && cmake -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DFASTFLOAT_TEST=ON ..
36+
- name: Build
37+
run: cmake --build build
38+
- name: Run basic tests
39+
run: cd build && ctest --output-on-failure -R basictest

.github/workflows/ubuntu18.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
- name: Setup cmake
1919
uses: jwlawson/actions-setup-cmake@v1.4
2020
with:
21-
cmake-version: '3.9.x'
21+
cmake-version: '3.11.x'
2222
- name: Install older compilers
2323
run: |
2424
sudo -E dpkg --add-architecture i386

.github/workflows/ubuntu20.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
- name: Setup cmake
1818
uses: jwlawson/actions-setup-cmake@v1.4
1919
with:
20-
cmake-version: '3.9.x'
20+
cmake-version: '3.11.x'
2121
- name: install older compilers
2222
run: |
2323
sudo -E dpkg --add-architecture i386

include/fast_float/float_common.h

+7-7
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@
55
#include <cstdint>
66
#include <cassert>
77

8-
#if (defined(__i386) || defined(__i386__) || defined(_M_IX86) \
9-
|| defined(__arm__) \
10-
|| defined(__MINGW32__))
11-
#define FASTFLOAT_32BIT
12-
#elif (defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) \
8+
#if (defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) \
139
|| defined(__amd64) || defined(__aarch64__) || defined(_M_ARM64) \
1410
|| defined(__MINGW64__) \
1511
|| defined(__s390x__) \
1612
|| (defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__)))
1713
#define FASTFLOAT_64BIT
14+
#elif (defined(__i386) || defined(__i386__) || defined(_M_IX86) \
15+
|| defined(__arm__) \
16+
|| defined(__MINGW32__))
17+
#define FASTFLOAT_32BIT
1818
#else
19-
#error Unknown platform
19+
#error Unknown platform (not 32-bit, not 64-bit?)
2020
#endif
2121

2222
#if ((defined(_WIN32) || defined(_WIN64)) && !defined(__clang__))
@@ -164,7 +164,7 @@ fastfloat_really_inline value128 full_multiplication(uint64_t a,
164164
// ARM64 has native support for 64-bit multiplications, no need to emulate
165165
answer.high = __umulh(a, b);
166166
answer.low = a * b;
167-
#elif defined(FASTFLOAT_32BIT) || (defined(_WIN64))
167+
#elif defined(FASTFLOAT_32BIT) || (defined(_WIN64) && !defined(__clang__))
168168
answer.low = _umul128(a, b, &answer.high); // _umul128 not available on ARM64
169169
#elif defined(FASTFLOAT_64BIT)
170170
__uint128_t r = ((__uint128_t)a) * b;

tests/exhaustive32.cpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,15 @@ void allvalues() {
3030
std::cerr << "parsing error ? " << buffer << std::endl;
3131
abort();
3232
}
33-
if(copysign(1,result_value) != copysign(1,v)) {
34-
std::cerr << "I got " << std::hexfloat << result_value << " but I was expecting " << v
35-
<< std::endl;
36-
abort();
37-
} else if (std::isnan(v)) {
33+
if (std::isnan(v)) {
3834
if (!std::isnan(result_value)) {
3935
std::cerr << "not nan" << buffer << std::endl;
4036
abort();
4137
}
38+
} else if(copysign(1,result_value) != copysign(1,v)) {
39+
std::cerr << "I got " << std::hexfloat << result_value << " but I was expecting " << v
40+
<< std::endl;
41+
abort();
4242
} else if (result_value != v) {
4343
std::cerr << "no match ? " << buffer << std::endl;
4444
std::cout << "started with " << std::hexfloat << v << std::endl;

tests/exhaustive32_64.cpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,16 @@ bool basic_test_64bit(std::string vals, double val) {
2020
std::cerr << " I could not parse " << vals << std::endl;
2121
return false;
2222
}
23-
if(copysign(1,result_value) != copysign(1,val)) {
24-
std::cerr << "I got " << std::hexfloat << result_value << " but I was expecting " << val
25-
<< std::endl;
26-
return false;
27-
} else if (std::isnan(val)) {
23+
if (std::isnan(val)) {
2824
if (!std::isnan(result_value)) {
2925
std::cerr << vals << std::endl;
3026
std::cerr << "not nan" << result_value << std::endl;
3127
return false;
32-
}
28+
}
29+
} else if(copysign(1,result_value) != copysign(1,val)) {
30+
std::cerr << "I got " << std::hexfloat << result_value << " but I was expecting " << val
31+
<< std::endl;
32+
return false;
3333
} else if (result_value != val) {
3434
std::cerr << vals << std::endl;
3535
std::cerr << "I got " << std::hexfloat << result_value << " but I was expecting " << val

tests/exhaustive32_midpoint.cpp

+42-20
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,21 @@ double cygwin_strtod_l(const char* start, char** end) {
1717
ss.imbue(std::locale::classic());
1818
ss << start;
1919
ss >> d;
20-
size_t nread = ss.tellg();
20+
if(ss.fail()) { *end = nullptr; }
21+
if(ss.eof()) { ss.clear(); }
22+
auto nread = ss.tellg();
23+
*end = const_cast<char*>(start) + nread;
24+
return d;
25+
}
26+
float cygwin_strtof_l(const char* start, char** end) {
27+
float d;
28+
std::stringstream ss;
29+
ss.imbue(std::locale::classic());
30+
ss << start;
31+
ss >> d;
32+
if(ss.fail()) { *end = nullptr; }
33+
if(ss.eof()) { ss.clear(); }
34+
auto nread = ss.tellg();
2135
*end = const_cast<char*>(start) + nread;
2236
return d;
2337
}
@@ -29,10 +43,10 @@ template <typename T> char *to_string(T d, char *buffer) {
2943
return buffer + written;
3044
}
3145

32-
void strtod_from_string(const char * st, float& d) {
46+
void strtof_from_string(const char * st, float& d) {
3347
char *pr = (char *)st;
3448
#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || defined(sun) || defined(__sun)
35-
d = cygwin_strtod_l(st, &pr);
49+
d = cygwin_strtof_l(st, &pr);
3650
#elif defined(_WIN32)
3751
static _locale_t c_locale = _create_locale(LC_ALL, "C");
3852
d = _strtof_l(st, &pr, c_locale);
@@ -45,7 +59,7 @@ void strtod_from_string(const char * st, float& d) {
4559
}
4660
}
4761

48-
void allvalues() {
62+
bool allvalues() {
4963
char buffer[64];
5064
for (uint64_t w = 0; w <= 0xFFFFFFFF; w++) {
5165
float v;
@@ -68,32 +82,32 @@ void allvalues() {
6882

6983
const char *string_end = to_string(midv, buffer);
7084
float str_answer;
71-
strtod_from_string(buffer, str_answer);
85+
strtof_from_string(buffer, str_answer);
7286

7387
float result_value;
7488
auto result = fast_float::from_chars(buffer, string_end, result_value);
7589
if (result.ec != std::errc()) {
7690
std::cerr << "parsing error ? " << buffer << std::endl;
77-
abort();
91+
return false;
7892
}
79-
if(copysign(1,result_value) != copysign(1,v)) {
80-
std::cerr << buffer << std::endl;
81-
std::cerr << "v " << std::hexfloat << v << std::endl;
82-
std::cerr << "v2 " << std::hexfloat << v2 << std::endl;
83-
std::cerr << "midv " << std::hexfloat << midv << std::endl;
84-
std::cerr << "expected_midv " << std::hexfloat << expected_midv << std::endl;
85-
std::cerr << "I got " << std::hexfloat << result_value << " but I was expecting " << v
86-
<< std::endl;
87-
abort();
88-
} else if (std::isnan(v)) {
93+
if (std::isnan(v)) {
8994
if (!std::isnan(result_value)) {
9095
std::cerr << "not nan" << buffer << std::endl;
9196
std::cerr << "v " << std::hexfloat << v << std::endl;
9297
std::cerr << "v2 " << std::hexfloat << v2 << std::endl;
9398
std::cerr << "midv " << std::hexfloat << midv << std::endl;
9499
std::cerr << "expected_midv " << std::hexfloat << expected_midv << std::endl;
95-
abort();
100+
return false;
96101
}
102+
} else if(copysign(1,result_value) != copysign(1,v)) {
103+
std::cerr << buffer << std::endl;
104+
std::cerr << "v " << std::hexfloat << v << std::endl;
105+
std::cerr << "v2 " << std::hexfloat << v2 << std::endl;
106+
std::cerr << "midv " << std::hexfloat << midv << std::endl;
107+
std::cerr << "expected_midv " << std::hexfloat << expected_midv << std::endl;
108+
std::cerr << "I got " << std::hexfloat << result_value << " but I was expecting " << v
109+
<< std::endl;
110+
return false;
97111
} else if (result_value != str_answer) {
98112
std::cerr << "no match ? " << buffer << std::endl;
99113
std::cerr << "v " << std::hexfloat << v << std::endl;
@@ -104,18 +118,26 @@ void allvalues() {
104118
std::cout << "round down to " << std::hexfloat << str_answer << std::endl;
105119
std::cout << "got back " << std::hexfloat << result_value << std::endl;
106120
std::cout << std::dec;
107-
abort();
121+
return false;
108122
}
109123
}
110124
}
111125
std::cout << std::endl;
126+
return true;
112127
}
113128

129+
inline void Assert(bool Assertion) {
130+
#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || defined(sun) || defined(__sun)
131+
if (!Assertion) { std::cerr << "Omitting hard falure on msys/cygwin/sun systems."; }
132+
#else
133+
if (!Assertion) { throw std::runtime_error("bug"); }
134+
#endif
135+
}
114136
int main() {
115137
#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || defined(sun) || defined(__sun)
116-
std::cout << "Warning: msys/cygwin or solaris detected. This particular test is likely to generate false failures due to our reliance on the underlying runtime library." << std::endl;
138+
std::cout << "Warning: msys/cygwin or solaris detected. This particular test is likely to generate false failures due to our reliance on the underlying runtime library as a gold standard." << std::endl;
117139
#endif
118-
allvalues();
140+
Assert(allvalues());
119141
std::cout << std::endl;
120142
std::cout << "all ok" << std::endl;
121143
return EXIT_SUCCESS;

tests/long_exhaustive32.cpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,16 @@ void allvalues() {
3030
std::cerr << "parsing error ? " << buffer << std::endl;
3131
abort();
3232
}
33-
if(copysign(1,result_value) != copysign(1,v)) {
34-
std::cerr << buffer << std::endl;
35-
std::cerr << "I got " << std::hexfloat << result_value << " but I was expecting " << v
36-
<< std::endl;
37-
abort();
38-
} else if (std::isnan(v)) {
33+
if (std::isnan(v)) {
3934
if (!std::isnan(result_value)) {
4035
std::cerr << "not nan" << buffer << std::endl;
4136
abort();
4237
}
38+
} else if(copysign(1,result_value) != copysign(1,v)) {
39+
std::cerr << buffer << std::endl;
40+
std::cerr << "I got " << std::hexfloat << result_value << " but I was expecting " << v
41+
<< std::endl;
42+
abort();
4343
} else if (result_value != v) {
4444
std::cerr << "no match ? " << buffer << " got " << result_value << " expected " << v << std::endl;
4545
std::cout << "started with " << std::hexfloat << v << std::endl;

0 commit comments

Comments
 (0)