mirror of
https://github.com/red0124/ssp.git
synced 2025-01-23 13:05:20 +01:00
Merge with master
This commit is contained in:
commit
560bf815dc
63
.github/workflows/win-msvc.yml
vendored
Normal file
63
.github/workflows/win-msvc.yml
vendored
Normal 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}}
|
11
README.md
11
README.md
@ -8,11 +8,12 @@
|
|||||||
```
|
```
|
||||||
|
|
||||||
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT)
|
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT)
|
||||||
![ubuntu-latest-gcc](https://github.com/red0124/ssp/workflows/ubuntu-latest-gcc-ci/badge.svg)
|
[![ubuntu-latest-gcc](https://github.com/red0124/ssp/workflows/ubuntu-latest-gcc-ci/badge.svg)](https://github.com/red0124/ssp/actions/workflows/ubuntu-latest-gcc.yml)
|
||||||
![ubuntu-latest-clang](https://github.com/red0124/ssp/workflows/ubuntu-latest-clang-ci/badge.svg)
|
[![ubuntu-latest-clang](https://github.com/red0124/ssp/workflows/ubuntu-latest-clang-ci/badge.svg)](https://github.com/red0124/ssp/actions/workflows/ubuntu-latest-clang.yml)
|
||||||
![ubuntu-latest-icc](https://github.com/red0124/ssp/workflows/ubuntu-latest-icc-ci/badge.svg)
|
[![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)
|
[![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)
|
[![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)
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ struct get_matcher<Matcher, T, Ts...> {
|
|||||||
struct is_matcher : is_instance_of_matcher<U, Matcher> {};
|
struct is_matcher : is_instance_of_matcher<U, Matcher> {};
|
||||||
|
|
||||||
static_assert(count_v<is_matcher, T, Ts...> <= 1,
|
static_assert(count_v<is_matcher, T, Ts...> <= 1,
|
||||||
"the same matcher is cannot"
|
"the same matcher cannot"
|
||||||
"be defined multiple times");
|
"be defined multiple times");
|
||||||
using type = std::conditional_t<is_matcher<T>::value, T,
|
using type = std::conditional_t<is_matcher<T>::value, T,
|
||||||
typename get_matcher<Matcher, Ts...>::type>;
|
typename get_matcher<Matcher, Ts...>::type>;
|
||||||
|
12
ssp.hpp
12
ssp.hpp
@ -17,6 +17,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#define SSP_DISABLE_FAST_FLOAT
|
#define SSP_DISABLE_FAST_FLOAT
|
||||||
|
|
||||||
|
|
||||||
namespace ss {
|
namespace ss {
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
@ -394,6 +395,7 @@ T to_object(U&& data) {
|
|||||||
|
|
||||||
} /* trait */
|
} /* trait */
|
||||||
|
|
||||||
|
|
||||||
namespace ss {
|
namespace ss {
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
@ -1380,6 +1382,7 @@ public:
|
|||||||
|
|
||||||
} /* ss */
|
} /* ss */
|
||||||
|
|
||||||
|
|
||||||
#ifndef SSP_DISABLE_FAST_FLOAT
|
#ifndef SSP_DISABLE_FAST_FLOAT
|
||||||
#else
|
#else
|
||||||
#endif
|
#endif
|
||||||
@ -1909,7 +1912,7 @@ private:
|
|||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
const split_data& resplit(line_ptr_type new_line, ssize_t new_size,
|
const split_data& resplit(line_ptr_type new_line, ssize_t new_size,
|
||||||
const std::string& delim = default_delimiter) {
|
const std::string& delim) {
|
||||||
return splitter_.resplit(new_line, new_size, delim);
|
return splitter_.resplit(new_line, new_size, delim);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2198,6 +2201,7 @@ private:
|
|||||||
|
|
||||||
} /* ss */
|
} /* ss */
|
||||||
|
|
||||||
|
|
||||||
namespace ss {
|
namespace ss {
|
||||||
|
|
||||||
template <typename... Matchers>
|
template <typename... Matchers>
|
||||||
@ -2339,8 +2343,7 @@ public:
|
|||||||
template <bool get_object, typename T, typename... Ts>
|
template <bool get_object, typename T, typename... Ts>
|
||||||
struct iterable {
|
struct iterable {
|
||||||
struct iterator {
|
struct iterator {
|
||||||
using value =
|
using value = std::conditional_t<get_object, T,
|
||||||
std::conditional_t<get_object, T,
|
|
||||||
no_void_validator_tup_t<T, Ts...>>;
|
no_void_validator_tup_t<T, Ts...>>;
|
||||||
|
|
||||||
iterator() : parser_{nullptr} {
|
iterator() : parser_{nullptr} {
|
||||||
@ -2812,7 +2815,8 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
next_line_converter_.resplit(next_line_buffer_, size);
|
next_line_converter_.resplit(next_line_buffer_, size,
|
||||||
|
delim_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#ifdef CMAKE_GITHUB_CI
|
#ifdef CMAKE_GITHUB_CI
|
||||||
#include <doctest/doctest.h>
|
#include <doctest/doctest.h>
|
||||||
@ -10,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;
|
||||||
|
@ -288,7 +288,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);
|
||||||
}
|
}
|
||||||
@ -383,7 +383,7 @@ TEST_CASE("parser test composite conversion") {
|
|||||||
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) { CHECK_EQ(data, expectedData); })
|
[&](auto&& data) { CHECK_EQ(data, expectedData); })
|
||||||
.on_error(fail)
|
.on_error(fail)
|
||||||
.or_else<test_tuple>(fail)
|
.or_else<test_tuple>(fail)
|
||||||
.values();
|
.values();
|
||||||
@ -401,7 +401,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)
|
||||||
@ -569,8 +569,6 @@ 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};
|
||||||
|
|
||||||
@ -585,12 +583,10 @@ struct my_string {
|
|||||||
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;
|
||||||
}
|
}
|
||||||
@ -614,49 +610,6 @@ struct xyz {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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;
|
||||||
|
Loading…
Reference in New Issue
Block a user