replace or_else_object with or_object inside the parser, update documentation

This commit is contained in:
ado 2021-01-02 02:31:45 +01:00
parent f39e1669f4
commit 60c8156fb7
3 changed files with 71 additions and 5 deletions

View File

@ -270,3 +270,69 @@ The shape enum will be in an example below. The **inline** is there just to prev
multiple definition errors. The function returns **true** if the conversion was
a success, and **false** otherwise. The function uses **const char*** begin and end
for performance reasons.
## Substitute conversions
The parser can also be used to effectively parse files whose rows are not
always in the same format (not a classical csv but still csv-like).
An example would be the best way to demonstrate such a scenario.
Supposing we have a file containing different shapes in given formats:
* circle radius
* rectangle side_a side_b
* triangle side_a side_b side_c
The delimiter is " ", and the number of columns varies depending on which
shape it is. We are required to read the file and to store information
(shape and area) of the shapes into a data structure in the same order
as they are in the file.
```cpp
ss::parser p{"shapes.txt", " "};
if (!p.valid()) {
std::cout << p.error_msg() << std::endl;
exit(EXIT_FAILURE);
}
p.set_error_mode(ss::error_mode::error_string);
std::vector<std::pair<shape, double>> shapes;
auto insert_circle = [&shapes](shape s, double r) {
if (s != shape::circle) {
return false;
}
shapes.emplace_back(s, r * r * M_PI);
return true;
};
auto insert_rectangle = [&shapes](shape s, double a, double b) {
if (s != shape::rectangle) {
return false;
}
shapes.emplace_back(s, a * b);
return true;
};
auto insert_triangle = [&shapes](shape s, double a, double b, double c) {
if (s != shape::triangle) {
return false;
}
double sh = (a + b + c) / 2;
shapes.emplace_back(s, sqrt(sh * (sh - a) * (sh - b) * (sh - c)));
return true;
};
while (!p.eof()) {
p.try_next<shape, double>(insert_circle)
.or_else<shape, double, double>(insert_rectangle)
.or_else<shape, double, double, double>(insert_triangle)
.on_error([](const std::string& error) {
std::cout << error << std::endl;
});
}
// do something with the stored data ...
```

View File

@ -107,7 +107,7 @@ public:
// 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{}) {
composite<Ts..., std::optional<U>> or_object(Fun&& fun = none{}) {
std::optional<U> value;
try_convert_and_invoke<U, Us...>(value, fun);
return composite_with(std::move(value));
@ -306,7 +306,7 @@ private:
}
void set_error_file_not_open() {
string_error_.append(file_name_).append(" could not be not open.");
string_error_.append(file_name_).append(" could not be opened.");
bool_error_ = true;
}

View File

@ -223,7 +223,7 @@ TEST_CASE("testing composite conversion") {
CHECK(std::tie(i1, i2, d) == expectedData);
})
.on_error(fail)
.or_else_object<test_struct, int, double, char>(fail)
.or_object<test_struct, int, double, char>(fail)
.on_error(fail)
.or_else<test_tuple>(fail)
.on_error(fail)
@ -291,7 +291,7 @@ TEST_CASE("testing composite conversion") {
auto [d1, d2, d3, d4, d5] =
p.try_next<int, int, double>(fail)
.or_else_object<test_struct, int, double, char>()
.or_object<test_struct, int, double, char>()
.or_else<test_struct>(expect_test_struct)
.or_else<test_tuple>(fail)
.or_else<std::tuple<int, double>>(fail)
@ -450,7 +450,7 @@ TEST_CASE("testing the moving of parsed composite values") {
.or_else<my_string, my_string, my_string, my_string>([](auto&&) {})
.or_else<my_string>([](auto&) {})
.or_else<xyz>([](auto&&) {})
.or_else_object<xyz, my_string, my_string, my_string>([](auto&&) {})
.or_object<xyz, my_string, my_string, my_string>([](auto&&) {})
.or_else<std::tuple<my_string, my_string, my_string>>(
[](auto&, auto&, auto&) {});
}