rename to_struct to to_object, refactor some code

This commit is contained in:
ado 2020-12-15 22:32:34 +01:00
parent 7b6794c4fa
commit 508e091469
4 changed files with 131 additions and 47 deletions

View File

@ -88,7 +88,7 @@ using no_void_validator_tup_t = typename no_void_validator_tup<Ts...>::type;
// tied class // 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 // the 'tied' method which is to be used for type deduction when converting
template <typename T, typename... Ts> template <typename T, typename... Ts>
struct tied_class { struct tied_class {
@ -116,9 +116,9 @@ class converter {
// parses line with given delimiter, returns a 'T' object created with // parses line with given delimiter, returns a 'T' object created with
// extracted values of type 'Ts' // extracted values of type 'Ts'
template <typename T, typename... Ts> template <typename T, typename... Ts>
T convert_struct(const char* const line, T convert_object(const char* const line,
const std::string& delim = "") { const std::string& delim = "") {
return to_struct<T>(convert<Ts...>(line, delim)); return to_object<T>(convert<Ts...>(line, delim));
} }
// parses line with given delimiter, returns tuple of objects with // 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 // parses already split line, returns 'T' object with extracted values
template <typename T, typename... Ts> template <typename T, typename... Ts>
T convert_struct(const split_input& elems) { T convert_object(const split_input& elems) {
return to_struct<T>(convert<Ts...>(elems)); return to_object<T>(convert<Ts...>(elems));
} }
// parses already split line, returns either a tuple of objects with // parses already split line, returns either a tuple of objects with
@ -150,7 +150,7 @@ class converter {
typename apply_trait<std::decay, typename apply_trait<std::decay,
arg_ref_tuple>::type; arg_ref_tuple>::type;
return to_struct<T>( return to_object<T>(
convert_impl(elems, (arg_tuple*){})); convert_impl(elems, (arg_tuple*){}));
} else { } else {
return convert_impl<T, Ts...>(elems); return convert_impl<T, Ts...>(elems);

View File

@ -56,8 +56,8 @@ class parser {
} }
template <typename T, typename... Ts> template <typename T, typename... Ts>
T get_struct() { T get_object() {
return to_struct<T>(get_next<Ts...>()); return to_object<T>(get_next<Ts...>());
} }
template <typename T, typename... Ts> template <typename T, typename... Ts>
@ -90,37 +90,74 @@ class parser {
: values_{values}, parser_{parser} { : values_{values}, parser_{parser} {
} }
// tries to convert the same line as different output if the // tries to convert the same line with a different output type
// previous conversion was not successful, returns composite // only if the previous conversion was not successful,
// containing itself and the new output as optional // returns composite containing itself and the new output
// if a parameter is passed which can be invoked with // as optional, additionally, if a parameter is passed, and
// the new output, it will be invoked if the returned value // that parameter can be invoked using the converted value,
// of the conversion is valid // than it will be invoked in the case of a valid conversion
template <typename... Us, typename Fun = None> template <typename... Us, typename Fun = None>
composite<Ts..., std::optional<no_void_validator_tup_t<Us...>>> composite<Ts..., std::optional<no_void_validator_tup_t<Us...>>>
or_else(Fun&& fun = None{}) { or_else(Fun&& fun = None{}) {
std::optional<no_void_validator_tup_t<Us...>> value; using Value = no_void_validator_tup_t<Us...>;
std::optional<Value> value;
if (!parser_.valid()) { try_convert_and_invoke<Value, Us...>(value, fun);
auto new_value = try_same<Us...>(); return composite_with(std::move(value));
if (parser_.valid()) {
value = new_value;
if constexpr (!std::is_same_v<Fun,
None>) {
fun(*value);
}
}
}
auto values =
std::tuple_cat(std::move(values_),
std::tuple{std::move(value)});
return {std::move(values), parser_};
} }
auto values() { return values_; } // same as or_else, but saves the result into a 'U' object
// instead of a tuple
template <typename U, typename... Us, typename Fun = None>
composite<Ts..., std::optional<U>> or_else_object(
Fun&& fun = None{}) {
std::optional<U> value;
try_convert_and_invoke<U, Us...>(value, fun);
return composite_with(std::move(value));
}
auto values() {
return values_;
}
template <typename Fun>
auto on_error(Fun fun) {
if (!parser_.valid()) {
fun(parser_.error_msg());
}
return *this;
}
private: private:
template <typename T>
composite<Ts..., T> composite_with(T&& new_value) {
auto merged_values =
std::tuple_cat(std::move(values_),
std::tuple{
std::forward<T>(new_value)});
return {std::move(merged_values), parser_};
}
template <typename U, typename... Us, typename Fun = None>
void try_convert_and_invoke(std::optional<U>& value,
Fun&& fun) {
if (!parser_.valid()) {
std::optional<U> new_value;
auto tuple_output = try_same<Us...>();
if constexpr (!std::is_same_v<
U, decltype(tuple_output)>) {
new_value = to_object<U>(tuple_output);
} else {
new_value = tuple_output;
}
if (parser_.valid()) {
value = new_value;
parser_.try_invoke(*value,
std::forward<Fun>(
fun));
}
}
}
template <typename U, typename... Us> template <typename U, typename... Us>
no_void_validator_tup_t<U, Us...> try_same() { no_void_validator_tup_t<U, Us...> try_same() {
parser_.clear_error(); parser_.clear_error();
@ -136,8 +173,8 @@ class parser {
parser& parser_; parser& parser_;
}; };
// tries to convert a line, but returns a composite which is // tries to convert a line and returns a composite which is
// able to chain additional conversions in case of failure // able to try additional conversions in case of failure
template <typename... Ts, typename Fun = None> template <typename... Ts, typename Fun = None>
composite<std::optional<no_void_validator_tup_t<Ts...>>> try_next( composite<std::optional<no_void_validator_tup_t<Ts...>>> try_next(
Fun&& fun = None{}) { Fun&& fun = None{}) {
@ -145,9 +182,7 @@ class parser {
auto new_value = get_next<Ts...>(); auto new_value = get_next<Ts...>();
if (valid()) { if (valid()) {
value = new_value; value = new_value;
if constexpr (!std::is_same_v<Fun, None>) { try_invoke(*value, std::forward<Fun>(fun));
fun(*value);
}
} }
return {value, *this}; return {value, *this};
}; };
@ -156,6 +191,47 @@ class parser {
template <typename...> template <typename...>
friend class composite; 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 <typename Arg, typename Fun = None>
void try_invoke(Arg&& arg, Fun&& fun) {
if constexpr (!std::is_same_v<std::decay_t<Fun>, None>) {
using Ret = decltype(
try_invoke_impl(arg, std::forward<Fun>(fun)));
if constexpr (!std::is_same_v<Ret, void>) {
if (!try_invoke_impl(arg,
std::forward<Fun>(fun))) {
set_error_failed_check();
}
} else {
try_invoke_impl(arg, std::forward<Fun>(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 <typename Arg, typename Fun = None>
auto try_invoke_impl(Arg&& arg, Fun&& fun) {
if constexpr (!std::is_same_v<Fun, None>) {
if constexpr (std::is_invocable_v<Fun>) {
return fun();
} else if constexpr (std::is_invocable_v<Fun, Arg>) {
return std::invoke(std::forward<Fun>(fun),
std::forward<Arg>(arg));
} else {
return std::apply(std::forward<Fun>(fun),
std::forward<Arg>(arg));
}
}
}
//////////////// ////////////////
// line reading // line reading
//////////////// ////////////////
@ -210,6 +286,15 @@ class parser {
bool_error_ = false; 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() { void set_error_file_not_open() {
if (error_mode_ == error_mode::String) { if (error_mode_ == error_mode::String) {
string_error_.append(file_name_) string_error_.append(file_name_)

View File

@ -327,16 +327,15 @@ struct is_instance_of<U<T>, U> {
//////////////// ////////////////
template <class S, std::size_t... Is, class Tup> template <class S, std::size_t... Is, class Tup>
S to_struct(std::index_sequence<Is...>, Tup&& tup) { S to_object(std::index_sequence<Is...>, Tup&& tup) {
using std::get; using std::get;
return {get<Is>(std::forward<Tup>(tup))...}; return {get<Is>(std::forward<Tup>(tup))...};
} }
template <class S, class Tup> template <class S, class Tup>
S to_struct(Tup&& tup) { S to_object(Tup&& tup) {
using T = std::remove_reference_t<Tup>; using T = std::remove_reference_t<Tup>;
return to_object<S>(std::make_index_sequence<std::tuple_size<T>{}>{},
return to_struct<S>(std::make_index_sequence<std::tuple_size<T>{}>{},
std::forward<Tup>(tup)); std::forward<Tup>(tup));
} }

View File

@ -60,7 +60,7 @@ TEST_CASE("testing parser") {
while (!p.eof()) { while (!p.eof()) {
auto a = p.get_next<int, double, std::string>(); auto a = p.get_next<int, double, std::string>();
i.emplace_back(ss::to_struct<X>(a)); i.emplace_back(ss::to_object<X>(a));
} }
CHECK(std::equal(i.begin(), i.end(), data.begin())); CHECK(std::equal(i.begin(), i.end(), data.begin()));
@ -73,7 +73,7 @@ TEST_CASE("testing parser") {
p.ignore_next(); p.ignore_next();
while (!p.eof()) { while (!p.eof()) {
auto a = p.get_next<int, double, std::string>(); auto a = p.get_next<int, double, std::string>();
i.emplace_back(ss::to_struct<X>(a)); i.emplace_back(ss::to_object<X>(a));
} }
CHECK(std::equal(i.begin(), i.end(), data.begin() + 1)); CHECK(std::equal(i.begin(), i.end(), data.begin() + 1));
@ -85,7 +85,7 @@ TEST_CASE("testing parser") {
while (!p.eof()) { while (!p.eof()) {
i.push_back( i.push_back(
p.get_struct<X, int, double, std::string>()); p.get_object<X, int, double, std::string>());
} }
CHECK(std::equal(i.begin(), i.end(), data.begin())); CHECK(std::equal(i.begin(), i.end(), data.begin()));
@ -108,7 +108,7 @@ TEST_CASE("testing parser") {
std::vector<X> i; std::vector<X> i;
while (!p.eof()) { while (!p.eof()) {
auto a = p.get_struct<X, ss::ax<int, excluded>, double, auto a = p.get_object<X, ss::ax<int, excluded>, double,
std::string>(); std::string>();
if (p.valid()) { if (p.valid()) {
i.push_back(a); i.push_back(a);
@ -125,7 +125,7 @@ TEST_CASE("testing parser") {
std::vector<X> i; std::vector<X> i;
while (!p.eof()) { while (!p.eof()) {
auto a = p.get_struct<X, ss::nx<int, 3>, double, auto a = p.get_object<X, ss::nx<int, 3>, double,
std::string>(); std::string>();
if (p.valid()) { if (p.valid()) {
i.push_back(a); i.push_back(a);
@ -223,7 +223,7 @@ TEST_CASE("testing the moving of parsed values") {
{ {
ss::parser p{f.name, ","}; ss::parser p{f.name, ","};
auto x = p.get_struct<Y, my_string, my_string, my_string>(); auto x = p.get_object<Y, my_string, my_string, my_string>();
CHECK(copy_called == 0); CHECK(copy_called == 0);
CHECK(move_called == 6 * move_called_one_col); CHECK(move_called == 6 * move_called_one_col);
move_called = copy_called = 0; move_called = copy_called = 0;