Skip to content

Commit 73fba4d

Browse files
author
MatthewColvin
committed
Use NTTP to get the comma count right on the required array.
1 parent a777d36 commit 73fba4d

1 file changed

Lines changed: 21 additions & 31 deletions

File tree

Platformio/lib/RapidJsonUtility/ObjectSchemaBuilder.hpp

Lines changed: 21 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
#include <string_view>
55
#include <tuple>
66

7-
// Base struct holding Member type and static size calculation helpers,
8-
// independent of N so tests can access them as ObjectSchemaBuilderBase::Member etc.
97
struct ObjectSchemaBuilderBase {
108
struct Member {
119
std::string_view key = "";
@@ -41,7 +39,7 @@ struct ObjectSchemaBuilderBase {
4139
}
4240
};
4341

44-
template <size_t N, typename... Members>
42+
template <size_t N, size_t RequiredMembersCount, typename... Members>
4543
struct ObjectSchemaBuilder : public ObjectSchemaBuilderBase {
4644
public:
4745
constexpr ObjectSchemaBuilder(Members... ms) : members(ms...) {}
@@ -69,37 +67,31 @@ struct ObjectSchemaBuilder : public ObjectSchemaBuilderBase {
6967
Member m{key, type, isMemberRequired};
7068
auto newMembers = std::tuple_cat(members, std::make_tuple(m));
7169

72-
constexpr size_t existingRequired = CountRequired<Members...>();
73-
constexpr size_t keyLengthInRequiredArray = existingRequired == 0
74-
? QuotationMark.size() + KeyLen + QuotationMark.size() // First one just has quotes no need for commas
75-
: CommaQuotationMark.size() + KeyLen + QuotationMark.size(); // Subsequent required members need a comma and quotes around the key
76-
constexpr size_t reqContrib = isMemberRequired
77-
? keyLengthInRequiredArray
78-
: 0; // Not required then does not go in the required array
70+
// Comma separated array of required members in the "required" field of the schema, with quotes around each key. Only contributes if the member being added is required.
71+
constexpr size_t arrayStringLength = RequiredMembersCount == 0
72+
? QuotationMark.size() + KeyLen + QuotationMark.size() // First one just has quotes no need for commas
73+
: CommaQuotationMark.size() + KeyLen + QuotationMark.size(); // Subsequent required members need a comma and quotes around the key
74+
constexpr size_t reqArrayKeyStringLength = isMemberRequired ? arrayStringLength : 0;
7975

8076
constexpr size_t existingTotal = sizeof...(Members);
81-
constexpr size_t propContrib = existingTotal == 0
82-
? QuotationMark.size() + KeyLen + MemberTypeString.size() + TypeLen + EndMemberTypeString.size()
83-
: CommaQuotationMark.size() + KeyLen + MemberTypeString.size() + TypeLen + EndMemberTypeString.size();
8477

85-
constexpr size_t newN = N + reqContrib + propContrib;
78+
// Object schema properties contribution for this member, which will be in the format "key":{"type":"type"}, with a comma if it's not the first property.
79+
// Always contributes regardless of whether the member is required or optional, since all members go in the properties object.
80+
constexpr size_t propertyObjectStringLength = existingTotal == 0
81+
? QuotationMark.size() + KeyLen + MemberTypeString.size() + TypeLen + EndMemberTypeString.size()
82+
: CommaQuotationMark.size() + KeyLen + MemberTypeString.size() + TypeLen + EndMemberTypeString.size();
83+
84+
constexpr size_t newMemberAdditionSize = reqArrayKeyStringLength + propertyObjectStringLength;
85+
constexpr size_t newSchemaSize = N + newMemberAdditionSize;
86+
constexpr size_t newRequiredMembersCount = RequiredMembersCount + (isMemberRequired ? 1 : 0);
8687

8788
return std::apply(
88-
[](auto &&...ms) {
89-
// Build a new object builder to add the new member and update the total size we need for the schema.
90-
return ObjectSchemaBuilder<newN, Members..., Member>(ms...); },
89+
[](auto &&...ms) {
90+
return ObjectSchemaBuilder<newSchemaSize, newRequiredMembersCount, Members..., Member>(ms...);
91+
},
9192
newMembers);
9293
}
9394

94-
template <typename... Ms>
95-
static constexpr size_t CountRequired() {
96-
if constexpr (sizeof...(Ms) == 0) {
97-
return 0;
98-
} else {
99-
return (size_t{0} + ... + (Ms{}.required ? 1 : 0));
100-
}
101-
}
102-
10395
constexpr void AppendRequiredMembers(const auto &aAppendFunc) const {
10496
bool firstRequired = true;
10597
std::apply([&](auto &&...ms) {
@@ -144,14 +136,12 @@ struct ObjectSchemaBuilder : public ObjectSchemaBuilderBase {
144136
std::tuple<Members...> members;
145137
};
146138

147-
// Start with the base size as an empty object schema, then as each member
148-
// is added we construct a new builder with the updated size based on the passed member.
149139
static constexpr size_t BaseSize =
150140
ObjectSchemaBuilderBase::BeginningString.size() +
151141
ObjectSchemaBuilderBase::PostRequiredMembersArrayString.size() +
152-
ObjectSchemaBuilderBase::EndString.size() +
153-
1; // null terminator
142+
ObjectSchemaBuilderBase::EndString.size();
143+
static constexpr size_t initialRequiredMembersCount = 0;
154144

155145
constexpr auto ObjectSchema() {
156-
return ObjectSchemaBuilder<BaseSize>{};
146+
return ObjectSchemaBuilder<BaseSize, initialRequiredMembersCount>{};
157147
}

0 commit comments

Comments
 (0)