diff --git a/include/ss/converter.hpp b/include/ss/converter.hpp index 3650576..a9e3156 100644 --- a/include/ss/converter.hpp +++ b/include/ss/converter.hpp @@ -1,4 +1,5 @@ #pragma once +#include "exception.hpp" #include "extract.hpp" #include "function_traits.hpp" #include "restrictions.hpp" @@ -95,11 +96,12 @@ constexpr bool tied_class_v = tied_class::value; // converter //////////////// -template +template class converter { - using line_ptr_type = typename splitter::line_ptr_type; + using line_ptr_type = typename splitter::line_ptr_type; - constexpr static auto string_error = setup::string_error; + constexpr static auto string_error = setup::string_error; + constexpr static auto throw_on_error = setup::throw_on_error; constexpr static auto default_delimiter = ","; using error_type = std::conditional_t; @@ -229,6 +231,7 @@ private: if constexpr (string_error) { error_.clear(); error_.append(splitter_.error_msg()); + throw_if_throw_on_error(error_); } else { error_ = true; } @@ -239,6 +242,7 @@ private: error_.clear(); splitter_.set_error_unterminated_escape(); error_.append(splitter_.error_msg()); + throw_if_throw_on_error(error_); } else { error_ = true; } @@ -247,7 +251,8 @@ private: void set_error_multiline_limit_reached() { if constexpr (string_error) { error_.clear(); - error_.append("multiline limit reached."); + error_.append("multiline limit reached"); + throw_if_throw_on_error(error_); } else { error_ = true; } @@ -258,6 +263,7 @@ private: error_.clear(); error_.append("invalid conversion for parameter ") .append(error_sufix(msg, pos)); + throw_if_throw_on_error(error_); } else { error_ = true; } @@ -268,6 +274,7 @@ private: if constexpr (string_error) { error_.clear(); error_.append(error).append(" ").append(error_sufix(msg, pos)); + throw_if_throw_on_error(error_); } else { error_ = true; } @@ -280,6 +287,7 @@ private: .append(std::to_string(expected_pos)) .append(", got: ") .append(std::to_string(pos)); + throw_if_throw_on_error(error_); } else { error_ = true; } @@ -295,6 +303,7 @@ private: .append(std::to_string(mapping_size)) .append(", got: ") .append(std::to_string(argument_size)); + throw_if_throw_on_error(error_); } else { error_ = true; } @@ -304,6 +313,7 @@ private: if constexpr (string_error) { error_.clear(); error_.append("received empty mapping"); + throw_if_throw_on_error(error_); } else { error_ = true; } @@ -317,6 +327,7 @@ private: .append(std::to_string(maximum_index)) .append(", greater then number of columns: ") .append(std::to_string(number_of_columnts)); + throw_if_throw_on_error(error_); } else { error_ = true; } @@ -472,7 +483,7 @@ private: //////////////// error_type error_{}; - splitter splitter_; + splitter splitter_; template friend class parser; diff --git a/include/ss/exception.hpp b/include/ss/exception.hpp new file mode 100644 index 0000000..4122a1f --- /dev/null +++ b/include/ss/exception.hpp @@ -0,0 +1,30 @@ +#pragma once +#include +#include + +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 +void throw_if_throw_on_error(const std::string& msg) { + if constexpr (throw_on_error) { + throw ss::exception(msg); + } +} + +} /* ss */ diff --git a/include/ss/parser.hpp b/include/ss/parser.hpp index d22cf45..28062ef 100644 --- a/include/ss/parser.hpp +++ b/include/ss/parser.hpp @@ -2,6 +2,7 @@ #include "common.hpp" #include "converter.hpp" +#include "exception.hpp" #include "extract.hpp" #include "restrictions.hpp" #include @@ -12,22 +13,23 @@ namespace ss { -template +template class parser { - constexpr static auto string_error = setup::string_error; + constexpr static auto string_error = setup::string_error; + constexpr static auto throw_on_error = setup::throw_on_error; - using multiline = typename setup::multiline; + using multiline = typename setup::multiline; using error_type = std::conditional_t; constexpr static bool escaped_multiline_enabled = - multiline::enabled && setup::escape::enabled; + multiline::enabled && setup::escape::enabled; constexpr static bool quoted_multiline_enabled = - multiline::enabled && setup::quote::enabled; + multiline::enabled && setup::quote::enabled; - constexpr static bool ignore_header = setup::ignore_header; + constexpr static bool ignore_header = setup::ignore_header; - constexpr static bool ignore_empty = setup::ignore_empty; + constexpr static bool ignore_empty = setup::ignore_empty; public: parser(const std::string& file_name, @@ -152,11 +154,11 @@ public: struct iterable { struct iterator { using value = std::conditional_t>; + no_void_validator_tup_t>; iterator() : parser_{nullptr} { } - iterator(parser* parser) : parser_{parser} { + iterator(parser* parser) : parser_{parser} { } value& operator*() { @@ -197,10 +199,10 @@ public: private: value value_; - parser* parser_; + parser* parser_; }; - iterable(parser* parser) : parser_{parser} { + iterable(parser* parser) : parser_{parser} { } iterator begin() { @@ -211,7 +213,7 @@ public: } private: - parser* parser_; + parser* parser_; }; template @@ -423,7 +425,8 @@ private: void set_error_failed_check() { if constexpr (string_error) { - error_.append(file_name_).append(" failed check."); + error_.append(file_name_).append(" failed check"); + throw_if_throw_on_error(error_); } else { error_ = true; } @@ -431,7 +434,8 @@ private: void set_error_file_not_open() { 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(error_); } else { error_ = true; } @@ -439,7 +443,8 @@ private: void set_error_eof_reached() { 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(error_); } else { error_ = true; } @@ -455,6 +460,7 @@ private: .append(": \"") .append(reader_.buffer_) .append("\""); + throw_if_throw_on_error(error_); } else { error_ = true; } @@ -467,6 +473,7 @@ private: .append("the header row is ignored within the setup, it cannot " "be used") .append("\""); + throw_if_throw_on_error(error_); } else { error_ = true; } @@ -477,6 +484,7 @@ private: error_.append(file_name_) .append(": header does not contain given field: ") .append(field); + throw_if_throw_on_error(error_); } else { error_ = true; } @@ -487,6 +495,7 @@ private: error_.append(file_name_) .append(": given field used multiple times: ") .append(field); + throw_if_throw_on_error(error_); } else { error_ = true; } @@ -650,7 +659,7 @@ private: const char* curr; for (curr = next_line_buffer_ + size - 1; curr >= next_line_buffer_ && - setup::escape::match(*curr); + setup::escape::match(*curr); --curr) { } return (next_line_buffer_ - curr + size) % 2 == 0; @@ -729,8 +738,8 @@ private: char* next_line_buffer_{nullptr}; char* helper_buffer_{nullptr}; - converter converter_; - converter next_line_converter_; + converter converter_; + converter next_line_converter_; size_t size_{0}; size_t next_line_size_{0}; diff --git a/include/ss/setup.hpp b/include/ss/setup.hpp index 62da91b..7fd8ce4 100644 --- a/include/ss/setup.hpp +++ b/include/ss/setup.hpp @@ -179,20 +179,26 @@ class ignore_header; class ignore_empty; +//////////////// +// throw_on_error +//////////////// + +class throw_on_error; + //////////////// // setup implementation //////////////// -template +template struct setup { private: - template + template struct is_matcher - : std::disjunction, - is_instance_of_matcher_t, - is_instance_of_matcher_t, - is_instance_of_matcher_t, - is_instance_of_matcher_t> {}; + : std::disjunction, + is_instance_of_matcher_t, + is_instance_of_matcher_t, + is_instance_of_matcher_t, + is_instance_of_matcher_t> {}; template struct is_string_error : std::is_same {}; @@ -203,39 +209,47 @@ private: template struct is_ignore_empty : std::is_same {}; - constexpr static auto count_matcher = count_v; + template + struct is_throw_on_error : std::is_same {}; + + constexpr static auto count_matcher = count_v; constexpr static auto count_multiline = - count_v; + count_v; - constexpr static auto count_string_error = count_v; + constexpr static auto count_string_error = count_v; constexpr static auto count_ignore_header = - count_v; + count_v; - constexpr static auto count_ignore_empty = count_v; + constexpr static auto count_throw_on_error = + count_v; + + constexpr static auto count_ignore_empty = count_v; constexpr static auto number_of_valid_setup_types = 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; - using trim_right_only = get_matcher_t; - using trim_all = get_matcher_t; + using trim_left_only = get_matcher_t; + using trim_right_only = get_matcher_t; + using trim_all = get_matcher_t; public: - using quote = get_matcher_t; - using escape = get_matcher_t; + using quote = get_matcher_t; + using escape = get_matcher_t; using trim_left = std::conditional_t; using trim_right = std::conditional_t; - using multiline = get_multiline_t; + using multiline = get_multiline_t; constexpr static bool string_error = (count_string_error == 1); constexpr static bool ignore_header = (count_ignore_header == 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: #define ASSERT_MSG "cannot have the same match character in multiple matchers" @@ -264,11 +278,11 @@ private: static_assert(count_string_error <= 1, "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"); }; -template -struct setup> : setup {}; +template +struct setup> : setup {}; } /* ss */ diff --git a/include/ss/splitter.hpp b/include/ss/splitter.hpp index dc2e0e7..02c8a21 100644 --- a/include/ss/splitter.hpp +++ b/include/ss/splitter.hpp @@ -1,5 +1,6 @@ #pragma once #include "common.hpp" +#include "exception.hpp" #include "setup.hpp" #include "type_traits.hpp" #include @@ -11,16 +12,17 @@ namespace ss { -template +template class splitter { private: - using quote = typename setup::quote; - using trim_left = typename setup::trim_left; - using trim_right = typename setup::trim_right; - using escape = typename setup::escape; - using multiline = typename setup::multiline; + using quote = typename setup::quote; + using trim_left = typename setup::trim_left; + using trim_right = typename setup::trim_right; + using escape = typename setup::escape; + using multiline = typename setup::multiline; - constexpr static auto string_error = setup::string_error; + constexpr static auto string_error = setup::string_error; + constexpr static auto throw_on_error = setup::throw_on_error; constexpr static auto is_const_line = !quote::enabled && !escape::enabled; using error_type = std::conditional_t; @@ -121,7 +123,8 @@ private: void set_error_empty_delimiter() { if constexpr (string_error) { error_.clear(); - error_.append("empt delimiter"); + error_.append("empty delimiter"); + throw_if_throw_on_error(error_); } else { error_ = true; } @@ -131,6 +134,7 @@ private: if constexpr (string_error) { error_.clear(); error_.append("mismatched quote at position: " + std::to_string(n)); + throw_if_throw_on_error(error_); } else { error_ = true; } @@ -140,6 +144,7 @@ private: if constexpr (string_error) { error_.clear(); error_.append("unterminated escape at the end of the line"); + throw_if_throw_on_error(error_); } else { error_ = true; } @@ -150,6 +155,7 @@ private: if constexpr (string_error) { error_.clear(); error_.append("unterminated quote"); + throw_if_throw_on_error(error_); } else { error_ = true; } @@ -161,6 +167,7 @@ private: error_.clear(); error_.append("invalid resplit, new line must be longer" "than the end of the last slice"); + throw_if_throw_on_error(error_); } else { error_ = true; }