Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
9 changes: 8 additions & 1 deletion include/rfl/parsing/VectorReader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
#define RFL_PARSING_VECTORREADER_HPP_

#include <optional>
#include <string>
#include <type_traits>

#include "../Result.hpp"
#include "Parser_base.hpp"
#include "is_inplace_vector.hpp"
#include "is_map_like.hpp"
#include "is_set_like.hpp"

Expand Down Expand Up @@ -47,14 +49,19 @@ class VectorReader {
const auto insert = [this](auto&& _var) -> std::optional<Error> {
if constexpr (is_map_like_v<VecType> || is_set_like_v<VecType>) {
vec_->insert(std::move(_var));
} else if constexpr (is_inplace_vector_v<VecType>) {
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));
}
return std::nullopt;
};
auto res = parse(_var).transform(insert);
if (res) {
return std::nullopt;
return *res;
} else {
return res.error();
}
Expand Down
37 changes: 37 additions & 0 deletions include/rfl/parsing/is_inplace_vector.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#ifndef RFL_PARSING_IS_INPLACE_VECTOR_HPP_
#define RFL_PARSING_IS_INPLACE_VECTOR_HPP_

#include <cstddef>
#include <type_traits>

#if __has_include(<inplace_vector>)
#include <inplace_vector>
#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 T>
class is_inplace_vector;

template <class T>
class is_inplace_vector : public std::false_type {};

#if defined(__cpp_lib_inplace_vector)
template <class T, std::size_t N>
class is_inplace_vector<std::inplace_vector<T, N>> : public std::true_type {};
#endif // __cpp_lib_inplace_vector

template <class T>
constexpr bool is_inplace_vector_v =
is_inplace_vector<std::remove_cvref_t<T>>::value;

} // namespace parsing
} // namespace rfl

#endif
7 changes: 7 additions & 0 deletions include/rfl/parsing/is_vector_like.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include <unordered_set>
#include <vector>

#include "is_inplace_vector.hpp"

namespace rfl::parsing {

/**
Expand Down Expand Up @@ -67,6 +69,11 @@ class is_vector_like<std::unordered_set<T, Hash, KeyEqual, Allocator>>
template <class T>
class is_vector_like<std::vector<T>> : public std::true_type {};

#if defined(__cpp_lib_inplace_vector)
template <class T, std::size_t N>
class is_vector_like<std::inplace_vector<T, N>> : public std::true_type {};
#endif // __cpp_lib_inplace_vector

template <class T>
constexpr bool is_vector_like_v = is_vector_like<std::remove_cvref_t<T>>::value;

Expand Down
38 changes: 38 additions & 0 deletions tests/json/test_inplace_vector.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include <rfl.hpp>
#include <rfl/json.hpp>
#include <string>

#include "write_and_read.hpp"

#if __has_include(<inplace_vector>)
#include <inplace_vector>
#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<std::string, 3> 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<Person>(
R"({"firstName":"Homer","children":["Bart","Lisa","Maggie","Hugo"]})");
EXPECT_FALSE(res && true);
}

} // namespace test_inplace_vector

#endif // __cpp_lib_inplace_vector
Loading