Implement throw_on_error functionality, rename some template parameters

This commit is contained in:
ado 2023-06-29 23:41:03 +02:00
parent 3eefac93b1
commit eeac30651a
5 changed files with 124 additions and 53 deletions

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
#include "exception.hpp"
#include "extract.hpp" #include "extract.hpp"
#include "function_traits.hpp" #include "function_traits.hpp"
#include "restrictions.hpp" #include "restrictions.hpp"
@ -95,11 +96,12 @@ constexpr bool tied_class_v = tied_class<Ts...>::value;
// converter // converter
//////////////// ////////////////
template <typename... Matchers> template <typename... Options>
class converter { class converter {
using line_ptr_type = typename splitter<Matchers...>::line_ptr_type; using line_ptr_type = typename splitter<Options...>::line_ptr_type;
constexpr static auto string_error = setup<Matchers...>::string_error; constexpr static auto string_error = setup<Options...>::string_error;
constexpr static auto throw_on_error = setup<Options...>::throw_on_error;
constexpr static auto default_delimiter = ","; constexpr static auto default_delimiter = ",";
using error_type = std::conditional_t<string_error, std::string, bool>; using error_type = std::conditional_t<string_error, std::string, bool>;
@ -229,6 +231,7 @@ private:
if constexpr (string_error) { if constexpr (string_error) {
error_.clear(); error_.clear();
error_.append(splitter_.error_msg()); error_.append(splitter_.error_msg());
throw_if_throw_on_error<throw_on_error>(error_);
} else { } else {
error_ = true; error_ = true;
} }
@ -239,6 +242,7 @@ private:
error_.clear(); error_.clear();
splitter_.set_error_unterminated_escape(); splitter_.set_error_unterminated_escape();
error_.append(splitter_.error_msg()); error_.append(splitter_.error_msg());
throw_if_throw_on_error<throw_on_error>(error_);
} else { } else {
error_ = true; error_ = true;
} }
@ -247,7 +251,8 @@ private:
void set_error_multiline_limit_reached() { void set_error_multiline_limit_reached() {
if constexpr (string_error) { if constexpr (string_error) {
error_.clear(); error_.clear();
error_.append("multiline limit reached."); error_.append("multiline limit reached");
throw_if_throw_on_error<throw_on_error>(error_);
} else { } else {
error_ = true; error_ = true;
} }
@ -258,6 +263,7 @@ private:
error_.clear(); error_.clear();
error_.append("invalid conversion for parameter ") error_.append("invalid conversion for parameter ")
.append(error_sufix(msg, pos)); .append(error_sufix(msg, pos));
throw_if_throw_on_error<throw_on_error>(error_);
} else { } else {
error_ = true; error_ = true;
} }
@ -268,6 +274,7 @@ private:
if constexpr (string_error) { if constexpr (string_error) {
error_.clear(); error_.clear();
error_.append(error).append(" ").append(error_sufix(msg, pos)); error_.append(error).append(" ").append(error_sufix(msg, pos));
throw_if_throw_on_error<throw_on_error>(error_);
} else { } else {
error_ = true; error_ = true;
} }
@ -280,6 +287,7 @@ private:
.append(std::to_string(expected_pos)) .append(std::to_string(expected_pos))
.append(", got: ") .append(", got: ")
.append(std::to_string(pos)); .append(std::to_string(pos));
throw_if_throw_on_error<throw_on_error>(error_);
} else { } else {
error_ = true; error_ = true;
} }
@ -295,6 +303,7 @@ private:
.append(std::to_string(mapping_size)) .append(std::to_string(mapping_size))
.append(", got: ") .append(", got: ")
.append(std::to_string(argument_size)); .append(std::to_string(argument_size));
throw_if_throw_on_error<throw_on_error>(error_);
} else { } else {
error_ = true; error_ = true;
} }
@ -304,6 +313,7 @@ private:
if constexpr (string_error) { if constexpr (string_error) {
error_.clear(); error_.clear();
error_.append("received empty mapping"); error_.append("received empty mapping");
throw_if_throw_on_error<throw_on_error>(error_);
} else { } else {
error_ = true; error_ = true;
} }
@ -317,6 +327,7 @@ private:
.append(std::to_string(maximum_index)) .append(std::to_string(maximum_index))
.append(", greater then number of columns: ") .append(", greater then number of columns: ")
.append(std::to_string(number_of_columnts)); .append(std::to_string(number_of_columnts));
throw_if_throw_on_error<throw_on_error>(error_);
} else { } else {
error_ = true; error_ = true;
} }
@ -472,7 +483,7 @@ private:
//////////////// ////////////////
error_type error_{}; error_type error_{};
splitter<Matchers...> splitter_; splitter<Options...> splitter_;
template <typename...> template <typename...>
friend class parser; friend class parser;

