浅复制到协议缓冲区的字节字段中

Chr*_*ris 13 c++ protocol-buffers

假设我有一个带字节字段的proto:

message MyProto {
    optional bytes data = 1;
}
Run Code Online (Sandbox Code Playgroud)

我无法控制的API为我提供了指向源数据及其大小的指针.我想在没有深度复制的情况下MyProto从这些数据中获取数据.我认为这很容易做到,但似乎不可能.深度复制很容易set_data.Protobuf提供了一个set_allocated_data函数,但它需要一个指向a的指针std::string,这对我没有帮助,因为(除非我弄错了)没有办法在std::string没有深度复制的情况下进行.

void populateProto(void* data, size_t size, MyProto* message) {
    // Deep copy is fine, I guess.
    message->set_data(data, size);

    // Shallow copy would be better...
    // message->set_allocated_data( ??? );
}
Run Code Online (Sandbox Code Playgroud)

有没有办法正确填充这个原型(以便以后可以序列化)而无需将源数据深度复制到字节字段中?

我知道我可以立即手动进行序列化,但如果可能的话,我宁愿不这样做.

Ale*_*aca 5

好问题。选项包括:

  1. 如果您可以更改.proto文件,请考虑为实施即将到来的C ++ 17的Google的ctypefield选项。这就是Google在内部处理此类案件的方式。该消息已经具有StringPiece的语义,但是Google尚未开源该实现。StringPiecestring_viewFieldOptions

    message MyProto {
        bytes data = 1 [ctype = STRING_PIECE];
    }
    
    Run Code Online (Sandbox Code Playgroud)

    请参阅此讨论以获取实施指南。您可以忽略关于竞技场分配的注释,这不适用于您的情况。值得向Google索取ETA。

  2. 使用不同的协议缓冲区实现,可能仅适用于此特定消息类型。protobuf-cprotobluff是看起来很有前途的C语言实现。

  3. 向您的第三方API提供缓冲区。我从评论中看到您无法做到,但出于完整性考虑,我将其包括在内。

    ::str::string* buf = myProto->mutable_data();
    buf->resize(size);
    api(buf->data(), size); // data is contiguous per c++11 std
    
    Run Code Online (Sandbox Code Playgroud)
  4. 非标准:通过覆盖字符串实例中的数据来破坏封装。C ++具有一些粗糙的功能,这些功能可以使您足够绞死自己。此选项不安全,取决于您的std::string实现和其他因素。

    // NEVER USE THIS IN PRODUCTION
    void string_jam(::std::string * target, void * buffer, size_t len) {
      /* On my system, std::string layout
       *   0: size_t capacity
       *   8: size_t size
       *  16: char * data (iff strlen > 22 chars) */
      assert(target->size() > 22);
      size_t * size_ptr = (size_t*)target;
      size_ptr[0] = len; // Overwrite capacity
      size_ptr[1] = len; // Overwrite length
    
      char ** buf_ptr = (char**)(size_ptr + 2); 
      free(*buf_ptr); // Free the existing buffer
      *buf_ptr = (char*)buffer; // Jam in our new buffer
    }
    
    Run Code Online (Sandbox Code Playgroud)

    注意:这可能会让您被解雇。如果您确实执行了零复制路线,但未在产品中进行,则这对于进行测试以衡量性能影响很有用。

如果使用选项#1,则可以释放源代码就很好了,因为许多其他人将从此功能中受益。祝你好运。