Add simple Message struct for sorting

This is going to be the simple object used to store and sort messages
before they have been matched.  Make sure operator< works, since that's
how we'll be sorting them.

Change-Id: Icc6b8f5b62024f6cd86e11d18dde438d09a9706b
diff --git a/aos/events/logging/logfile_utils.cc b/aos/events/logging/logfile_utils.cc
index 330c78e..3a39803 100644
--- a/aos/events/logging/logfile_utils.cc
+++ b/aos/events/logging/logfile_utils.cc
@@ -461,6 +461,34 @@
   ++next_part_index_;
 }
 
+bool Message::operator<(const Message &m2) const {
+  if (this->timestamp < m2.timestamp) {
+    return true;
+  } else if (this->timestamp > m2.timestamp) {
+    return false;
+  }
+
+  if (this->channel_index < m2.channel_index) {
+    return true;
+  } else if (this->channel_index > m2.channel_index) {
+    return false;
+  }
+
+  return this->queue_index < m2.queue_index;
+}
+
+bool Message::operator>=(const Message &m2) const { return !(*this < m2); }
+
+std::ostream &operator<<(std::ostream &os, const Message &m) {
+  os << "{.channel_index=" << m.channel_index
+     << ", .queue_index=" << m.queue_index << ", .timestamp=" << m.timestamp
+     << ", .data="
+     << aos::FlatbufferToJson(m.data,
+                              {.multi_line = false, .max_vector_size = 1})
+     << "}";
+  return os;
+}
+
 SplitMessageReader::SplitMessageReader(
     const std::vector<std::string> &filenames)
     : filenames_(filenames),
diff --git a/aos/events/logging/logfile_utils.h b/aos/events/logging/logfile_utils.h
index 985a6bc..25f02f9 100644
--- a/aos/events/logging/logfile_utils.h
+++ b/aos/events/logging/logfile_utils.h
@@ -309,6 +309,23 @@
   monotonic_clock::time_point newest_timestamp_ = monotonic_clock::min_time;
 };
 
+// Struct to hold a message as it gets sorted on a single node.
+struct Message {
+  // The channel.
+  uint32_t channel_index = 0xffffffff;
+  // The local queue index.
+  uint32_t queue_index = 0xffffffff;
+  // The local timestamp on the monotonic clock.
+  monotonic_clock::time_point timestamp = monotonic_clock::min_time;
+  // The data (either a timestamp header, or a data header).
+  SizePrefixedFlatbufferVector<MessageHeader> data;
+
+  bool operator<(const Message &m2) const;
+  bool operator>=(const Message &m2) const;
+};
+
+std::ostream &operator<<(std::ostream &os, const Message &m);
+
 class TimestampMerger;
 
 // A design requirement is that the relevant data for a channel is not more than
diff --git a/aos/events/logging/logfile_utils_test.cc b/aos/events/logging/logfile_utils_test.cc
index 14d1de7..dafb452 100644
--- a/aos/events/logging/logfile_utils_test.cc
+++ b/aos/events/logging/logfile_utils_test.cc
@@ -215,6 +215,40 @@
   EXPECT_EQ(reader.newest_timestamp(), monotonic_clock::max_time);
 }
 
+// Tests that Message's operator < works as expected.
+TEST(MessageTest, Sorting) {
+  const aos::monotonic_clock::time_point e = monotonic_clock::epoch();
+
+  Message m1{.channel_index = 0,
+             .queue_index = 0,
+             .timestamp = e + chrono::milliseconds(1),
+             .data = SizePrefixedFlatbufferVector<MessageHeader>::Empty()};
+  Message m2{.channel_index = 0,
+             .queue_index = 0,
+             .timestamp = e + chrono::milliseconds(2),
+             .data = SizePrefixedFlatbufferVector<MessageHeader>::Empty()};
+
+  EXPECT_LT(m1, m2);
+  EXPECT_GE(m2, m1);
+
+  m1.timestamp = e;
+  m2.timestamp = e;
+
+  m1.channel_index = 1;
+  m2.channel_index = 2;
+
+  EXPECT_LT(m1, m2);
+  EXPECT_GE(m2, m1);
+
+  m1.channel_index = 0;
+  m2.channel_index = 0;
+  m1.queue_index = 0;
+  m2.queue_index = 1;
+
+  EXPECT_LT(m1, m2);
+  EXPECT_GE(m2, m1);
+}
+
 }  // namespace testing
 }  // namespace logger
 }  // namespace aos