Skip to content

Commit

Permalink
Allow to add a custom base class as an extension point to json nodes
Browse files Browse the repository at this point in the history
* by default an empty class is used and the library behaves as it already did
* if a user explicitly adds a base class (last template parameter) each node inherits it
* this can be used to add custom extensions (e.g. add metadata / visitor methods)
* add test for this feature
  • Loading branch information
barcode committed Oct 30, 2021
1 parent fec56a1 commit f3671da
Show file tree
Hide file tree
Showing 6 changed files with 410 additions and 13 deletions.
20 changes: 20 additions & 0 deletions include/nlohmann/detail/json_custom_base_class.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once

#include <type_traits>

namespace nlohmann
{
namespace detail
{

struct json_default_base {};

template<class T>
using json_base_class = typename std::conditional<
std::is_same<T, void>::value,
json_default_base,
T
>::type;

} // namespace detail
} // namespace nlohmann
5 changes: 3 additions & 2 deletions include/nlohmann/detail/macro_scope.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,13 @@
class NumberUnsignedType, class NumberFloatType, \
template<typename> class AllocatorType, \
template<typename, typename = void> class JSONSerializer, \
class BinaryType>
class BinaryType, \
class CustomBaseClass>

#define NLOHMANN_BASIC_JSON_TPL \
basic_json<ObjectType, ArrayType, StringType, BooleanType, \
NumberIntegerType, NumberUnsignedType, NumberFloatType, \
AllocatorType, JSONSerializer, BinaryType>
AllocatorType, JSONSerializer, BinaryType, CustomBaseClass>

// Macros to simplify conversion from/to types

