Merge pull request #184 from dariomt/master
Implementation of get_ref()
This commit is contained in:
		
						commit
						663ad13fc3
					
				
					 4 changed files with 330 additions and 0 deletions
				
			
		
							
								
								
									
										26
									
								
								doc/examples/get_ref.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								doc/examples/get_ref.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | |||
| #include <json.hpp> | ||||
| 
 | ||||
| using namespace nlohmann; | ||||
| 
 | ||||
| int main() | ||||
| { | ||||
|     // create a JSON number
 | ||||
|     json value = 17; | ||||
| 
 | ||||
|     // explicitly getting references
 | ||||
|     auto r1 = value.get_ref<const json::number_integer_t&>(); | ||||
|     auto r2 = value.get_ref<json::number_integer_t&>(); | ||||
| 
 | ||||
|     // print the values
 | ||||
|     std::cout << r1 << ' ' << r2 << '\n'; | ||||
|      | ||||
|     // incompatible type throws exception
 | ||||
|     try | ||||
|     { | ||||
|         auto r3 = value.get_ref<json::number_float_t&>(); | ||||
|     } | ||||
|     catch(std::domain_error& ex) | ||||
|     { | ||||
|         std::cout << ex.what() << '\n'; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										59
									
								
								src/json.hpp
									
										
									
									
									
								
							
							
						
						
									
										59
									
								
								src/json.hpp
									
										
									
									
									
								
							|  | @ -2416,6 +2416,19 @@ class basic_json | |||
|         return is_number_float() ? &m_value.number_float : nullptr; | ||||
|     } | ||||
| 
 | ||||
| 	/// helper function to implement get_ref without code duplication 
 | ||||
| 	/// for const and non-const overloads
 | ||||
| 	/// ThisType will be deduced as 'basic_jason' or 'const basic_json'
 | ||||
| 	template<typename ReferenceType, typename ThisType> | ||||
|     static ReferenceType get_ref_impl(ThisType& obj) | ||||
|     { | ||||
| 		using PointerType = typename std::add_pointer<ReferenceType>::type; | ||||
|         // delegate the call to get_ptr<>()
 | ||||
|         auto ptr = obj.template get_ptr<PointerType>(); | ||||
| 		if (ptr) return *ptr; | ||||
| 		throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " + obj.type_name()); | ||||
|     } | ||||
| 
 | ||||
|   public: | ||||
| 
 | ||||
|     /// @name value access
 | ||||
|  | @ -2563,6 +2576,52 @@ class basic_json | |||
|         return get_impl_ptr(static_cast<const PointerType>(nullptr)); | ||||
|     } | ||||
| 
 | ||||
| 	/*!
 | ||||
|     @brief get a reference value (implicit) | ||||
| 
 | ||||
|     Implict reference access to the internally stored JSON value. No copies are | ||||
|     made. | ||||
| 
 | ||||
|     @warning Writing data to the referee of the result yields an undefined | ||||
|     state. | ||||
| 
 | ||||
|     @tparam ReferenceType reference type; must be a reference to @ref array_t, @ref | ||||
|     object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or @ref | ||||
|     number_float_t. | ||||
| 
 | ||||
|     @return reference to the internally stored JSON value if the requested reference | ||||
|     type @a ReferenceType fits to the JSON value; throws std::domain_error otherwise | ||||
| 
 | ||||
| 	@throw std::domain_error in case passed type @a ReferenceType is incompatible | ||||
|     with the stored JSON value | ||||
| 
 | ||||
|     @complexity Constant. | ||||
|     */ | ||||
|     template<typename ReferenceType, typename | ||||
|              std::enable_if< | ||||
|                  std::is_reference<ReferenceType>::value | ||||
|                  , int>::type = 0> | ||||
|     ReferenceType get_ref() | ||||
|     { | ||||
| 		// delegate call to get_ref_impl
 | ||||
| 		return get_ref_impl<ReferenceType>(*this); | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief get a reference value (implicit) | ||||
|     @copydoc get_ref() | ||||
|     */ | ||||
|     template<typename ReferenceType, typename | ||||
|              std::enable_if< | ||||
|                  std::is_reference<ReferenceType>::value | ||||
|                  and std::is_const< typename std::remove_reference<ReferenceType>::type >::value | ||||
|                  , int>::type = 0> | ||||
|     ReferenceType get_ref() const | ||||
|     { | ||||
| 		// delegate call to get_ref_impl
 | ||||
| 		return get_ref_impl<ReferenceType>(*this); | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief get a value (implicit) | ||||
| 
 | ||||
|  |  | |||
|  | @ -2416,6 +2416,19 @@ class basic_json | |||
|         return is_number_float() ? &m_value.number_float : nullptr; | ||||
|     } | ||||
| 
 | ||||
| 	/// helper function to implement get_ref without code duplication  | ||||
| 	/// for const and non-const overloads | ||||
| 	/// ThisType will be deduced as 'basic_jason' or 'const basic_json' | ||||
| 	template<typename ReferenceType, typename ThisType> | ||||
|     static ReferenceType get_ref_impl(ThisType& obj) | ||||
|     { | ||||
| 		using PointerType = typename std::add_pointer<ReferenceType>::type; | ||||
|         // delegate the call to get_ptr<>() | ||||
|         auto ptr = obj.template get_ptr<PointerType>(); | ||||
| 		if (ptr) return *ptr; | ||||
| 		throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " + obj.type_name()); | ||||
|     } | ||||
| 
 | ||||
|   public: | ||||
| 
 | ||||
|     /// @name value access | ||||
|  | @ -2563,6 +2576,52 @@ class basic_json | |||
|         return get_impl_ptr(static_cast<const PointerType>(nullptr)); | ||||
|     } | ||||
| 
 | ||||
