Skip to content

Commit

Permalink
Added example using base/child classes. Fixed issue with nullable types
Browse files Browse the repository at this point in the history
Added example using base/child classes. Fixed issue with nullable types
that could not be copied/moved but the wrapper accepts
pointers(unique/shared ptr/T *)
  • Loading branch information
beached committed Jan 8, 2023
1 parent a053672 commit 8ff8543
Show file tree
Hide file tree
Showing 7 changed files with 212 additions and 9 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
cmake_minimum_required( VERSION 3.14 )

project( "daw-json-link"
VERSION "3.13.0"
VERSION "3.14.0"
DESCRIPTION "Static JSON parsing in C++"
HOMEPAGE_URL "https://github.com/beached/daw_json_link"
LANGUAGES C CXX )
Expand Down
18 changes: 18 additions & 0 deletions include/daw/json/concepts/daw_nullable_value.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,12 @@ namespace daw::json {
#endif
}

constexpr nullable_type DAW_JSON_CPP23_STATIC_CALL_OP operator( )(
construct_nullable_with_pointer_t,
value_type *ptr ) DAW_JSON_CPP23_STATIC_CALL_OP_CONST noexcept {
return nullable_type( ptr );
}

constexpr nullable_type DAW_JSON_CPP23_STATIC_CALL_OP
operator( )( construct_nullable_with_empty_t )
DAW_JSON_CPP23_STATIC_CALL_OP_CONST noexcept {
Expand Down Expand Up @@ -187,6 +193,12 @@ namespace daw::json {
#endif
}

constexpr nullable_type DAW_JSON_CPP23_STATIC_CALL_OP operator( )(
construct_nullable_with_pointer_t,
value_type *ptr ) DAW_JSON_CPP23_STATIC_CALL_OP_CONST noexcept {
return nullable_type( ptr );
}

constexpr nullable_type DAW_JSON_CPP23_STATIC_CALL_OP
operator( )( construct_nullable_with_empty_t )
DAW_JSON_CPP23_STATIC_CALL_OP_CONST noexcept {
Expand Down Expand Up @@ -236,6 +248,12 @@ namespace daw::json {
#endif
}

constexpr nullable_type DAW_JSON_CPP23_STATIC_CALL_OP operator( )(
construct_nullable_with_pointer_t,
value_type *ptr ) DAW_JSON_CPP23_STATIC_CALL_OP_CONST noexcept {
return ptr;
}

DAW_JSON_CPP23_STATIC_CALL_OP constexpr nullable_type
operator( )( construct_nullable_with_empty_t )
DAW_JSON_CPP23_STATIC_CALL_OP_CONST noexcept {
Expand Down
21 changes: 18 additions & 3 deletions include/daw/json/concepts/daw_nullable_value_fwd.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,21 @@ namespace daw::json {

} // namespace nullable_impl

struct construct_nullable_with_value_t {};

struct construct_nullable_with_value_t {
explicit construct_nullable_with_value_t( ) = default;
};
inline constexpr auto construct_nullable_with_value =
construct_nullable_with_value_t{ };

struct construct_nullable_with_empty_t {};
struct construct_nullable_with_pointer_t {
explicit construct_nullable_with_pointer_t( ) = default;
};
inline constexpr auto construct_nullable_with_pointer =
construct_nullable_with_pointer_t{ };

struct construct_nullable_with_empty_t {
explicit construct_nullable_with_empty_t( ) = default;
};
inline constexpr auto construct_nullable_with_empty =
construct_nullable_with_empty_t{ };

Expand Down Expand Up @@ -122,6 +131,12 @@ namespace daw::json {
std::is_invocable_v<nullable_value_traits<T>,
construct_nullable_with_value_t, Args...>;

template<typename T, typename... Args>
inline constexpr bool is_nullable_pointer_constructible_v =
is_nullable_value_v<T> and
std::is_invocable_v<nullable_value_traits<T>,
construct_nullable_with_pointer_t, Args...>;

template<typename T, typename... Args>
inline constexpr bool is_nullable_value_nothrow_constructible_v =
is_nullable_value_constructible_v<T, Args...> and
Expand Down
13 changes: 13 additions & 0 deletions include/daw/json/impl/daw_json_default_constuctor.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,19 @@ namespace daw::json {
return rtraits_t{ }( concepts::construct_nullable_with_value,
DAW_FWD( args )... );
}

template<typename Pointer,
std::enable_if_t<
concepts::is_nullable_pointer_constructible_v<T, Pointer *>,
std::nullptr_t> = nullptr>
[[nodiscard]] DAW_ATTRIB_INLINE
DAW_JSON_CPP23_STATIC_CALL_OP constexpr auto
operator( )( concepts::construct_nullable_with_pointer_t,
Pointer *ptr ) DAW_JSON_CPP23_STATIC_CALL_OP_CONST
noexcept(
concepts::is_nullable_value_nothrow_constructible_v<T, Pointer> ) {
return rtraits_t{ }( concepts::construct_nullable_with_pointer, ptr );
}
};
} // namespace DAW_JSON_VER
} // namespace daw::json
24 changes: 19 additions & 5 deletions include/daw/json/impl/daw_json_parse_value.h
Original file line number Diff line number Diff line change
Expand Up @@ -349,10 +349,24 @@ namespace daw::json {
parse_state.trim_left_checked( );
return construct_empty( );
}
return construct_value(
template_args<base_member_type, constructor_t>, parse_state,
parse_value<base_member_type>(
parse_state, ParseTag<base_member_type::expected_type>{ } ) );
using parse_to_t = typename base_member_type::parse_to_t;
if constexpr( not std::is_move_constructible_v<parse_to_t> and
not std::is_copy_constructible_v<parse_to_t> ) {
static_assert(
std::is_invocable_v<
concepts::nullable_value_traits<json_result<JsonMember>>,
concepts::construct_nullable_with_pointer_t, parse_to_t *> );
return construct_value(
template_args<base_member_type, constructor_t>, parse_state,
concepts::construct_nullable_with_pointer,
new parse_to_t{ parse_value<base_member_type>(
parse_state, ParseTag<base_member_type::expected_type>{ } ) } );
} else {
return construct_value(
template_args<base_member_type, constructor_t>, parse_state,
parse_value<base_member_type>(
parse_state, ParseTag<base_member_type::expected_type>{ } ) );
}
}
}

