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
#include "exception.hpp"
#include "extract.hpp"
#include "function_traits.hpp"
#include "restrictions.hpp"
@ -95,11 +96,12 @@ constexpr bool tied_class_v = tied_class<Ts...>::value;
// converter
////////////////
template <typename... Matchers>
template <typename... Options>
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 = ",";
using error_type = std::conditional_t<string_error, std::string, bool>;
@ -229,6 +231,7 @@ private:
if constexpr (string_error) {
error_.clear();
error_.append(splitter_.error_msg());
throw_if_throw_on_error<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<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<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<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<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<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<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<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<throw_on_error>(error_);
} else {
error_ = true;
}
@ -472,7 +483,7 @@ private:
////////////////
error_type error_{};
splitter<Matchers...> splitter_;
splitter<Options...> splitter_;
template <typename...>
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 "converter.hpp"
#include "exception.hpp"
#include "extract.hpp"
#include "restrictions.hpp"
#include <cstdlib>
@ -12,22 +13,23 @@
namespace ss {
template <typename... Matchers>
template <typename... Options>
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>;
constexpr static bool escaped_multiline_enabled =
multiline::enabled && setup<Matchers...>::escape::enabled;
multiline::enabled && setup<Options...>::escape::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:
parser(const std::string& file_name,
@ -156,7 +158,7 @@ public:
iterator() : parser_{nullptr} {
}
iterator(parser<Matchers...>* parser) : parser_{parser} {
iterator(parser<Options...>* parser) : parser_{parser} {
}
value& operator*() {
@ -197,10 +199,10 @@ public:
private:
value value_;
parser<Matchers...>* parser_;
parser<Options...>* parser_;
};
iterable(parser<Matchers...>* parser) : parser_{parser} {
iterable(parser<Options...>* parser) : parser_{parser} {
}
iterator begin() {
@ -211,7 +213,7 @@ public:
}
private:
parser<Matchers...>* parser_;
parser<Options...>* parser_;
};
template <typename... Ts>
@ -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<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<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<throw_on_error>(error_);
} else {
error_ = true;
}
@ -455,6 +460,7 @@ private:
.append(": \"")
.append(reader_.buffer_)
.append("\"");
throw_if_throw_on_error<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<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<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<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<Matchers...>::escape::match(*curr);
setup<Options...>::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<Matchers...> converter_;
converter<Matchers...> next_line_converter_;
converter<Options...> converter_;
converter<Options...> next_line_converter_;
size_t size_{0};
size_t next_line_size_{0};

View File

@ -179,20 +179,26 @@ class ignore_header;
class ignore_empty;
////////////////
// throw_on_error
////////////////
class throw_on_error;
////////////////
// setup implementation
////////////////
template <typename... Ts>
template <typename... Options>
struct setup {
private:
template <typename T>
template <typename Option>
struct is_matcher
: std::disjunction<is_instance_of_matcher_t<T, quote>,
is_instance_of_matcher_t<T, escape>,
is_instance_of_matcher_t<T, trim>,
is_instance_of_matcher_t<T, trim_left>,
is_instance_of_matcher_t<T, trim_right>> {};
: std::disjunction<is_instance_of_matcher_t<Option, quote>,
is_instance_of_matcher_t<Option, escape>,
is_instance_of_matcher_t<Option, trim>,
is_instance_of_matcher_t<Option, trim_left>,
is_instance_of_matcher_t<Option, trim_right>> {};
template <typename T>
struct is_string_error : std::is_same<T, string_error> {};
@ -203,39 +209,47 @@ private:
template <typename T>
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 =
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 =
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 =
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_right_only = get_matcher_t<trim_right, Ts...>;
using trim_all = get_matcher_t<trim, Ts...>;
using trim_left_only = get_matcher_t<trim_left, Options...>;
using trim_right_only = get_matcher_t<trim_right, Options...>;
using trim_all = get_matcher_t<trim, Options...>;
public:
using quote = get_matcher_t<quote, Ts...>;
using escape = get_matcher_t<escape, Ts...>;
using quote = get_matcher_t<quote, Options...>;
using escape = get_matcher_t<escape, Options...>;
using trim_left =
std::conditional_t<trim_all::enabled, trim_all, trim_left_only>;
using trim_right =
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 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 <typename... Ts>
struct setup<setup<Ts...>> : setup<Ts...> {};
template <typename... Options>
struct setup<setup<Options...>> : setup<Options...> {};
} /* ss */

View File

@ -1,5 +1,6 @@
#pragma once
#include "common.hpp"
#include "exception.hpp"
#include "setup.hpp"
#include "type_traits.hpp"
#include <algorithm>
@ -11,16 +12,17 @@
namespace ss {
template <typename... Ts>
template <typename... Options>
class splitter {
private:
using quote = typename setup<Ts...>::quote;
using trim_left = typename setup<Ts...>::trim_left;
using trim_right = typename setup<Ts...>::trim_right;
using escape = typename setup<Ts...>::escape;
using multiline = typename setup<Ts...>::multiline;
using quote = typename setup<Options...>::quote;
using trim_left = typename setup<Options...>::trim_left;
using trim_right = typename setup<Options...>::trim_right;
using escape = typename setup<Options...>::escape;
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;
using error_type = std::conditional_t<string_error, std::string, bool>;
@ -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<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<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<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<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<throw_on_error>(error_);
} else {
error_ = true;
}