Browse Source

Rework some of the element instancers and the pool. Use pools for assigning plain Elements and ElementTextDefault.

Michael Ragazzon 6 years ago
parent
commit
25b8b45ca7

+ 0 - 2
Cmake/FileList.cmake

@@ -128,8 +128,6 @@ set(Core_PUB_HDR_FILES
     ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Element.inl
     ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/ElementDocument.h
     ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/ElementInstancer.h
-    ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/ElementInstancerGeneric.h
-    ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/ElementInstancerGeneric.inl
     ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/ElementScroll.h
     ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/ElementText.h
     ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/ElementUtilities.h

+ 0 - 1
Include/RmlUi/Core/Core.h

@@ -42,7 +42,6 @@
 #include "Element.h"
 #include "ElementDocument.h"
 #include "ElementInstancer.h"
-#include "ElementInstancerGeneric.h"
 #include "ElementScroll.h"
 #include "ElementText.h"
 #include "ElementUtilities.h"

+ 59 - 4
Include/RmlUi/Core/ElementInstancer.h

@@ -40,15 +40,16 @@ class Element;
 
 /**
 	An element instancer provides a method for allocating
-	an deallocating elements.
-
-	Node handlers are reference counted, so that the same handler
-	can be used for multiple tags.
+	and deallocating elements.
 
 	It is important at the same instancer that allocated
 	the element releases it. This ensures there are no
 	issues with memory from different DLLs getting mixed up.
 
+	The returned element is a unique pointer. When this is
+	destroyed, it will call	ReleaseElement on the instancer 
+	in which it was instanced.
+
 	@author Lloyd Weehuizen
  */ 
 
@@ -61,12 +62,66 @@ public:
 	/// @param[in] parent The element the new element is destined to be parented to.
 	/// @param[in] tag The tag of the element to instance.
 	/// @param[in] attributes Dictionary of attributes.
+	/// @return A unique pointer to the instanced element.
 	virtual ElementPtr InstanceElement(Element* parent, const String& tag, const XMLAttributes& attributes) = 0;
 	/// Releases an element instanced by this instancer.
 	/// @param[in] element The element to release.
 	virtual void ReleaseElement(Element* element) = 0;
 };
 
+
+
+/**
+	The element instancer constructs a plain Element, and is used for most elements.
+	This is a slightly faster version of the generic instancer, making use of a memory
+	pool for allocations.
+ */
+
+class RMLUICORE_API ElementInstancerElement : public ElementInstancer
+{
+public:
+	ElementPtr InstanceElement(Element* parent, const String& tag, const XMLAttributes& attributes) override;
+	void ReleaseElement(Element* element) override;
+};
+
+/**
+	The element text default instancer constructs ElementTextDefault.
+	This is a slightly faster version of the generic instancer, making use of a memory
+	pool for allocations.
+ */
+
+class RMLUICORE_API ElementInstancerTextDefault : public ElementInstancer
+{
+public:
+	ElementPtr InstanceElement(Element* parent, const String& tag, const XMLAttributes& attributes) override;
+	void ReleaseElement(Element* element) override;
+};
+
+
+/**
+	Generic Instancer that creates the provided element type using new and delete. This instancer
+	is typically used specialized element types.
+ */
+
+template <typename T>
+class ElementInstancerGeneric : public ElementInstancer
+{
+public:
+	virtual ~ElementInstancerGeneric() {}
+
+	ElementPtr InstanceElement(Element* parent, const String& tag, const XMLAttributes& attributes) override 
+	{
+		RMLUI_ZoneScopedN("ElementGenericInstance");
+		return ElementPtr(new T(tag));
+	}
+
+	void ReleaseElement(Element* element) override
+	{
+		RMLUI_ZoneScopedN("ElementGenericRelease");
+		delete element;
+	}
+};
+
 }
 }
 

+ 0 - 67
Include/RmlUi/Core/ElementInstancerGeneric.h

