summaryrefslogtreecommitdiff
path: root/src/components/utils/include/utils/singleton.h
diff options
context:
space:
mode:
authorJustin Dickow <jjdickow@gmail.com>2014-10-20 17:44:41 -0400
committerJustin Dickow <jjdickow@gmail.com>2014-10-20 17:44:41 -0400
commit34e7256493ff0e6594029b9857d7e2aa31f5dbeb (patch)
tree367306b507c52d3af211533810adbc22004e0192 /src/components/utils/include/utils/singleton.h
parent2eef966e9b5fd4d94dd98820095eb765e200c64b (diff)
downloadsdl_core-34e7256493ff0e6594029b9857d7e2aa31f5dbeb.tar.gz
SDL 3.8!
Signed-off-by: Justin Dickow <jjdickow@gmail.com>
Diffstat (limited to 'src/components/utils/include/utils/singleton.h')
-rw-r--r--src/components/utils/include/utils/singleton.h179
1 files changed, 179 insertions, 0 deletions
diff --git a/src/components/utils/include/utils/singleton.h b/src/components/utils/include/utils/singleton.h
new file mode 100644
index 0000000000..d7b625e0a1
--- /dev/null
+++ b/src/components/utils/include/utils/singleton.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2013, Ford Motor Company
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Ford Motor Company nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef SRC_COMPONENTS_UTILS_INCLUDE_UTILS_SINGLETON_H_
+#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_SINGLETON_H_
+
+#include "utils/lock.h"
+#include "utils/memory_barrier.h"
+#include "utils/atomic.h"
+
+namespace utils {
+
+namespace deleters {
+
+class DummyDeleter {
+ public:
+ void grab(void* pointer) {
+ }
+};
+
+template<typename T>
+class Deleter {
+ public:
+ Deleter() : pointer_(0) {
+ }
+ ~Deleter() {
+ if (pointer_) {
+ delete pointer_;
+ }
+ }
+ void grab(T* pointer) {
+ pointer_ = pointer;
+ }
+ private:
+ T* pointer_;
+};
+
+} // namespace deleters
+
+template<typename T, class Deleter = deleters::DummyDeleter>
+class Singleton {
+/**
+ * @brief Singleton template
+ * Singleton classes must derive from this template specialized with class itself:
+ *
+ * class MySingleton : public Singleton<MySingleton> {...};
+ *
+ * All such classes must declare instance() method as friend
+ * by adding FRIEND_BASE_SINGLETON_CLASS macro from macro.h to class definition:
+ *
+ * FRIEND_BASE_SINGLETON_CLASS(MySingleton);
+ *
+ * Instance of this class (if created) can be deleted by Deleter destructor
+ * which is called after main() (or from exit())
+ * This requires T destructor to be accessible for Deleter (e.g. public)
+ * Deleter template parameter can be specified with any class
+ * with public default constructor, destructor and method
+ * void grab(T*);
+ * However, default Deleter specification does nothing
+ *
+ * Also instance can be deleted explicitly by calling destroy() method
+ *
+ * Both instance() and destroy() methods are thread safe
+ * but not thread safety between simultaneous calls
+ * of instance() and destroy() is cared about
+ */
+ public:
+/**
+ * @brief Returns the singleton of class
+ */
+ static T* instance();
+/**
+ * @brief Destroys the singleton (if it had been created)
+ */
+ static void destroy();
+/**
+ * @brief Checks whether the singleton exists
+ */
+ static bool exists();
+
+ private:
+
+ static T** instance_pointer();
+ static Deleter* deleter();
+};
+
+template<typename T, class Deleter>
+T* Singleton<T, Deleter>::instance() {
+ static sync_primitives::Lock lock;
+
+ T* local_instance;
+ atomic_pointer_assign(local_instance, *instance_pointer());
+ memory_barrier();
+
+ if (!local_instance) {
+ lock.Acquire();
+ local_instance = *instance_pointer();
+ if (!local_instance) {
+ local_instance = new T();
+ memory_barrier();
+ atomic_pointer_assign(*instance_pointer(), local_instance);
+ deleter()->grab(local_instance);
+ }
+ lock.Release();
+ }
+
+ return local_instance;
+}
+
+template<typename T, class Deleter>
+void Singleton<T, Deleter>::destroy() {
+ static sync_primitives::Lock lock;
+
+ T* local_instance;
+ atomic_pointer_assign(local_instance, *instance_pointer());
+ memory_barrier();
+
+ if (local_instance) {
+ lock.Acquire();
+ local_instance = *instance_pointer();
+ if (local_instance) {
+ atomic_pointer_assign(*instance_pointer(), 0);
+ memory_barrier();
+ delete local_instance;
+ deleter()->grab(0);
+ }
+ lock.Release();
+ }
+}
+
+template<typename T, class Deleter>
+bool Singleton<T, Deleter>::exists() {
+ return *instance_pointer() != 0;
+}
+
+template<typename T, class Deleter>
+T** Singleton<T, Deleter>::instance_pointer() {
+ static T* instance = 0;
+ return &instance;
+}
+
+template<typename T, class Deleter>
+Deleter* Singleton<T, Deleter>::deleter() {
+ static Deleter deleter;
+ return &deleter;
+}
+
+} // namespace utils
+
+#endif // SRC_COMPONENTS_UTILS_INCLUDE_UTILS_SINGLETON_H_