From 27dfb31210d6d05a68103408e39b9dd40032b2f3 Mon Sep 17 00:00:00 2001 From: Charles Cabergs Date: Wed, 7 Oct 2026 13:40:05 +0200 Subject: [PATCH] Add inplace vector support --- README.md | 1 + include/rfl/parsing/VectorReader.hpp | 9 +++++- include/rfl/parsing/is_inplace_vector.hpp | 37 ++++++++++++++++++++++ include/rfl/parsing/is_vector_like.hpp | 7 +++++ tests/json/test_inplace_vector.cpp | 38 +++++++++++++++++++++++ 5 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 include/rfl/parsing/is_inplace_vector.hpp create mode 100644 tests/json/test_inplace_vector.cpp diff --git a/README.md b/README.md index bc6467601..c0d73a51d 100644 --- a/README.md +++ b/README.md @@ -621,6 +621,7 @@ reflect-cpp supports the following containers from the C++ standard library: - `std::chrono::duration` - `std::filesystem::path` - `std::forward_list` +- `std::inplace_vector` (C++26) - `std::map` - `std::multimap` - `std::multiset` diff --git a/include/rfl/parsing/VectorReader.hpp b/include/rfl/parsing/VectorReader.hpp index ac2c72c99..c7abd90d3 100644 --- a/include/rfl/parsing/VectorReader.hpp +++ b/include/rfl/parsing/VectorReader.hpp @@ -2,10 +2,12 @@ #define RFL_PARSING_VECTORREADER_HPP_ #include +#include #include #include "../Result.hpp" #include "Parser_base.hpp" +#include "is_inplace_vector.hpp" #include "is_map_like.hpp" #include "is_set_like.hpp" @@ -47,6 +49,11 @@ class VectorReader { const auto insert = [this](auto&& _var) -> std::optional { if constexpr (is_map_like_v || is_set_like_v) { vec_->insert(std::move(_var)); + } else if constexpr (is_inplace_vector_v) { + if (!vec_->try_emplace_back(std::move(_var))) { + return Error("Too many elements, capacity is " + + std::to_string(vec_->capacity()) + "."); + } } else { vec_->emplace_back(std::move(_var)); } @@ -54,7 +61,7 @@ class VectorReader { }; auto res = parse(_var).transform(insert); if (res) { - return std::nullopt; + return *res; } else { return res.error(); } diff --git a/include/rfl/parsing/is_inplace_vector.hpp b/include/rfl/parsing/is_inplace_vector.hpp new file mode 100644 index 000000000..7e42970ab --- /dev/null +++ b/include/rfl/parsing/is_inplace_vector.hpp @@ -0,0 +1,37 @@ +#ifndef RFL_PARSING_IS_INPLACE_VECTOR_HPP_ +#define RFL_PARSING_IS_INPLACE_VECTOR_HPP_ + +#include +#include + +#if __has_include() +#include +#endif + +namespace rfl { +namespace parsing { + +/** + * @brief Trait to check if a type is a std::inplace_vector. + * + * @tparam T The type to check. + */ +template +class is_inplace_vector; + +template +class is_inplace_vector : public std::false_type {}; + +#if defined(__cpp_lib_inplace_vector) +template +class is_inplace_vector> : public std::true_type {}; +#endif // __cpp_lib_inplace_vector + +template +constexpr bool is_inplace_vector_v = + is_inplace_vector>::value; + +} // namespace parsing +} // namespace rfl + +#endif diff --git a/include/rfl/parsing/is_vector_like.hpp b/include/rfl/parsing/is_vector_like.hpp index 25cb25d36..3583608f6 100644 --- a/include/rfl/parsing/is_vector_like.hpp +++ b/include/rfl/parsing/is_vector_like.hpp @@ -10,6 +10,8 @@ #include #include +#include "is_inplace_vector.hpp" + namespace rfl::parsing { /** @@ -67,6 +69,11 @@ class is_vector_like> template class is_vector_like> : public std::true_type {}; +#if defined(__cpp_lib_inplace_vector) +template +class is_vector_like> : public std::true_type {}; +#endif // __cpp_lib_inplace_vector + template constexpr bool is_vector_like_v = is_vector_like>::value; diff --git a/tests/json/test_inplace_vector.cpp b/tests/json/test_inplace_vector.cpp new file mode 100644 index 000000000..fc010f3be --- /dev/null +++ b/tests/json/test_inplace_vector.cpp @@ -0,0 +1,38 @@ +#include +#include +#include + +#include "write_and_read.hpp" + +#if __has_include() +#include +#endif + +#if defined(__cpp_lib_inplace_vector) + +namespace test_inplace_vector { + +struct Person { + rfl::Rename<"firstName", std::string> first_name; + rfl::Rename<"lastName", std::string> last_name = "Simpson"; + std::inplace_vector children; +}; + +TEST(json, test_inplace_vector) { + const auto homer = + Person{.first_name = "Homer", .children = {"Bart", "Lisa", "Maggie"}}; + + write_and_read( + homer, + R"({"firstName":"Homer","lastName":"Simpson","children":["Bart","Lisa","Maggie"]})"); +} + +TEST(json, test_inplace_vector_overflow) { + const auto res = rfl::json::read( + R"({"firstName":"Homer","children":["Bart","Lisa","Maggie","Hugo"]})"); + EXPECT_FALSE(res && true); +} + +} // namespace test_inplace_vector + +#endif // __cpp_lib_inplace_vector