| 	/*! | ||||
|     @brief get a reference value (implicit) | ||||
| 
 | ||||
|     Implict reference access to the internally stored JSON value. No copies are | ||||
|     made. | ||||
| 
 | ||||
|     @warning Writing data to the referee of the result yields an undefined | ||||
|     state. | ||||
| 
 | ||||
|     @tparam ReferenceType reference type; must be a reference to @ref array_t, @ref | ||||
|     object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or @ref | ||||
|     number_float_t. | ||||
| 
 | ||||
|     @return reference to the internally stored JSON value if the requested reference | ||||
|     type @a ReferenceType fits to the JSON value; throws std::domain_error otherwise | ||||
| 
 | ||||
| 	@throw std::domain_error in case passed type @a ReferenceType is incompatible | ||||
|     with the stored JSON value | ||||
| 
 | ||||
|     @complexity Constant. | ||||
|     */ | ||||
|     template<typename ReferenceType, typename | ||||
|              std::enable_if< | ||||
|                  std::is_reference<ReferenceType>::value | ||||
|                  , int>::type = 0> | ||||
|     ReferenceType get_ref() | ||||
|     { | ||||
| 		// delegate call to get_ref_impl | ||||
| 		return get_ref_impl<ReferenceType>(*this); | ||||
|     } | ||||
| 
 | ||||
|     /*! | ||||
|     @brief get a reference value (implicit) | ||||
|     @copydoc get_ref() | ||||
|     */ | ||||
|     template<typename ReferenceType, typename | ||||
|              std::enable_if< | ||||
|                  std::is_reference<ReferenceType>::value | ||||
|                  and std::is_const< typename std::remove_reference<ReferenceType>::type >::value | ||||
|                  , int>::type = 0> | ||||
|     ReferenceType get_ref() const | ||||
|     { | ||||
| 		// delegate call to get_ref_impl | ||||
| 		return get_ref_impl<ReferenceType>(*this); | ||||
|     } | ||||
| 
 | ||||
