From 60c8156fb77dda14c66ebfeb1fa874b8678ef4be Mon Sep 17 00:00:00 2001 From: ado Date: Sat, 2 Jan 2021 02:31:45 +0100 Subject: [PATCH] replace or_else_object with or_object inside the parser, update documentation --- README.md | 66 +++++++++++++++++++++++++++++++++++++++++++ include/ss/parser.hpp | 4 +-- test/test_parser.cpp | 6 ++-- 3 files changed, 71 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 50b4171..dd53c5f 100644 --- a/README.md +++ b/README.md @@ -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> 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(insert_circle) + .or_else(insert_rectangle) + .or_else(insert_triangle) + .on_error([](const std::string& error) { + std::cout << error << std::endl; + }); +} + +// do something with the stored data ... +``` diff --git a/include/ss/parser.hpp b/include/ss/parser.hpp index 2cef130..305a24f 100644 --- a/include/ss/parser.hpp +++ b/include/ss/parser.hpp @@ -107,7 +107,7 @@ public: // same as or_else, but saves the result into a 'U' object // instead of a tuple template - composite> or_else_object(Fun&& fun = none{}) { + composite> or_object(Fun&& fun = none{}) { std::optional value; try_convert_and_invoke(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; } diff --git a/test/test_parser.cpp b/test/test_parser.cpp index f3d81e2..671d7f7 100644 --- a/test/test_parser.cpp +++ b/test/test_parser.cpp @@ -223,7 +223,7 @@ TEST_CASE("testing composite conversion") { CHECK(std::tie(i1, i2, d) == expectedData); }) .on_error(fail) - .or_else_object(fail) + .or_object(fail) .on_error(fail) .or_else(fail) .on_error(fail) @@ -291,7 +291,7 @@ TEST_CASE("testing composite conversion") { auto [d1, d2, d3, d4, d5] = p.try_next(fail) - .or_else_object() + .or_object() .or_else(expect_test_struct) .or_else(fail) .or_else>(fail) @@ -450,7 +450,7 @@ TEST_CASE("testing the moving of parsed composite values") { .or_else([](auto&&) {}) .or_else([](auto&) {}) .or_else([](auto&&) {}) - .or_else_object([](auto&&) {}) + .or_object([](auto&&) {}) .or_else>( [](auto&, auto&, auto&) {}); }