replace tuple-based singleton with individual singletons

The tuple-based singletons did not actually enforce singleton behavior
and the requirement of the accessor mechanism to include all of the
member types at once was starting to cause a header prerequisite
tangle. This removes the cross-dependencies and enforces actual
singletons by making a single way to access the class.

Tested: Run ipmitool to show that behavior has not changed

Change-Id: Ie966e1142363d279365b1095066380c8383e9f9b
Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
diff --git a/sd_event_loop.hpp b/sd_event_loop.hpp
index 60b4434..1c3d1c2 100644
--- a/sd_event_loop.hpp
+++ b/sd_event_loop.hpp
@@ -1,5 +1,6 @@
 #pragma once
 
+#include "main.hpp"
 #include "sol/sol_manager.hpp"
 
 #include <systemd/sd-event.h>
@@ -40,8 +41,14 @@
 
 class EventLoop
 {
+  private:
+    struct Private
+    {
+    };
+
   public:
-    explicit EventLoop(std::shared_ptr<boost::asio::io_context> io) : io(io)
+    EventLoop(std::shared_ptr<boost::asio::io_context>& io, const Private&) :
+        io(io)
     {
     }
     EventLoop() = delete;
@@ -51,6 +58,22 @@
     EventLoop(EventLoop&&) = delete;
     EventLoop& operator=(EventLoop&&) = delete;
 
+    /**
+     * @brief Get a reference to the singleton EventLoop
+     *
+     * @return EventLoop reference
+     */
+    static EventLoop& get()
+    {
+        static std::shared_ptr<EventLoop> ptr = nullptr;
+        if (!ptr)
+        {
+            std::shared_ptr<boost::asio::io_context> io = getIo();
+            ptr = std::make_shared<EventLoop>(io, Private());
+        }
+        return *ptr;
+    }
+
     /** @brief Initialise the event loop and add the handler for incoming
      *         IPMI packets.
      *