Expand Down Expand Up @@ -752,7 +766,7 @@ namespace daw::json {
return parse_value<JsonMember, KnownBounds>(
parse_state, ParseTag<JsonMember::expected_type>{ } );
} else {
daw_json_error( ErrorReason::UnexpectedJSONVariantType );
daw_json_error( ErrorReason::UnexpectedJSONVariantType );
}
}

Expand Down
6 changes: 6 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,12 @@ add_test( NAME carray_test_test COMMAND carray_test )
add_dependencies( ci_tests carray_test )
add_dependencies( full carray_test )

add_executable( base_child_class_test src/base_child_class_test.cpp )
target_link_libraries( base_child_class_test json_test )
add_test( NAME base_child_class_test_test COMMAND base_child_class_test )
add_dependencies( ci_tests base_child_class_test )
add_dependencies( full base_child_class_test )

add_executable( json_bench_viewer src/json_bench_viewer.cpp )
target_link_libraries( json_bench_viewer json_test )

Expand Down
137 changes: 137 additions & 0 deletions tests/src/base_child_class_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// Copyright (c) Darrell Wright
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/beached/daw_json_link
//

#include <daw/json/daw_json_link.h>

#include <cassert>
#include <memory>
#include <string_view>

struct Base {
explicit Base( ) = default;
virtual ~Base( ) = default;
Base( Base const & ) = delete;
Base( Base && ) = delete;
Base &operator=( Base const & ) = delete;
Base &operator=( Base && ) = delete;

[[nodiscard]] virtual int type( ) const = 0;
[[nodiscard]] virtual int value( ) const = 0;
};

struct Child0 : Base {
int v;

explicit Child0( int V ) noexcept
: v( V ) {}

[[nodiscard]] int type( ) const override {
return 0;
}

[[nodiscard]] int value( ) const override {
return v;
}
};

namespace daw::json {
template<>
struct json_data_contract<Child0> {
static constexpr char const v[] = "v";
using type = json_member_list<json_number<v, int>>;

static constexpr auto to_json_data( Child0 const &c0 ) {
return std::forward_as_tuple( c0.v );
}
};
} // namespace daw::json

struct Child1 : Base {
int d;

explicit Child1( int D ) noexcept
: d( D ) {}

[[nodiscard]] int type( ) const override {
return 1;
}

[[nodiscard]] int value( ) const override {
return d;
}
};

namespace daw::json {
template<>
struct json_data_contract<Child1> {
static constexpr char const d[] = "d";
using type = json_member_list<json_number<d, int>>;

static constexpr auto to_json_data( Child1 const &c1 ) {
return std::forward_as_tuple( c1.d );
}
};
} // namespace daw::json

struct Switcher {
// Convert JSON tag member to type index
constexpr size_t operator( )( int type ) const {
return static_cast<std::size_t>( type );
}
// Get value for Tag from class value
int operator( )( Base const &b ) const {
return static_cast<int>( b.type( ) );
}
};

struct Foo {
std::unique_ptr<Base> value;
};

struct FooMaker {
std::unique_ptr<Base> operator( )( char const *str, std::size_t sz ) const {
using namespace daw::json;
auto jv = json_value( daw::string_view( str, sz ) );
(void)jv;
switch( as<std::size_t>( jv["type"] ) ) {
case 0:
return from_json<std::unique_ptr<Child0>>( jv );
case 1:
return from_json<std::unique_ptr<Child1>>( jv );
default:
std::terminate( );
}
}
};

namespace daw::json {
template<>
struct json_data_contract<Foo> {
static constexpr char const value[] = "value";
using type =
json_member_list<json_raw<value, std::unique_ptr<Base>, FooMaker>>;
};
} // namespace daw::json

constexpr std::string_view json_doc = R"json(
[
{"value":{ "type": 0, "v": 42 }},
{"value":{ "type": 1, "d": 66 }},
{"value":{ "type": 0, "v": 77 }}
]
)json";

int main( ) {
auto foo = daw::json::from_json<std::vector<Foo>>( json_doc );
assert( foo[0].value->type( ) == 0 );
assert( foo[0].value->value( ) == 42 );
assert( foo[1].value->type( ) == 1 );
assert( foo[1].value->value( ) == 66 );
assert( foo[2].value->type( ) == 0 );
assert( foo[2].value->value( ) == 77 );
}

0 comments on commit 8ff8543

Please sign in to comment.