|     /*! | ||||
|     @brief get a value (implicit) | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										186
									
								
								test/unit.cpp
									
										
									
									
									
								
							
							
						
						
									
										186
									
								
								test/unit.cpp
									
										
									
									
									
								
							|  | @ -2604,6 +2604,22 @@ TEST_CASE("pointer access") | |||
|         CHECK(value.get_ptr<json::number_float_t*>() == nullptr); | ||||
|     } | ||||
| 
 | ||||
| 	SECTION("pointer access to const object_t") | ||||
|     { | ||||
|         using test_type = json::object_t; | ||||
|         const json value = {{"one", 1}, {"two", 2}}; | ||||
| 
 | ||||
| 		// this should not compile
 | ||||
| 		// test_type* p1 = value.get_ptr<test_type*>();
 | ||||
| 
 | ||||
|         // check if pointers are returned correctly
 | ||||
|         const test_type* p2 = value.get_ptr<const test_type*>(); | ||||
|         CHECK(*p2 == value.get<test_type>()); | ||||
| 
 | ||||
|         const test_type* const p3 = value.get_ptr<const test_type* const>(); | ||||
|         CHECK(p2 == p3); | ||||
|     } | ||||
| 
 | ||||
|     SECTION("pointer access to array_t") | ||||
|     { | ||||
|         using test_type = json::array_t; | ||||
|  | @ -2740,6 +2756,176 @@ TEST_CASE("pointer access") | |||
|     } | ||||
| } | ||||
| 
 | ||||
| TEST_CASE("reference access") | ||||
| { | ||||
|     // create a JSON value with different types
 | ||||
|     json json_types = | ||||
|     { | ||||
|         {"boolean", true}, | ||||
|         { | ||||
|             "number", { | ||||
|                 {"integer", 42}, | ||||
|                 {"floating-point", 17.23} | ||||
|             } | ||||
|         }, | ||||
|         {"string", "Hello, world!"}, | ||||
|         {"array", {1, 2, 3, 4, 5}}, | ||||
|         {"null", nullptr} | ||||
|     }; | ||||
| 
 | ||||
|     SECTION("reference access to object_t") | ||||
|     { | ||||
|         using test_type = json::object_t; | ||||
|         json value = {{"one", 1}, {"two", 2}}; | ||||
| 
 | ||||
|         // check if references are returned correctly
 | ||||
|         test_type& p1 = value.get_ref<test_type&>(); | ||||
|         CHECK(&p1 == value.get_ptr<test_type*>()); | ||||
| 		CHECK(p1 == value.get<test_type>()); | ||||
| 
 | ||||
|         const test_type& p2 = value.get_ref<const test_type&>(); | ||||
|         CHECK(&p2 == value.get_ptr<const test_type*>()); | ||||
|         CHECK(p2 == value.get<test_type>()); | ||||
| 
 | ||||
|         // check if mismatching references throw correctly
 | ||||
| 		CHECK_NOTHROW(value.get_ref<json::object_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::array_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::string_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::boolean_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::number_integer_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::number_float_t&>()); | ||||
|     } | ||||
| 
 | ||||
| 	SECTION("const reference access to const object_t") | ||||
|     { | ||||
|         using test_type = json::object_t; | ||||
|         const json value = {{"one", 1}, {"two", 2}}; | ||||
| 
 | ||||
| 		// this should not compile
 | ||||
| 		// test_type& p1 = value.get_ref<test_type&>();
 | ||||
| 
 | ||||
|         // check if references are returned correctly
 | ||||
|         const test_type& p2 = value.get_ref<const test_type&>(); | ||||
|         CHECK(&p2 == value.get_ptr<const test_type*>()); | ||||
|         CHECK(p2 == value.get<test_type>()); | ||||
|     } | ||||
| 
 | ||||
|     SECTION("reference access to array_t") | ||||
|     { | ||||
|         using test_type = json::array_t; | ||||
|         json value = {1, 2, 3, 4}; | ||||
| 
 | ||||
|         // check if references are returned correctly
 | ||||
|         test_type& p1 = value.get_ref<test_type&>(); | ||||
|         CHECK(&p1 == value.get_ptr<test_type*>()); | ||||
| 		CHECK(p1 == value.get<test_type>()); | ||||
| 
 | ||||
|         const test_type& p2 = value.get_ref<const test_type&>(); | ||||
|         CHECK(&p2 == value.get_ptr<const test_type*>()); | ||||
|         CHECK(p2 == value.get<test_type>()); | ||||
| 
 | ||||
|         // check if mismatching references throw correctly
 | ||||
|         CHECK_THROWS(value.get_ref<json::object_t&>()); | ||||
|         CHECK_NOTHROW(value.get_ref<json::array_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::string_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::boolean_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::number_integer_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::number_float_t&>()); | ||||
|     } | ||||
| 
 | ||||
|     SECTION("reference access to string_t") | ||||
|     { | ||||
|         using test_type = json::string_t; | ||||
|         json value = "hello"; | ||||
| 
 | ||||
|         // check if references are returned correctly
 | ||||
|         test_type& p1 = value.get_ref<test_type&>(); | ||||
|         CHECK(&p1 == value.get_ptr<test_type*>()); | ||||
| 		CHECK(p1 == value.get<test_type>()); | ||||
| 
 | ||||
|         const test_type& p2 = value.get_ref<const test_type&>(); | ||||
|         CHECK(&p2 == value.get_ptr<const test_type*>()); | ||||
|         CHECK(p2 == value.get<test_type>()); | ||||
| 
 | ||||
|         // check if mismatching references throw correctly
 | ||||
|         CHECK_THROWS(value.get_ref<json::object_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::array_t&>()); | ||||
|         CHECK_NOTHROW(value.get_ref<json::string_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::boolean_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::number_integer_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::number_float_t&>()); | ||||
|     } | ||||
| 
 | ||||
|     SECTION("reference access to boolean_t") | ||||
|     { | ||||
|         using test_type = json::boolean_t; | ||||
|         json value = false; | ||||
| 
 | ||||
|         // check if references are returned correctly
 | ||||
|         test_type& p1 = value.get_ref<test_type&>(); | ||||
|         CHECK(&p1 == value.get_ptr<test_type*>()); | ||||
| 		CHECK(p1 == value.get<test_type>()); | ||||
| 
 | ||||
|         const test_type& p2 = value.get_ref<const test_type&>(); | ||||
|         CHECK(&p2 == value.get_ptr<const test_type*>()); | ||||
|         CHECK(p2 == value.get<test_type>()); | ||||
| 
 | ||||
|         // check if mismatching references throw correctly
 | ||||
|         CHECK_THROWS(value.get_ref<json::object_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::array_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::string_t&>()); | ||||
|         CHECK_NOTHROW(value.get_ref<json::boolean_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::number_integer_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::number_float_t&>()); | ||||
|     } | ||||
| 
 | ||||
|     SECTION("reference access to number_integer_t") | ||||
|     { | ||||
|         using test_type = json::number_integer_t; | ||||
|         json value = 23; | ||||
| 
 | ||||
| 		// check if references are returned correctly
 | ||||
|         test_type& p1 = value.get_ref<test_type&>(); | ||||
|         CHECK(&p1 == value.get_ptr<test_type*>()); | ||||
| 		CHECK(p1 == value.get<test_type>()); | ||||
| 
 | ||||
|         const test_type& p2 = value.get_ref<const test_type&>(); | ||||
|         CHECK(&p2 == value.get_ptr<const test_type*>()); | ||||
|         CHECK(p2 == value.get<test_type>()); | ||||
| 
 | ||||
|         // check if mismatching references throw correctly
 | ||||
|         CHECK_THROWS(value.get_ref<json::object_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::array_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::string_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::boolean_t&>()); | ||||
|         CHECK_NOTHROW(value.get_ref<json::number_integer_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::number_float_t&>()); | ||||
|     } | ||||
| 
 | ||||
|     SECTION("reference access to number_float_t") | ||||
|     { | ||||
|         using test_type = json::number_float_t; | ||||
|         json value = 42.23; | ||||
| 
 | ||||
| 		// check if references are returned correctly
 | ||||
|         test_type& p1 = value.get_ref<test_type&>(); | ||||
|         CHECK(&p1 == value.get_ptr<test_type*>()); | ||||
| 		CHECK(p1 == value.get<test_type>()); | ||||
| 
 | ||||
|         const test_type& p2 = value.get_ref<const test_type&>(); | ||||
|         CHECK(&p2 == value.get_ptr<const test_type*>()); | ||||
|         CHECK(p2 == value.get<test_type>()); | ||||
| 
 | ||||
|         // check if mismatching references throw correctly
 | ||||
|         CHECK_THROWS(value.get_ref<json::object_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::array_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::string_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::boolean_t&>()); | ||||
|         CHECK_THROWS(value.get_ref<json::number_integer_t&>()); | ||||
|         CHECK_NOTHROW(value.get_ref<json::number_float_t&>()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| TEST_CASE("element access") | ||||
| { | ||||
|     SECTION("array") | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue