Reallocate-Arena #1
@@ -162,11 +162,12 @@ namespace Juliet
|
||||
return (x + alignment - 1) & ~(alignment - 1);
|
||||
}
|
||||
|
||||
inline void Swap(auto* Restrict a, auto* Restrict b)
|
||||
template <typename T>
|
||||
inline void Swap(T* Restrict a, T* Restrict b)
|
||||
{
|
||||
auto temp = *a;
|
||||
*a = *b;
|
||||
*b = temp;
|
||||
T temp = std::move(*a);
|
||||
*a = std::move(*b);
|
||||
*b = std::move(temp);
|
||||
}
|
||||
|
||||
// Move to another file dedicated to those
|
||||
|
||||
@@ -3,75 +3,80 @@
|
||||
#include <Core/Common/NonNullPtr.h>
|
||||
#include <Core/Memory/MemoryArena.h>
|
||||
#include <vector>
|
||||
#include <WinSock2.h>
|
||||
|
||||
namespace Juliet
|
||||
{
|
||||
template <typename Type>
|
||||
struct VectorArena
|
||||
{
|
||||
public:
|
||||
VectorArena()
|
||||
: First(nullptr)
|
||||
, Last(nullptr)
|
||||
, Count(0)
|
||||
, Stride(sizeof(Type))
|
||||
void Create()
|
||||
{
|
||||
Arena = ArenaAllocate();
|
||||
Assert(!Arena);
|
||||
|
||||
DataFirst = DataLast = nullptr;
|
||||
Count = 0;
|
||||
Stride = sizeof(Type);
|
||||
Arena = ArenaAllocate();
|
||||
}
|
||||
void Destroy()
|
||||
{
|
||||
ArenaRelease(Arena);
|
||||
DataFirst = DataLast = nullptr;
|
||||
Count = 0;
|
||||
Stride = 0;
|
||||
Arena = nullptr;
|
||||
}
|
||||
|
||||
~VectorArena() { ArenaRelease(Arena); }
|
||||
void PushBack(const Type& value)
|
||||
{
|
||||
Assert(Arena);
|
||||
|
||||
VectorArena(const VectorArena&)
|
||||
: Arena(nullptr)
|
||||
, First(nullptr)
|
||||
, Last(nullptr)
|
||||
, Count(0)
|
||||
, Stride(sizeof(Type))
|
||||
{
|
||||
Assert(false, "Copying VectorArena is not allowed");
|
||||
Type* entry = ArenaPushStruct<Type>(Arena);
|
||||
*entry = value;
|
||||
|
||||
if (Count == 0)
|
||||
{
|
||||
DataFirst = entry;
|
||||
}
|
||||
DataLast = entry;
|
||||
++Count;
|
||||
}
|
||||
VectorArena(VectorArena&&) noexcept
|
||||
: Arena(nullptr)
|
||||
, First(nullptr)
|
||||
, Last(nullptr)
|
||||
, Count(0)
|
||||
, Stride(sizeof(Type))
|
||||
{
|
||||
Assert(false, "Moving VectorArena is not allowed");
|
||||
}
|
||||
void operator=(const VectorArena&) { Assert(false, "Copying VectorArena is not allowed"); }
|
||||
void operator=(VectorArena&&) noexcept { Assert(false, "Moving VectorArena is not allowed"); }
|
||||
|
||||
void PushBack(Type&& value)
|
||||
{
|
||||
Assert(Arena);
|
||||
|
||||
Type* entry = ArenaPushStruct<Type>(Arena);
|
||||
*entry = std::move(value);
|
||||
|
||||
if (Count == 0)
|
||||
{
|
||||
First = entry;
|
||||
DataFirst = entry;
|
||||
}
|
||||
Last = entry;
|
||||
|
||||
DataLast = entry;
|
||||
++Count;
|
||||
}
|
||||
|
||||
void RemoveAtFast(index_t index)
|
||||
{
|
||||
Assert(Arena);
|
||||
Assert(index < Count);
|
||||
Assert(Count > 0);
|
||||
|
||||
Type* elementAdr = First + index;
|
||||
Type* elementAdr = DataFirst + index;
|
||||
|
||||
// Swap Last and element
|
||||
Swap(Last, elementAdr);
|
||||
--Last;
|
||||
// Swap DataLast and element
|
||||
if (DataLast != elementAdr)
|
||||
{
|
||||
Swap(DataLast, elementAdr);
|
||||
}
|
||||
|
||||
--DataLast;
|
||||
--Count;
|
||||
|
||||
if (Count == 0)
|
||||
{
|
||||
First = Last = nullptr;
|
||||
DataFirst = DataLast = nullptr;
|
||||
}
|
||||
|
||||
ArenaPop(Arena, Stride);
|
||||
@@ -79,34 +84,36 @@ namespace Juliet
|
||||
|
||||
void Clear()
|
||||
{
|
||||
Assert(Arena);
|
||||
|
||||
ArenaClear(Arena);
|
||||
First = Last = nullptr;
|
||||
Count = 0;
|
||||
DataFirst = DataLast = nullptr;
|
||||
Count = 0;
|
||||
}
|
||||
|
||||
// C++ Accessors for loop supports and Index based access
|
||||
Type& operator[](size_t index) { return First[index]; }
|
||||
const Type& operator[](size_t index) const { return First[index]; }
|
||||
Type& operator[](size_t index) { return DataFirst[index]; }
|
||||
const Type& operator[](size_t index) const { return DataFirst[index]; }
|
||||
|
||||
Type* begin() { return First; }
|
||||
Type* end() { return First + Count; }
|
||||
Type* begin() { return DataFirst; }
|
||||
Type* end() { return DataFirst + Count; }
|
||||
|
||||
const Type* begin() const { return First; }
|
||||
const Type* end() const { return First + Count; }
|
||||
const Type* begin() const { return DataFirst; }
|
||||
const Type* end() const { return DataFirst + Count; }
|
||||
|
||||
Type* First() { return DataFirst; }
|
||||
Type* Last() { return DataLast; }
|
||||
|
||||
size_t Size() const { return Count; }
|
||||
|
||||
private:
|
||||
Arena* Arena;
|
||||
Type* First;
|
||||
Type* Last;
|
||||
Type* DataFirst;
|
||||
Type* DataLast;
|
||||
size_t Count;
|
||||
size_t Stride;
|
||||
};
|
||||
|
||||
// TODO : Create my own Vector class based on https://github.com/niklas-ourmachinery/bitsquid-foundation/blob/master/collection_types.h
|
||||
template <typename T>
|
||||
class Vector : public std::vector<T>
|
||||
{
|
||||
};
|
||||
static_assert(std::is_standard_layout_v<VectorArena<int>>,
|
||||
"VectorArena must have a standard layout to remain POD-like.");
|
||||
static_assert(std::is_trivially_copyable_v<VectorArena<int>>,
|
||||
"VectorArena must be trivially copyable (no custom destructors/assignment).");
|
||||
} // namespace Juliet
|
||||
|
||||
@@ -5,6 +5,12 @@
|
||||
|
||||
namespace Juliet
|
||||
{
|
||||
// TODO Use VectorArena
|
||||
template <typename T>
|
||||
class Vector : public std::vector<T>
|
||||
{
|
||||
};
|
||||
|
||||
class NetworkPacket
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -10,7 +10,9 @@ namespace Juliet
|
||||
namespace
|
||||
{
|
||||
DisplayDevice* g_CurrentDisplayDevice = nullptr;
|
||||
}
|
||||
|
||||
void DestroyPlatformWindow(index_t windowIndex);
|
||||
} // namespace
|
||||
|
||||
namespace Internal::Display
|
||||
{
|
||||
@@ -60,9 +62,9 @@ namespace Juliet
|
||||
}
|
||||
|
||||
// Destroy all Windows that are still alive
|
||||
if (g_CurrentDisplayDevice->MainWindow)
|
||||
for (index_t idx = g_CurrentDisplayDevice->Windows.Size(); idx-- > 0;)
|
||||
{
|
||||
DestroyPlatformWindow(g_CurrentDisplayDevice->MainWindow);
|
||||
DestroyPlatformWindow(idx);
|
||||
}
|
||||
|
||||
g_CurrentDisplayDevice->Shutdown(g_CurrentDisplayDevice);
|
||||
@@ -78,44 +80,59 @@ namespace Juliet
|
||||
{
|
||||
Assert(g_CurrentDisplayDevice->CreatePlatformWindow);
|
||||
|
||||
auto* arena = g_CurrentDisplayDevice->Arena;
|
||||
Assert(arena);
|
||||
Window window = {};
|
||||
window.Arena = ArenaAllocate();
|
||||
window.Width = width;
|
||||
window.Height = height;
|
||||
|
||||
auto* window = ArenaPushStruct<Window>(arena);
|
||||
Assert(window);
|
||||
window.Title = StringCopy(window.Arena, WrapString(title));
|
||||
|
||||
window->Width = width;
|
||||
window->Height = height;
|
||||
g_CurrentDisplayDevice->Windows.PushBack(window);
|
||||
|
||||
window->Title = StringCopy(arena, WrapString(title));
|
||||
|
||||
g_CurrentDisplayDevice->MainWindow = window;
|
||||
if (!g_CurrentDisplayDevice->CreatePlatformWindow(g_CurrentDisplayDevice, window))
|
||||
auto* pWindow = g_CurrentDisplayDevice->Windows.Last();
|
||||
if (!g_CurrentDisplayDevice->CreatePlatformWindow(g_CurrentDisplayDevice, pWindow))
|
||||
{
|
||||
// Note: We don't "free" from arena easily, but since this is catastrophic
|
||||
// and persistent, we just leak the small amount of arena space or handle it if we had a marker.
|
||||
ArenaRelease(window.Arena);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// TODO : make SHOW optional on creation with a flag
|
||||
g_CurrentDisplayDevice->ShowWindow(g_CurrentDisplayDevice, window);
|
||||
g_CurrentDisplayDevice->ShowWindow(g_CurrentDisplayDevice, pWindow);
|
||||
|
||||
return window;
|
||||
return pWindow;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
void DestroyPlatformWindow(index_t windowIndex)
|
||||
{
|
||||
VectorArena<Window>& windows = g_CurrentDisplayDevice->Windows;
|
||||
Window* window = &windows[windowIndex];
|
||||
|
||||
HideWindow(window);
|
||||
|
||||
g_CurrentDisplayDevice->DestroyPlatformWindow(g_CurrentDisplayDevice, window);
|
||||
|
||||
ArenaClear(window->Arena);
|
||||
ArenaRelease(window->Arena);
|
||||
|
||||
windows.RemoveAtFast(windowIndex);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void DestroyPlatformWindow(NonNullPtr<Window> window)
|
||||
{
|
||||
Assert(g_CurrentDisplayDevice->MainWindow == window.Get());
|
||||
|
||||
HideWindow(window);
|
||||
|
||||
// TODO: Pop from arena.
|
||||
window->Title.Data = nullptr;
|
||||
window->Title.Size = 0;
|
||||
|
||||
g_CurrentDisplayDevice->DestroyPlatformWindow(g_CurrentDisplayDevice, window);
|
||||
|
||||
g_CurrentDisplayDevice->MainWindow = nullptr;
|
||||
// Find and destroy
|
||||
VectorArena<Window>& windows = g_CurrentDisplayDevice->Windows;
|
||||
for (index_t idx = windows.Size() - 1; idx != 0; --idx)
|
||||
{
|
||||
Window& windowRef = windows[idx];
|
||||
if (windowRef.ID == window->ID)
|
||||
{
|
||||
DestroyPlatformWindow(idx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShowWindow(NonNullPtr<Window> window)
|
||||
|
||||
@@ -29,9 +29,7 @@ namespace Juliet
|
||||
// Events
|
||||
void (*PumpEvents)(NonNullPtr<DisplayDevice> self);
|
||||
|
||||
// TODO : Use vector
|
||||
VectorArena<Window*> Windows;
|
||||
Window* MainWindow = nullptr;
|
||||
VectorArena<Window> Windows;
|
||||
};
|
||||
|
||||
struct DisplayDeviceFactory
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
#include <Core/HAL/Display/DisplayDevice.h>
|
||||
#include <Core/HAL/Display/Win32/Win32DisplayEvent.h>
|
||||
#include <Core/HAL/Display/Win32/Win32Window.h>
|
||||
#include <Core/Memory/Allocator.h>
|
||||
#include <Core/Memory/EngineArena.h>
|
||||
#include <Core/Memory/Utils.h>
|
||||
|
||||
namespace Juliet::Win32
|
||||
{
|
||||
@@ -14,7 +12,10 @@ namespace Juliet::Win32
|
||||
return true;
|
||||
}
|
||||
void Shutdown(NonNullPtr<DisplayDevice> /*self*/) {}
|
||||
void Free(NonNullPtr<DisplayDevice> /*self*/) {}
|
||||
void Free(NonNullPtr<DisplayDevice> device)
|
||||
{
|
||||
device->Windows.Destroy();
|
||||
}
|
||||
|
||||
DisplayDevice* CreateDevice(Arena* arena)
|
||||
{
|
||||
@@ -36,6 +37,8 @@ namespace Juliet::Win32
|
||||
|
||||
device->PumpEvents = PumpEvents;
|
||||
|
||||
device->Windows.Create();
|
||||
|
||||
return device;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@@ -14,10 +14,9 @@
|
||||
// For GET_X_LPARAM, GET_Y_LPARAM.
|
||||
#include <windowsx.h>
|
||||
|
||||
#include <imgui.h> // Need For IMGUI_IMPL_API
|
||||
#include <imgui.h> // Need For IMGUI_IMPL_API
|
||||
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
|
||||
namespace Juliet::Win32
|
||||
{
|
||||
namespace
|
||||
@@ -29,17 +28,12 @@ namespace Juliet::Win32
|
||||
{
|
||||
if (auto* displayDevice = GetDisplayDevice())
|
||||
{
|
||||
auto* window = displayDevice->MainWindow;
|
||||
// TODO : use a vector
|
||||
// for (Window* window : displayDevice->MainWindow)
|
||||
for (auto& window : displayDevice->Windows)
|
||||
{
|
||||
if (window)
|
||||
auto state = static_cast<Window32State*>(window.State);
|
||||
if (state && state->Handle == handle)
|
||||
{
|
||||
auto state = static_cast<Window32State*>(window->State);
|
||||
if (state && state->Handle == handle)
|
||||
{
|
||||
return state;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -158,7 +152,6 @@ namespace Juliet::Win32
|
||||
|
||||
LRESULT returnCode = -1;
|
||||
|
||||
|
||||
// Wait until the window state is created before doing anything
|
||||
auto* windowState = GetWindowStateFromHandle(handle);
|
||||
if (!windowState)
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Juliet::Win32
|
||||
|
||||
bool SetupWindowState(NonNullPtr<DisplayDevice> /*self*/, NonNullPtr<Window> window, HWND handle)
|
||||
{
|
||||
auto state = ArenaPushType<Window32State>(GetEngineArena(), ConstString("Window32State"));
|
||||
auto* state = ArenaPushStruct<Window32State>(window->Arena);
|
||||
|
||||
window->State = state;
|
||||
state->Handle = handle;
|
||||
@@ -23,18 +23,15 @@ namespace Juliet::Win32
|
||||
|
||||
state->IsMouseTracked = false;
|
||||
|
||||
// TODO Use SetProp to associate data to the window handle. Could be used to fetch it from the WinProc
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CleanUpWindowState(NonNullPtr<DisplayDevice> /*self*/, NonNullPtr<Window> window)
|
||||
{
|
||||
if (auto* state = static_cast<Window32State*>(window->State))
|
||||
{
|
||||
ReleaseDC(state->Handle, state->HDC);
|
||||
DestroyWindow(state->Handle);
|
||||
}
|
||||
auto* state = static_cast<Window32State*>(window->State);
|
||||
Assert(state);
|
||||
ReleaseDC(state->Handle, state->HDC);
|
||||
DestroyWindow(state->Handle);
|
||||
window->State = nullptr;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@@ -15,9 +15,10 @@ namespace Juliet
|
||||
{
|
||||
WindowID ID;
|
||||
WindowState* State;
|
||||
Arena* Arena;
|
||||
|
||||
int32 Width;
|
||||
int32 Height;
|
||||
int32 Width;
|
||||
int32 Height;
|
||||
String Title;
|
||||
};
|
||||
} // namespace Juliet
|
||||
|
||||
@@ -31,7 +31,8 @@ namespace Juliet
|
||||
{
|
||||
// Test 1: Integer VectorArena
|
||||
{
|
||||
VectorArena<int> vec;
|
||||
VectorArena<int> vec = {};
|
||||
vec.Create();
|
||||
VerifyVectorState(vec, 0);
|
||||
|
||||
vec.PushBack(10);
|
||||
@@ -58,11 +59,14 @@ namespace Juliet
|
||||
sum += val;
|
||||
}
|
||||
Assert(sum == 60);
|
||||
vec.Destroy();
|
||||
}
|
||||
|
||||
// Test 2: RemoveAtFast
|
||||
{
|
||||
VectorArena<int> vec;
|
||||
VectorArena<int> vec = {};
|
||||
vec.Create();
|
||||
|
||||
vec.PushBack(10);
|
||||
vec.PushBack(20);
|
||||
vec.PushBack(30);
|
||||
@@ -84,11 +88,15 @@ namespace Juliet
|
||||
// Remove remaining element
|
||||
vec.RemoveAtFast(0);
|
||||
VerifyVectorState(vec, 0);
|
||||
|
||||
vec.Destroy();
|
||||
}
|
||||
|
||||
// Test 3: Clear and Reuse
|
||||
{
|
||||
VectorArena<int> vec;
|
||||
VectorArena<int> vec = {};
|
||||
vec.Create();
|
||||
|
||||
vec.PushBack(100);
|
||||
vec.PushBack(200);
|
||||
VerifyVectorState(vec, 2);
|
||||
@@ -100,6 +108,8 @@ namespace Juliet
|
||||
VerifyVectorState(vec, 1);
|
||||
Assert(vec[0] == 300);
|
||||
Assert(*(vec.end() - 1) == 300);
|
||||
|
||||
vec.Destroy();
|
||||
}
|
||||
|
||||
// Test 4: Struct VectorArena
|
||||
@@ -116,7 +126,9 @@ namespace Juliet
|
||||
}
|
||||
};
|
||||
|
||||
VectorArena<TestItem> vec;
|
||||
VectorArena<TestItem> vec = {};
|
||||
vec.Create();
|
||||
|
||||
VerifyVectorState(vec, 0);
|
||||
|
||||
vec.PushBack({ 1, 1.0f });
|
||||
@@ -129,11 +141,15 @@ namespace Juliet
|
||||
VerifyVectorState(vec, 2);
|
||||
Assert(vec[0] == (TestItem{ 1, 1.0f }));
|
||||
Assert(vec[1] == (TestItem{ 3, 3.0f }));
|
||||
|
||||
vec.Destroy();
|
||||
}
|
||||
|
||||
// Test 5: Add 2, Remove 2 -> Expect nullptr
|
||||
{
|
||||
VectorArena<int> vec;
|
||||
VectorArena<int> vec = {};
|
||||
vec.Create();
|
||||
|
||||
vec.PushBack(1);
|
||||
vec.PushBack(2);
|
||||
VerifyVectorState(vec, 2);
|
||||
@@ -141,11 +157,15 @@ namespace Juliet
|
||||
vec.RemoveAtFast(0);
|
||||
vec.RemoveAtFast(0);
|
||||
VerifyVectorState(vec, 0);
|
||||
|
||||
vec.Destroy();
|
||||
}
|
||||
|
||||
// Test 6: Volume Test (100 items)
|
||||
{
|
||||
VectorArena<int> vec;
|
||||
VectorArena<int> vec = {};
|
||||
vec.Create();
|
||||
|
||||
VerifyVectorState(vec, 0);
|
||||
|
||||
// Push 100 items
|
||||
@@ -170,6 +190,8 @@ namespace Juliet
|
||||
|
||||
vec.Clear();
|
||||
VerifyVectorState(vec, 0);
|
||||
|
||||
vec.Destroy();
|
||||
}
|
||||
}
|
||||
} // namespace Juliet
|
||||
|
||||
Reference in New Issue
Block a user