From 8ff85432dd6bdd7969a957ebe79fa712ecd68654 Mon Sep 17 00:00:00 2001 From: Darrell Wright Date: Sat, 7 Jan 2023 23:15:33 -0500 Subject: [PATCH] Added example using base/child classes. Fixed issue with nullable types 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 *) --- CMakeLists.txt | 2 +- .../daw/json/concepts/daw_nullable_value.h | 18 +++ .../json/concepts/daw_nullable_value_fwd.h | 21 ++- .../json/impl/daw_json_default_constuctor.h | 13 ++ include/daw/json/impl/daw_json_parse_value.h | 24 ++- tests/CMakeLists.txt | 6 + tests/src/base_child_class_test.cpp | 137 ++++++++++++++++++ 7 files changed, 212 insertions(+), 9 deletions(-) create mode 100644 tests/src/base_child_class_test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0aa7bd2bd..624f10541 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 ) diff --git a/include/daw/json/concepts/daw_nullable_value.h b/include/daw/json/concepts/daw_nullable_value.h index f69b4c386..695d4546b 100644 --- a/include/daw/json/concepts/daw_nullable_value.h +++ b/include/daw/json/concepts/daw_nullable_value.h @@ -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 { @@ -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 { @@ -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 { diff --git a/include/daw/json/concepts/daw_nullable_value_fwd.h b/include/daw/json/concepts/daw_nullable_value_fwd.h index 9a1c84cd5..a6485c9f4 100644 --- a/include/daw/json/concepts/daw_nullable_value_fwd.h +++ b/include/daw/json/concepts/daw_nullable_value_fwd.h @@ -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{ }; @@ -122,6 +131,12 @@ namespace daw::json { std::is_invocable_v, construct_nullable_with_value_t, Args...>; + template + inline constexpr bool is_nullable_pointer_constructible_v = + is_nullable_value_v and + std::is_invocable_v, + construct_nullable_with_pointer_t, Args...>; + template inline constexpr bool is_nullable_value_nothrow_constructible_v = is_nullable_value_constructible_v and diff --git a/include/daw/json/impl/daw_json_default_constuctor.h b/include/daw/json/impl/daw_json_default_constuctor.h index 04badbee5..e0b55d402 100644 --- a/include/daw/json/impl/daw_json_default_constuctor.h +++ b/include/daw/json/impl/daw_json_default_constuctor.h @@ -257,6 +257,19 @@ namespace daw::json { return rtraits_t{ }( concepts::construct_nullable_with_value, DAW_FWD( args )... ); } + + template, + 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 ) { + return rtraits_t{ }( concepts::construct_nullable_with_pointer, ptr ); + } }; } // namespace DAW_JSON_VER } // namespace daw::json diff --git a/include/daw/json/impl/daw_json_parse_value.h b/include/daw/json/impl/daw_json_parse_value.h index f23ede0c8..6e6d6fcdf 100644 --- a/include/daw/json/impl/daw_json_parse_value.h +++ b/include/daw/json/impl/daw_json_parse_value.h @@ -349,10 +349,24 @@ namespace daw::json { parse_state.trim_left_checked( ); return construct_empty( ); } - return construct_value( - template_args, parse_state, - parse_value( - parse_state, ParseTag{ } ) ); + using parse_to_t = typename base_member_type::parse_to_t; + if constexpr( not std::is_move_constructible_v and + not std::is_copy_constructible_v ) { + static_assert( + std::is_invocable_v< + concepts::nullable_value_traits>, + concepts::construct_nullable_with_pointer_t, parse_to_t *> ); + return construct_value( + template_args, parse_state, + concepts::construct_nullable_with_pointer, + new parse_to_t{ parse_value( + parse_state, ParseTag{ } ) } ); + } else { + return construct_value( + template_args, parse_state, + parse_value( + parse_state, ParseTag{ } ) ); + } } } @@ -752,7 +766,7 @@ namespace daw::json { return parse_value( parse_state, ParseTag{ } ); } else { - daw_json_error( ErrorReason::UnexpectedJSONVariantType ); + daw_json_error( ErrorReason::UnexpectedJSONVariantType ); } } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a953fab1e..a3b276d6b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -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 ) diff --git a/tests/src/base_child_class_test.cpp b/tests/src/base_child_class_test.cpp new file mode 100644 index 000000000..6189bb7fe --- /dev/null +++ b/tests/src/base_child_class_test.cpp @@ -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 + +#include +#include +#include + +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 { + static constexpr char const v[] = "v"; + using type = json_member_list>; + + 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 { + static constexpr char const d[] = "d"; + using type = json_member_list>; + + 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( type ); + } + // Get value for Tag from class value + int operator( )( Base const &b ) const { + return static_cast( b.type( ) ); + } +}; + +struct Foo { + std::unique_ptr value; +}; + +struct FooMaker { + std::unique_ptr 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( jv["type"] ) ) { + case 0: + return from_json>( jv ); + case 1: + return from_json>( jv ); + default: + std::terminate( ); + } + } +}; + +namespace daw::json { + template<> + struct json_data_contract { + static constexpr char const value[] = "value"; + using type = + json_member_list, 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>( 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 ); +}