mirror of
				https://github.com/red0124/ssp.git
				synced 2025-10-31 05:06:46 +01:00 
			
		
		
		
	implement the try_object method, update unit tests, update documentation
This commit is contained in:
		
							parent
							
								
									0487f33eb1
								
							
						
					
					
						commit
						f39e1669f4
					
				
							
								
								
									
										25
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								README.md
									
									
									
									
									
								
							| @ -245,3 +245,28 @@ struct even { | |||||||
| auto [name, age] = p.get_next<std::string, even<int>, void>(); | auto [name, age] = p.get_next<std::string, even<int>, void>(); | ||||||
| ``` | ``` | ||||||
| ## Custom conversions | ## 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<std::string, shape> | ||||||
|  |         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. | ||||||
|  | |||||||
| @ -184,6 +184,19 @@ public: | |||||||
|         return {std::move(value), *this}; |         return {std::move(value), *this}; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |     // identical to try_next but returns composite with object instead of a
 | ||||||
|  |     // tuple
 | ||||||
|  |     template <typename T, typename... Ts, typename Fun = none> | ||||||
|  |     composite<std::optional<T>> try_object(Fun&& fun = none{}) { | ||||||
|  |         std::optional<T> value; | ||||||
|  |         auto new_value = get_object<T, Ts...>(); | ||||||
|  |         if (valid()) { | ||||||
|  |             value = std::move(new_value); | ||||||
|  |             try_invoke(*value, std::forward<Fun>(fun)); | ||||||
|  |         } | ||||||
|  |         return {std::move(value), *this}; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     template <typename...> |     template <typename...> | ||||||
|     friend class composite; |     friend class composite; | ||||||
| @ -327,7 +340,7 @@ private: | |||||||
|     const std::string file_name_; |     const std::string file_name_; | ||||||
|     const std::string delim_; |     const std::string delim_; | ||||||
|     std::string string_error_; |     std::string string_error_; | ||||||
|     bool bool_error_; |     bool bool_error_{false}; | ||||||
|     error_mode error_mode_{error_mode::error_bool}; |     error_mode error_mode_{error_mode::error_bool}; | ||||||
|     converter converter_; |     converter converter_; | ||||||
|     converter::split_input split_input_; |     converter::split_input split_input_; | ||||||
|  | |||||||
| @ -179,8 +179,9 @@ TEST_CASE("testing composite conversion") { | |||||||
|     unique_file_name f; |     unique_file_name f; | ||||||
|     { |     { | ||||||
|         std::ofstream out{f.name}; |         std::ofstream out{f.name}; | ||||||
|         for (auto& i : {"10,a,11.1", "10,20,11.1", "junk", "10,11.1", |         for (auto& i : | ||||||
|                         "1,11.1,a", "junk", "10,junk", "11,junk"}) { |              {"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; |             out << i << std::endl; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -241,9 +242,9 @@ TEST_CASE("testing composite conversion") { | |||||||
|         REQUIRE(!p.eof()); |         REQUIRE(!p.eof()); | ||||||
| 
 | 
 | ||||||
|         auto [d1, d2, d3, d4, d5] = |         auto [d1, d2, d3, d4, d5] = | ||||||
|             p.try_next<int, int, double>(fail) |             p.try_object<test_struct, int, double, char>(fail) | ||||||
|                 .on_error(expect_error) |                 .on_error(expect_error) | ||||||
|                 .or_else_object<test_struct, int, double, char>(fail) |                 .or_else<int, char, char>(fail) | ||||||
|                 .or_else<test_struct>(fail) |                 .or_else<test_struct>(fail) | ||||||
|                 .or_else<test_tuple>(fail) |                 .or_else<test_tuple>(fail) | ||||||
|                 .or_else<int, char, double>(fail) |                 .or_else<int, char, double>(fail) | ||||||
| @ -334,6 +335,20 @@ TEST_CASE("testing composite conversion") { | |||||||
|         REQUIRE(!d2); |         REQUIRE(!d2); | ||||||
|         CHECK(*d1 == std::tuple{11, std::variant<int, std::string>{"junk"}}); |         CHECK(*d1 == std::tuple{11, std::variant<int, std::string>{"junk"}}); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     { | ||||||
|  |         REQUIRE(!p.eof()); | ||||||
|  | 
 | ||||||
|  |         auto [d1, d2] = p.try_object<test_struct, int, double, char>() | ||||||
|  |                             .or_else<int>(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; | size_t move_called = 0; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user