Resolve clang-tidy warnings (#48)

* Resolve clang-tidy warnings, update single_header_generator.py

* Update single header test, resolve additional clang-tidy warnings
This commit is contained in:
red0124 2024-03-12 18:31:24 +01:00 committed by GitHub
parent 457defadaa
commit 69875c238e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 160 additions and 92 deletions

2
.gitignore vendored
View File

@ -1,7 +1,7 @@
compile_commands.json compile_commands.json
.clang-format .clang-format
.clang-tidy .clang-tidy
.ccls-cache/* .ccls-cache/
.cache/ .cache/
experiment/ experiment/
build/ build/

View File

@ -1,11 +1,15 @@
#pragma once #pragma once
#include <cerrno> #include <cerrno>
#include <cstdint>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <vector> #include <vector>
#if !__unix__
#include <array>
#include <cstdint>
#endif
namespace ss { namespace ss {
struct none {}; struct none {};
@ -17,13 +21,13 @@ constexpr inline auto default_delimiter = ",";
constexpr inline auto get_line_initial_buffer_size = 128; constexpr inline auto get_line_initial_buffer_size = 128;
template <bool StringError> template <bool StringError>
inline void assert_string_error_defined() { void assert_string_error_defined() {
static_assert(StringError, static_assert(StringError,
"'string_error' needs to be enabled to use 'error_msg'"); "'string_error' needs to be enabled to use 'error_msg'");
} }
template <bool ThrowOnError> template <bool ThrowOnError>
inline void assert_throw_on_error_not_defined() { 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");
} }
@ -46,7 +50,7 @@ inline ssize_t get_line_file(char*& lineptr, size_t& n, FILE* file) {
using ssize_t = intptr_t; using ssize_t = intptr_t;
inline ssize_t get_line_file(char*& lineptr, size_t& n, FILE* file) { inline ssize_t get_line_file(char*& lineptr, size_t& n, FILE* file) {
char buff[get_line_initial_buffer_size]; std::array<char, get_line_initial_buffer_size> buff;
if (lineptr == nullptr || n < sizeof(buff)) { if (lineptr == nullptr || n < sizeof(buff)) {
size_t new_n = sizeof(buff); size_t new_n = sizeof(buff);
@ -57,9 +61,9 @@ inline ssize_t get_line_file(char*& lineptr, size_t& n, FILE* file) {
lineptr[0] = '\0'; lineptr[0] = '\0';
size_t line_used = 0; size_t line_used = 0;
while (std::fgets(buff, sizeof(buff), file) != nullptr) { while (std::fgets(buff.data(), sizeof(buff), file) != nullptr) {
line_used = std::strlen(lineptr); line_used = std::strlen(lineptr);
size_t buff_used = std::strlen(buff); size_t buff_used = std::strlen(buff.data());
if (n <= buff_used + line_used) { if (n <= buff_used + line_used) {
size_t new_n = n * 2; size_t new_n = n * 2;
@ -67,7 +71,7 @@ inline ssize_t get_line_file(char*& lineptr, size_t& n, FILE* file) {
n = new_n; n = new_n;
} }
std::memcpy(lineptr + line_used, buff, buff_used); std::memcpy(lineptr + line_used, buff.data(), buff_used);
line_used += buff_used; line_used += buff_used;
lineptr[line_used] = '\0'; lineptr[line_used] = '\0';
@ -89,7 +93,7 @@ inline ssize_t get_line_buffer(char*& lineptr, size_t& n,
} }
if (lineptr == nullptr || n < get_line_initial_buffer_size) { if (lineptr == nullptr || n < get_line_initial_buffer_size) {
auto new_lineptr = static_cast<char*>( auto* new_lineptr = static_cast<char*>(
strict_realloc(lineptr, get_line_initial_buffer_size)); strict_realloc(lineptr, get_line_initial_buffer_size));
lineptr = new_lineptr; lineptr = new_lineptr;
n = get_line_initial_buffer_size; n = get_line_initial_buffer_size;
@ -122,7 +126,7 @@ inline std::tuple<ssize_t, bool> get_line(char*& buffer, size_t& buffer_size,
FILE* file, FILE* file,
const char* const csv_data_buffer, const char* const csv_data_buffer,
size_t csv_data_size, size_t& curr_char) { size_t csv_data_size, size_t& curr_char) {
ssize_t ssize; ssize_t ssize = 0;
if (file) { if (file) {
ssize = get_line_file(buffer, buffer_size, file); ssize = get_line_file(buffer, buffer_size, file);
curr_char += ssize; curr_char += ssize;

View File

@ -224,8 +224,9 @@ private:
} }
std::string error_sufix(const string_range msg, size_t pos) const { std::string error_sufix(const string_range msg, size_t pos) const {
constexpr static auto reserve_size = 32;
std::string error; std::string error;
error.reserve(32); error.reserve(reserve_size);
error.append("at column ") error.append("at column ")
.append(std::to_string(pos + 1)) .append(std::to_string(pos + 1))
.append(": \'") .append(": \'")
@ -391,7 +392,7 @@ private:
//////////////// ////////////////
bool columns_mapped() const { bool columns_mapped() const {
return column_mappings_.size() != 0; return !column_mappings_.empty();
} }
size_t column_position(size_t tuple_position) const { size_t column_position(size_t tuple_position) const {
@ -404,7 +405,7 @@ private:
// assumes positions are valid and the vector is not empty // assumes positions are valid and the vector is not empty
void set_column_mapping(std::vector<size_t> positions, void set_column_mapping(std::vector<size_t> positions,
size_t number_of_columns) { size_t number_of_columns) {
column_mappings_ = positions; column_mappings_ = std::move(positions);
number_of_columns_ = number_of_columns; number_of_columns_ = number_of_columns;
} }
@ -490,7 +491,7 @@ private:
friend class parser; friend class parser;
std::vector<size_t> column_mappings_; std::vector<size_t> column_mappings_;
size_t number_of_columns_; size_t number_of_columns_{0};
}; };
} /* namespace ss */ } /* namespace ss */

