Merge pull request #25 from red0124/feature/win_msvc_ci

Feature/win msvc ci
This commit is contained in:
red0124 2023-07-29 16:25:26 +02:00 committed by GitHub
commit 78c75abec7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 927 additions and 950 deletions

63
.github/workflows/win-msvc.yml vendored Normal file
View File

@ -0,0 +1,63 @@
name: win-msvc-ci
on:
push:
branches:
- master
- feature/**
- improvement/**
- bugfix/**
pull_request:
branches:
- master
- feature/**
- improvement/**
- bugfix/**
jobs:
ci:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
defaults:
run:
shell: bash
runs-on: ${{ matrix.config.os }}
strategy:
fail-fast: false
matrix:
config:
- os: windows-2019
vs: "Visual Studio 16 2019"
- os: windows-latest
vs: "Visual Studio 17 2022"
build: [Debug, Release]
platform: [Win32, x64]
name: "${{matrix.config.vs}}:${{matrix.platform}}:${{matrix.build}}"
steps:
- name: checkout
uses: actions/checkout@v2
- name: Install dependencies
run: script/ci_install_deps.sh
- name: Configure
run: >-
cmake -S test -B build -D CMAKE_BUILD_TYPE=${{matrix.build}}
-G "${{matrix.config.vs}}" -A ${{matrix.platform}}
- name: Build
run: cmake --build build -j ${{steps.cores.outputs.count}}
- name: Run
working-directory: build
run: >-
ctest -C Debug --output-on-failure -j ${{steps.cores.outputs.count}}

View File

@ -13,6 +13,7 @@
[![ubuntu-latest-icc](https://github.com/red0124/ssp/workflows/ubuntu-latest-icc-ci/badge.svg)](https://github.com/red0124/ssp/actions/workflows/ubuntu-latest-icc.yml) [![ubuntu-latest-icc](https://github.com/red0124/ssp/workflows/ubuntu-latest-icc-ci/badge.svg)](https://github.com/red0124/ssp/actions/workflows/ubuntu-latest-icc.yml)
[![windows-msys2-gcc](https://github.com/red0124/ssp/workflows/win-msys2-gcc-ci/badge.svg)](https://github.com/red0124/ssp/actions/workflows/win-msys2-gcc.yml) [![windows-msys2-gcc](https://github.com/red0124/ssp/workflows/win-msys2-gcc-ci/badge.svg)](https://github.com/red0124/ssp/actions/workflows/win-msys2-gcc.yml)
[![windows-msys2-clang](https://github.com/red0124/ssp/workflows/win-msys2-clang-ci/badge.svg)](https://github.com/red0124/ssp/actions/workflows/win-msys2-clang.yml) [![windows-msys2-clang](https://github.com/red0124/ssp/workflows/win-msys2-clang-ci/badge.svg)](https://github.com/red0124/ssp/actions/workflows/win-msys2-clang.yml)
[![win-msvc-ci](https://github.com/red0124/ssp/workflows/win-msvc-ci/badge.svg)](https://github.com/red0124/ssp/actions/workflows/win-msvc.yml)
A header only "csv" parser which is fast and versatile with modern C++ api. Requires compiler with C++17 support. [Can also be used to convert strings to specific types.](#The-converter) A header only "csv" parser which is fast and versatile with modern C++ api. Requires compiler with C++17 support. [Can also be used to convert strings to specific types.](#The-converter)

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <cstdlib>
#include <cstring> #include <string>
#ifdef CMAKE_GITHUB_CI #ifdef CMAKE_GITHUB_CI
#include <doctest/doctest.h> #include <doctest/doctest.h>
@ -9,40 +9,22 @@
#endif #endif
struct buffer { struct buffer {
char* data_{nullptr}; std::string data_;
char* operator()(const char* data) { char *operator()(const std::string &data) {
if (data_) { data_ = data;
delete[] data_; return data_.data();
}
data_ = new char[strlen(data) + 1];
strcpy(data_, data);
return data_;
} }
char* append(const char* data) { char *append(const std::string &data) {
if (data_) { data_ += data;
char* new_data_ = new char[strlen(data_) + strlen(data) + 1]; return data_.data();
strcpy(new_data_, data_);
strcat(new_data_, data);
delete[] data_;
data_ = new_data_;
return data_;
} else {
return operator()(data);
}
} }
char* append_overwrite_last(const char* data, size_t size) { char *append_overwrite_last(const std::string &data, size_t size) {
data_[strlen(data_) - size] = '\0'; data_.resize(data_.size() - size);
return append(data); return append(data);
} }
~buffer() {
if (data_) {
delete[] data_;
}
}
}; };
[[maybe_unused]] inline buffer buff; [[maybe_unused]] inline buffer buff;

View File

@ -20,18 +20,15 @@ struct unique_file_name {
const std::string name; const std::string name;
unique_file_name() unique_file_name()
: name{"random_" + std::to_string(i++) + time_now_rand() + : name{"random_" + std::to_string(i++) + time_now_rand() + "_file.csv"} {}
"_file.csv"} {
}
~unique_file_name() { ~unique_file_name() { std::filesystem::remove(name); }
std::filesystem::remove(name);
}
}; };
void replace_all(std::string &s, const std::string &from, void replace_all(std::string &s, const std::string &from,
const std::string &to) { const std::string &to) {
if (from.empty()) return; if (from.empty())
return;
size_t start_pos = 0; size_t start_pos = 0;
while ((start_pos = s.find(from, start_pos)) != std::string::npos) { while ((start_pos = s.find(from, start_pos)) != std::string::npos) {
s.replace(start_pos, from.length(), to); s.replace(start_pos, from.length(), to);
@ -65,9 +62,7 @@ struct X {
.append(delim) .append(delim)
.append(s); .append(s);
} }
auto tied() const { auto tied() const { return std::tie(i, d, s); }
return std::tie(i, d, s);
}
}; };
template <typename T> template <typename T>
@ -261,15 +256,14 @@ TEST_CASE("parser test various cases") {
std::vector<X> i2; std::vector<X> i2;
while (!p.eof()) { while (!p.eof()) {
auto a = auto a = p.get_object<X, ss::ax<int, excluded>, double, std::string>();
p.get_object<X, ss::ax<int, excluded>, double, std::string>();
if (p.valid()) { if (p.valid()) {
i.push_back(a); i.push_back(a);
} }
} }
for (auto&& a : p2.iterate_object<X, ss::ax<int, excluded>, double, for (auto &&a :
std::string>()) { p2.iterate_object<X, ss::ax<int, excluded>, double, std::string>()) {
if (p2.valid()) { if (p2.valid()) {
i2.push_back(std::move(a)); i2.push_back(std::move(a));
} }
@ -283,7 +277,7 @@ TEST_CASE("parser test various cases") {
} }
std::copy_if(data.begin(), data.end(), expected.begin(), std::copy_if(data.begin(), data.end(), expected.begin(),
[](const X& x) { return x.i != excluded; }); [&](const X &x) { return x.i != excluded; });
CHECK_EQ(i, expected); CHECK_EQ(i, expected);
CHECK_EQ(i2, expected); CHECK_EQ(i2, expected);
} }
@ -344,13 +338,10 @@ struct test_struct {
int i; int i;
double d; double d;
char c; char c;
auto tied() { auto tied() { return std::tie(i, d, c); }
return std::tie(i, d, c);
}
}; };
void expect_test_struct(const test_struct&) { void expect_test_struct(const test_struct &) {}
}
// various scenarios // various scenarios
TEST_CASE("parser test composite conversion") { TEST_CASE("parser test composite conversion") {
@ -374,11 +365,11 @@ TEST_CASE("parser test composite conversion") {
{ {
constexpr static auto expectedData = std::tuple{10, 'a', 11.1}; constexpr static auto expectedData = std::tuple{10, 'a', 11.1};
auto [d1, d2, d3, d4] = auto [d1, d2, d3, d4] = p.try_next<int, int, double>(fail)
p.try_next<int, int, double>(fail)
.or_else<test_struct>(fail) .or_else<test_struct>(fail)
.or_else<int, char, double>( .or_else<int, char, double>([&](auto &&data) {
[](auto&& data) { CHECK_EQ(data, expectedData); }) CHECK_EQ(data, expectedData);
})
.on_error(fail) .on_error(fail)
.or_else<test_tuple>(fail) .or_else<test_tuple>(fail)
.values(); .values();
@ -396,7 +387,7 @@ TEST_CASE("parser test composite conversion") {
constexpr static auto expectedData = std::tuple{10, 20, 11.1}; constexpr static auto expectedData = std::tuple{10, 20, 11.1};
auto [d1, d2, d3, d4] = auto [d1, d2, d3, d4] =
p.try_next<int, int, double>([](auto& i1, auto i2, double d) { p.try_next<int, int, double>([&](auto &i1, auto i2, double d) {
CHECK_EQ(std::tie(i1, i2, d), expectedData); CHECK_EQ(std::tie(i1, i2, d), expectedData);
}) })
.on_error(fail) .on_error(fail)
@ -438,8 +429,7 @@ TEST_CASE("parser test composite conversion") {
{ {
REQUIRE(!p.eof()); REQUIRE(!p.eof());
auto [d1, d2] = auto [d1, d2] = p.try_next<int, double>([](auto &i, auto &d) {
p.try_next<int, double>([](auto& i, auto& d) {
REQUIRE_EQ(std::tie(i, d), std::tuple{10, 11.1}); REQUIRE_EQ(std::tie(i, d), std::tuple{10, 11.1});
}) })
.or_else<int, double>([](auto &, auto &) { FAIL(""); }) .or_else<int, double>([](auto &, auto &) { FAIL(""); })
@ -466,8 +456,7 @@ TEST_CASE("parser test composite conversion") {
{ {
REQUIRE(!p.eof()); REQUIRE(!p.eof());
auto [d1, d2, d3, d4, d5] = auto [d1, d2, d3, d4, d5] = p.try_next<int, int, double>(fail)
p.try_next<int, int, double>(fail)
.or_object<test_struct, int, double, char>() .or_object<test_struct, int, double, char>()
.or_else<test_struct>(expect_test_struct) .or_else<test_struct>(expect_test_struct)
.or_else<test_tuple>(fail) .or_else<test_tuple>(fail)
@ -564,28 +553,22 @@ TEST_CASE("parser test composite conversion") {
CHECK(p.eof()); CHECK(p.eof());
} }
size_t move_called = 0;
struct my_string { struct my_string {
char *data{nullptr}; char *data{nullptr};
my_string() = default; my_string() = default;
~my_string() { ~my_string() { delete[] data; }
delete[] data;
}
// make sure no object is copied // make sure no object is copied
my_string(const my_string &) = delete; my_string(const my_string &) = delete;
my_string &operator=(const my_string &) = delete; my_string &operator=(const my_string &) = delete;
my_string(my_string &&other) : data{other.data} { my_string(my_string &&other) : data{other.data} {
move_called++;
other.data = nullptr; other.data = nullptr;
} }
my_string &operator=(my_string &&other) { my_string &operator=(my_string &&other) {
move_called++;
data = other.data; data = other.data;
return *this; return *this;
} }
@ -604,54 +587,9 @@ struct xyz {
my_string x; my_string x;
my_string y; my_string y;
my_string z; my_string z;
auto tied() { auto tied() { return std::tie(x, y, z); }
return std::tie(x, y, z);
}
}; };
TEST_CASE("parser test the moving of parsed values") {
{
unique_file_name f;
{
std::ofstream out{f.name};
out << "x" << std::endl;
}
ss::parser p{f.name, ","};
auto x = p.get_next<my_string>();
CHECK_LE(move_called, 1);
move_called = 0;
}
unique_file_name f;
{
std::ofstream out{f.name};
out << "a,b,c" << std::endl;
}
{
ss::parser p{f.name, ","};
auto x = p.get_next<my_string, my_string, my_string>();
CHECK_LE(move_called, 3);
move_called = 0;
}
{
ss::parser p{f.name, ","};
auto x = p.get_object<xyz, my_string, my_string, my_string>();
CHECK_LE(move_called, 6);
move_called = 0;
}
{
ss::parser p{f.name, ","};
auto x = p.get_next<xyz>();
CHECK_LE(move_called, 6);
move_called = 0;
}
}
TEST_CASE("parser test the moving of parsed composite values") { TEST_CASE("parser test the moving of parsed composite values") {
// to compile is enough // to compile is enough
return; return;
@ -735,12 +673,9 @@ std::string no_escape(std::string& s) {
TEST_CASE("parser test csv on multiple lines with escapes") { TEST_CASE("parser test csv on multiple lines with escapes") {
unique_file_name f; unique_file_name f;
std::vector<X> data = {{1, 2, "x\\\nx\\\r\nx"}, std::vector<X> data = {
{5, 6, "z\\\nz\\\nz"}, {1, 2, "x\\\nx\\\r\nx"}, {5, 6, "z\\\nz\\\nz"}, {7, 8, "u"},
{7, 8, "u"}, {3, 4, "y\\\ny\\\ny"}, {9, 10, "v\\\\"}, {11, 12, "w\\\n"}};
{3, 4, "y\\\ny\\\ny"},
{9, 10, "v\\\\"},
{11, 12, "w\\\n"}};
for (auto &[_, __, s] : data) { for (auto &[_, __, s] : data) {
update_if_crlf(s); update_if_crlf(s);
} }
@ -833,8 +768,8 @@ TEST_CASE("parser test multiline restricted") {
out << "19,20,just strings" << std::endl; out << "19,20,just strings" << std::endl;
} }
ss::parser<ss::multiline_restricted<2>, ss::quote<'"'>, ss::escape<'\\'>> ss::parser<ss::multiline_restricted<2>, ss::quote<'"'>, ss::escape<'\\'>> p{
p{f.name, ","}; f.name, ","};
std::vector<X> i; std::vector<X> i;
while (!p.eof()) { while (!p.eof()) {
@ -859,16 +794,13 @@ TEST_CASE("parser test multiline restricted") {
CHECK_EQ(i, data); CHECK_EQ(i, data);
} }
template <typename T, typename Tuple> template <typename T, typename Tuple> struct has_type;
struct has_type;
template <typename T, typename... Us> template <typename T, typename... Us>
struct has_type<T, std::tuple<Us...>> struct has_type<T, std::tuple<Us...>>
: std::disjunction<std::is_same<T, Us>...> {}; : std::disjunction<std::is_same<T, Us>...> {};
void checkSize(size_t size1, size_t size2) { void checkSize(size_t size1, size_t size2) { CHECK_EQ(size1, size2); }
CHECK_EQ(size1, size2);
}
template <typename... Ts> template <typename... Ts>
void testFields(const std::string file_name, const std::vector<X> &data, void testFields(const std::string file_name, const std::vector<X> &data,
@ -996,8 +928,7 @@ TEST_CASE("parser test various cases with header") {
p.use_fields(Str, Int, Dbl); p.use_fields(Str, Int, Dbl);
{ {
auto [string_, int_, double_] = auto [string_, int_, double_] = p.get_next<std::string, int, double>();
p.get_next<std::string, int, double>();
CHECK_EQ(double_, data[3].d); CHECK_EQ(double_, data[3].d);
CHECK_EQ(int_, data[3].i); CHECK_EQ(int_, data[3].i);
CHECK_EQ(string_, data[3].s); CHECK_EQ(string_, data[3].s);