@@ -1,67 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-#ifndef RMLUICOREELEMENTINSTANCERGENERIC_H
-#define RMLUICOREELEMENTINSTANCERGENERIC_H
-
-#include "ElementInstancer.h"
-
-namespace Rml {
-namespace Core {
-
-/**
-	Generic Instancer that creates a plain old Element
-
-	This instancer is used for most elements and is by default
-	registered as the "*" fallback handler.
-
-	@author Lloyd Weehuizen
- */
-
-template <typename T>
-class ElementInstancerGeneric : public ElementInstancer
-{
-public:
-	virtual ~ElementInstancerGeneric();
-	
-	/// Instances an element given the tag name and attributes
-	/// @param tag Name of the element to instance
-	/// @param attributes vector of name value pairs
-	ElementPtr InstanceElement(Element* parent, const String& tag, const XMLAttributes& attributes) override;
-
-	/// Releases the given element
-	/// @param element to release
-	void ReleaseElement(Element* element) override;
-};
-
-}
-}
-
-#include "ElementInstancerGeneric.inl"
-
-#endif

+ 0 - 56
Include/RmlUi/Core/ElementInstancerGeneric.inl

@@ -1,56 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-namespace Rml {
-namespace Core {
-
-template <typename T>
-ElementInstancerGeneric<T>::~ElementInstancerGeneric()
-{
-}
-
-// Instances an element given the tag name and attributes
-template <typename T>
-ElementPtr ElementInstancerGeneric<T>::InstanceElement(Element* /*parent*/, const String& tag, const XMLAttributes& /*attributes*/)
-{
-	RMLUI_ZoneScopedN("ElementInstance");
-	return ElementPtr(new T(tag));
-}
-
-
-
-// Releases the given element
-template <typename T>
-void ElementInstancerGeneric<T>::ReleaseElement(Element* element)
-{
-	RMLUI_ZoneScopedN("ElementRelease");
-	delete element;
-}
-
-}
-}

+ 1 - 1
Source/Controls/Controls.cpp

@@ -27,7 +27,7 @@
  */
 
 #include "../../Include/RmlUi/Controls/Controls.h"
-#include "../../Include/RmlUi/Core/ElementInstancerGeneric.h"
+#include "../../Include/RmlUi/Core/ElementInstancer.h"
 #include "../../Include/RmlUi/Core/Factory.h"
 #include "../../Include/RmlUi/Core/StyleSheetSpecification.h"
 #include "../../Include/RmlUi/Core/XMLParser.h"

+ 4 - 23
Source/Core/Element.cpp

@@ -86,11 +86,6 @@ public:
 // Determines how many levels up in the hierarchy the OnChildAdd and OnChildRemove are called (starting at the child itself)
 static constexpr int ChildNotifyLevels = 2;
 
-
-struct ElementMetaChunk;
-static Pool< ElementMetaChunk > element_meta_chunk_pool(200, true);
-
-
 // Meta objects for element collected in a single struct to reduce memory allocations
 struct ElementMeta 
 {
@@ -102,24 +97,10 @@ struct ElementMeta
 	ElementDecoration decoration;
 	ElementScroll scroll;
 	Style::ComputedValues computed_values;
+};
 
-	void* operator new(size_t size)
-	{
-		void* memory = element_meta_chunk_pool.AllocateObject();
-		return memory;
-	}
-	void operator delete(void* chunk)
-	{
-		element_meta_chunk_pool.DeallocateObject((ElementMetaChunk*)chunk);
-	}
-}; 
 
-struct alignas(ElementMeta) ElementMetaChunk
-{
-	ElementMetaChunk() { memset(buffer, 0, size); }
-	static constexpr size_t size = sizeof(ElementMeta);
-	char buffer[size];
-};
+static Pool< ElementMeta > element_meta_chunk_pool(200, true);
 
 
 /// Constructs a new RmlUi element.
@@ -157,7 +138,7 @@ transform_state(), transform_state_perspective_dirty(true), transform_state_tran
 	clipping_enabled = false;
 	clipping_state_dirty = true;
 
-	element_meta = new ElementMeta(this);
+	element_meta = element_meta_chunk_pool.AllocateAndConstruct(this);
 
 	event_dispatcher = &element_meta->event_dispatcher;
 	style = &element_meta->style;