View File

@ -12,10 +12,10 @@ class exception : public std::exception {
std::string msg_; std::string msg_;
public: public:
exception(const std::string& msg): msg_{msg} { exception(std::string msg): msg_{std::move(msg)} {
} }
virtual char const* what() const noexcept { char const* what() const noexcept override {
return msg_.c_str(); return msg_.c_str();
} }
}; };

View File

@ -2,8 +2,8 @@
#include "type_traits.hpp" #include "type_traits.hpp"
#include <charconv> #include <charconv>
#include <cstdint>
#include <cstring> #include <cstring>
#include <functional>
#include <optional> #include <optional>
#include <string> #include <string>
#include <string_view> #include <string_view>
@ -14,6 +14,7 @@
#else #else
#include <algorithm> #include <algorithm>
#include <cstdlib> #include <cstdlib>
#include <array>
#endif #endif
namespace ss { namespace ss {
@ -45,16 +46,17 @@ std::enable_if_t<std::is_floating_point_v<T>, std::optional<T>> to_num(
"Conversion to long double is disabled"); "Conversion to long double is disabled");
constexpr static auto buff_max = 64; constexpr static auto buff_max = 64;
char short_buff[buff_max]; std::array<char, buff_max> short_buff;
size_t string_range = std::distance(begin, end); size_t string_range = std::distance(begin, end);
std::string long_buff; std::string long_buff;
char* buff; char* buff = nullptr;
if (string_range > buff_max) { if (string_range > buff_max) {
long_buff = std::string{begin, end}; long_buff = std::string{begin, end};
buff = long_buff.data(); buff = long_buff.data();
} else { } else {
buff = short_buff; buff = short_buff.data();
buff[string_range] = '\0'; buff[string_range] = '\0';
std::copy_n(begin, string_range, buff); std::copy_n(begin, string_range, buff);
} }
@ -92,6 +94,8 @@ struct numeric_wrapper {
numeric_wrapper& operator=(numeric_wrapper&&) = default; numeric_wrapper& operator=(numeric_wrapper&&) = default;
numeric_wrapper& operator=(const numeric_wrapper&) = default; numeric_wrapper& operator=(const numeric_wrapper&) = default;
~numeric_wrapper() = default;
numeric_wrapper(T other) : value{other} { numeric_wrapper(T other) : value{other} {
} }
@ -215,10 +219,13 @@ inline bool extract(const char* begin, const char* end, bool& value) {
return false; return false;
} }
} else { } else {
constexpr static auto true_size = 4;
constexpr static auto false_size = 5;
size_t size = end - begin; size_t size = end - begin;
if (size == 4 && std::strncmp(begin, "true", size) == 0) { if (size == true_size && std::strncmp(begin, "true", size) == 0) {
value = true; value = true;
} else if (size == 5 && std::strncmp(begin, "false", size) == 0) { } else if (size == false_size &&
std::strncmp(begin, "false", size) == 0) {
value = false; value = false;
} else { } else {
return false; return false;

View File

@ -2,7 +2,6 @@
#include <cstdlib> #include <cstdlib>
#include <functional> #include <functional>
#include <tuple>
namespace ss { namespace ss {

View File

@ -5,7 +5,6 @@
#include "exception.hpp" #include "exception.hpp"
#include "extract.hpp" #include "extract.hpp"
#include "restrictions.hpp" #include "restrictions.hpp"
#include <cerrno>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <optional> #include <optional>
@ -33,9 +32,8 @@ class parser {
constexpr static bool ignore_empty = setup<Options...>::ignore_empty; constexpr static bool ignore_empty = setup<Options...>::ignore_empty;
public: public:
parser(const std::string& file_name, parser(std::string file_name, std::string delim = ss::default_delimiter)
const std::string& delim = ss::default_delimiter) : file_name_{std::move(file_name)}, reader_{file_name_, delim} {
: file_name_{file_name}, reader_{file_name_, delim} {
if (reader_.file_) { if (reader_.file_) {
read_line(); read_line();
if constexpr (ignore_header) { if constexpr (ignore_header) {
@ -68,6 +66,7 @@ public:
parser(parser&& other) = default; parser(parser&& other) = default;
parser& operator=(parser&& other) = default; parser& operator=(parser&& other) = default;
~parser() = default;
parser() = delete; parser() = delete;
parser(const parser& other) = delete; parser(const parser& other) = delete;
@ -237,6 +236,10 @@ public:
iterator(const iterator& other) = default; iterator(const iterator& other) = default;
iterator(iterator&& other) = default; iterator(iterator&& other) = default;
~iterator() = default;
iterator& operator=(const iterator& other) = delete;
iterator& operator=(iterator&& other) = delete;
value& operator*() { value& operator*() {
return value_; return value_;
@ -261,8 +264,10 @@ public:
return *this; return *this;
} }
iterator& operator++(int) { iterator operator++(int) {
return ++*this; auto result = *this;
++*this;
return result;
} }
friend bool operator==(const iterator& lhs, const iterator& rhs) { friend bool operator==(const iterator& lhs, const iterator& rhs) {
@ -326,7 +331,7 @@ public:
Fun&& fun = none{}) { Fun&& fun = none{}) {
using Value = no_void_validator_tup_t<Us...>; using Value = no_void_validator_tup_t<Us...>;
std::optional<Value> value; std::optional<Value> value;
try_convert_and_invoke<Value, Us...>(value, fun); try_convert_and_invoke<Value, Us...>(value, std::forward<Fun>(fun));
return composite_with(std::move(value)); return composite_with(std::move(value));
} }
@ -335,7 +340,7 @@ public:
template <typename U, typename... Us, typename Fun = none> template <typename U, typename... Us, typename Fun = none>
composite<Ts..., std::optional<U>> or_object(Fun&& fun = none{}) { composite<Ts..., std::optional<U>> or_object(Fun&& fun = none{}) {
std::optional<U> value; std::optional<U> value;
try_convert_and_invoke<U, Us...>(value, fun); try_convert_and_invoke<U, Us...>(value, std::forward<Fun>(fun));
return composite_with(std::move(value)); return composite_with(std::move(value));
} }
@ -443,7 +448,8 @@ private:
using Ret = decltype(try_invoke_impl(arg, std::forward<Fun>(fun))); using Ret = decltype(try_invoke_impl(arg, std::forward<Fun>(fun)));
constexpr bool returns_void = std::is_same_v<Ret, void>; constexpr bool returns_void = std::is_same_v<Ret, void>;
if constexpr (!returns_void) { if constexpr (!returns_void) {
if (!try_invoke_impl(arg, std::forward<Fun>(fun))) { if (!try_invoke_impl(std::forward<Arg>(arg),
std::forward<Fun>(fun))) {
handle_error_failed_check(); handle_error_failed_check();
} }
} else { } else {
@ -478,7 +484,7 @@ private:
if (valid()) { if (valid()) {
try_invoke(*value, std::forward<Fun>(fun)); try_invoke(*value, std::forward<Fun>(fun));
} }
return {valid() ? std::move(value) : std::nullopt, *this}; return {valid() ? std::forward<T>(value) : std::nullopt, *this};
} }
//////////////// ////////////////
@ -674,17 +680,18 @@ private:
} }
struct reader { struct reader {
reader(const std::string& file_name_, const std::string& delim) reader(const std::string& file_name_, std::string delim)
: delim_{delim}, file_{std::fopen(file_name_.c_str(), "rb")} { : delim_{std::move(delim)},
file_{std::fopen(file_name_.c_str(), "rb")} {
} }
reader(const char* const buffer, size_t csv_data_size, reader(const char* const buffer, size_t csv_data_size,
const std::string& delim) std::string delim)
: delim_{delim}, csv_data_buffer_{buffer}, : delim_{std::move(delim)}, csv_data_buffer_{buffer},
csv_data_size_{csv_data_size} { csv_data_size_{csv_data_size} {
} }
reader(reader&& other) reader(reader&& other) noexcept
: buffer_{other.buffer_}, : buffer_{other.buffer_},
next_line_buffer_{other.next_line_buffer_}, next_line_buffer_{other.next_line_buffer_},
helper_buffer_{other.helper_buffer_}, helper_buffer_{other.helper_buffer_},
@ -705,7 +712,7 @@ private:
other.file_ = nullptr; other.file_ = nullptr;
} }
reader& operator=(reader&& other) { reader& operator=(reader&& other) noexcept {
if (this != &other) { if (this != &other) {
buffer_ = other.buffer_; buffer_ = other.buffer_;
next_line_buffer_ = other.next_line_buffer_; next_line_buffer_ = other.next_line_buffer_;
@ -853,7 +860,7 @@ private:
} }
bool escaped_eol(size_t size) { bool escaped_eol(size_t size) {
const char* curr; const char* curr = nullptr;
for (curr = next_line_buffer_ + size - 1; for (curr = next_line_buffer_ + size - 1;
curr >= next_line_buffer_ && curr >= next_line_buffer_ &&
setup<Options...>::escape::match(*curr); setup<Options...>::escape::match(*curr);
@ -899,7 +906,7 @@ private:
size_t& buffer_size, const char* const second, size_t& buffer_size, const char* const second,
size_t second_size) { size_t second_size) {
buffer_size = first_size + second_size + 3; buffer_size = first_size + second_size + 3;
auto new_first = static_cast<char*>( auto* new_first = static_cast<char*>(
strict_realloc(static_cast<void*>(first), buffer_size)); strict_realloc(static_cast<void*>(first), buffer_size));
first = new_first; first = new_first;

View File

@ -2,7 +2,6 @@
#include "common.hpp" #include "common.hpp"
#include "exception.hpp" #include "exception.hpp"
#include "setup.hpp" #include "setup.hpp"
#include "type_traits.hpp"
#include <algorithm> #include <algorithm>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
@ -321,8 +320,9 @@ private:
trim_left_if_enabled(begin_); trim_left_if_enabled(begin_);
for (done_ = false; !done_; read(delim)) for (done_ = false; !done_;) {
; read(delim);
}
return split_data_; return split_data_;
} }

View File

@ -34,7 +34,11 @@ struct left_of_impl;
template <size_t N, typename T, typename... Ts> template <size_t N, typename T, typename... Ts>
struct left_of_impl { struct left_of_impl {
static_assert(N < 128, "recursion limit reached"); private:
constexpr static auto recursion_limit = 128;
public:
static_assert(N < recursion_limit, "recursion limit reached");
static_assert(N != 0, "cannot take the whole tuple"); static_assert(N != 0, "cannot take the whole tuple");
using type = tup_cat_t<T, typename left_of_impl<N - 1, Ts...>::type>; using type = tup_cat_t<T, typename left_of_impl<N - 1, Ts...>::type>;
}; };

View File

@ -14,14 +14,21 @@ headers = ['type_traits.hpp',
combined_file = [] combined_file = []
includes = [] includes = []
in_pp_block = False
for header in headers: for header in headers:
with open(headers_dir + header) as f: with open(headers_dir + header) as f:
for line in f.read().splitlines(): for line in f.read().splitlines():
if '#if ' in line:
in_pp_block = True
if '#endif' in line:
in_pp_block = False
if '#include "' in line or '#include <fast_float' in line: if '#include "' in line or '#include <fast_float' in line:
continue continue
if '#include <' in line: if '#include <' in line and not in_pp_block:
includes.append(line) includes.append(line)
continue continue

105
ssp.hpp
View File

@ -49,7 +49,11 @@ struct left_of_impl;
template <size_t N, typename T, typename... Ts> template <size_t N, typename T, typename... Ts>
struct left_of_impl { struct left_of_impl {
static_assert(N < 128, "recursion limit reached"); private:
constexpr static auto recursion_limit = 128;
public:
static_assert(N < recursion_limit, "recursion limit reached");
static_assert(N != 0, "cannot take the whole tuple"); static_assert(N != 0, "cannot take the whole tuple");
using type = tup_cat_t<T, typename left_of_impl<N - 1, Ts...>::type>; using type = tup_cat_t<T, typename left_of_impl<N - 1, Ts...>::type>;
}; };
@ -405,10 +409,10 @@ class exception : public std::exception {
std::string msg_; std::string msg_;
public: public:
exception(const std::string& msg): msg_{msg} { exception(std::string msg): msg_{std::move(msg)} {
} }
virtual char const* what() const noexcept { char const* what() const noexcept override {
return msg_.c_str(); return msg_.c_str();
} }
}; };
@ -617,6 +621,11 @@ struct ne {
} /* namespace ss */ } /* namespace ss */
#if !__unix__
#include <array>
#include <cstdint>
#endif
namespace ss { namespace ss {
struct none {}; struct none {};
@ -628,13 +637,13 @@ constexpr inline auto default_delimiter = ",";
constexpr inline auto get_line_initial_buffer_size = 128; constexpr inline auto get_line_initial_buffer_size = 128;
template <bool StringError> template <bool StringError>
inline void assert_string_error_defined() { void assert_string_error_defined() {
static_assert(StringError, static_assert(StringError,
"'string_error' needs to be enabled to use 'error_msg'"); "'string_error' needs to be enabled to use 'error_msg'");
} }
template <bool ThrowOnError> template <bool ThrowOnError>
inline void assert_throw_on_error_not_defined() { 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");
} }
@ -657,7 +666,7 @@ inline ssize_t get_line_file(char*& lineptr, size_t& n, FILE* file) {
using ssize_t = intptr_t; using ssize_t = intptr_t;
inline ssize_t get_line_file(char*& lineptr, size_t& n, FILE* file) { inline ssize_t get_line_file(char*& lineptr, size_t& n, FILE* file) {
char buff[get_line_initial_buffer_size]; std::array<char, get_line_initial_buffer_size> buff;
if (lineptr == nullptr || n < sizeof(buff)) { if (lineptr == nullptr || n < sizeof(buff)) {
size_t new_n = sizeof(buff); size_t new_n = sizeof(buff);
@ -668,9 +677,9 @@ inline ssize_t get_line_file(char*& lineptr, size_t& n, FILE* file) {
lineptr[0] = '\0'; lineptr[0] = '\0';
size_t line_used = 0; size_t line_used = 0;
while (std::fgets(buff, sizeof(buff), file) != nullptr) { while (std::fgets(buff.data(), sizeof(buff), file) != nullptr) {
line_used = std::strlen(lineptr); line_used = std::strlen(lineptr);
size_t buff_used = std::strlen(buff); size_t buff_used = std::strlen(buff.data());
if (n <= buff_used + line_used) { if (n <= buff_used + line_used) {
size_t new_n = n * 2; size_t new_n = n * 2;
@ -678,7 +687,7 @@ inline ssize_t get_line_file(char*& lineptr, size_t& n, FILE* file) {
n = new_n; n = new_n;
} }
std::memcpy(lineptr + line_used, buff, buff_used); std::memcpy(lineptr + line_used, buff.data(), buff_used);
line_used += buff_used; line_used += buff_used;
lineptr[line_used] = '\0'; lineptr[line_used] = '\0';
@ -700,7 +709,7 @@ inline ssize_t get_line_buffer(char*& lineptr, size_t& n,
} }
if (lineptr == nullptr || n < get_line_initial_buffer_size) { if (lineptr == nullptr || n < get_line_initial_buffer_size) {
auto new_lineptr = static_cast<char*>( auto* new_lineptr = static_cast<char*>(
strict_realloc(lineptr, get_line_initial_buffer_size)); strict_realloc(lineptr, get_line_initial_buffer_size));
lineptr = new_lineptr; lineptr = new_lineptr;
n = get_line_initial_buffer_size; n = get_line_initial_buffer_size;
@ -733,7 +742,7 @@ inline std::tuple<ssize_t, bool> get_line(char*& buffer, size_t& buffer_size,
FILE* file, FILE* file,
const char* const csv_data_buffer, const char* const csv_data_buffer,
size_t csv_data_size, size_t& curr_char) { size_t csv_data_size, size_t& curr_char) {
ssize_t ssize; ssize_t ssize = 0;
if (file) { if (file) {
ssize = get_line_file(buffer, buffer_size, file); ssize = get_line_file(buffer, buffer_size, file);
curr_char += ssize; curr_char += ssize;
@ -1359,8 +1368,9 @@ private:
trim_left_if_enabled(begin_); trim_left_if_enabled(begin_);
for (done_ = false; !done_; read(delim)) for (done_ = false; !done_;) {
; read(delim);
}
return split_data_; return split_data_;
} }
@ -1552,16 +1562,17 @@ std::enable_if_t<std::is_floating_point_v<T>, std::optional<T>> to_num(
"Conversion to long double is disabled"); "Conversion to long double is disabled");
constexpr static auto buff_max = 64; constexpr static auto buff_max = 64;
char short_buff[buff_max]; std::array<char, buff_max> short_buff;
size_t string_range = std::distance(begin, end); size_t string_range = std::distance(begin, end);
std::string long_buff; std::string long_buff;
char* buff; char* buff = nullptr;
if (string_range > buff_max) { if (string_range > buff_max) {
long_buff = std::string{begin, end}; long_buff = std::string{begin, end};
buff = long_buff.data(); buff = long_buff.data();
} else { } else {
buff = short_buff; buff = short_buff.data();
buff[string_range] = '\0'; buff[string_range] = '\0';
std::copy_n(begin, string_range, buff); std::copy_n(begin, string_range, buff);
} }
@ -1599,6 +1610,8 @@ struct numeric_wrapper {
numeric_wrapper& operator=(numeric_wrapper&&) = default; numeric_wrapper& operator=(numeric_wrapper&&) = default;
numeric_wrapper& operator=(const numeric_wrapper&) = default; numeric_wrapper& operator=(const numeric_wrapper&) = default;
~numeric_wrapper() = default;
numeric_wrapper(T other) : value{other} { numeric_wrapper(T other) : value{other} {
} }
@ -1649,7 +1662,7 @@ template <typename T>
struct unsupported_type { struct unsupported_type {
constexpr static bool value = false; constexpr static bool value = false;
}; };
} /* namespace error */ } /* namespace errors */
template <typename T> template <typename T>
std::enable_if_t<!std::is_integral_v<T> && !std::is_floating_point_v<T> && std::enable_if_t<!std::is_integral_v<T> && !std::is_floating_point_v<T> &&
@ -1722,10 +1735,13 @@ inline bool extract(const char* begin, const char* end, bool& value) {
return false; return false;
} }
} else { } else {
constexpr static auto true_size = 4;
constexpr static auto false_size = 5;
size_t size = end - begin; size_t size = end - begin;
if (size == 4 && std::strncmp(begin, "true", size) == 0) { if (size == true_size && std::strncmp(begin, "true", size) == 0) {
value = true; value = true;
} else if (size == 5 && std::strncmp(begin, "false", size) == 0) { } else if (size == false_size &&
std::strncmp(begin, "false", size) == 0) {
value = false; value = false;
} else { } else {
return false; return false;
@ -1971,8 +1987,9 @@ private:
} }
std::string error_sufix(const string_range msg, size_t pos) const { std::string error_sufix(const string_range msg, size_t pos) const {
constexpr static auto reserve_size = 32;
std::string error; std::string error;
error.reserve(32); error.reserve(reserve_size);
error.append("at column ") error.append("at column ")
.append(std::to_string(pos + 1)) .append(std::to_string(pos + 1))
.append(": \'") .append(": \'")
@ -2138,7 +2155,7 @@ private:
//////////////// ////////////////
bool columns_mapped() const { bool columns_mapped() const {
return column_mappings_.size() != 0; return !column_mappings_.empty();
} }
size_t column_position(size_t tuple_position) const { size_t column_position(size_t tuple_position) const {
@ -2151,7 +2168,7 @@ private:
// assumes positions are valid and the vector is not empty // assumes positions are valid and the vector is not empty
void set_column_mapping(std::vector<size_t> positions, void set_column_mapping(std::vector<size_t> positions,
size_t number_of_columns) { size_t number_of_columns) {
column_mappings_ = positions; column_mappings_ = std::move(positions);
number_of_columns_ = number_of_columns; number_of_columns_ = number_of_columns;
} }
@ -2237,7 +2254,7 @@ private:
friend class parser; friend class parser;
std::vector<size_t> column_mappings_; std::vector<size_t> column_mappings_;
size_t number_of_columns_; size_t number_of_columns_{0};
}; };
} /* namespace ss */ } /* namespace ss */
@ -2264,9 +2281,8 @@ class parser {
constexpr static bool ignore_empty = setup<Options...>::ignore_empty; constexpr static bool ignore_empty = setup<Options...>::ignore_empty;
public: public:
parser(const std::string& file_name, parser(std::string file_name, std::string delim = ss::default_delimiter)
const std::string& delim = ss::default_delimiter) : file_name_{std::move(file_name)}, reader_{file_name_, delim} {
: file_name_{file_name}, reader_{file_name_, delim} {
if (reader_.file_) { if (reader_.file_) {
read_line(); read_line();
if constexpr (ignore_header) { if constexpr (ignore_header) {
@ -2299,6 +2315,7 @@ public:
parser(parser&& other) = default; parser(parser&& other) = default;
parser& operator=(parser&& other) = default; parser& operator=(parser&& other) = default;
~parser() = default;
parser() = delete; parser() = delete;
parser(const parser& other) = delete; parser(const parser& other) = delete;
@ -2468,6 +2485,10 @@ public:
iterator(const iterator& other) = default; iterator(const iterator& other) = default;
iterator(iterator&& other) = default; iterator(iterator&& other) = default;
~iterator() = default;
iterator& operator=(const iterator& other) = delete;
iterator& operator=(iterator&& other) = delete;
value& operator*() { value& operator*() {
return value_; return value_;
@ -2492,8 +2513,10 @@ public:
return *this; return *this;
} }
iterator& operator++(int) { iterator operator++(int) {
return ++*this; auto result = *this;
++*this;
return result;
} }
friend bool operator==(const iterator& lhs, const iterator& rhs) { friend bool operator==(const iterator& lhs, const iterator& rhs) {
@ -2557,7 +2580,7 @@ public:
Fun&& fun = none{}) { Fun&& fun = none{}) {
using Value = no_void_validator_tup_t<Us...>; using Value = no_void_validator_tup_t<Us...>;
std::optional<Value> value; std::optional<Value> value;
try_convert_and_invoke<Value, Us...>(value, fun); try_convert_and_invoke<Value, Us...>(value, std::forward<Fun>(fun));
return composite_with(std::move(value)); return composite_with(std::move(value));
} }
@ -2566,7 +2589,7 @@ public:
template <typename U, typename... Us, typename Fun = none> template <typename U, typename... Us, typename Fun = none>
composite<Ts..., std::optional<U>> or_object(Fun&& fun = none{}) { composite<Ts..., std::optional<U>> or_object(Fun&& fun = none{}) {
std::optional<U> value; std::optional<U> value;
try_convert_and_invoke<U, Us...>(value, fun); try_convert_and_invoke<U, Us...>(value, std::forward<Fun>(fun));
return composite_with(std::move(value)); return composite_with(std::move(value));
} }
@ -2674,7 +2697,8 @@ private:
using Ret = decltype(try_invoke_impl(arg, std::forward<Fun>(fun))); using Ret = decltype(try_invoke_impl(arg, std::forward<Fun>(fun)));
constexpr bool returns_void = std::is_same_v<Ret, void>; constexpr bool returns_void = std::is_same_v<Ret, void>;
if constexpr (!returns_void) { if constexpr (!returns_void) {
if (!try_invoke_impl(arg, std::forward<Fun>(fun))) { if (!try_invoke_impl(std::forward<Arg>(arg),
std::forward<Fun>(fun))) {
handle_error_failed_check(); handle_error_failed_check();
} }
} else { } else {
@ -2709,7 +2733,7 @@ private:
if (valid()) { if (valid()) {
try_invoke(*value, std::forward<Fun>(fun)); try_invoke(*value, std::forward<Fun>(fun));
} }
return {valid() ? std::move(value) : std::nullopt, *this}; return {valid() ? std::forward<T>(value) : std::nullopt, *this};
} }
//////////////// ////////////////
@ -2905,17 +2929,18 @@ private:
} }
struct reader { struct reader {
reader(const std::string& file_name_, const std::string& delim) reader(const std::string& file_name_, std::string delim)
: delim_{delim}, file_{std::fopen(file_name_.c_str(), "rb")} { : delim_{std::move(delim)},
file_{std::fopen(file_name_.c_str(), "rb")} {
} }
reader(const char* const buffer, size_t csv_data_size, reader(const char* const buffer, size_t csv_data_size,
const std::string& delim) std::string delim)
: delim_{delim}, csv_data_buffer_{buffer}, : delim_{std::move(delim)}, csv_data_buffer_{buffer},
csv_data_size_{csv_data_size} { csv_data_size_{csv_data_size} {
} }
reader(reader&& other) reader(reader&& other) noexcept
: buffer_{other.buffer_}, : buffer_{other.buffer_},
next_line_buffer_{other.next_line_buffer_}, next_line_buffer_{other.next_line_buffer_},
helper_buffer_{other.helper_buffer_}, helper_buffer_{other.helper_buffer_},
@ -2936,7 +2961,7 @@ private:
other.file_ = nullptr; other.file_ = nullptr;
} }
reader& operator=(reader&& other) { reader& operator=(reader&& other) noexcept {
if (this != &other) { if (this != &other) {
buffer_ = other.buffer_; buffer_ = other.buffer_;
next_line_buffer_ = other.next_line_buffer_; next_line_buffer_ = other.next_line_buffer_;
@ -3084,7 +3109,7 @@ private:
} }
bool escaped_eol(size_t size) { bool escaped_eol(size_t size) {
const char* curr; const char* curr = nullptr;
for (curr = next_line_buffer_ + size - 1; for (curr = next_line_buffer_ + size - 1;
curr >= next_line_buffer_ && curr >= next_line_buffer_ &&
setup<Options...>::escape::match(*curr); setup<Options...>::escape::match(*curr);
@ -3130,7 +3155,7 @@ private:
size_t& buffer_size, const char* const second, size_t& buffer_size, const char* const second,
size_t second_size) { size_t second_size) {
buffer_size = first_size + second_size + 3; buffer_size = first_size + second_size + 3;
auto new_first = static_cast<char*>( auto* new_first = static_cast<char*>(
strict_realloc(static_cast<void*>(first), buffer_size)); strict_realloc(static_cast<void*>(first), buffer_size));
first = new_first; first = new_first;

View File

@ -3,12 +3,14 @@
set -x set -x
set -e set -e
python3 script/single_header_generator.py > ssp.cpp TMP_HDR=test_single_header.hpp
TMP_SRC=test_single_header.cpp
TMP_BIN=test_single_header
echo 'int main(){ ss::parser p{""}; p.get_next<int, float>(); return 0; }' \ python3 script/single_header_generator.py > ${TMP_HDR}
>> ssp.cpp cat ${TMP_HDR} test/test_single_header_main.txt > ${TMP_SRC}
g++ -std=c++17 ssp.cpp -o ssp.bin -Wall -Wextra g++ -std=c++17 ${TMP_SRC} -o ${TMP_BIN} -Wall -Wextra
./ssp.bin ./${TMP_BIN}
rm ssp.cpp ssp.bin rm ${TMP_HDR} ${TMP_SRC} ${TMP_BIN}

View File

@ -0,0 +1,12 @@
int main() {
using quote = ss::quote<'"'>;
using escape = ss::escape<'\\'>;
using trim = ss::trim<' '>;
std::string data = "1,string,2.34,c";
ss::parser<quote, escape, trim, ss::multiline> p{data.c_str(), data.size()};
auto tup = p.get_next<int, std::string, float, std::optional<char>>();
return 0;
}