Expand Down
13 changes: 10 additions & 3 deletions include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ SOFTWARE.
#include <nlohmann/detail/iterators/iteration_proxy.hpp>
#include <nlohmann/detail/iterators/json_reverse_iterator.hpp>
#include <nlohmann/detail/iterators/primitive_iterator.hpp>
#include <nlohmann/detail/json_custom_base_class.hpp>
#include <nlohmann/detail/json_pointer.hpp>
#include <nlohmann/detail/json_ref.hpp>
#include <nlohmann/detail/macro_scope.hpp>
Expand Down Expand Up @@ -174,6 +175,7 @@ Format](https://tools.ietf.org/html/rfc8259)
*/
NLOHMANN_BASIC_JSON_TPL_DECLARATION
class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
: public ::nlohmann::detail::json_base_class<CustomBaseClass>
{
private:
template<detail::value_t> friend struct detail::external_constructor;
Expand All @@ -196,6 +198,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec

/// workaround type for MSVC
using basic_json_t = NLOHMANN_BASIC_JSON_TPL;
using json_base_class_t = ::nlohmann::detail::json_base_class<CustomBaseClass>;

JSON_PRIVATE_UNLESS_TESTED:
// convenience aliases for types residing in namespace detail;
Expand Down Expand Up @@ -2188,7 +2191,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
@since version 1.0.0
*/
basic_json(const basic_json& other)
: m_type(other.m_type)
: json_base_class_t(other),
m_type(other.m_type)
{
// check of passed value is valid
other.assert_invariant();
Expand Down Expand Up @@ -2280,7 +2284,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
@since version 1.0.0
*/
basic_json(basic_json&& other) noexcept
: m_type(std::move(other.m_type)),
: json_base_class_t(std::move(other)),
m_type(std::move(other.m_type)),
m_value(std::move(other.m_value))
{
// check that passed value is valid
Expand Down Expand Up @@ -2321,7 +2326,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
std::is_nothrow_move_constructible<value_t>::value&&
std::is_nothrow_move_assignable<value_t>::value&&
std::is_nothrow_move_constructible<json_value>::value&&
std::is_nothrow_move_assignable<json_value>::value
std::is_nothrow_move_assignable<json_value>::value&&
std::is_nothrow_move_assignable<json_base_class_t>::value
)
{
// check that passed value is valid
Expand All @@ -2330,6 +2336,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
using std::swap;
swap(m_type, other.m_type);
swap(m_value, other.m_value);
json_base_class_t::operator=(std::move(other));

set_parents();
assert_invariant();
Expand Down
3 changes: 2 additions & 1 deletion include/nlohmann/json_fwd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ template<template<typename U, typename V, typename... Args> class ObjectType =
template<typename U> class AllocatorType = std::allocator,
template<typename T, typename SFINAE = void> class JSONSerializer =
adl_serializer,
class BinaryType = std::vector<std::uint8_t>>
class BinaryType = std::vector<std::uint8_t>,
class CustomBaseClass = void>
class basic_json;

/*!
Expand Down
44 changes: 37 additions & 7 deletions single_include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2420,12 +2420,13 @@ using is_detected_convertible =
class NumberUnsignedType, class NumberFloatType, \
template<typename> class AllocatorType, \
template<typename, typename = void> class JSONSerializer, \
class BinaryType>
class BinaryType, \
class CustomBaseClass>

#define NLOHMANN_BASIC_JSON_TPL \
basic_json<ObjectType, ArrayType, StringType, BooleanType, \
NumberIntegerType, NumberUnsignedType, NumberFloatType, \
AllocatorType, JSONSerializer, BinaryType>
AllocatorType, JSONSerializer, BinaryType, CustomBaseClass>

// Macros to simplify conversion from/to types

Expand Down Expand Up @@ -3444,7 +3445,8 @@ template<template<typename U, typename V, typename... Args> class ObjectType =
template<typename U> class AllocatorType = std::allocator,
template<typename T, typename SFINAE = void> class JSONSerializer =
adl_serializer,
class BinaryType = std::vector<std::uint8_t>>
class BinaryType = std::vector<std::uint8_t>,
class CustomBaseClass = void>
class basic_json;

/*!
Expand Down Expand Up @@ -12448,6 +12450,28 @@ class json_reverse_iterator : public std::reverse_iterator<Base>

// #include <nlohmann/detail/iterators/primitive_iterator.hpp>

// #include <nlohmann/detail/json_custom_base_class.hpp>


#include <type_traits>

namespace nlohmann
{
namespace detail
{

struct json_default_base {};

template<class T>
using json_base_class = typename std::conditional<
std::is_same<T, void>::value,
json_default_base,
T
>::type;

} // namespace detail
} // namespace nlohmann

// #include <nlohmann/detail/json_pointer.hpp>


Expand Down Expand Up @@ -17675,6 +17699,7 @@ Format](https://tools.ietf.org/html/rfc8259)
*/
NLOHMANN_BASIC_JSON_TPL_DECLARATION
class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
: public ::nlohmann::detail::json_base_class<CustomBaseClass>
{
private:
template<detail::value_t> friend struct detail::external_constructor;
Expand All @@ -17697,6 +17722,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec

/// workaround type for MSVC
using basic_json_t = NLOHMANN_BASIC_JSON_TPL;
using json_base_class_t = ::nlohmann::detail::json_base_class<CustomBaseClass>;

JSON_PRIVATE_UNLESS_TESTED:
// convenience aliases for types residing in namespace detail;
Expand All @@ -17708,7 +17734,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
detail::parser_callback_t<basic_json>cb = nullptr,
const bool allow_exceptions = true,
const bool ignore_comments = false
)
)
{
return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter),
std::move(cb), allow_exceptions, ignore_comments);
Expand Down Expand Up @@ -19689,7 +19715,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
@since version 1.0.0
*/
basic_json(const basic_json& other)
: m_type(other.m_type)
: json_base_class_t(other),
m_type(other.m_type)
{
// check of passed value is valid
other.assert_invariant();
Expand Down Expand Up @@ -19781,7 +19808,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
@since version 1.0.0
*/
basic_json(basic_json&& other) noexcept
: m_type(std::move(other.m_type)),
: json_base_class_t(std::move(other)),
m_type(std::move(other.m_type)),
m_value(std::move(other.m_value))
{
// check that passed value is valid
Expand Down Expand Up @@ -19822,7 +19850,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
std::is_nothrow_move_constructible<value_t>::value&&
std::is_nothrow_move_assignable<value_t>::value&&
std::is_nothrow_move_constructible<json_value>::value&&
std::is_nothrow_move_assignable<json_value>::value
std::is_nothrow_move_assignable<json_value>::value&&
std::is_nothrow_move_assignable<json_base_class_t>::value
)
{
// check that passed value is valid
Expand All @@ -19831,6 +19860,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
using std::swap;
swap(m_type, other.m_type);
swap(m_value, other.m_value);
json_base_class_t::operator=(std::move(other));

set_parents();
assert_invariant();
Expand Down
Loading

0 comments on commit f3671da

Please sign in to comment.