Added get_ref()

Same as get_ptr() but for references.
If the type is incompatible it throws (get_ptr() returns null).
Implemented in terms of get_ptr().
This commit is contained in:
dariomt 2015-10-16 15:23:57 +02:00
parent 8f97e99feb
commit bd2783f45c
3 changed files with 273 additions and 2 deletions

26
doc/examples/get_ref.cpp Normal file
View 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';
}
}

View file

@ -2251,6 +2251,19 @@ class basic_json
return is_number_float() ? &m_value.number_float : nullptr; 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 = std::add_pointer<ReferenceType>::type;
// delegate the call to get_ptr<>()
auto ptr = obj.get_ptr<PointerType>();
if (ptr) return *ptr;
throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " + obj.type_name());
}
public: public:
/// @name value access /// @name value access
@ -2387,10 +2400,56 @@ class basic_json
std::is_pointer<PointerType>::value std::is_pointer<PointerType>::value
and std::is_const< typename std::remove_pointer<PointerType>::type >::value and std::is_const< typename std::remove_pointer<PointerType>::type >::value
, int>::type = 0> , int>::type = 0>
const PointerType get_ptr() const noexcept PointerType get_ptr() const noexcept
{ {
// delegate the call to get_impl_ptr<>() const // delegate the call to get_impl_ptr<>() const
return get_impl_ptr(static_cast<const PointerType>(nullptr)); return get_impl_ptr(static_cast<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);
} }
/*! /*!

View file

@ -2494,6 +2494,22 @@ TEST_CASE("pointer access")
CHECK(value.get_ptr<json::number_float_t*>() == nullptr); 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") SECTION("pointer access to array_t")
{ {
using test_type = json::array_t; using test_type = json::array_t;
@ -2630,6 +2646,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") TEST_CASE("element access")
{ {
SECTION("array") SECTION("array")