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:
parent
8f97e99feb
commit
bd2783f45c
3 changed files with 273 additions and 2 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';
|
||||||
|
}
|
||||||
|
}
|
63
src/json.hpp
63
src/json.hpp
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
186
test/unit.cpp
186
test/unit.cpp
|
@ -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")
|
||||||
|
|
Loading…
Reference in a new issue