Skip to content

Commit

Permalink
worked on #91
Browse files Browse the repository at this point in the history
- implemented `get_ptr` function to return pointer to value member
- overworked `get` function to support pointer types
- added test cases
- added documentation (see
http://nlohmann.github.io/json/classnlohmann_1_1basic__json.html) with
examples
  • Loading branch information
nlohmann committed Jun 24, 2015
1 parent 4575721 commit 40312fb
Show file tree
Hide file tree
Showing 11 changed files with 698 additions and 18 deletions.
20 changes: 20 additions & 0 deletions doc/examples/get__PointerType.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include <json.hpp>

using namespace nlohmann;

int main()
{
// create a JSON boolean
json value = 17;

// explicitly getting pointers
auto p1 = value.get<const json::number_integer_t*>();
auto p2 = value.get<json::number_integer_t*>();
auto p3 = value.get<json::number_integer_t* const>();
auto p4 = value.get<const json::number_integer_t* const>();
auto p5 = value.get<json::number_float_t*>();

// print the pointees
std::cout << *p1 << ' ' << *p2 << ' ' << *p3 << ' ' << *p4 << '\n';
std::cout << std::boolalpha << (p5 == nullptr) << '\n';
}
2 changes: 2 additions & 0 deletions doc/examples/get__PointerType.output
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
17 17 17 17
true
49 changes: 49 additions & 0 deletions doc/examples/get__ValueType_const.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include <json.hpp>
#include <unordered_map>

using namespace nlohmann;

int main()
{
// 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}
};

// use explicit conversions
auto v1 = json_types["boolean"].get<bool>();
auto v2 = json_types["number"]["integer"].get<int>();
auto v3 = json_types["number"]["integer"].get<short>();
auto v4 = json_types["number"]["floating-point"].get<float>();
auto v5 = json_types["number"]["floating-point"].get<int>();
auto v6 = json_types["string"].get<std::string>();
auto v7 = json_types["array"].get<std::vector<short>>();
auto v8 = json_types.get<std::unordered_map<std::string, json>>();

// print the conversion results
std::cout << v1 << '\n';
std::cout << v2 << ' ' << v3 << '\n';
std::cout << v4 << ' ' << v5 << '\n';
std::cout << v6 << '\n';

for (auto i : v7)
{
std::cout << i << ' ';
}
std::cout << "\n\n";

for (auto i : v8)
{
std::cout << i.first << ": " << i.second << '\n';
}
}
11 changes: 11 additions & 0 deletions doc/examples/get__ValueType_const.output
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
1
42 42
17.23 17
Hello, world!
1 2 3 4 5

string: "Hello, world!"
number: {"floating-point":17.23,"integer":42}
null: null
boolean: true
array: [1,2,3,4,5]
20 changes: 20 additions & 0 deletions doc/examples/get_ptr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include <json.hpp>

using namespace nlohmann;

int main()
{
// create a JSON boolean
json value = 17;

// explicitly getting pointers
auto p1 = value.get_ptr<const json::number_integer_t*>();
auto p2 = value.get_ptr<json::number_integer_t*>();
auto p3 = value.get_ptr<json::number_integer_t* const>();
auto p4 = value.get_ptr<const json::number_integer_t* const>();
auto p5 = value.get_ptr<json::number_float_t*>();

// print the pointees
std::cout << *p1 << ' ' << *p2 << ' ' << *p3 << ' ' << *p4 << '\n';
std::cout << std::boolalpha << (p5 == nullptr) << '\n';
}
2 changes: 2 additions & 0 deletions doc/examples/get_ptr.output
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
17 17 17 17
true
49 changes: 49 additions & 0 deletions doc/examples/operator__ValueType.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include <json.hpp>
#include <unordered_map>

using namespace nlohmann;

int main()
{
// 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}
};

// use implicit conversions
bool v1 = json_types["boolean"];
int v2 = json_types["number"]["integer"];
short v3 = json_types["number"]["integer"];
float v4 = json_types["number"]["floating-point"];
int v5 = json_types["number"]["floating-point"];
std::string v6 = json_types["string"];
std::vector<short> v7 = json_types["array"];
std::unordered_map<std::string, json> v8 = json_types;

// print the conversion results
std::cout << v1 << '\n';
std::cout << v2 << ' ' << v3 << '\n';
std::cout << v4 << ' ' << v5 << '\n';
std::cout << v6 << '\n';

for (auto i : v7)
{
std::cout << i << ' ';
}
std::cout << "\n\n";

for (auto i : v8)
{
std::cout << i.first << ": " << i.second << '\n';
}
}
11 changes: 11 additions & 0 deletions doc/examples/operator__ValueType.output
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
1
42 42
17.23 17
Hello, world!
1 2 3 4 5

string: "Hello, world!"
number: {"floating-point":17.23,"integer":42}
null: null
boolean: true
array: [1,2,3,4,5]
186 changes: 177 additions & 9 deletions src/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1787,24 +1787,192 @@ class basic_json
}
}

/// get a pointer to the value (object)
const object_t* get_impl_ptr(object_t*) const noexcept
{
return is_object() ? m_value.object : nullptr;
}

/// get a pointer to the value (array)
const array_t* get_impl_ptr(array_t*) const noexcept
{
return is_array() ? m_value.array : nullptr;
}

