src: Yearly copyright bump
[quassel.git] / src / common / singleton.h
index b3e4dfd..d051b4c 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005-2018 by the Quassel Project                        *
+ *   Copyright (C) 2005-2019 by the Quassel Project                        *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
 
 #pragma once
 
-#include <QtGlobal>
+#include <iostream>
+
+// For Windows DLLs, we must not export the template function.
+// For other systems, we must, otherwise the local static variables won't work across library boundaries...
+#ifndef Q_OS_WIN
+#    include "common-export.h"
+#    define QUASSEL_SINGLETON_EXPORT COMMON_EXPORT
+#else
+#    define QUASSEL_SINGLETON_EXPORT
+#endif
+
+namespace detail {
+
+// This needs to be a free function instead of a member function of Singleton, because
+// - MSVC can't deal with static attributes in an exported template class
+// - Clang produces weird and unreliable results for local static variables in static member functions
+//
+// We need to export the function on anything not using Windows DLLs, otherwise local static members don't
+// work across library boundaries.
+template<typename T>
+QUASSEL_SINGLETON_EXPORT T* getOrSetInstance(T* instance = nullptr, bool destroyed = false)
+{
+    static T* _instance = instance;
+    static bool _destroyed = destroyed;
+
+    if (destroyed) {
+        _destroyed = true;
+        return _instance = nullptr;
+    }
+    if (instance) {
+        if (_destroyed) {
+            std::cerr << "Trying to reinstantiate a destroyed singleton, this must not happen!\n";
+            abort();  // This produces a backtrace, which is highly useful for finding the culprit
+        }
+        if (_instance != instance) {
+            std::cerr << "Trying to reinstantiate a singleton that is already instantiated, this must not happen!\n";
+            abort();
+        }
+    }
+    if (!_instance) {
+        std::cerr << "Trying to access a singleton that has not been instantiated yet!\n";
+        abort();
+    }
+    return _instance;
+}
+
+}  // detail
 
 /**
  * Mixin class for "pseudo" singletons.
@@ -47,24 +93,16 @@ public:
      *
      * @param instance Pointer to the instance being created, i.e. the 'this' pointer of the parent class
      */
-    Singleton(T *instance)
+    Singleton(Tinstance)
     {
-        if (_destroyed) {
-            qFatal("Trying to reinstantiate a destroyed singleton, this must not happen!");
-            abort();  // This produces a backtrace, which is highly useful for finding the culprit
-        }
-        if (_instance) {
-            qFatal("Trying to reinstantiate a singleton that is already instantiated, this must not happen!");
-            abort();
-        }
-        _instance = instance;
+        detail::getOrSetInstance<T>(instance);
     }
 
     // Satisfy Rule of Five
-    Singleton(const Singleton &) = delete;
-    Singleton(Singleton &&) = delete;
-    Singleton &operator=(const Singleton &) = delete;
-    Singleton &operator=(Singleton &&) = delete;
+    Singleton(const Singleton&) = delete;
+    Singleton(Singleton&&) = delete;
+    Singleton& operator=(const Singleton&) = delete;
+    Singleton& operator=(Singleton&&) = delete;
 
     /**
      * Destructor.
@@ -73,8 +111,7 @@ public:
      */
     ~Singleton()
     {
-        _instance = nullptr;
-        _destroyed = true;
+        detail::getOrSetInstance<T>(nullptr, true);
     }
 
     /**
@@ -85,23 +122,8 @@ public:
      *
      * @returns A pointer to the instance
      */
-    static T *instance()
+    static Tinstance()
     {
-        if (_instance) {
-            return _instance;
-        }
-        qFatal("Trying to access a singleton that has not been instantiated yet");
-        abort();
+        return detail::getOrSetInstance<T>();
     }
-
-private:
-    static T *_instance;
-    static bool _destroyed;
-
 };
-
-template<typename T>
-T *Singleton<T>::_instance{nullptr};
-
-template<typename T>
-bool Singleton<T>::_destroyed{false};