@@ -189,7 +170,7 @@ Element::~Element()
 	children.clear();
 	num_non_dom_children = 0;
 
-	delete element_meta;
+	element_meta_chunk_pool.DestroyAndDeallocate(element_meta);
 }
 
 void Element::Update(float dp_ratio)

+ 28 - 0
Source/Core/ElementInstancer.cpp

@@ -29,6 +29,8 @@
 #include "precompiled.h"
 #include "../../Include/RmlUi/Core/ElementInstancer.h"
 #include "XMLParseTools.h"
+#include "Pool.h"
+#include "ElementTextDefault.h"
 
 namespace Rml {
 namespace Core {
@@ -37,5 +39,31 @@ ElementInstancer::~ElementInstancer()
 {
 }
 
+static Pool< Element > pool_element(200, true);
+static Pool< ElementTextDefault > pool_text_default(200, true);
+
+
+ElementPtr ElementInstancerElement::InstanceElement(Element* /*parent*/, const String& tag, const XMLAttributes& /*attributes*/)
+{
+	Element* ptr = pool_element.AllocateAndConstruct(tag);
+	return ElementPtr(ptr);
+}
+
+void ElementInstancerElement::ReleaseElement(Element* element)
+{
+	pool_element.DestroyAndDeallocate(element);
+}
+
+ElementPtr ElementInstancerTextDefault::InstanceElement(Element* /*parent*/, const String& tag, const XMLAttributes& /*attributes*/)
+{
+	ElementTextDefault* ptr = pool_text_default.AllocateAndConstruct(tag);
+	return ElementPtr(static_cast<Element*>(ptr));
+}
+
+void ElementInstancerTextDefault::ReleaseElement(Element* element)
+{
+	pool_text_default.DestroyAndDeallocate(static_cast<ElementTextDefault*>(element));
+}
+
 }
 }

+ 2 - 2
Source/Core/Factory.cpp