/// get a pointer to the value (string)
const string_t* get_impl_ptr(string_t*) const noexcept
{
return is_string() ? m_value.string : nullptr;
}

/// get a pointer to the value (boolean)
const boolean_t* get_impl_ptr(boolean_t*) const noexcept
{
return is_boolean() ? &m_value.boolean : nullptr;
}

/// get a pointer to the value (integer number)
const number_integer_t* get_impl_ptr(number_integer_t*) const noexcept
{
return is_number_integer() ? &m_value.number_integer : nullptr;
}

/// get a pointer to the value (floating-point number)
const number_float_t* get_impl_ptr(number_float_t*) const noexcept
{
return is_number_float() ? &m_value.number_float : nullptr;
}

public:

/// @name value access
/// @{

/// get a value (explicit)
// <http://stackoverflow.com/a/8315197/266378>
template<typename T>
T get() const
/*!
@brief get a value (explicit)
Explicit type conversion between the JSON value and a compatible value.
@tparam ValueType non-pointer type compatible to the JSON value, for
instance `int` for JSON integer numbers, `bool` for JSON booleans, or
`std::vector` types for JSON arrays
@return copy of the JSON value, converted to type @a ValueType
@throw std::domain_error in case passed type @a ValueType is incompatible
to JSON
@complexity Linear in the size of the JSON value.
@liveexample{The example below shows serveral conversions from JSON values
to other types. There a few things to note: (1) Floating-point numbers can
be converted to integers\, (2) A JSON array can be converted to a standard
`std::vector<short>`\, (3) A JSON object can be converted to C++
assiciative containers such as `std::unordered_map<std::string\,
json>`.,get__ValueType_const}
@internal
The idea of using a casted null pointer to choose the correct
implementation is from <http://stackoverflow.com/a/8315197/266378>.
@endinternal
@sa @ref operator ValueType() const for implicit conversion
@sa @ref get() for pointer-member access
*/
template<typename ValueType, typename
std::enable_if<
not std::is_pointer<ValueType>::value
, int>::type = 0>
ValueType get() const
{
return get_impl(static_cast<T*>(nullptr));
return get_impl(static_cast<ValueType*>(nullptr));
}

/// get a value (implicit)
template<typename T>
operator T() const
/*!
@brief get a pointer value (explicit)
Explicit pointer access to the internally stored JSON value. No copies are
made.
@warning Writing data to the pointee of the result yields an undefined
state.
@tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or @ref
number_float_t.
@return pointer to the internally stored JSON value if the requested pointer
type @a PointerType fits to the JSON value; `nullptr` otherwise
@complexity Constant.
@liveexample{The example below shows how pointers to internal values of a
JSON value can be requested. Note that no type conversions are made and a
`nullptr` is returned if the value and the requested pointer type does not
match.,get__PointerType}
@sa @ref get_ptr() for explicit pointer-member access
*/
template<typename PointerType, typename
std::enable_if<
std::is_pointer<PointerType>::value
, int>::type = 0>
PointerType get() const noexcept
{
// delegate the call to get_ptr
return get_ptr<PointerType>();
}

/*!
@brief get a pointer value (implicit)
Implict pointer access to the internally stored JSON value. No copies are
made.
@warning Writing data to the pointee of the result yields an undefined
state.
@tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or @ref
number_float_t.
@return pointer to the internally stored JSON value if the requested pointer
type @a PointerType fits to the JSON value; `nullptr` otherwise
@complexity Constant.
@liveexample{The example below shows how pointers to internal values of a
JSON value can be requested. Note that no type conversions are made and a
`nullptr` is returned if the value and the requested pointer type does not
match.,get_ptr}
*/
template<typename PointerType, typename
std::enable_if<
std::is_pointer<PointerType>::value
, int>::type = 0>
PointerType get_ptr() const noexcept
{
// get_impl_ptr will only work with non-const and non-volatile pointer
// types. Therefore, we case away all cv properties to be able to
// select the correct function. The cv properties will then be added
// again by the const const cast to PointerType.
return const_cast<PointerType>(get_impl_ptr(
static_cast<typename std::add_pointer<typename std::remove_cv<typename std::remove_pointer<PointerType>::type>::type>::type>
(nullptr)));
}

/*!
@brief get a value (implicit)
Implict type conversion between the JSON value and a compatible value. The
call is realized by calling @ref get() const.
@tparam ValueType non-pointer type compatible to the JSON value, for
instance `int` for JSON integer numbers, `bool` for JSON booleans, or
`std::vector` types for JSON arrays
@return copy of the JSON value, converted to type @a ValueType
@throw std::domain_error in case passed type @a ValueType is incompatible
to JSON, thrown by @ref get() const
@complexity Linear in the size of the JSON value.
@liveexample{The example below shows serveral conversions from JSON values
to other types. There a few things to note: (1) Floating-point numbers can
be converted to integers\, (2) A JSON array can be converted to a standard
`std::vector<short>`\, (3) A JSON object can be converted to C++
assiciative containers such as `std::unordered_map<std::string\,
json>`.,operator__ValueType}
*/
template<typename ValueType, typename
std::enable_if<
not std::is_pointer<ValueType>::value
, int>::type = 0>
operator ValueType() const
{
return get<T>();
// delegate the call to get<>() const
return get<ValueType>();
}

/// @}
Expand Down
Loading

0 comments on commit 40312fb

Please sign in to comment.