diff --git a/README.md b/README.md index 8eb70a3..bca0895 100644 --- a/README.md +++ b/README.md @@ -395,3 +395,4 @@ p.try_next() .or_object() .on_error([] { /* int and x (all) conversions failed */ }); ``` +*See unit tests for more examples.* diff --git a/include/ss/parser.hpp b/include/ss/parser.hpp index 305a24f..1dd978d 100644 --- a/include/ss/parser.hpp +++ b/include/ss/parser.hpp @@ -134,24 +134,25 @@ public: composite composite_with(T&& new_value) { auto merged_values = std::tuple_cat(std::move(values_), - std::tuple{std::forward(new_value)}); + std::tuple{parser_.valid() + ? std::forward(new_value) + : std::nullopt}); return {std::move(merged_values), parser_}; } template void try_convert_and_invoke(std::optional& value, Fun&& fun) { if (!parser_.valid()) { - std::optional new_value; auto tuple_output = try_same(); + if (!parser_.valid()) { + return; + } if constexpr (!std::is_same_v) { - new_value = to_object(std::move(tuple_output)); + value = to_object(std::move(tuple_output)); } else { - new_value = std::move(tuple_output); - } - if (parser_.valid()) { - value = std::move(new_value); - parser_.try_invoke(*value, std::forward(fun)); + value = std::move(tuple_output); } + parser_.try_invoke(*value, std::forward(fun)); } } @@ -175,26 +176,17 @@ public: template composite>> try_next( Fun&& fun = none{}) { - std::optional> value; - auto new_value = get_next(); - if (valid()) { - value = std::move(new_value); - try_invoke(*value, std::forward(fun)); - } - return {std::move(value), *this}; + using Ret = no_void_validator_tup_t; + return try_invoke_and_make_composite< + std::optional>(get_next(), std::forward(fun)); }; // identical to try_next but returns composite with object instead of a // tuple template composite> try_object(Fun&& fun = none{}) { - std::optional value; - auto new_value = get_object(); - if (valid()) { - value = std::move(new_value); - try_invoke(*value, std::forward(fun)); - } - return {std::move(value), *this}; + return try_invoke_and_make_composite< + std::optional>(get_object(), std::forward(fun)); }; private: @@ -243,6 +235,14 @@ private: } } + template + composite try_invoke_and_make_composite(T&& value, Fun&& fun) { + if (valid()) { + try_invoke(*value, std::forward(fun)); + } + return {valid() ? std::move(value) : std::nullopt, *this}; + } + //////////////// // line reading //////////////// diff --git a/test/test_parser.cpp b/test/test_parser.cpp index 671d7f7..4f87622 100644 --- a/test/test_parser.cpp +++ b/test/test_parser.cpp @@ -181,7 +181,7 @@ TEST_CASE("testing composite conversion") { std::ofstream out{f.name}; for (auto& i : {"10,a,11.1", "10,20,11.1", "junk", "10,11.1", "1,11.1,a", "junk", - "10,junk", "11,junk", "10,11.1,c"}) { + "10,junk", "11,junk", "10,11.1,c", "10,20", "10,22.2,f"}) { out << i << std::endl; } } @@ -348,6 +348,42 @@ TEST_CASE("testing composite conversion") { CHECK(d1->tied() == std::tuple{10, 11.1, 'c'}); } + { + REQUIRE(!p.eof()); + + auto [d1, d2, d3, d4] = + p.try_next([] { return false; }) + .or_else([](auto&) { return false; }) + .or_else() + .or_else(fail) + .values(); + + REQUIRE(p.valid()); + REQUIRE(!d1); + REQUIRE(!d2); + REQUIRE(d3); + REQUIRE(!d4); + CHECK(d3.value() == std::tuple{10, 20}); + } + + { + REQUIRE(!p.eof()); + + auto [d1, d2, d3, d4] = + p.try_object([] { return false; }) + .or_else([](auto&) { return false; }) + .or_object() + .or_else(fail) + .values(); + + REQUIRE(p.valid()); + REQUIRE(!d1); + REQUIRE(!d2); + REQUIRE(d3); + REQUIRE(!d4); + CHECK(d3->tied() == std::tuple{10, 22.2, 'f'}); + } + CHECK(p.eof()); }