diff --git a/include/simdjson/generic/ondemand/json_string_builder-inl.h b/include/simdjson/generic/ondemand/json_string_builder-inl.h index 172adf143..56956d307 100644 --- a/include/simdjson/generic/ondemand/json_string_builder-inl.h +++ b/include/simdjson/generic/ondemand/json_string_builder-inl.h @@ -519,8 +519,8 @@ simdjson_inline void string_builder::append(const T &opt) { template requires(require_custom_serialization) -simdjson_inline void string_builder::append(const T &val) { - serialize(*this, val); +simdjson_inline void string_builder::append(T &&val) { + serialize(*this, std::forward(val)); } template diff --git a/include/simdjson/generic/ondemand/json_string_builder.h b/include/simdjson/generic/ondemand/json_string_builder.h index 275e91114..ed005ec0a 100644 --- a/include/simdjson/generic/ondemand/json_string_builder.h +++ b/include/simdjson/generic/ondemand/json_string_builder.h @@ -24,9 +24,8 @@ struct has_custom_serialization : std::false_type {}; inline constexpr struct serialize_tag { template - requires custom_deserializable - constexpr void operator()(SIMDJSON_IMPLEMENTATION::builder::string_builder& b, T& obj) const{ - return tag_invoke(*this, b, obj); + constexpr void operator()(SIMDJSON_IMPLEMENTATION::builder::string_builder& b, T&& obj) const{ + return tag_invoke(*this, b, std::forward(obj)); } @@ -165,7 +164,7 @@ public: template requires(require_custom_serialization) - simdjson_inline void append(const T &val); + simdjson_inline void append(T &&val); // Support for string-like types template diff --git a/tests/builder/builder_string_builder_tests.cpp b/tests/builder/builder_string_builder_tests.cpp index 4cee7b6a4..c67fab13f 100644 --- a/tests/builder/builder_string_builder_tests.cpp +++ b/tests/builder/builder_string_builder_tests.cpp @@ -17,6 +17,33 @@ struct Car { std::vector tire_pressure; }; // Car + +#if SIMDJSON_SUPPORTS_CONCEPTS +struct Car2549 { + std::string make; + std::string model; + int64_t year; + std::vector tire_pressure; +}; +namespace simdjson { + // we intentionally pass by non-const reference to car. + template + void tag_invoke(serialize_tag, builder_type& builder, Car2549& car) { + builder.start_object(); + builder.append_key_value("make", car.make); + builder.append_comma(); + builder.append_key_value("model", car.model); + builder.append_comma(); + builder.append_key_value("year", car.year); + builder.append_comma(); + builder.append_key_value("tire_pressure", car.tire_pressure); + builder.end_object(); + } +} // namespace simdjson + +static_assert(simdjson::require_custom_serialization); +#endif + namespace builder_tests { using namespace std; @@ -428,6 +455,21 @@ bool car_test() { TEST_SUCCEED(); } #if SIMDJSON_SUPPORTS_CONCEPTS + +bool issue2549() { + TEST_START(); + simdjson::builder::string_builder sb; + Car2549 c = { "Toyota", "Corolla", 2017, {1.0f,2.0f,3.0f} }; + sb.start_object(); + sb.append_key_value("car", c); + sb.end_object(); + std::string_view p; + auto result = sb.view().get(p); + ASSERT_SUCCESS(result); + ASSERT_EQUAL(p, "{\"car\":{\"make\":\"Toyota\",\"model\":\"Corolla\",\"year\":2017,\"tire_pressure\":[1.0,2.0,3.0]}}"); + TEST_SUCCEED(); +} + bool car_test_template() { TEST_START(); simdjson::builder::string_builder sb; @@ -616,7 +658,7 @@ bool run() { #endif #endif #if SIMDJSON_SUPPORTS_CONCEPTS - car_test_template() && serialize_optional() && + issue2549() && car_test_template() && serialize_optional() && #endif append_char() && append_integer() && append_float() && append_null() && clear() && escape_and_append() && escape_and_append_with_quotes() && diff --git a/tests/compile_time/compile_time_json_tests.cpp b/tests/compile_time/compile_time_json_tests.cpp index aca747c54..160862d61 100644 --- a/tests/compile_time/compile_time_json_tests.cpp +++ b/tests/compile_time/compile_time_json_tests.cpp @@ -661,6 +661,8 @@ bool test_array_of_objects_with_concept() { TEST_SUCCEED(); } +#if defined(__cpp_pp_embed) && __cpp_pp_embed >= 202502L +#define TEST_EMBED_SUPPORTED /** * Test: #embed support for external JSON files (C++26) */ @@ -688,6 +690,7 @@ bool test_embed_twitter_json() { TEST_SUCCEED(); } +#endif // defined(__cpp_pp_embed) && __cpp_pp_embed >= 202502L bool run() { return test_basic_object() && @@ -713,8 +716,11 @@ bool run() { test_user_config_example() && test_nested_servers_example() && test_top_level_array_example() && - test_array_of_objects_with_concept() && - test_embed_twitter_json(); + test_array_of_objects_with_concept() +#ifdef TEST_EMBED_SUPPORTED + && test_embed_twitter_json() +#endif +; } } // namespace compile_time_json_tests