mirror of
https://github.com/red0124/ssp.git
synced 2025-01-23 04:55:20 +01:00
rename to_struct to to_object, refactor some code
This commit is contained in:
parent
7b6794c4fa
commit
508e091469
@ -88,7 +88,7 @@ using no_void_validator_tup_t = typename no_void_validator_tup<Ts...>::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 <typename T, typename... Ts>
|
||||
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 <typename T, typename... Ts>
|
||||
T convert_struct(const char* const line,
|
||||
T convert_object(const char* const line,
|
||||
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
|
||||
@ -132,8 +132,8 @@ class converter {
|
||||
|
||||
// parses already split line, returns 'T' object with extracted values
|
||||
template <typename T, typename... Ts>
|
||||
T convert_struct(const split_input& elems) {
|
||||
return to_struct<T>(convert<Ts...>(elems));
|
||||
T convert_object(const split_input& elems) {
|
||||
return to_object<T>(convert<Ts...>(elems));
|
||||
}
|
||||
|
||||
// parses already split line, returns either a tuple of objects with
|
||||
@ -150,7 +150,7 @@ class converter {
|
||||
typename apply_trait<std::decay,
|
||||
arg_ref_tuple>::type;
|
||||
|
||||
return to_struct<T>(
|
||||
return to_object<T>(
|
||||
convert_impl(elems, (arg_tuple*){}));
|
||||
} else {
|
||||
return convert_impl<T, Ts...>(elems);
|
||||
|
@ -56,8 +56,8 @@ class parser {
|
||||
}
|
||||
|
||||
template <typename T, typename... Ts>
|
||||
T get_struct() {
|
||||
return to_struct<T>(get_next<Ts...>());
|
||||
T get_object() {
|
||||
return to_object<T>(get_next<Ts...>());
|
||||
}
|
||||
|
||||
template <typename T, typename... Ts>
|
||||
@ -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 <typename... Us, typename Fun = None>
|
||||
composite<Ts..., std::optional<no_void_validator_tup_t<Us...>>>
|
||||
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;
|
||||
try_convert_and_invoke<Value, Us...>(value, fun);
|
||||
return composite_with(std::move(value));
|
||||
}
|
||||
|
||||
// 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()) {
|
||||
auto new_value = try_same<Us...>();
|
||||
if (parser_.valid()) {
|
||||
value = new_value;
|
||||
if constexpr (!std::is_same_v<Fun,
|
||||
None>) {
|
||||
fun(*value);
|
||||
fun(parser_.error_msg());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
auto values =
|
||||
std::tuple_cat(std::move(values_),
|
||||
std::tuple{std::move(value)});
|
||||
return {std::move(values), parser_};
|
||||
}
|
||||
|
||||
auto values() { return values_; }
|
||||
|
||||
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>
|
||||
no_void_validator_tup_t<U, Us...> 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 <typename... Ts, typename Fun = None>
|
||||
composite<std::optional<no_void_validator_tup_t<Ts...>>> try_next(
|
||||
Fun&& fun = None{}) {
|
||||
@ -145,9 +182,7 @@ class parser {
|
||||
auto new_value = get_next<Ts...>();
|
||||
if (valid()) {
|
||||
value = new_value;
|
||||
if constexpr (!std::is_same_v<Fun, None>) {
|
||||
fun(*value);
|
||||
}
|
||||
try_invoke(*value, std::forward<Fun>(fun));
|
||||
}
|
||||
return {value, *this};
|
||||
};
|
||||
@ -156,6 +191,47 @@ class parser {
|
||||
template <typename...>
|
||||
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
|
||||
////////////////
|
||||
@ -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_)
|
||||
|
@ -327,16 +327,15 @@ struct is_instance_of<U<T>, U> {
|
||||
////////////////
|
||||
|
||||
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;
|
||||
return {get<Is>(std::forward<Tup>(tup))...};
|
||||
}
|
||||
|
||||
template <class S, class Tup>
|
||||
S to_struct(Tup&& tup) {
|
||||
S to_object(Tup&& tup) {
|
||||
using T = std::remove_reference_t<Tup>;
|
||||
|
||||
return to_struct<S>(std::make_index_sequence<std::tuple_size<T>{}>{},
|
||||
return to_object<S>(std::make_index_sequence<std::tuple_size<T>{}>{},
|
||||
std::forward<Tup>(tup));
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ TEST_CASE("testing parser") {
|
||||
|
||||
while (!p.eof()) {
|
||||
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()));
|
||||
@ -73,7 +73,7 @@ TEST_CASE("testing parser") {
|
||||
p.ignore_next();
|
||||
while (!p.eof()) {
|
||||
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));
|
||||
@ -85,7 +85,7 @@ TEST_CASE("testing parser") {
|
||||
|
||||
while (!p.eof()) {
|
||||
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()));
|
||||
@ -108,7 +108,7 @@ TEST_CASE("testing parser") {
|
||||
std::vector<X> i;
|
||||
|
||||
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>();
|
||||
if (p.valid()) {
|
||||
i.push_back(a);
|
||||
@ -125,7 +125,7 @@ TEST_CASE("testing parser") {
|
||||
std::vector<X> i;
|
||||
|
||||
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>();
|
||||
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<Y, my_string, my_string, my_string>();
|
||||
auto x = p.get_object<Y, my_string, my_string, my_string>();
|
||||
CHECK(copy_called == 0);
|
||||
CHECK(move_called == 6 * move_called_one_col);
|
||||
move_called = copy_called = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user