Make LogReader own SimulatedEventLoopFactory

This reduces some code duplication and makes things easier once we start
need to be able to mess with the config from the LogReader.

Change-Id: Ia1c04f37865cfd284c3675ca138d38b3f4b7717f
diff --git a/aos/BUILD b/aos/BUILD
index e964066..80ba32a 100644
--- a/aos/BUILD
+++ b/aos/BUILD
@@ -302,6 +302,7 @@
     tables = [
         "Configuration",
         "Channel",
+        "Connection",
         "Map",
         "Node",
     ],
diff --git a/aos/events/logging/log_cat.cc b/aos/events/logging/log_cat.cc
index 45f0811..1d1dd8b 100644
--- a/aos/events/logging/log_cat.cc
+++ b/aos/events/logging/log_cat.cc
@@ -28,12 +28,10 @@
   aos::InitGoogle(&argc, &argv);
 
   aos::logger::LogReader reader(FLAGS_logfile);
-  aos::SimulatedEventLoopFactory log_reader_factory(reader.configuration(),
-                                                    reader.node());
-  reader.Register(&log_reader_factory);
+  reader.Register();
 
   std::unique_ptr<aos::EventLoop> printer_event_loop =
-      log_reader_factory.MakeEventLoop("printer");
+      reader.event_loop_factory()->MakeEventLoop("printer");
   printer_event_loop->SkipTimingReport();
 
   bool found_channel = false;
@@ -88,9 +86,7 @@
     LOG(FATAL) << "Could not find any channels";
   }
 
-  log_reader_factory.Run();
-
-  reader.Deregister();
+  reader.event_loop_factory()->Run();
 
   aos::Cleanup();
   return 0;
diff --git a/aos/events/logging/logger.cc b/aos/events/logging/logger.cc
index 22c1a6e..3e790b6 100644
--- a/aos/events/logging/logger.cc
+++ b/aos/events/logging/logger.cc
@@ -225,7 +225,7 @@
 }
 
 LogReader::~LogReader() {
-  CHECK(!event_loop_unique_ptr_) << ": Did you remember to call Deregister?";
+  Deregister();
 }
 
 const Configuration *LogReader::configuration() const {
@@ -242,9 +242,15 @@
   return sorted_message_reader_.realtime_start_time();
 }
 
+void LogReader::Register() {
+  event_loop_factory_unique_ptr_ =
+      std::make_unique<SimulatedEventLoopFactory>(configuration(), node());
+  Register(event_loop_factory_unique_ptr_.get());
+}
+
 void LogReader::Register(SimulatedEventLoopFactory *event_loop_factory) {
-  event_loop_unique_ptr_ = event_loop_factory->MakeEventLoop("log_reader");
   event_loop_factory_ = event_loop_factory;
+  event_loop_unique_ptr_ = event_loop_factory_->MakeEventLoop("log_reader");
   // We don't run timing reports when trying to print out logged data, because
   // otherwise we would end up printing out the timing reports themselves...
   // This is only really relevant when we are replaying into a simulation.
@@ -334,13 +340,16 @@
 }
 
 void LogReader::Deregister() {
+  // Make sure that things get destroyed in the correct order, rather than
+  // relying on getting the order correct in the class definition.
   for (size_t i = 0; i < channels_.size(); ++i) {
     channels_[i].reset();
   }
 
-  event_loop_factory_ = nullptr;
   event_loop_unique_ptr_.reset();
   event_loop_ = nullptr;
+  event_loop_factory_unique_ptr_.reset();
+  event_loop_factory_ = nullptr;
 }
 
 }  // namespace logger
diff --git a/aos/events/logging/logger.h b/aos/events/logging/logger.h
index a35b453..e5b91ac 100644
--- a/aos/events/logging/logger.h
+++ b/aos/events/logging/logger.h
@@ -62,17 +62,24 @@
   LogReader(std::string_view filename);
   ~LogReader();
 
+  // Registers everything, but also updates the real time time in sync.  Runs
+  // until the log file starts.
+  // Note that if you use any call other than the Register() call with no
+  // arguments, the user is responsible for making sure that the config of the
+  // supplied event loop (factory) provides any necessary remapped configs.
+  void Register();
+  // Does the same as Register(), except it uses a pre-provided event loop
+  // factory.
+  void Register(SimulatedEventLoopFactory *event_loop_factory);
   // Registers the timer and senders used to resend the messages from the log
   // file.
   void Register(EventLoop *event_loop);
-  // Registers everything, but also updates the real time time in sync.  Runs
-  // until the log file starts.
-  void Register(SimulatedEventLoopFactory *factory);
-  // Unregisters the senders.
+  // Unregisters the senders. You only need to call this if you separately
+  // supplied an event loop or event loop factory and the lifetimes are such
+  // that they need to be explicitly destroyed before the LogReader destructor
+  // gets called.
   void Deregister();
 
-  // TODO(austin): Remap channels?
-
   // Returns the configuration from the log file.
   const Configuration *configuration() const;
 
@@ -83,6 +90,10 @@
   monotonic_clock::time_point monotonic_start_time();
   realtime_clock::time_point realtime_start_time();
 
+  SimulatedEventLoopFactory *event_loop_factory() {
+    return event_loop_factory_;
+  }
+
   // TODO(austin): Add the ability to re-publish the fetched messages.  Add 2
   // options, one which publishes them *now*, and another which publishes them
   // to the simulated event loop factory back in time where they actually
@@ -95,12 +106,17 @@
   // Log chunk reader.
   SortedMessageReader sorted_message_reader_;
 