30
include/ss/exception.hpp Normal file
View File

@ -0,0 +1,30 @@
#pragma once
#include <exception>
#include <string>
namespace ss {
////////////////
// exception
////////////////
class exception : public std::exception {
std::string msg_;
public:
exception(const std::string& msg): msg_{msg} {
}
virtual char const* what() const noexcept {
return msg_.c_str();
}
};
template <bool throw_on_error>
void throw_if_throw_on_error(const std::string& msg) {
if constexpr (throw_on_error) {
throw ss::exception(msg);
}
}
} /* ss */

View File

@ -2,6 +2,7 @@
#include "common.hpp" #include "common.hpp"
#include "converter.hpp" #include "converter.hpp"
#include "exception.hpp"
#include "extract.hpp" #include "extract.hpp"
#include "restrictions.hpp" #include "restrictions.hpp"
#include <cstdlib> #include <cstdlib>
@ -12,22 +13,23 @@
namespace ss { namespace ss {
template <typename... Matchers> template <typename... Options>
class parser { class parser {
constexpr static auto string_error = setup<Matchers...>::string_error; constexpr static auto string_error = setup<Options...>::string_error;
constexpr static auto throw_on_error = setup<Options...>::throw_on_error;
using multiline = typename setup<Matchers...>::multiline; using multiline = typename setup<Options...>::multiline;
using error_type = std::conditional_t<string_error, std::string, bool>; using error_type = std::conditional_t<string_error, std::string, bool>;
constexpr static bool escaped_multiline_enabled = constexpr static bool escaped_multiline_enabled =
multiline::enabled && setup<Matchers...>::escape::enabled; multiline::enabled && setup<Options...>::escape::enabled;
constexpr static bool quoted_multiline_enabled = constexpr static bool quoted_multiline_enabled =
multiline::enabled && setup<Matchers...>::quote::enabled; multiline::enabled && setup<Options...>::quote::enabled;
constexpr static bool ignore_header = setup<Matchers...>::ignore_header; constexpr static bool ignore_header = setup<Options...>::ignore_header;
constexpr static bool ignore_empty = setup<Matchers...>::ignore_empty; constexpr static bool ignore_empty = setup<Options...>::ignore_empty;
public: public:
parser(const std::string& file_name, parser(const std::string& file_name,
@ -156,7 +158,7 @@ public:
iterator() : parser_{nullptr} { iterator() : parser_{nullptr} {
} }
iterator(parser<Matchers...>* parser) : parser_{parser} { iterator(parser<Options...>* parser) : parser_{parser} {
} }
value& operator*() { value& operator*() {
@ -197,10 +199,10 @@ public:
private: private:
value value_; value value_;
parser<Matchers...>* parser_; parser<Options...>* parser_;
}; };
iterable(parser<Matchers...>* parser) : parser_{parser} { iterable(parser<Options...>* parser) : parser_{parser} {
} }
iterator begin() { iterator begin() {
@ -211,7 +213,7 @@ public:
} }
private: private:
parser<Matchers...>* parser_; parser<Options...>* parser_;
}; };
template <typename... Ts> template <typename... Ts>
@ -423,7 +425,8 @@ private:
void set_error_failed_check() { void set_error_failed_check() {
if constexpr (string_error) { if constexpr (string_error) {
error_.append(file_name_).append(" failed check."); error_.append(file_name_).append(" failed check");
throw_if_throw_on_error<throw_on_error>(error_);
} else { } else {
error_ = true; error_ = true;
} }
@ -431,7 +434,8 @@ private:
void set_error_file_not_open() { void set_error_file_not_open() {
if constexpr (string_error) { if constexpr (string_error) {
error_.append(file_name_).append(" could not be opened."); error_.append(file_name_).append(" could not be opened");
throw_if_throw_on_error<throw_on_error>(error_);
} else { } else {
error_ = true; error_ = true;
} }
@ -439,7 +443,8 @@ private:
void set_error_eof_reached() { void set_error_eof_reached() {
if constexpr (string_error) { if constexpr (string_error) {
error_.append(file_name_).append(" reached end of file."); error_.append(file_name_).append(" reached end of file");
throw_if_throw_on_error<throw_on_error>(error_);
} else { } else {
error_ = true; error_ = true;
} }
@ -455,6 +460,7 @@ private:
.append(": \"") .append(": \"")
.append(reader_.buffer_) .append(reader_.buffer_)
.append("\""); .append("\"");
throw_if_throw_on_error<throw_on_error>(error_);
} else { } else {
error_ = true; error_ = true;
} }
@ -467,6 +473,7 @@ private:
.append("the header row is ignored within the setup, it cannot " .append("the header row is ignored within the setup, it cannot "
"be used") "be used")
.append("\""); .append("\"");
throw_if_throw_on_error<throw_on_error>(error_);
} else { } else {
error_ = true; error_ = true;
} }
@ -477,6 +484,7 @@ private:
error_.append(file_name_) error_.append(file_name_)
.append(": header does not contain given field: ") .append(": header does not contain given field: ")
.append(field); .append(field);
throw_if_throw_on_error<throw_on_error>(error_);
} else { } else {
error_ = true; error_ = true;
} }
@ -487,6 +495,7 @@ private:
error_.append(file_name_) error_.append(file_name_)
.append(": given field used multiple times: ") .append(": given field used multiple times: ")
.append(field); .append(field);
throw_if_throw_on_error<throw_on_error>(error_);
} else { } else {
error_ = true; error_ = true;
} }
@ -650,7 +659,7 @@ private:
const char* curr; const char* curr;
for (curr = next_line_buffer_ + size - 1; for (curr = next_line_buffer_ + size - 1;
curr >= next_line_buffer_ && curr >= next_line_buffer_ &&
setup<Matchers...>::escape::match(*curr); setup<Options...>::escape::match(*curr);
--curr) { --curr) {
} }
return (next_line_buffer_ - curr + size) % 2 == 0; return (next_line_buffer_ - curr + size) % 2 == 0;
@ -729,8 +738,8 @@ private:
char* next_line_buffer_{nullptr}; char* next_line_buffer_{nullptr};
char* helper_buffer_{nullptr}; char* helper_buffer_{nullptr};
converter<Matchers...> converter_; converter<Options...> converter_;
converter<Matchers...> next_line_converter_; converter<Options...> next_line_converter_;
size_t size_{0}; size_t size_{0};
size_t next_line_size_{0}; size_t next_line_size_{0};

View File

@ -179,20 +179,26 @@ class ignore_header;
class ignore_empty; class ignore_empty;
////////////////
// throw_on_error
////////////////
class throw_on_error;
//////////////// ////////////////
// setup implementation // setup implementation
//////////////// ////////////////
template <typename... Ts> template <typename... Options>
struct setup { struct setup {
private: private:
template <typename T> template <typename Option>
struct is_matcher struct is_matcher
: std::disjunction<is_instance_of_matcher_t<T, quote>, : std::disjunction<is_instance_of_matcher_t<Option, quote>,
is_instance_of_matcher_t<T, escape>, is_instance_of_matcher_t<Option, escape>,
is_instance_of_matcher_t<T, trim>, is_instance_of_matcher_t<Option, trim>,
is_instance_of_matcher_t<T, trim_left>, is_instance_of_matcher_t<Option, trim_left>,
is_instance_of_matcher_t<T, trim_right>> {}; is_instance_of_matcher_t<Option, trim_right>> {};
template <typename T> template <typename T>
struct is_string_error : std::is_same<T, string_error> {}; struct is_string_error : std::is_same<T, string_error> {};
@ -203,39 +209,47 @@ private:
template <typename T> template <typename T>
struct is_ignore_empty : std::is_same<T, ignore_empty> {}; struct is_ignore_empty : std::is_same<T, ignore_empty> {};
constexpr static auto count_matcher = count_v<is_matcher, Ts...>; template <typename T>
struct is_throw_on_error : std::is_same<T, throw_on_error> {};
constexpr static auto count_matcher = count_v<is_matcher, Options...>;
constexpr static auto count_multiline = constexpr static auto count_multiline =
count_v<is_instance_of_multiline, Ts...>; count_v<is_instance_of_multiline, Options...>;
constexpr static auto count_string_error = count_v<is_string_error, Ts...>; constexpr static auto count_string_error = count_v<is_string_error, Options...>;
constexpr static auto count_ignore_header = constexpr static auto count_ignore_header =
count_v<is_ignore_header, Ts...>; count_v<is_ignore_header, Options...>;
constexpr static auto count_ignore_empty = count_v<is_ignore_empty, Ts...>; constexpr static auto count_throw_on_error =
count_v<is_throw_on_error, Options...>;
constexpr static auto count_ignore_empty = count_v<is_ignore_empty, Options...>;
constexpr static auto number_of_valid_setup_types = constexpr static auto number_of_valid_setup_types =
count_matcher + count_multiline + count_string_error + count_matcher + count_multiline + count_string_error +
count_ignore_header + count_ignore_empty; count_ignore_header + count_ignore_empty + count_throw_on_error;
using trim_left_only = get_matcher_t<trim_left, Ts...>; using trim_left_only = get_matcher_t<trim_left, Options...>;
using trim_right_only = get_matcher_t<trim_right, Ts...>; using trim_right_only = get_matcher_t<trim_right, Options...>;
using trim_all = get_matcher_t<trim, Ts...>; using trim_all = get_matcher_t<trim, Options...>;
public: public:
using quote = get_matcher_t<quote, Ts...>; using quote = get_matcher_t<quote, Options...>;
using escape = get_matcher_t<escape, Ts...>; using escape = get_matcher_t<escape, Options...>;
using trim_left = using trim_left =
std::conditional_t<trim_all::enabled, trim_all, trim_left_only>; std::conditional_t<trim_all::enabled, trim_all, trim_left_only>;
using trim_right = using trim_right =
std::conditional_t<trim_all::enabled, trim_all, trim_right_only>; std::conditional_t<trim_all::enabled, trim_all, trim_right_only>;
using multiline = get_multiline_t<Ts...>; using multiline = get_multiline_t<Options...>;
constexpr static bool string_error = (count_string_error == 1); constexpr static bool string_error = (count_string_error == 1);
constexpr static bool ignore_header = (count_ignore_header == 1); constexpr static bool ignore_header = (count_ignore_header == 1);
constexpr static bool ignore_empty = (count_ignore_empty == 1); constexpr static bool ignore_empty = (count_ignore_empty == 1);
constexpr static bool throw_on_error = (count_throw_on_error == 1);
// TODO set string_error if throw_on_error is defined
private: private:
#define ASSERT_MSG "cannot have the same match character in multiple matchers" #define ASSERT_MSG "cannot have the same match character in multiple matchers"
@ -264,11 +278,11 @@ private:
static_assert(count_string_error <= 1, static_assert(count_string_error <= 1,
"string_error defined multiple times"); "string_error defined multiple times");
static_assert(number_of_valid_setup_types == sizeof...(Ts), static_assert(number_of_valid_setup_types == sizeof...(Options),
"one or multiple invalid setup parameters defined"); "one or multiple invalid setup parameters defined");
}; };
template <typename... Ts> template <typename... Options>
struct setup<setup<Ts...>> : setup<Ts...> {}; struct setup<setup<Options...>> : setup<Options...> {};
} /* ss */ } /* ss */

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "common.hpp" #include "common.hpp"
#include "exception.hpp"
#include "setup.hpp" #include "setup.hpp"
#include "type_traits.hpp" #include "type_traits.hpp"
#include <algorithm> #include <algorithm>
@ -11,16 +12,17 @@
namespace ss { namespace ss {
template <typename... Ts> template <typename... Options>
class splitter { class splitter {
private: private:
using quote = typename setup<Ts...>::quote; using quote = typename setup<Options...>::quote;
using trim_left = typename setup<Ts...>::trim_left; using trim_left = typename setup<Options...>::trim_left;
using trim_right = typename setup<Ts...>::trim_right; using trim_right = typename setup<Options...>::trim_right;
using escape = typename setup<Ts...>::escape; using escape = typename setup<Options...>::escape;
using multiline = typename setup<Ts...>::multiline; using multiline = typename setup<Options...>::multiline;
constexpr static auto string_error = setup<Ts...>::string_error; constexpr static auto string_error = setup<Options...>::string_error;
constexpr static auto throw_on_error = setup<Options...>::throw_on_error;
constexpr static auto is_const_line = !quote::enabled && !escape::enabled; constexpr static auto is_const_line = !quote::enabled && !escape::enabled;
using error_type = std::conditional_t<string_error, std::string, bool>; using error_type = std::conditional_t<string_error, std::string, bool>;
@ -121,7 +123,8 @@ private:
void set_error_empty_delimiter() { void set_error_empty_delimiter() {
if constexpr (string_error) { if constexpr (string_error) {
error_.clear(); error_.clear();
error_.append("empt delimiter"); error_.append("empty delimiter");
throw_if_throw_on_error<throw_on_error>(error_);
} else { } else {
error_ = true; error_ = true;
} }
@ -131,6 +134,7 @@ private:
if constexpr (string_error) { if constexpr (string_error) {
error_.clear(); error_.clear();
error_.append("mismatched quote at position: " + std::to_string(n)); error_.append("mismatched quote at position: " + std::to_string(n));
throw_if_throw_on_error<throw_on_error>(error_);
} else { } else {
error_ = true; error_ = true;
} }
@ -140,6 +144,7 @@ private:
if constexpr (string_error) { if constexpr (string_error) {
error_.clear(); error_.clear();
error_.append("unterminated escape at the end of the line"); error_.append("unterminated escape at the end of the line");
throw_if_throw_on_error<throw_on_error>(error_);
} else { } else {
error_ = true; error_ = true;
} }
@ -150,6 +155,7 @@ private:
if constexpr (string_error) { if constexpr (string_error) {
error_.clear(); error_.clear();
error_.append("unterminated quote"); error_.append("unterminated quote");
throw_if_throw_on_error<throw_on_error>(error_);
} else { } else {
error_ = true; error_ = true;
} }
@ -161,6 +167,7 @@ private:
error_.clear(); error_.clear();
error_.append("invalid resplit, new line must be longer" error_.append("invalid resplit, new line must be longer"
"than the end of the last slice"); "than the end of the last slice");
throw_if_throw_on_error<throw_on_error>(error_);
} else { } else {
error_ = true; error_ = true;
} }