Browse Source

Minor singleton optimizations

Panagiotis Christopoulos Charitos 2 years ago
parent
commit
8627cee45b

+ 17 - 0
AnKi/Ui/Common.cpp

@@ -0,0 +1,17 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <AnKi/Ui/Common.h>
+#include <AnKi/Ui/UiObject.h>
+
+namespace anki {
+
+void UiObjectDeleter::operator()(UiObject* x)
+{
+	x->~UiObject();
+	UiMemoryPool::getSingleton().free(x);
+}
+
+} // end namespace anki

+ 3 - 8
AnKi/Ui/Common.h

@@ -43,27 +43,22 @@ private:
 
 ANKI_DEFINE_SUBMODULE_UTIL_CONTAINERS(Ui, UiMemoryPool)
 
-template<typename T>
 class UiObjectDeleter
 {
 public:
-	void operator()(T* x)
-	{
-		static_cast<UiObject*>(x)->~UiObject();
-		UiMemoryPool::getSingleton().free(x);
-	}
+	void operator()(UiObject* x);
 };
 
 #define ANKI_UI_OBJECT_FW(className) \
 	class className; \
-	using className##Ptr = IntrusivePtr<className, UiObjectDeleter<className>>;
+	using className##Ptr = IntrusivePtr<className, UiObjectDeleter>;
 
 ANKI_UI_OBJECT_FW(Font)
 ANKI_UI_OBJECT_FW(Canvas)
 ANKI_UI_OBJECT_FW(UiImmediateModeBuilder)
 #undef ANKI_UI_OBJECT
 
