From 508e091469cac1fd69b8f6783fdfb6fb1ff26f9e Mon Sep 17 00:00:00 2001 From: ado Date: Tue, 15 Dec 2020 22:32:34 +0100 Subject: [PATCH] rename to_struct to to_object, refactor some code --- include/ss/converter.hpp | 12 +-- include/ss/parser.hpp | 147 +++++++++++++++++++++++++++++-------- include/ss/type_traits.hpp | 7 +- test/test_parser.cpp | 12 +-- 4 files changed, 131 insertions(+), 47 deletions(-) diff --git a/include/ss/converter.hpp b/include/ss/converter.hpp index 6bc5c35..886ad39 100644 --- a/include/ss/converter.hpp +++ b/include/ss/converter.hpp @@ -88,7 +88,7 @@ using no_void_validator_tup_t = typename no_void_validator_tup::type; // tied class //////////////// -// check if parameter pack is only one element which is a class and has +// check if the parameter pack is only one element which is a class and has // the 'tied' method which is to be used for type deduction when converting template struct tied_class { @@ -116,9 +116,9 @@ class converter { // parses line with given delimiter, returns a 'T' object created with // extracted values of type 'Ts' template - T convert_struct(const char* const line, + T convert_object(const char* const line, const std::string& delim = "") { - return to_struct(convert(line, delim)); + return to_object(convert(line, delim)); } // parses line with given delimiter, returns tuple of objects with @@ -132,8 +132,8 @@ class converter { // parses already split line, returns 'T' object with extracted values template - T convert_struct(const split_input& elems) { - return to_struct(convert(elems)); + T convert_object(const split_input& elems) { + return to_object(convert(elems)); } // parses already split line, returns either a tuple of objects with @@ -150,7 +150,7 @@ class converter { typename apply_trait::type; - return to_struct( + return to_object( convert_impl(elems, (arg_tuple*){})); } else { return convert_impl(elems); diff --git a/include/ss/parser.hpp b/include/ss/parser.hpp index b73ccf5..67cc908 100644 --- a/include/ss/parser.hpp +++ b/include/ss/parser.hpp @@ -56,8 +56,8 @@ class parser { } template - T get_struct() { - return to_struct(get_next()); + T get_object() { + return to_object(get_next()); } template @@ -90,37 +90,74 @@ class parser { : values_{values}, parser_{parser} { } - // tries to convert the same line as different output if the - // previous conversion was not successful, returns composite - // containing itself and the new output as optional - // if a parameter is passed which can be invoked with - // the new output, it will be invoked if the returned value - // of the conversion is valid + // tries to convert the same line with a different output type + // only if the previous conversion was not successful, + // returns composite containing itself and the new output + // as optional, additionally, if a parameter is passed, and + // that parameter can be invoked using the converted value, + // than it will be invoked in the case of a valid conversion template composite>> or_else(Fun&& fun = None{}) { - std::optional> value; - - if (!parser_.valid()) { - auto new_value = try_same(); - if (parser_.valid()) { - value = new_value; - if constexpr (!std::is_same_v) { - fun(*value); - } - } - } - - auto values = - std::tuple_cat(std::move(values_), - std::tuple{std::move(value)}); - return {std::move(values), parser_}; + using Value = no_void_validator_tup_t; + std::optional value; + try_convert_and_invoke(value, fun); + return composite_with(std::move(value)); } - auto values() { return values_; } + // same as or_else, but saves the result into a 'U' object + // instead of a tuple + template + composite> or_else_object( + Fun&& fun = None{}) { + std::optional value; + try_convert_and_invoke(value, fun); + return composite_with(std::move(value)); + } + + auto values() { + return values_; + } + + template + auto on_error(Fun fun) { + if (!parser_.valid()) { + fun(parser_.error_msg()); + } + return *this; + } private: + template + composite composite_with(T&& new_value) { + auto merged_values = + std::tuple_cat(std::move(values_), + std::tuple{ + std::forward(new_value)}); + return {std::move(merged_values), parser_}; + } + + template + void try_convert_and_invoke(std::optional& value, + Fun&& fun) { + if (!parser_.valid()) { + std::optional new_value; + auto tuple_output = try_same(); + if constexpr (!std::is_same_v< + U, decltype(tuple_output)>) { + new_value = to_object(tuple_output); + } else { + new_value = tuple_output; + } + if (parser_.valid()) { + value = new_value; + parser_.try_invoke(*value, + std::forward( + fun)); + } + } + } + template no_void_validator_tup_t try_same() { parser_.clear_error(); @@ -136,8 +173,8 @@ class parser { parser& parser_; }; - // tries to convert a line, but returns a composite which is - // able to chain additional conversions in case of failure + // tries to convert a line and returns a composite which is + // able to try additional conversions in case of failure template composite>> try_next( Fun&& fun = None{}) { @@ -145,9 +182,7 @@ class parser { auto new_value = get_next(); if (valid()) { value = new_value; - if constexpr (!std::is_same_v) { - fun(*value); - } + try_invoke(*value, std::forward(fun)); } return {value, *this}; }; @@ -156,6 +191,47 @@ class parser { template friend class composite; + // tries to invoke the given function (see below), if the function + // returns a value which can be used as a conditional, and it returns + // false, the function sets an error, and allows the invoke of the + // next possible conversion as if the validation of the current one + // failed + template + void try_invoke(Arg&& arg, Fun&& fun) { + if constexpr (!std::is_same_v, None>) { + using Ret = decltype( + try_invoke_impl(arg, std::forward(fun))); + if constexpr (!std::is_same_v) { + if (!try_invoke_impl(arg, + std::forward(fun))) { + set_error_failed_check(); + } + } else { + try_invoke_impl(arg, std::forward(fun)); + } + } + } + + // tries to invoke the function if not None + // it first tries to invoke the function without arguments, + // than with one argument if the function accepts the whole tuple + // as an argument, and finally tries to invoke it with the tuple + // laid out as a parameter pack + template + auto try_invoke_impl(Arg&& arg, Fun&& fun) { + if constexpr (!std::is_same_v) { + if constexpr (std::is_invocable_v) { + return fun(); + } else if constexpr (std::is_invocable_v) { + return std::invoke(std::forward(fun), + std::forward(arg)); + } else { + return std::apply(std::forward(fun), + std::forward(arg)); + } + } + } + //////////////// // line reading //////////////// @@ -210,6 +286,15 @@ class parser { bool_error_ = false; } + void set_error_failed_check() { + if (error_mode_ == error_mode::String) { + string_error_.append(file_name_) + .append(" failed check."); + } else { + bool_error_ = true; + } + } + void set_error_file_not_open() { if (error_mode_ == error_mode::String) { string_error_.append(file_name_) diff --git a/include/ss/type_traits.hpp b/include/ss/type_traits.hpp index c637dfb..1c8fa19 100644 --- a/include/ss/type_traits.hpp +++ b/include/ss/type_traits.hpp @@ -327,16 +327,15 @@ struct is_instance_of, U> { //////////////// template -S to_struct(std::index_sequence, Tup&& tup) { +S to_object(std::index_sequence, Tup&& tup) { using std::get; return {get(std::forward(tup))...}; } template -S to_struct(Tup&& tup) { +S to_object(Tup&& tup) { using T = std::remove_reference_t; - - return to_struct(std::make_index_sequence{}>{}, + return to_object(std::make_index_sequence{}>{}, std::forward(tup)); } diff --git a/test/test_parser.cpp b/test/test_parser.cpp index e84fe83..d346ad4 100644 --- a/test/test_parser.cpp +++ b/test/test_parser.cpp @@ -60,7 +60,7 @@ TEST_CASE("testing parser") { while (!p.eof()) { auto a = p.get_next(); - i.emplace_back(ss::to_struct(a)); + i.emplace_back(ss::to_object(a)); } CHECK(std::equal(i.begin(), i.end(), data.begin())); @@ -73,7 +73,7 @@ TEST_CASE("testing parser") { p.ignore_next(); while (!p.eof()) { auto a = p.get_next(); - i.emplace_back(ss::to_struct(a)); + i.emplace_back(ss::to_object(a)); } CHECK(std::equal(i.begin(), i.end(), data.begin() + 1)); @@ -85,7 +85,7 @@ TEST_CASE("testing parser") { while (!p.eof()) { i.push_back( - p.get_struct()); + p.get_object()); } CHECK(std::equal(i.begin(), i.end(), data.begin())); @@ -108,7 +108,7 @@ TEST_CASE("testing parser") { std::vector i; while (!p.eof()) { - auto a = p.get_struct, double, + auto a = p.get_object, double, std::string>(); if (p.valid()) { i.push_back(a); @@ -125,7 +125,7 @@ TEST_CASE("testing parser") { std::vector i; while (!p.eof()) { - auto a = p.get_struct, double, + auto a = p.get_object, double, std::string>(); if (p.valid()) { i.push_back(a); @@ -223,7 +223,7 @@ TEST_CASE("testing the moving of parsed values") { { ss::parser p{f.name, ","}; - auto x = p.get_struct(); + auto x = p.get_object(); CHECK(copy_called == 0); CHECK(move_called == 6 * move_called_one_col); move_called = copy_called = 0;