+  std::unique_ptr<FlatbufferDetachedBuffer<Configuration>>
+      remapped_configuration_buffer_;
+
   std::vector<std::unique_ptr<RawSender>> channels_;
 
-  SimulatedEventLoopFactory *event_loop_factory_ = nullptr;
   std::unique_ptr<EventLoop> event_loop_unique_ptr_;
   EventLoop *event_loop_ = nullptr;
   TimerHandler *timer_handler_;
+
+  std::unique_ptr<SimulatedEventLoopFactory> event_loop_factory_unique_ptr_;
+  SimulatedEventLoopFactory *event_loop_factory_ = nullptr;
 };
 
 }  // namespace logger
diff --git a/aos/events/logging/logger_test.cc b/aos/events/logging/logger_test.cc
index 91190e7..d96d4c6 100644
--- a/aos/events/logging/logger_test.cc
+++ b/aos/events/logging/logger_test.cc
@@ -64,16 +64,16 @@
   LOG(INFO) << "Config " << FlatbufferToJson(reader.configuration());
   EXPECT_EQ(reader.node(), nullptr);
 
-  SimulatedEventLoopFactory log_reader_factory(reader.configuration());
-
   // This sends out the fetched messages and advances time to the start of the
   // log file.
-  reader.Register(&log_reader_factory);
+  reader.Register();
 
-  EXPECT_EQ(log_reader_factory.node(), nullptr);
+  EXPECT_EQ(reader.node(), nullptr);
+
+  EXPECT_EQ(reader.event_loop_factory()->node(), nullptr);
 
   std::unique_ptr<EventLoop> test_event_loop =
-      log_reader_factory.MakeEventLoop("log_reader");
+      reader.event_loop_factory()->MakeEventLoop("log_reader");
 
   int ping_count = 10;
   int pong_count = 10;
@@ -93,10 +93,8 @@
         EXPECT_EQ(ping_count, pong_count);
       });
 
-  log_reader_factory.RunFor(std::chrono::seconds(100));
+  reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
   EXPECT_EQ(ping_count, 2010);
-
-  reader.Deregister();
 }
 
 // Tests that a large number of messages per second doesn't overwhelm writev.
@@ -209,22 +207,22 @@
   }
 
   LogReader reader(logfile);
-  ASSERT_NE(reader.node(), nullptr);
-  EXPECT_EQ(reader.node()->name()->string_view(), "pi1");
 
   // TODO(austin): Also replay as pi2 or pi3 and make sure we see the pong
   // messages.  This won't work today yet until the log reading code gets
   // significantly better.
-  SimulatedEventLoopFactory log_reader_factory(reader.configuration(),
-                                               reader.node());
-  log_reader_factory.set_send_delay(chrono::microseconds(0));
 
   // This sends out the fetched messages and advances time to the start of the
   // log file.
-  reader.Register(&log_reader_factory);
+  reader.Register();
+
+  ASSERT_NE(reader.node(), nullptr);
+  EXPECT_EQ(reader.node()->name()->string_view(), "pi1");
+
+  reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
 
   std::unique_ptr<EventLoop> test_event_loop =
-      log_reader_factory.MakeEventLoop("test");
+      reader.event_loop_factory()->MakeEventLoop("test");
 
   int ping_count = 10;
   int pong_count = 10;
@@ -252,11 +250,9 @@
         EXPECT_EQ(ping_count, pong_count);
       });
 
-  log_reader_factory.RunFor(std::chrono::seconds(100));
+  reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
   EXPECT_EQ(ping_count, 2010);
   EXPECT_EQ(pong_count, 2010);
-
-  reader.Deregister();
 }
 
 }  // namespace testing
diff --git a/frc971/analysis/py_log_reader.cc b/frc971/analysis/py_log_reader.cc
index 5a6fce4..6a002df 100644
--- a/frc971/analysis/py_log_reader.cc
+++ b/frc971/analysis/py_log_reader.cc
@@ -43,7 +43,6 @@
 // All the objects that we need for managing reading a logfile.
 struct LogReaderTools {
   std::unique_ptr<aos::logger::LogReader> reader;
-  std::unique_ptr<aos::SimulatedEventLoopFactory> event_loop_factory;
   // Event loop to use for subscribing to buses.
   std::unique_ptr<aos::EventLoop> event_loop;
   std::vector<ChannelData> channel_data;
@@ -58,9 +57,6 @@
 
 void LogReader_dealloc(LogReaderType *self) {
   LogReaderTools *tools = self->tools;
-  if (!tools->processed) {
-    tools->reader->Deregister();
-  }
   delete tools;
   Py_TYPE(self)->tp_free((PyObject *)self);
 }
@@ -89,11 +85,10 @@
 
   LogReaderTools *tools = CHECK_NOTNULL(self->tools);
   tools->reader = std::make_unique<aos::logger::LogReader>(log_file_name);
-  tools->event_loop_factory = std::make_unique<aos::SimulatedEventLoopFactory>(
-      tools->reader->configuration());
-  tools->reader->Register(tools->event_loop_factory.get());
+  tools->reader->Register();
 
-  tools->event_loop = tools->event_loop_factory->MakeEventLoop("data_fetcher");
+  tools->event_loop =
+      tools->reader->event_loop_factory()->MakeEventLoop("data_fetcher");
   tools->event_loop->SkipTimingReport();
 
   return 0;
@@ -199,8 +194,7 @@
 
   tools->processed = true;
 
-  tools->event_loop_factory->Run();
-  tools->reader->Deregister();
+  tools->reader->event_loop_factory()->Run();
 
   Py_RETURN_NONE;
 }