]> granicus.if.org Git - icinga2/commitdiff
Implement LazyInit<T>
authorAlexander A. Klimov <alexander.klimov@icinga.com>
Tue, 12 Feb 2019 10:47:03 +0000 (11:47 +0100)
committerAlexander A. Klimov <alexander.klimov@icinga.com>
Mon, 1 Apr 2019 09:40:14 +0000 (11:40 +0200)
lib/base/CMakeLists.txt
lib/base/lazy-init.hpp [new file with mode: 0644]

index 6d7661080ae51ac2950f28b60d97acbfe3784d2d..9e04de723f7e9c32fea608ad24662f2130f158ea 100644 (file)
@@ -35,6 +35,7 @@ set(base_SOURCES
   function.cpp function.hpp function-ti.hpp function-script.cpp functionwrapper.hpp
   initialize.cpp initialize.hpp
   json.cpp json.hpp json-script.cpp
+  lazy-init.hpp
   library.cpp library.hpp
   loader.cpp loader.hpp
   logger.cpp logger.hpp logger-ti.hpp
diff --git a/lib/base/lazy-init.hpp b/lib/base/lazy-init.hpp
new file mode 100644 (file)
index 0000000..dd20a80
--- /dev/null
@@ -0,0 +1,89 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012-2018 Icinga Development Team (https://icinga.com/)      *
+ *                                                                            *
+ * This program is free software; you can redistribute it and/or              *
+ * modify it under the terms of the GNU General Public License                *
+ * as published by the Free Software Foundation; either version 2             *
+ * of the License, or (at your option) any later version.                     *
+ *                                                                            *
+ * This program is distributed in the hope that it will be useful,            *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
+ * GNU General Public License for more details.                               *
+ *                                                                            *
+ * You should have received a copy of the GNU General Public License          *
+ * along with this program; if not, write to the Free Software Foundation     *
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
+ ******************************************************************************/
+
+#ifndef LAZY_INIT
+#define LAZY_INIT
+
+#include <atomic>
+#include <functional>
+#include <mutex>
+#include <utility>
+
+namespace icinga
+{
+
+/**
+ * Lazy object initialization abstraction inspired from
+ * <https://docs.microsoft.com/en-us/dotnet/api/system.lazy-1?view=netframework-4.7.2>.
+ *
+ * @ingroup base
+ */
+template<class T>
+class LazyInit
+{
+public:
+       inline
+       LazyInit(std::function<T()> initializer = []() { return T(); }) : m_Initializer(std::move(initializer))
+       {
+               m_Underlying.store(nullptr, std::memory_order_release);
+       }
+
+       LazyInit(const LazyInit&) = delete;
+       LazyInit(LazyInit&&) = delete;
+       LazyInit& operator=(const LazyInit&) = delete;
+       LazyInit& operator=(LazyInit&&) = delete;
+
+       inline
+       ~LazyInit()
+       {
+               auto ptr (m_Underlying.load(std::memory_order_acquire));
+
+               if (ptr != nullptr) {
+                       delete ptr;
+               }
+       }
+
+       inline
+       T& Get()
+       {
+               auto ptr (m_Underlying.load(std::memory_order_acquire));
+
+               if (ptr == nullptr) {
+                       std::unique_lock<std::mutex> lock (m_Mutex);
+
+                       ptr = m_Underlying.load(std::memory_order_acquire);
+
+                       if (ptr == nullptr) {
+                               ptr = new T(m_Initializer());
+                               m_Underlying.store(ptr, std::memory_order_release);
+                       }
+               }
+
+               return *ptr;
+       }
+
+private:
+       std::function<T()> m_Initializer;
+       std::mutex m_Mutex;
+       std::atomic<T*> m_Underlying;
+};
+
+}
+
+#endif /* LAZY_INIT */