35
votes

I want to compare two Messages or (two sub parameters) of Google protocol buffers. I don't find an API to achieve it.

Any ideas?

6
Can you specify what exactly you want to compare: message structure, message's field values or the both at once?abyss.7

6 Answers

40
votes

You can use the class google::protobuf::util::MessageDifferencer for this. I think it's only available since v3.0.2:

Introduced new utility functions/classes in the google/protobuf/util directory:

  • MessageDifferencer: compare two proto messages and report their differences.
#include <google/protobuf/util/message_differencer.h>

MessageDifferencer::Equals(msg1, msg2);
10
votes

You can rely on the fact that all of your protobuf messages inherit from the google::protobuf::MesageLite type, which in turn has everything you need to compare any two protobuf messages, regardless of if they are even of the same derived type:

bool operator==(const google::protobuf::MessageLite& msg_a,
                const google::protobuf::MessageLite& msg_b) {
  return (msg_a.GetTypeName() == msg_b.GetTypeName()) &&
      (msg_a.SerializeAsString() == msg_b.SerializeAsString());
}

EDIT

As was pointed out in the comments below, and especially for map fields, this answer is incorrect. map elements have non-deterministic ordering. Use MessageDifferencer if map fields might be present in your messages.

7
votes

Instead of using message.DebugString you could also do

std::string strMsg;
message.SerializeToString(&strMsg);

with both messages and then compare the two (binary) strings. I didn't test the performance but I assume that it is faster than comparing the human readable message strings returned by .DebugString(). +You can do that with the protobuf-lite library (while for message.DebugString you need the full version).

0
votes

Well, a protocol buffer is just a serialization format for some object type. Why not use the protocol buffer to reconstruct the original objects, and then allow those objects to compare themselves, using whatever comparison logic you've built into the class?

-1
votes

This might not be the ideal solution, but I think it could be done by:

messageA.DebugString() == messageB.DebugString();

Other than that, I think the only solution would be to create your own Message child class and implement a bool operator==(const Message&).

-4
votes

You can compare the descriptor's pointer (super fast):

if (mMessages[i]->body()->GetDescriptor() == T::descriptor())

mMessages it's a pool of network messages with header and crypto which creates a packet with the protobuf body(google::protobuf::Message*).

so, to get the right kind of message i compare the descriptors constant pointer which is the same for every single type of message (not %100 sure but i haven't got any problem so far).

That would be the fastest way to compare a protobuf Message wthout having to use string comparasion, which by the way you gan get the type name from the descriptor. :-)