-using UiObjectPtr = IntrusivePtr<UiObject, UiObjectDeleter<UiObject>>;
+using UiObjectPtr = IntrusivePtr<UiObject, UiObjectDeleter>;
 
 class UiExternalSubsystems
 {

+ 2 - 2
AnKi/Ui/UiManager.h

@@ -30,7 +30,7 @@ public:
 
 	/// Create a new UI object.
 	template<typename T, typename Y, typename... Args>
-	Error newInstance(IntrusivePtr<Y, UiObjectDeleter<Y>>& ptr, Args&&... args)
+	Error newInstance(IntrusivePtr<Y, UiObjectDeleter>& ptr, Args&&... args)
 	{
 		T* p = anki::newInstance<T>(UiMemoryPool::getSingleton());
 		ptr.reset(static_cast<Y*>(p));
@@ -39,7 +39,7 @@ public:
 
 	/// Create a new UI object.
 	template<typename T, typename... Args>
-	Error newInstance(IntrusivePtr<T, UiObjectDeleter<T>>& ptr, Args&&... args)
+	Error newInstance(IntrusivePtr<T, UiObjectDeleter>& ptr, Args&&... args)
 	{
 		ptr.reset(anki::newInstance<T>(UiMemoryPool::getSingleton()));
 		return ptr->init(args...);

+ 0 - 3
AnKi/Ui/UiObject.h

@@ -15,9 +15,6 @@ namespace anki {
 /// The base of all UI objects.
 class UiObject
 {
-	template<typename>
-	friend class UiObjectDeleter;
-
 public:
 	virtual ~UiObject() = default;
 

+ 49 - 0
AnKi/Util/Singleton.h

@@ -22,6 +22,55 @@ extern I32 g_singletonsAllocated;
 template<typename T>
 class MakeSingleton
 {
+public:
+	ANKI_FORCE_INLINE static T& getSingleton()
+	{
+		ANKI_ASSERT(m_initialized);
+		return *reinterpret_cast<T*>(m_global);
+	}
+
+	template<typename... TArgs>
+	static T& allocateSingleton(TArgs... args)
+	{
+		ANKI_ASSERT(!m_initialized);
+		::new(m_global) T(args...);
+		m_initialized = true;
+#if ANKI_ENABLE_ASSERTIONS
+		++g_singletonsAllocated;
+#endif
+
+		return *reinterpret_cast<T*>(m_global);
+	}
+
+	static void freeSingleton()
+	{
+		if(m_initialized)
+		{
+			reinterpret_cast<T*>(m_global)->~T();
+			m_initialized = false;
+#if ANKI_ENABLE_ASSERTIONS
+			--g_singletonsAllocated;
+#endif
+		}
+	}
+
+	static Bool isAllocated()
+	{
+		return m_initialized;
+	}
+
+private:
+	static U8 m_global[];
+	static inline Bool m_initialized = false;
+};
+
+template<typename T>
+alignas(alignof(T)) U8 MakeSingleton<T>::m_global[sizeof(T)];
+
+/// If class inherits that it will become a singleton.
+template<typename T>
+class MakeSingletonPtr
+{
 public:
 	ANKI_FORCE_INLINE static T& getSingleton()
 	{

+ 4 - 4
AnKi/Window/Input.h

@@ -23,10 +23,10 @@ enum class InputEvent : U8
 
 /// Handle the input and other events
 /// @note All positions are in NDC space
-class Input : public MakeSingleton<Input>
+class Input : public MakeSingletonPtr<Input>
 {
 	template<typename>
-	friend class MakeSingleton;
+	friend class MakeSingletonPtr;
 
 public:
 	Error init();
@@ -163,9 +163,9 @@ protected:
 
 template<>
 template<>
-Input& MakeSingleton<Input>::allocateSingleton<>();
+Input& MakeSingletonPtr<Input>::allocateSingleton<>();
 
 template<>
-void MakeSingleton<Input>::freeSingleton();
+void MakeSingletonPtr<Input>::freeSingleton();
 
 } // end namespace anki

+ 2 - 2
AnKi/Window/InputAndroid.cpp

@@ -11,7 +11,7 @@ namespace anki {
 
 template<>
 template<>
-Input& MakeSingleton<Input>::allocateSingleton<>()
+Input& MakeSingletonPtr<Input>::allocateSingleton<>()
 {
 	ANKI_ASSERT(m_global == nullptr);
 	m_global = new InputAndroid;
@@ -24,7 +24,7 @@ Input& MakeSingleton<Input>::allocateSingleton<>()
 }
 
 template<>
-void MakeSingleton<Input>::freeSingleton()
+void MakeSingletonPtr<Input>::freeSingleton()
 {
 	if(m_global)
 	{

+ 2 - 2
AnKi/Window/InputDummy.cpp

@@ -10,7 +10,7 @@ namespace anki {
 
 template<>
 template<>
-Input& MakeSingleton<Input>::allocateSingleton<>()
+Input& MakeSingletonPtr<Input>::allocateSingleton<>()
 {
 	ANKI_ASSERT(m_global == nullptr);
 	m_global = new Input;
@@ -23,7 +23,7 @@ Input& MakeSingleton<Input>::allocateSingleton<>()
 }
 
 template<>
-void MakeSingleton<Input>::freeSingleton()
+void MakeSingletonPtr<Input>::freeSingleton()
 {
 	if(m_global)
 	{

+ 2 - 2
AnKi/Window/InputSdl.cpp

@@ -50,7 +50,7 @@ static KeyCode sdlKeytoAnKi(SDL_Keycode sdlk)
 
 template<>
 template<>
-Input& MakeSingleton<Input>::allocateSingleton<>()
+Input& MakeSingletonPtr<Input>::allocateSingleton<>()
 {
 	ANKI_ASSERT(m_global == nullptr);
 	m_global = new InputSdl;
@@ -63,7 +63,7 @@ Input& MakeSingleton<Input>::allocateSingleton<>()
 }
 
 template<>
-void MakeSingleton<Input>::freeSingleton()
+void MakeSingletonPtr<Input>::freeSingleton()
 {
 	if(m_global)
 	{

+ 4 - 4
AnKi/Window/NativeWindow.h

@@ -31,10 +31,10 @@ public:
 };
 
 /// Native window.
-class NativeWindow : public MakeSingleton<NativeWindow>
+class NativeWindow : public MakeSingletonPtr<NativeWindow>
 {
 	template<typename>
-	friend class MakeSingleton;
+	friend class MakeSingletonPtr;
 
 public:
 	Error init(const NativeWindowInitInfo& inf);
@@ -71,9 +71,9 @@ protected:
 
 template<>
 template<>
-NativeWindow& MakeSingleton<NativeWindow>::allocateSingleton<>();
+NativeWindow& MakeSingletonPtr<NativeWindow>::allocateSingleton<>();
 
 template<>
-void MakeSingleton<NativeWindow>::freeSingleton();
+void MakeSingletonPtr<NativeWindow>::freeSingleton();
 
 } // end namespace anki

+ 2 - 2
AnKi/Window/NativeWindowAndroid.cpp

@@ -9,7 +9,7 @@ namespace anki {
 
 template<>
 template<>
-NativeWindow& MakeSingleton<NativeWindow>::allocateSingleton<>()
+NativeWindow& MakeSingletonPtr<NativeWindow>::allocateSingleton<>()
 {
 	ANKI_ASSERT(m_global == nullptr);
 	m_global = new NativeWindowAndroid();
@@ -20,7 +20,7 @@ NativeWindow& MakeSingleton<NativeWindow>::allocateSingleton<>()
 }
 
 template<>
-void MakeSingleton<NativeWindow>::freeSingleton()
+void MakeSingletonPtr<NativeWindow>::freeSingleton()
 {
 	if(m_global)
 	{

+ 2 - 2
AnKi/Window/NativeWindowHeadless.cpp

@@ -9,7 +9,7 @@ namespace anki {
 
 template<>
 template<>
-NativeWindow& MakeSingleton<NativeWindow>::allocateSingleton<>()
+NativeWindow& MakeSingletonPtr<NativeWindow>::allocateSingleton<>()
 {
 	ANKI_ASSERT(m_global == nullptr);
 	m_global = new NativeWindowHeadless();
@@ -20,7 +20,7 @@ NativeWindow& MakeSingleton<NativeWindow>::allocateSingleton<>()
 }
 
 template<>
-void MakeSingleton<NativeWindow>::freeSingleton()
+void MakeSingletonPtr<NativeWindow>::freeSingleton()
 {
 	if(m_global)
 	{

+ 2 - 2
AnKi/Window/NativeWindowSdl.cpp

@@ -13,7 +13,7 @@ namespace anki {
 
 template<>
 template<>
-NativeWindow& MakeSingleton<NativeWindow>::allocateSingleton<>()
+NativeWindow& MakeSingletonPtr<NativeWindow>::allocateSingleton<>()
 {
 	ANKI_ASSERT(m_global == nullptr);
 	m_global = new NativeWindowSdl();
@@ -24,7 +24,7 @@ NativeWindow& MakeSingleton<NativeWindow>::allocateSingleton<>()
 }
 
 template<>
-void MakeSingleton<NativeWindow>::freeSingleton()
+void MakeSingletonPtr<NativeWindow>::freeSingleton()
 {
 	if(m_global)
 	{

+ 1 - 1
Tests/Ui/Ui.cpp

@@ -87,7 +87,7 @@ ANKI_TEST(Ui, Ui)
 		CanvasPtr canvas;
 		ANKI_TEST_EXPECT_NO_ERR(ui->newInstance(canvas, font, 20, win->getWidth(), win->getHeight()));
 
-		IntrusivePtr<Label, UiObjectDeleter<Label>> label;
+		IntrusivePtr<Label, UiObjectDeleter> label;
 		ANKI_TEST_EXPECT_NO_ERR(ui->newInstance(label));
 
 		Bool done = false;