summaryrefslogtreecommitdiffstats
path: root/external/optick/optick_memory.h
diff options
context:
space:
mode:
Diffstat (limited to 'external/optick/optick_memory.h')
-rw-r--r--external/optick/optick_memory.h419
1 files changed, 419 insertions, 0 deletions
diff --git a/external/optick/optick_memory.h b/external/optick/optick_memory.h
new file mode 100644
index 0000000..45249c6
--- /dev/null
+++ b/external/optick/optick_memory.h
@@ -0,0 +1,419 @@
+#pragma once
+
+#include "optick_common.h"
+
+#if USE_OPTICK
+
+#include <cstring>
+#include <new>
+#include <stdlib.h>
+#include <atomic>
+
+#include <array>
+#include <list>
+#include <string>
+#include <sstream>
+#include <unordered_set>
+#include <unordered_map>
+#include <vector>
+
+namespace Optick
+{
+ class Memory
+ {
+ struct Header
+ {
+ uint64_t size;
+ };
+
+ static std::atomic<uint64_t> memAllocated;
+
+ static void* (*allocate)(size_t);
+ static void (*deallocate)(void* p);
+ public:
+ static OPTICK_INLINE void* Alloc(size_t size)
+ {
+ size_t totalSize = size + sizeof(Header);
+ void *ptr = allocate(totalSize);
+ OPTICK_VERIFY(ptr, "Can't allocate memory", return nullptr);
+
+ Header* header = (Header*)ptr;
+ header->size = totalSize;
+ memAllocated += totalSize;
+
+ return (uint8_t*)ptr + sizeof(Header);
+ }
+
+ static OPTICK_INLINE void Free(void* p)
+ {
+ if (p != nullptr)
+ {
+ uint8_t* basePtr = (uint8_t*)p - sizeof(Header);
+ Header* header = (Header*)basePtr;
+ memAllocated -= header->size;
+ deallocate(basePtr);
+ }
+ }
+
+ static OPTICK_INLINE size_t GetAllocatedSize()
+ {
+ return (size_t)memAllocated;
+ }
+
+ template<class T>
+ static T* New()
+ {
+ return new (Memory::Alloc(sizeof(T))) T();
+ }
+
+ template<class T, class P1>
+ static T* New(P1 p1)
+ {
+ return new (Memory::Alloc(sizeof(T))) T(p1);
+ }
+
+ template<class T, class P1, class P2>
+ static T* New(P1 p1, P2 p2)
+ {
+ return new (Memory::Alloc(sizeof(T))) T(p1, p2);
+ }
+
+ template<class T>
+ static void Delete(T* p)
+ {
+ if (p)
+ {
+ p->~T();
+ Free(p);
+ }
+ }
+
+ static void SetAllocator(void* (*allocateFn)(size_t), void(*deallocateFn)(void*))
+ {
+ allocate = allocateFn;
+ deallocate = deallocateFn;
+ }
+
+ template<typename T>
+ struct Allocator : public std::allocator<T>
+ {
+ Allocator() {}
+ template<class U>
+ Allocator(const Allocator<U>&) {}
+ template<typename U> struct rebind { typedef Allocator<U> other; };
+
+ typename std::allocator<T>::pointer allocate(typename std::allocator<T>::size_type n, typename std::allocator<void>::const_pointer = 0)
+ {
+ return reinterpret_cast<typename std::allocator<T>::pointer>(Memory::Alloc(n * sizeof(T)));
+ }
+
+ void deallocate(typename std::allocator<T>::pointer p, typename std::allocator<T>::size_type)
+ {
+ Memory::Free(p);
+ }
+ };
+ };
+
+ // std::* section
+ template <typename T, size_t _Size> class array : public std::array<T, _Size>{};
+ template <typename T> class vector : public std::vector<T, Memory::Allocator<T>>{};
+ template <typename T> class list : public std::list<T, Memory::Allocator<T>>{};
+ template <typename T> class unordered_set : public std::unordered_set<T, std::hash<T>, std::equal_to<T>, Memory::Allocator<T>>{};
+ template <typename T, typename V> class unordered_map : public std::unordered_map<T, V, std::hash<T>, std::equal_to<T>, Memory::Allocator<std::pair<const T, V>>>{};
+
+ using string = std::basic_string<char, std::char_traits<char>, Memory::Allocator<char>>;
+ using wstring = std::basic_string<wchar_t, std::char_traits<wchar_t>, Memory::Allocator<wchar_t>>;
+
+ using istringstream = std::basic_istringstream<char, std::char_traits<char>, Memory::Allocator<char>>;
+ using ostringstream = std::basic_ostringstream<char, std::char_traits<char>, Memory::Allocator<char>>;
+ using stringstream = std::basic_stringstream<char, std::char_traits<char>, Memory::Allocator<char>>;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ template<class T, uint32 SIZE>
+ struct MemoryChunk
+ {
+ OPTICK_ALIGN_CACHE T data[SIZE];
+ MemoryChunk* next;
+ MemoryChunk* prev;
+
+ MemoryChunk() : next(0), prev(0) {}
+
+ ~MemoryChunk()
+ {
+ MemoryChunk* chunk = this;
+ while (chunk->next)
+ chunk = chunk->next;
+
+ while (chunk != this)
+ {
+ MemoryChunk* toDelete = chunk;
+ chunk = toDelete->prev;
+ Memory::Delete(toDelete);
+ }
+
+ if (prev != nullptr)
+ {
+ prev->next = nullptr;
+ prev = nullptr;
+ }
+ }
+ };
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ template<class T, uint32 SIZE = 16>
+ class MemoryPool
+ {
+ typedef MemoryChunk<T, SIZE> Chunk;
+ Chunk* root;
+ Chunk* chunk;
+ uint32 index;
+
+ OPTICK_INLINE void AddChunk()
+ {
+ index = 0;
+ if (!chunk || !chunk->next)
+ {
+ Chunk* newChunk = Memory::New<Chunk>();
+ if (chunk)
+ {
+ chunk->next = newChunk;
+ newChunk->prev = chunk;
+ chunk = newChunk;
+ }
+ else
+ {
+ root = chunk = newChunk;
+ }
+ }
+ else
+ {
+ chunk = chunk->next;
+ }
+ }
+ public:
+ MemoryPool() : root(nullptr), chunk(nullptr), index(SIZE) {}
+
+ OPTICK_INLINE T& Add()
+ {
+ if (index >= SIZE)
+ AddChunk();
+
+ return chunk->data[index++];
+ }
+
+ OPTICK_INLINE T& Add(const T& item)
+ {
+ return Add() = item;
+ }
+
+ OPTICK_INLINE T* AddRange(const T* items, size_t count, bool allowOverlap = true)
+ {
+ if (count == 0 || (count > SIZE && !allowOverlap))
+ return nullptr;
+
+ if (count >= (SIZE - index) && !allowOverlap)
+ {
+ AddChunk();
+ }
+
+ T* result = &chunk->data[index];
+
+ while (count)
+ {
+ size_t numLeft = SIZE - index;
+ size_t numCopy = numLeft < count ? numLeft : count;
+ std::memcpy(&chunk->data[index], items, sizeof(T) * numCopy);
+
+ count -= numCopy;
+ items += numCopy;
+ index += (uint32_t)numCopy;
+
+ if (count)
+ AddChunk();
+ }
+
+ return result;
+ }
+
+
+ OPTICK_INLINE T* TryAdd(int count)
+ {
+ if (index + count <= SIZE)
+ {
+ T* res = &chunk->data[index];
+ index += count;
+ return res;
+ }
+
+ return nullptr;
+ }
+
+ OPTICK_INLINE T* Back()
+ {
+ if (chunk && index > 0)
+ return &chunk->data[index - 1];
+
+ if (chunk && chunk->prev != nullptr)
+ return &chunk->prev->data[SIZE - 1];
+
+ return nullptr;
+ }
+
+ OPTICK_INLINE size_t Size() const
+ {
+ if (root == nullptr)
+ return 0;
+
+ size_t count = 0;
+
+ for (const Chunk* it = root; it != chunk; it = it->next)
+ count += SIZE;
+
+ return count + index;
+ }
+
+ OPTICK_INLINE bool IsEmpty() const
+ {
+ return (chunk == nullptr) || (chunk == root && index == 0);
+ }
+
+ OPTICK_INLINE void Clear(bool preserveMemory = true)
+ {
+ if (!preserveMemory)
+ {
+ if (root)
+ {
+ Memory::Delete(root);
+ root = nullptr;
+ chunk = nullptr;
+ index = SIZE;
+ }
+ }
+ else if (root)
+ {
+ index = 0;
+ chunk = root;
+ }
+ }
+
+ class const_iterator
+ {
+ void advance()
+ {
+ if (chunkIndex < SIZE - 1)
+ {
+ ++chunkIndex;
+ }
+ else
+ {
+ chunkPtr = chunkPtr->next;
+ chunkIndex = 0;
+ }
+ }
+ public:
+ typedef const_iterator self_type;
+ typedef T value_type;
+ typedef T& reference;
+ typedef T* pointer;
+ typedef int difference_type;
+ const_iterator(const Chunk* ptr, size_t index) : chunkPtr(ptr), chunkIndex(index) { }
+ self_type operator++()
+ {
+ self_type i = *this;
+ advance();
+ return i;
+ }
+ self_type operator++(int /*junk*/)
+ {
+ advance();
+ return *this;
+ }
+ reference operator*() { return (reference)chunkPtr->data[chunkIndex]; }
+ const pointer operator->() { return &chunkPtr->data[chunkIndex]; }
+ bool operator==(const self_type& rhs) { return (chunkPtr == rhs.chunkPtr) && (chunkIndex == rhs.chunkIndex); }
+ bool operator!=(const self_type& rhs) { return (chunkPtr != rhs.chunkPtr) || (chunkIndex != rhs.chunkIndex); }
+ private:
+ const Chunk* chunkPtr;
+ size_t chunkIndex;
+ };
+
+ const_iterator begin() const
+ {
+ return const_iterator(root, 0);
+ }
+
+ const_iterator end() const
+ {
+ return const_iterator(chunk, index);
+ }
+
+ template<class Func>
+ void ForEach(Func func) const
+ {
+ for (const Chunk* it = root; it != chunk; it = it->next)
+ for (uint32 i = 0; i < SIZE; ++i)
+ func(it->data[i]);
+
+ if (chunk)
+ for (uint32 i = 0; i < index; ++i)
+ func(chunk->data[i]);
+ }
+
+ template<class Func>
+ void ForEach(Func func)
+ {
+ for (Chunk* it = root; it != chunk; it = it->next)
+ for (uint32 i = 0; i < SIZE; ++i)
+ func(it->data[i]);
+
+ if (chunk)
+ for (uint32 i = 0; i < index; ++i)
+ func(chunk->data[i]);
+ }
+
+ template<class Func>
+ void ForEachChunk(Func func) const
+ {
+ for (const Chunk* it = root; it != chunk; it = it->next)
+ func(it->data, SIZE);
+
+ if (chunk)
+ func(chunk->data, index);
+ }
+
+ void ToArray(T* destination) const
+ {
+ uint32 curIndex = 0;
+
+ for (const Chunk* it = root; it != chunk; it = it->next)
+ {
+ memcpy(&destination[curIndex], it->data, sizeof(T) * SIZE);
+ curIndex += SIZE;
+ }
+
+ if (chunk && index > 0)
+ {
+ memcpy(&destination[curIndex], chunk->data, sizeof(T) * index);
+ }
+ }
+ };
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ template<uint32 CHUNK_SIZE>
+ class MemoryBuffer : private MemoryPool<uint8, CHUNK_SIZE>
+ {
+ public:
+ template<class U>
+ U* Add(U* data, size_t size, bool allowOverlap = true)
+ {
+ return (U*)(MemoryPool<uint8, CHUNK_SIZE>::AddRange((uint8*)data, size, allowOverlap));
+ }
+
+ template<class T>
+ T* Add(const T& val, bool allowOverlap = true)
+ {
+ return static_cast<T*>(Add(&val, sizeof(T), allowOverlap));
+ }
+ };
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+}
+
+#endif //USE_OPTICK \ No newline at end of file