为什么protobuf序列化“oneof”消息使用if-else

时间:2018-04-20 08:09:46

标签: protocol-buffers

我有一个像这样的消息定义:

message Command{
  oneof type{
    Point       point       = 1;
    Rotate      rotate      = 2;
    Move        move        = 3;
    ... //about 100 messages
  } 
}

然后protoc生成SerializeWithCachedSizes函数:

void Command::SerializeWithCachedSizes(
    ::google::protobuf::io::CodedOutputStream* output) const {
  // @@protoc_insertion_point(serialize_start:coopshare.proto.Command)
  ::google::protobuf::uint32 cached_has_bits = 0;
  (void) cached_has_bits;

  // .coopshare.proto.Point point = 1;
  if (has_point()) {
    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
      1, *type_.point_, output);
  }

  // .coopshare.proto.Rotate rotate = 2;
  if (has_rotate()) {
    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
      2, *type_.rotate_, output);
  }

  // .coopshare.proto.Move move = 3;
  if (has_move()) {
    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
      3, *type_.move_, output);
  }

“oneof”消息将特定类型保存在_oneof_case_中。我认为使用switch-case更有效率。

但为什么protobuf仍会生成这样的代码?

1 个答案:

答案 0 :(得分:1)

Oneofs内部处理类似于可选字段。事实上,descriptor.proto将它们表示为一组可选字段,只有一个额外的oneof_index来表示它们属于一起。这是一个合理的选择,因为它允许oneofs在添加任何特殊支持之前立即与许多库一起使用。

我假设C ++代码生成器对可选字段和oneofs使用相同的结构。

switch-case有可能生成更高效的代码,在这种情况下,建议将其作为protobuf项目的改进是有用的。但是,正如JorgeBellón在评论中指出的那样,编译器完全有可能自动优化这种结构。人们必须进行测试和基准测试才能确定。