Panagiotis Christopoulos Charitos 13 лет назад
Родитель
Сommit
0e112046ea
2 измененных файлов с 108 добавлено и 113 удалено
  1. 28 113
      include/anki/util/Memory.h
  2. 80 0
      src/util/Memory.cpp

+ 28 - 113
include/anki/util/Memory.h

@@ -1,7 +1,9 @@
 #ifndef ANKI_UTIL_MEMORY_H
 #define ANKI_UTIL_MEMORY_H
 
-#include "anki/util/Allocator.h"
+#include "anki/util/StdTypes.h"
+#include "anki/util/NonCopyable.h"
+#include <atomic>
 
 namespace anki {
 
@@ -10,132 +12,45 @@ namespace anki {
 /// @addtogroup memory
 /// @{
 
-#if 0
-
-/// Function that imitates the new operator. The function allocates memory for
-/// a number of elements and calls their constructor. The interesting thing is
-/// that if the elements size is >1 then it allocates size bigger than the
-/// required. The extra chunk is a number that will be used in
-/// deleteObjectArray to identify the number of elements that were allocated
-template<typename T, typename Alloc = Allocator<T>>
-struct New
-{
-	PtrSize n; ///< Number of elements
-	Alloc alloc; ///< The allocator
-
-	New(PtrSize n_ = 1, const Alloc& alloc_ = Alloc())
-		: n(n_), alloc(alloc_)
-	{}
-
-	template<typename... Args>
-	T* operator()(Args&&... args)
-	{
-		ANKI_ASSERT(n != 0);
-		T* out;
-
-		// If the number of elements is then do a simple allocaton
-		if(n == 1)
-		{
-			out = alloc.allocate(n);
-		}
-		else
-		{
-			// Allocate a memory block that includes the array size
-			typedef typename Alloc::template rebind<U8>::other CharAlloc;
-			CharAlloc charAlloc(alloc);
-			U8* mem = charAlloc.allocate(sizeof(PtrSize) + n * sizeof(T));
-
-			// Set the size of the block
-			*(PtrSize*)mem = n;
-
-			// Set the output address
-			out = (T*)(mem + sizeof(PtrSize));
-		}
-
-		// Call the constuctors
-		for(PtrSize i = 0; i < n; i++)
-		{
-			alloc.construct(&out[i], std::forward<Args>(args)...);
-		}
-
-		// Return result
-		return out;
-	}
-};
-
-/// Function that imitates the delete operator
-template<typename T, typename Alloc = Allocator<T>>
-struct Delete
+/// Thread safe memory pool
+class StackedMemoryPool: public NonCopyable
 {
-	Alloc alloc;
+public:
+	/// Default constructor
+	StackedMemoryPool(PtrSize size, U32 alignmentBits = 16);
 
-	Delete(const Alloc& alloc_ = Alloc())
-		: alloc(alloc_)
-	{}
+	/// Move
+	StackedMemoryPool(StackedMemoryPool&& other);
 
-	void operator()(void* ptr)
-	{
-		T* p = (T*)ptr;
+	~StackedMemoryPool();
 
-		// Make sure the type is defined
-		typedef U8 TypeMustBeComplete[sizeof(T) ? 1 : -1];
-		(void) sizeof(TypeMustBeComplete);
+	/// Allocate memory in StackedMemoryPool
+	void* allocate(PtrSize size) throw();
 
-		if(p)
-		{
-			// Rebind allocator because the Alloc may be of another type
-			typename Alloc::template rebind<T>::other alloc(alloc);
+	/// Free memory in StackedMemoryPool
+	Bool free(void* ptr) throw();
 
-			// Call the destructor
-			alloc.destroy(p);
+private:
+	/// Allocated memory
+	U8* memory = nullptr;
 
-			// Deallocate
-			alloc.deallocate(p, 1);
-		}
-	}
-};
+	/// Size of the allocated memory
+	PtrSize memsize = 0;
 
-/// Function that imitates the delete[] operator
-template<typename T, typename Alloc = Allocator<T>>
-struct DeleteArray
-{
-	Alloc alloc;
+	/// Points to the memory and more specifically to the address of the next
+	/// allocation
+	std::atomic<U8*> ptr = {nullptr};
 
-	DeleteArray(const Alloc& alloc_ = Alloc())
-		: alloc(alloc_)
-	{}
+	/// Alignment
+	U32 alignmentBits;
 
-	void operator()(void* ptr)
+	/// Calculate tha aligned size
+	PtrSize calcAlignSize(PtrSize size) const
 	{
-		// Make sure the type is defined
-		typedef U8 TypeMustBeComplete[sizeof(T) ? 1 : -1];
-		(void) sizeof(TypeMustBeComplete);
-
-		T* p = (T*)ptr;
-
-		if(p)
-		{
-			// Get the allocated block
-			U8* block = (U8*)(p) - sizeof(PtrSize);
-
-			// Get number of elements
-			const PtrSize n = *(PtrSize*)block;
-
-			// Call the destructors
-			for(PtrSize i = 0; i < n; i++)
-			{
-				alloc.destroy(&p[i]);
-			}
-
-			// Deallocate the block
-			typename Alloc::template rebind<U8>::other allocc(alloc);
-			allocc.deallocate(block, n * sizeof(T) + sizeof(PtrSize));
-		}
+		return size + (size % (alignmentBits / 8));
 	}
 };
 
-#endif
-
 /// @}
 /// @}
 

+ 80 - 0
src/util/Memory.cpp

@@ -0,0 +1,80 @@
+#include "anki/util/Memory.h"
+#include "anki/util/Assert.h"
+#include "anki/util/Exception.h"
+#include <limits>
+#include <cstdlib>
+
+namespace anki {
+
+//==============================================================================
+struct StackedMemoryPoolBlock
+{
+	U32 size;
+};
+
+//==============================================================================
+StackedMemoryPool::StackedMemoryPool(PtrSize size_, U32 alignmentBits_)
+	: memsize(size_), alignmentBits(alignmentBits_)
+{
+	ANKI_ASSERT(memsize > 0);
+	memory = (U8*)::malloc(memsize);
+
+	if(memory != nullptr)
+	{
+		ptr = memory;
+	}
+	else
+	{
+		throw ANKI_EXCEPTION("malloc() failed");
+	}
+}
+
+//==============================================================================
+void* StackedMemoryPool::allocate(PtrSize size_) throw()
+{
+	PtrSize size = calcAlignSize(size_ + sizeof(StackedMemoryPoolBlock));
+
+	ANKI_ASSERT(size < std::numeric_limits<U32>::max() && "Too big allocation");
+
+	U8* out = ptr.fetch_add(size);
+
+	if(out + size <= memory + memsize)
+	{
+		// Write the block
+		((StackedMemoryPoolBlock*)out)->size = size;
+
+		// Set the correct output
+		out += sizeof(StackedMemoryPoolBlock);
+	}
+	else
+	{
+		// Error
+		out = nullptr;
+	}
+
+	return out;
+}
+
+//==============================================================================
+Bool StackedMemoryPool::free(void* p) throw()
+{
+	// Correct the p
+	U8* realp = (U8*)p - sizeof(StackedMemoryPoolBlock);
+
+	// Get block size
+	U32 size = ((StackedMemoryPoolBlock*)realp)->size;
+
+	// Atomic stuff
+	U8* expected = realp + size;
+	U8* desired = realp;
+
+	// if(ptr == expected)
+	//     ptr = desired
+	// else
+	//     expected = ptr
+	Bool exchange = ptr.compare_exchange_strong(expected, desired);
+
+	return exchange;
+}
+
+} // end namespace anki