When am iterating over a a protobuf message fields using reflection, I'd like to check if a sub-message or a map's value has a default value. I am currently checking for ByteSizeLong() == 0
, which works, but according to the documentation is linear in the number of sub-fields, making it inefficient for large sub-messages.
I tried to use HasField()
instead, but it isn't working.
Is there a problem in my code or can HasField()
not be used for this? And if the latter is the case, is there an O(1) function that can be used?
Here's a minimal example:
The .proto file:
message Wrapper {
string value = 1;
}
message M {
map<int64, Wrapper> map = 1;
optional Wrapper msg = 2;
}
And the C++ code:
int main() {
M msg;
auto status = JsonStringToMessage(R"(
{
"map": {
"1": { "value": "string1" },
"2": {}
},
"msg": {}
})",
&msg);
test(msg);
}
void test(const Message& msg) {
const auto* descr = msg.GetDescriptor();
const auto* refl = msg.GetReflection();
for (int i = 0; i < descr->field_count(); ++i) {
const auto* fd = descr->field(i);
if (fd->is_map()) {
for (const auto& element : refl->GetRepeatedFieldRef<Message>(msg, fd)) {
const auto* descr = element.GetDescriptor();
const auto* refl = element.GetReflection();
const auto* fdValue = descr->map_value();
std::cout << "Element size: " << refl->GetMessage(element, fdValue).ByteSizeLong()
<< ", has field: " << refl->HasField(element, fdValue) << "\n";
}
continue;
}
if (fd->type() == FieldDescriptor::TYPE_MESSAGE && !fd->is_repeated()) {
std::cout << "Message size: " << refl->GetMessage(msg, fd).ByteSizeLong()
<< ", has field: " << refl->HasField(msg, fd) << "\n";
}
}
}
And finally, the results:
Element size: 9, has field: 1
Element size: 0, has field: 1
Message size: 0, has field: 1
Aucun commentaire:
Enregistrer un commentaire