mirror of
https://github.com/red0124/ssp.git
synced 2025-12-16 06:39:55 +01:00
Compare commits
7 Commits
f8fdb97151
...
improvemen
| Author | SHA1 | Date | |
|---|---|---|---|
| d978e986de | |||
| 99d445bafe | |||
| 397cf21d18 | |||
| eb8f205300 | |||
| b618384054 | |||
| 4e4c3a6e02 | |||
| 0b3b719155 |
2
.github/workflows/coverage.yml
vendored
2
.github/workflows/coverage.yml
vendored
@@ -56,7 +56,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Run
|
- name: Run
|
||||||
working-directory: build
|
working-directory: build
|
||||||
run: ctest --output-on-failure
|
run: ctest --output-on-failure -j ${{steps.cores.outputs.count}}
|
||||||
|
|
||||||
- name: Generate coverage report
|
- name: Generate coverage report
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
2
.github/workflows/ubuntu-latest-clang.yml
vendored
2
.github/workflows/ubuntu-latest-clang.yml
vendored
@@ -66,4 +66,4 @@ jobs:
|
|||||||
|
|
||||||
- name: Run
|
- name: Run
|
||||||
working-directory: build
|
working-directory: build
|
||||||
run: ctest --output-on-failure
|
run: ctest --output-on-failure -j ${{steps.cores.outputs.count}}
|
||||||
|
|||||||
2
.github/workflows/ubuntu-latest-gcc.yml
vendored
2
.github/workflows/ubuntu-latest-gcc.yml
vendored
@@ -56,4 +56,4 @@ jobs:
|
|||||||
|
|
||||||
- name: Run
|
- name: Run
|
||||||
working-directory: build
|
working-directory: build
|
||||||
run: ctest --output-on-failure
|
run: ctest --output-on-failure -j ${{steps.cores.outputs.count}}
|
||||||
|
|||||||
2
.github/workflows/ubuntu-latest-icc.yml
vendored
2
.github/workflows/ubuntu-latest-icc.yml
vendored
@@ -74,4 +74,4 @@ jobs:
|
|||||||
|
|
||||||
- name: Run
|
- name: Run
|
||||||
working-directory: build
|
working-directory: build
|
||||||
run: ctest --output-on-failure
|
run: ctest --output-on-failure -j ${{steps.cores.outputs.count}}
|
||||||
|
|||||||
2
.github/workflows/win-msvc.yml
vendored
2
.github/workflows/win-msvc.yml
vendored
@@ -62,4 +62,4 @@ jobs:
|
|||||||
- name: Run
|
- name: Run
|
||||||
working-directory: build
|
working-directory: build
|
||||||
run: >-
|
run: >-
|
||||||
ctest -C Debug --output-on-failure
|
ctest -C Debug --output-on-failure -j ${{steps.cores.outputs.count}}
|
||||||
|
|||||||
2
.github/workflows/win-msys2-clang.yml
vendored
2
.github/workflows/win-msys2-clang.yml
vendored
@@ -73,4 +73,4 @@ jobs:
|
|||||||
|
|
||||||
- name: Run
|
- name: Run
|
||||||
working-directory: build
|
working-directory: build
|
||||||
run: ctest --output-on-failure
|
run: ctest --output-on-failure -j ${{steps.cores.outputs.count}}
|
||||||
|
|||||||
2
.github/workflows/win-msys2-gcc.yml
vendored
2
.github/workflows/win-msys2-gcc.yml
vendored
@@ -71,4 +71,4 @@ jobs:
|
|||||||
|
|
||||||
- name: Run
|
- name: Run
|
||||||
working-directory: build
|
working-directory: build
|
||||||
run: ctest --output-on-failure
|
run: ctest --output-on-failure -j ${{steps.cores.outputs.count}}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.14)
|
|||||||
|
|
||||||
project(
|
project(
|
||||||
ssp
|
ssp
|
||||||
VERSION 1.6.2
|
VERSION 1.6.1
|
||||||
DESCRIPTION "csv parser"
|
DESCRIPTION "csv parser"
|
||||||
HOMEPAGE_URL "https://github.com/red0124/ssp"
|
HOMEPAGE_URL "https://github.com/red0124/ssp"
|
||||||
LANGUAGES CXX
|
LANGUAGES CXX
|
||||||
|
|||||||
@@ -1,20 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <cerrno>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace ss {
|
namespace ss {
|
||||||
|
|
||||||
struct none {};
|
struct none {};
|
||||||
|
|
||||||
using string_range = std::pair<const char*, const char*>;
|
using string_range = std::pair<const char*, const char*>;
|
||||||
using split_data = std::vector<string_range>;
|
using split_data = std::vector<string_range>;
|
||||||
|
|
||||||
constexpr inline auto default_delimiter = ",";
|
constexpr inline auto default_delimiter = ",";
|
||||||
constexpr inline auto get_line_initial_buffer_size = 128;
|
|
||||||
|
|
||||||
template <bool StringError>
|
template <bool StringError>
|
||||||
inline void assert_string_error_defined() {
|
inline void assert_string_error_defined() {
|
||||||
@@ -27,66 +20,4 @@ inline void assert_throw_on_error_not_defined() {
|
|||||||
static_assert(!ThrowOnError, "cannot handle errors manually if "
|
static_assert(!ThrowOnError, "cannot handle errors manually if "
|
||||||
"'throw_on_error' is enabled");
|
"'throw_on_error' is enabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __unix__
|
|
||||||
inline ssize_t get_line(char** lineptr, size_t* n, FILE* stream) {
|
|
||||||
return getline(lineptr, n, stream);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
|
|
||||||
using ssize_t = int64_t;
|
|
||||||
|
|
||||||
ssize_t get_line(char** lineptr, size_t* n, FILE* fp) {
|
|
||||||
if (lineptr == nullptr || n == nullptr || fp == nullptr) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char buff[get_line_initial_buffer_size];
|
|
||||||
|
|
||||||
if (*lineptr == nullptr || *n < sizeof(buff)) {
|
|
||||||
size_t new_n = sizeof(buff);
|
|
||||||
auto new_lineptr = static_cast<char*>(realloc(*lineptr, new_n));
|
|
||||||
if (new_lineptr == nullptr) {
|
|
||||||
errno = ENOMEM;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
*lineptr = new_lineptr;
|
|
||||||
*n = new_n;
|
|
||||||
}
|
|
||||||
|
|
||||||
(*lineptr)[0] = '\0';
|
|
||||||
|
|
||||||
while (fgets(buff, sizeof(buff), fp) != nullptr) {
|
|
||||||
size_t line_used = strlen(*lineptr);
|
|
||||||
size_t buff_used = strlen(buff);
|
|
||||||
|
|
||||||
if (*n < buff_used + line_used) {
|
|
||||||
size_t new_n = *n * 2;
|
|
||||||
|
|
||||||
auto new_lineptr = static_cast<char*>(realloc(*lineptr, *n));
|
|
||||||
if (new_lineptr == nullptr) {
|
|
||||||
errno = ENOMEM;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
*lineptr = new_lineptr;
|
|
||||||
*n = new_n;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(*lineptr + line_used, buff, buff_used);
|
|
||||||
line_used += buff_used;
|
|
||||||
(*lineptr)[line_used] = '\0';
|
|
||||||
|
|
||||||
if ((*lineptr)[line_used - 1] == '\n') {
|
|
||||||
return line_used;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} /* ss */
|
} /* ss */
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@ project(
|
|||||||
'cpp_std=c++17',
|
'cpp_std=c++17',
|
||||||
'buildtype=debugoptimized',
|
'buildtype=debugoptimized',
|
||||||
'wrap_mode=forcefallback'],
|
'wrap_mode=forcefallback'],
|
||||||
version: '1.6.2',
|
version: '1.6.1',
|
||||||
meson_version:'>=0.54.0')
|
meson_version:'>=0.54.0')
|
||||||
|
|
||||||
fast_float_dep = dependency('fast_float')
|
fast_float_dep = dependency('fast_float')
|
||||||
|
|||||||
69
ssp.hpp
69
ssp.hpp
@@ -1,6 +1,5 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cerrno>
|
|
||||||
#include <charconv>
|
#include <charconv>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
@@ -626,7 +625,6 @@ using string_range = std::pair<const char*, const char*>;
|
|||||||
using split_data = std::vector<string_range>;
|
using split_data = std::vector<string_range>;
|
||||||
|
|
||||||
constexpr inline auto default_delimiter = ",";
|
constexpr inline auto default_delimiter = ",";
|
||||||
constexpr inline auto get_line_initial_buffer_size = 128;
|
|
||||||
|
|
||||||
template <bool StringError>
|
template <bool StringError>
|
||||||
inline void assert_string_error_defined() {
|
inline void assert_string_error_defined() {
|
||||||
@@ -645,60 +643,55 @@ inline ssize_t get_line(char** lineptr, size_t* n, FILE* stream) {
|
|||||||
return getline(lineptr, n, stream);
|
return getline(lineptr, n, stream);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
||||||
using ssize_t = int64_t;
|
using ssize_t = int64_t;
|
||||||
|
inline ssize_t get_line(char** lineptr, size_t* n, FILE* stream) {
|
||||||
|
size_t pos;
|
||||||
|
int c;
|
||||||
|
|
||||||
ssize_t get_line(char** lineptr, size_t* n, FILE* fp) {
|
if (lineptr == nullptr || stream == nullptr || n == nullptr) {
|
||||||
if (lineptr == nullptr || n == nullptr || fp == nullptr) {
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char buff[get_line_initial_buffer_size];
|
c = getc(stream);
|
||||||
|
if (c == EOF) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (*lineptr == nullptr || *n < sizeof(buff)) {
|
if (*lineptr == nullptr) {
|
||||||
size_t new_n = sizeof(buff);
|
*lineptr = static_cast<char*>(malloc(128));
|
||||||
auto new_lineptr = static_cast<char*>(realloc(*lineptr, new_n));
|
if (*lineptr == nullptr) {
|
||||||
if (new_lineptr == nullptr) {
|
|
||||||
errno = ENOMEM;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
*n = 128;
|
||||||
*lineptr = new_lineptr;
|
|
||||||
*n = new_n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(*lineptr)[0] = '\0';
|
pos = 0;
|
||||||
|
while (c != EOF) {
|
||||||
while (fgets(buff, sizeof(buff), fp) != nullptr) {
|
if (pos + 1 >= *n) {
|
||||||
size_t line_used = strlen(*lineptr);
|
size_t new_size = *n + (*n >> 2);
|
||||||
size_t buff_used = strlen(buff);
|
if (new_size < 128) {
|
||||||
|
new_size = 128;
|
||||||
if (*n < buff_used + line_used) {
|
}
|
||||||
size_t new_n = *n * 2;
|
char* new_ptr = static_cast<char*>(
|
||||||
|
realloc(static_cast<void*>(*lineptr), new_size));
|
||||||
auto new_lineptr = static_cast<char*>(realloc(*lineptr, *n));
|
if (new_ptr == nullptr) {
|
||||||
if (new_lineptr == nullptr) {
|
|
||||||
errno = ENOMEM;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
*n = new_size;
|
||||||
*lineptr = new_lineptr;
|
*lineptr = new_ptr;
|
||||||
*n = new_n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(*lineptr + line_used, buff, buff_used);
|
(*lineptr)[pos++] = c;
|
||||||
line_used += buff_used;
|
if (c == '\n') {
|
||||||
(*lineptr)[line_used] = '\0';
|
break;
|
||||||
|
|
||||||
if ((*lineptr)[line_used - 1] == '\n') {
|
|
||||||
return line_used;
|
|
||||||
}
|
}
|
||||||
|
c = getc(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
(*lineptr)[pos] = '\0';
|
||||||
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} /* ss */
|
} /* ss */
|
||||||
@@ -2288,7 +2281,7 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header_.empty() && !eof()) {
|
if (header_.empty()) {
|
||||||
split_header_data();
|
split_header_data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -897,7 +897,7 @@ void test_multiline_restricted() {
|
|||||||
out << "17,18,\"ju\\\n\\\n\\\n\\\\\n\nnk\"" << std::endl;
|
out << "17,18,\"ju\\\n\\\n\\\n\\\\\n\nnk\"" << std::endl;
|
||||||
out << "19,20,just strings" << std::endl;
|
out << "19,20,just strings" << std::endl;
|
||||||
}
|
}
|
||||||
auto bad_lines = 15;
|
auto bad_lines = 19;
|
||||||
auto num_errors = 0;
|
auto num_errors = 0;
|
||||||
|
|
||||||
ss::parser<ss::multiline_restricted<2>, ss::quote<'"'>, ss::escape<'\\'>,
|
ss::parser<ss::multiline_restricted<2>, ss::quote<'"'>, ss::escape<'\\'>,
|
||||||
@@ -1641,6 +1641,7 @@ void test_ignore_empty(const std::vector<X>& data) {
|
|||||||
test_ignore_empty_impl<ss::throw_on_error>(data);
|
test_ignore_empty_impl<ss::throw_on_error>(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO test with different initial buffer sizes
|
||||||
TEST_CASE("parser test various cases with empty lines") {
|
TEST_CASE("parser test various cases with empty lines") {
|
||||||
test_ignore_empty({{1, 2, "x"}, {3, 4, "y"}, {9, 10, "v"}, {11, 12, "w"}});
|
test_ignore_empty({{1, 2, "x"}, {3, 4, "y"}, {9, 10, "v"}, {11, 12, "w"}});
|
||||||
|
|
||||||
@@ -1670,13 +1671,53 @@ TEST_CASE("parser test various cases with empty lines") {
|
|||||||
{9, 10, X::empty},
|
{9, 10, X::empty},
|
||||||
{11, 12, X::empty}});
|
{11, 12, X::empty}});
|
||||||
|
|
||||||
test_ignore_empty(
|
test_ignore_empty({{1, 2, X::empty},
|
||||||
{{1, 2, "x"}, {3, 4, X::empty}, {9, 10, X::empty}, {11, 12, X::empty}});
|
{3, 4, X::empty},
|
||||||
|
{5, 6, X::empty},
|
||||||
|
{7, 8, X::empty},
|
||||||
|
{9, 10, X::empty},
|
||||||
|
{11, 12, X::empty},
|
||||||
|
{13, 14, X::empty},
|
||||||
|
{15, 16, X::empty},
|
||||||
|
{17, 18, X::empty}});
|
||||||
|
|
||||||
test_ignore_empty(
|
test_ignore_empty({{1, 2, X::empty},
|
||||||
{{1, 2, X::empty}, {3, 4, X::empty}, {9, 10, X::empty}, {11, 12, "w"}});
|
{3, 4, X::empty},
|
||||||
|
{5, 6, X::empty},
|
||||||
|
{7, 8, X::empty},
|
||||||
|
{9, 10, X::empty},
|
||||||
|
{11, 12, X::empty},
|
||||||
|
{13, 14, X::empty},
|
||||||
|
{15, 16, X::empty},
|
||||||
|
{17, 18, "x"}});
|
||||||
|
|
||||||
test_ignore_empty({{11, 12, X::empty}});
|
test_ignore_empty({{1, 2, "x"},
|
||||||
|
{3, 4, X::empty},
|
||||||
|
{9, 10, X::empty},
|
||||||
|
{11, 12, X::empty}});
|
||||||
|
|
||||||
test_ignore_empty({});
|
test_ignore_empty({{1, 2, "x"},
|
||||||
|
{3, 4, X::empty},
|
||||||
|
{3, 4, X::empty},
|
||||||
|
{5, 6, X::empty},
|
||||||
|
{7, 8, X::empty},
|
||||||
|
{9, 10, X::empty},
|
||||||
|
{11, 12, X::empty}});
|
||||||
|
|
||||||
|
test_ignore_empty({{1, 2, "x"},
|
||||||
|
{3, 4, X::empty},
|
||||||
|
{3, 4, X::empty},
|
||||||
|
{5, 6, X::empty},
|
||||||
|
{7, 8, X::empty},
|
||||||
|
{9, 10, X::empty},
|
||||||
|
{11, 12, "y"}});
|
||||||
|
|
||||||
|
test_ignore_empty({{1, 2, X::empty},
|
||||||
|
{3, 4, X::empty},
|
||||||
|
{9, 10, X::empty},
|
||||||
|
{11, 12, "w"}});
|
||||||
|
|
||||||
|
test_ignore_empty({{11, 12, X::empty}});
|
||||||
|
|
||||||
|
test_ignore_empty({});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user