diff --git a/README.md b/README.md index e0b80bd..50b4171 100644 --- a/README.md +++ b/README.md @@ -245,3 +245,28 @@ struct even { auto [name, age] = p.get_next, void>(); ``` ## Custom conversions + +Custom types can be used when converting values. An override of the **ss::extract** +function needs to be made and you are good to go. Custom conversion for an enum +would look like this: +```cpp +enum class shape { circle, rectangle, triangle }; + +template <> +inline bool ss::extract(const char* begin, const char* end, shape& dst) { + const static std::unordered_map + shapes{{"circle", shape::circle}, + {"rectangle", shape::rectangle}, + {"triangle", shape::triangle}}; + + if (auto it = shapes.find(std::string(begin, end)); it != shapes.end()) { + dst = it->second; + return true; + } + return false; +} +``` +The shape enum will be in an example below. The **inline** is there just to prevent +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. diff --git a/include/ss/parser.hpp b/include/ss/parser.hpp index e12ad32..2cef130 100644 --- a/include/ss/parser.hpp +++ b/include/ss/parser.hpp @@ -184,6 +184,19 @@ public: return {std::move(value), *this}; }; + // 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}; + }; + private: template friend class composite; @@ -327,7 +340,7 @@ private: const std::string file_name_; const std::string delim_; std::string string_error_; - bool bool_error_; + bool bool_error_{false}; error_mode error_mode_{error_mode::error_bool}; converter converter_; converter::split_input split_input_; diff --git a/test/test_parser.cpp b/test/test_parser.cpp index bb48cb4..f3d81e2 100644 --- a/test/test_parser.cpp +++ b/test/test_parser.cpp @@ -179,8 +179,9 @@ TEST_CASE("testing composite conversion") { unique_file_name f; { 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"}) { + 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"}) { out << i << std::endl; } } @@ -241,9 +242,9 @@ TEST_CASE("testing composite conversion") { REQUIRE(!p.eof()); auto [d1, d2, d3, d4, d5] = - p.try_next(fail) + p.try_object(fail) .on_error(expect_error) - .or_else_object(fail) + .or_else(fail) .or_else(fail) .or_else(fail) .or_else(fail) @@ -334,6 +335,20 @@ TEST_CASE("testing composite conversion") { REQUIRE(!d2); CHECK(*d1 == std::tuple{11, std::variant{"junk"}}); } + + { + REQUIRE(!p.eof()); + + auto [d1, d2] = p.try_object() + .or_else(fail) + .values(); + REQUIRE(p.valid()); + REQUIRE(d1); + REQUIRE(!d2); + CHECK(d1->tied() == std::tuple{10, 11.1, 'c'}); + } + + CHECK(p.eof()); } size_t move_called = 0;