mirror of
https://github.com/red0124/ssp.git
synced 2025-01-23 13:05: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
|
// 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);
|
||||||
|
@ -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;
|
||||||
|
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()) {
|
if (!parser_.valid()) {
|
||||||
auto new_value = try_same<Us...>();
|
fun(parser_.error_msg());
|
||||||
if (parser_.valid()) {
|
|
||||||
value = new_value;
|
|
||||||
if constexpr (!std::is_same_v<Fun,
|
|
||||||
None>) {
|
|
||||||
fun(*value);
|
|
||||||
}
|
}
|
||||||
|
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:
|
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_)
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user