@@ -83,9 +83,9 @@ struct DefaultInstancers {
 	Ptr<ContextInstancer> context_default;
 	Ptr<EventInstancer> event_default;
 
-	Ptr<ElementInstancer> element_default = std::make_unique<ElementInstancerGeneric<Element>>();
+	Ptr<ElementInstancer> element_default = std::make_unique<ElementInstancerElement>();
+	Ptr<ElementInstancer> element_text_default = std::make_unique<ElementInstancerTextDefault>();
 	Ptr<ElementInstancer> element_img = std::make_unique<ElementInstancerGeneric<ElementImage>>();
-	Ptr<ElementInstancer> element_text_default = std::make_unique<ElementInstancerGeneric<ElementTextDefault>>();
 	Ptr<ElementInstancer> element_handle = std::make_unique<ElementInstancerGeneric<ElementHandle>>();
 	Ptr<ElementInstancer> element_body = std::make_unique<ElementInstancerGeneric<ElementDocument>>();
 

+ 4 - 9
Source/Core/LayoutEngine.cpp

@@ -45,15 +45,10 @@ namespace Core {
 
 #define MAX(a, b) (a > b ? a : b)
 
-struct alignas(LayoutBlockBox) LayoutChunk
+struct LayoutChunk
 {
-	LayoutChunk()
-	{
-		memset(buffer, 0, size);
-	}
-
 	static const unsigned int size = MAX(sizeof(LayoutBlockBox), MAX(sizeof(LayoutInlineBox), MAX(sizeof(LayoutInlineBoxText), MAX(sizeof(LayoutLineBox), sizeof(LayoutBlockBoxSpace)))));
-	char buffer[size];
+	alignas(std::max_align_t) char buffer[size];
 };
 
 static Pool< LayoutChunk > layout_chunk_pool(200, true);
@@ -270,12 +265,12 @@ void* LayoutEngine::AllocateLayoutChunk(size_t RMLUI_UNUSED_ASSERT_PARAMETER(siz
 
 	RMLUI_ASSERT(size <= LayoutChunk::size);
 
-	return layout_chunk_pool.AllocateObject();
+	return layout_chunk_pool.AllocateAndConstruct();
 }
 
 void LayoutEngine::DeallocateLayoutChunk(void* chunk)
 {
-	layout_chunk_pool.DeallocateObject((LayoutChunk*) chunk);
+	layout_chunk_pool.DestroyAndDeallocate((LayoutChunk*) chunk);
 }
 
 // Positions a single element and its children within this layout.

+ 13 - 10
Source/Core/Pool.h

@@ -39,15 +39,18 @@ template < typename PoolType >
 class Pool
 {
 private:
-	class PoolNode
+	static constexpr size_t N = sizeof(PoolType);
+	static constexpr size_t A = alignof(PoolType);
+
+	class PoolNode : public NonCopyMoveable
 	{
 	public:
-		PoolType object;
+		alignas(A) unsigned char object[N];
 		PoolNode* previous;
 		PoolNode* next;
 	};
 
-	class PoolChunk
+	class PoolChunk : public NonCopyMoveable
 	{
 	public:
 		PoolNode* chunk;
@@ -111,16 +114,16 @@ public:
 	/// Returns the head of the linked list of allocated objects.
 	inline Iterator Begin();
 
-	/// Attempts to allocate a deallocated object in the memory pool. If
-	/// the process is successful, the newly allocated object is returned.
-	/// If the process fails (due to no free objects being available), nullptr
-	/// is returned.
-	inline PoolType* AllocateObject();
+	/// Attempts to allocate an object into a free slot in the memory pool and construct it using the given arguments.
+	/// If the process is successful, the newly constructed object is returned. Otherwise, if the process fails due to
+	/// no free objects being available, nullptr is returned.
+	template<typename... Args>
+	inline PoolType* AllocateAndConstruct(Args&&... args);
 
 	/// Deallocates the object pointed to by the given iterator.
-	inline void DeallocateObject(Iterator& iterator);
+	inline void DestroyAndDeallocate(Iterator& iterator);
 	/// Deallocates the given object.
-	inline void DeallocateObject(PoolType* object);
+	inline void DestroyAndDeallocate(PoolType* object);
 
 	/// Returns the number of objects in the pool.
 	inline int GetSize() const;

+ 8 - 7
Source/Core/Pool.inl

@@ -89,8 +89,9 @@ typename Pool< PoolType >::Iterator Pool< PoolType >::Begin()
 }
 
 // Attempts to allocate a deallocated object in the memory pool.
-template < typename PoolType >
-PoolType* Pool< PoolType >::AllocateObject()
+template<typename PoolType>
+template<typename ...Args>
+inline PoolType* Pool<PoolType>::AllocateAndConstruct(Args&&... args)
 {
 	// We can't allocate a new object if the deallocated list is empty.
 	if (first_free_node == nullptr)
@@ -133,18 +134,18 @@ PoolType* Pool< PoolType >::AllocateObject()
 
 	first_allocated_node = allocated_object;
 
-	return new (&allocated_object->object) PoolType();
+	return new (allocated_object->object) PoolType(std::forward<Args>(args)...);
 }
 
 // Deallocates the object pointed to by the given iterator.
 template < typename PoolType >
-void Pool< PoolType >::DeallocateObject(Iterator& iterator)
+void Pool< PoolType >::DestroyAndDeallocate(Iterator& iterator)
 {
 	// We're about to deallocate an object.
 	--num_allocated_objects;
 
 	PoolNode* object = iterator.node;
-	object->object.~PoolType();
+	reinterpret_cast<PoolType*>(object->object)->~PoolType();
 
 	// Get the previous and next pointers now, because they will be overwritten
 	// before we're finished.
@@ -182,12 +183,12 @@ void Pool< PoolType >::DeallocateObject(Iterator& iterator)
 
 // Deallocates the given object.
 template < typename PoolType >
-void Pool< PoolType >::DeallocateObject(PoolType* object)
+void Pool< PoolType >::DestroyAndDeallocate(PoolType* object)
 {
 	// This assumes the object has the same address as the node, which will be
 	// true as long as the struct definition does not change.
 	Iterator iterator((PoolNode*) object);
-	DeallocateObject(iterator);
+	DestroyAndDeallocate(iterator);
 }
 
 // Returns the number of objects in the pool.