Simplified VectorArena to always take an arena and to not support change of capacity
This commit is contained in:
@@ -0,0 +1,92 @@
|
|||||||
|
# Workload Analysis: Removing C++ Stdlib & Migrating to Pure C
|
||||||
|
|
||||||
|
This analysis outlines the required workload, technical impact, and migration strategy for:
|
||||||
|
1. Removing all standard C++ library dependencies (`std::*`) from the Juliet codebase.
|
||||||
|
2. Moving completely from C++ to pure C.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Scope Overview
|
||||||
|
|
||||||
|
The repository consists of multiple sub-projects (**Juliet Core Engine**, **JulietApp**, **Game**, **Romeo**, and **External dependencies**). Eliminating stdlib dependencies versus migrating completely to pure C represent two distinct milestones:
|
||||||
|
|
||||||
|
| Metric / Domain | Task 1: Eliminate C++ stdlib | Task 2: Pure C Migration |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| **Language Target** | C++20 (without standard libraries) | Pure C (C11 / C99 standard) |
|
||||||
|
| **Containers & Math** | Custom templates (`Vector<T>`, `HashTable<K,V>`, custom algorithms) | C structs + `void*` / macro templates + explicit functions |
|
||||||
|
| **Threading & Sync** | Win32 / OS APIs directly (`CreateThread`, `SRWLOCK`) | Native OS APIs (`CreateThread`, `SRWLOCK`, atomic primitives) |
|
||||||
|
| **External Third-Party** | Native Direct3D 12, ImGui | `cimgui` (C bindings), DirectX C COM interfaces (`ID3D12Device*`) |
|
||||||
|
| **OOP & Templates** | Kept intact | Struct-based vtables, no function overloading, no references (`&`) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Phase 1: Removing C++ stdlib Dependencies
|
||||||
|
|
||||||
|
### A. Containers & Utility Replacement
|
||||||
|
- **Current Usages**: `<vector>`, `<queue>`, `<list>`, `<forward_list>`, `<algorithm>`, `<bit>`, `<concepts>`, `<type_traits>`, `<source_location>`.
|
||||||
|
- **Workload**:
|
||||||
|
1. **Containers**: Replace container implementations (such as `Juliet/include/Core/Container/Vector.h`, which currently includes `<vector>`) with custom dynamically resizing arrays / buffer allocators backed by `MemoryArena`.
|
||||||
|
2. **Type Traits & Concepts**: Replace `<type_traits>` and `<concepts>` usage in files like `Game/Entity/Entity.h` with compiler intrinsics (e.g. `__is_enum`, `__is_base_of`) or internal lightweight trait structures.
|
||||||
|
3. **Algorithms & Math Utilities**: Implement custom `Min`, `Max`, `Clamp`, `Sort`, and `Swap` functions in `CoreUtils.h` or custom inline header helpers.
|
||||||
|
|
||||||
|
### B. Threading & Synchronization
|
||||||
|
- **Current Usages**: `<thread>`, `<mutex>`, `std::thread`, `std::mutex`, `std::lock_guard`.
|
||||||
|
- **Workload**:
|
||||||
|
1. Replace `<thread>` in `Thread.h` and `Romeo/src/main.cpp` with platform abstraction wrappers using Win32 `CreateThread` / `CloseHandle`.
|
||||||
|
2. Replace `<mutex>` in `Mutex.h` with `SRWLOCK` or `CRITICAL_SECTION`.
|
||||||
|
|
||||||
|
### C. Time & File I/O
|
||||||
|
- **Current Usages**: `<chrono>`, `<cstdio>`, `<fstream>`, `<ios>`, `<iosfwd>`, `<cstdlib>`.
|
||||||
|
- **Workload**:
|
||||||
|
1. Replace `<chrono>` in `LogManager.cpp` and `SystemEvent.cpp` with `QueryPerformanceCounter` / `QueryPerformanceFrequency` on Windows.
|
||||||
|
2. Standardize filesystem I/O on Win32 API (`CreateFileW`, `ReadFile`, `WriteFile`) or minimal C runtime headers (`<stdio.h>`, `<stdlib.h>`, `<string.h>`).
|
||||||
|
|
||||||
|
### D. Memory Allocators & RTTI
|
||||||
|
- **Current Usages**: `<new>`, `<typeinfo>` (`typeid` in `MemoryArena.h`), `<memory>`.
|
||||||
|
- **Workload**:
|
||||||
|
1. Replace placement `new` with custom inline placement functions or custom explicit initialization methods.
|
||||||
|
2. Replace `typeid` / `type_info` usages with custom type hashing or enum type IDs.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Phase 2: Complete Migration to C
|
||||||
|
|
||||||
|
Transitioning fully to C requires refactoring away all C++ language constructs.
|
||||||
|
|
||||||
|
### A. DirectX 12 & Agility SDK Integration
|
||||||
|
- **D3D12 Header Interface**: Switch from C++ COM smart pointers / methods (`device->CreateCommandAllocator(...)`) to standard C COM interfaces (`ID3D12Device_CreateCommandAllocator(device, ...)`).
|
||||||
|
- **D3DX12 Helper Library**: `d3dx12_state_object.h` and helper files rely heavily on stdlib (`std::vector`, `std::memory`, C++ structures). These must be rewritten in plain C or replaced with native DirectX 12 C struct initializers.
|
||||||
|
|
||||||
|
### B. UI Framework (ImGui)
|
||||||
|
- Dear ImGui is natively C++.
|
||||||
|
- **Workload**: Switch from standard `imgui.h` / `imgui_stdlib.h` to [cimgui](https://github.com/cimgui/cimgui) (C-compatible wrappers for ImGui) or maintain a minimal C++ bridge file specifically for ImGui.
|
||||||
|
|
||||||
|
### C. Codebase Refactoring (Language Paradigm)
|
||||||
|
1. **Classes to Structs**: Convert classes in `Juliet` core, `Game`, and `Romeo` to C structs.
|
||||||
|
2. **Virtual Functions**: Replace polymorphism with explicit `void*` context pointers and function pointer tables (vtables).
|
||||||
|
3. **Namespaces & Function Overloading**: Prefix function names (e.g., `Juliet_Log_Info(...)`) as C does not support namespaces or function overloading.
|
||||||
|
4. **Member Functions to Free Functions**: Convert `obj.Method(args)` to `Method(&obj, args)`.
|
||||||
|
5. **No Reference Arguments (`&`)**: Replace all pass-by-reference parameters with explicit pointers (`*`).
|
||||||
|
6. **Casting Rules**: Remove `static_cast` and `reinterpret_cast` in favor of standard C explicit casts `(Type)val`.
|
||||||
|
|
||||||
|
### D. Build System (`Romeo.bff` / `fbuild.bff`)
|
||||||
|
- Update compiler settings in FastBuild (`.bff` files) and Visual Studio project settings from `/std:c++20` to C compiler flags (`/std:c11` or `/TC`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Estimated Workload Matrix
|
||||||
|
|
||||||
|
| Task Module | Complexity | Estimated Relative Effort | Risks / Key Considerations |
|
||||||
|
| :--- | :--- | :--- | :--- |
|
||||||
|
| **1. Stdlib-Free Containers & Utils** | Moderate | ~15% | Custom array/hash table implementation. |
|
||||||
|
| **2. OS Threading & Time Abstraction** | Low-Moderate | ~10% | Clean Windows API replacements (`QueryPerformanceCounter`, `SRWLOCK`). |
|
||||||
|
| **3. C Struct & Syntax Refactoring** | High | ~40% | Large volume of mechanical refactoring (references, namespaces, overloading, methods). |
|
||||||
|
| **4. Graphics / D3D12 C Refactoring** | High | ~20% | `d3dx12` heavily relies on C++ templates/stdlib; rewriting helper structs in C. |
|
||||||
|
| **5. ImGui / Romeo GUI Integration** | Moderate | ~15% | Needs `cimgui` integration or a C-wrapper boundary. |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Recommendation & Phasing
|
||||||
|
|
||||||
|
1. **Step 1 (Stdlib Removal)**: Keep C++20 language features (classes, templates, member methods), but remove all stdlib inclusions (`<vector>`, `<thread>`, `<chrono>`, `<algorithm>`). Replace them with custom `Juliet` engine primitives.
|
||||||
|
2. **Step 2 (Evaluate C Migration)**: Re-evaluate if moving to pure C provides enough benefit vs. keeping a clean, stdlib-free C++ subset ("C with Classes" / stdlib-free C++).
|
||||||
@@ -2,50 +2,29 @@
|
|||||||
|
|
||||||
#include <Core/Common/NonNullPtr.h>
|
#include <Core/Common/NonNullPtr.h>
|
||||||
#include <Core/Memory/MemoryArena.h>
|
#include <Core/Memory/MemoryArena.h>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
{
|
{
|
||||||
template <typename Type, size_t ReserveSize = 16, bool AllowRealloc = false>
|
template <typename Type, size_t ReserveSize = 16>
|
||||||
struct VectorArena
|
struct VectorArena
|
||||||
{
|
{
|
||||||
void Create(JULIET_DEBUG_PARAM_FIRST(const char* name = nullptr))
|
|
||||||
{
|
|
||||||
Assert(!Arena);
|
|
||||||
static_assert(AllowRealloc == false);
|
|
||||||
|
|
||||||
DataFirst = DataLast = nullptr;
|
|
||||||
Count = 0;
|
|
||||||
|
|
||||||
JULIET_DEBUG_ONLY(Name = name ? name : Name;)
|
|
||||||
ArenaParams params{ .AllowRealloc = AllowRealloc JULIET_DEBUG_PARAM(.CanReserveMore = false) };
|
|
||||||
Arena = ArenaAllocate(params JULIET_DEBUG_PARAM(Name));
|
|
||||||
InternalArena = true;
|
|
||||||
|
|
||||||
Reserve(ReserveSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Create(NonNullPtr<Arena> arena JULIET_DEBUG_PARAM(const char* name = nullptr))
|
void Create(NonNullPtr<Arena> arena JULIET_DEBUG_PARAM(const char* name = nullptr))
|
||||||
{
|
{
|
||||||
Assert(!Arena);
|
Assert(!Arena);
|
||||||
|
|
||||||
JULIET_DEBUG_ONLY(Name = name ? name : Name;)
|
JULIET_DEBUG_ONLY(Name = name ? name : Name;)
|
||||||
|
|
||||||
DataFirst = DataLast = nullptr;
|
DataFirst = DataLast = Data = nullptr;
|
||||||
Count = 0;
|
Count = 0;
|
||||||
Arena = arena.Get();
|
Capacity = 0;
|
||||||
InternalArena = false;
|
Arena = arena;
|
||||||
|
|
||||||
Reserve(ReserveSize);
|
Reserve(ReserveSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Destroy()
|
void Destroy()
|
||||||
{
|
{
|
||||||
if (InternalArena)
|
DataFirst = DataLast = Data = nullptr;
|
||||||
{
|
|
||||||
ArenaRelease(Arena);
|
|
||||||
}
|
|
||||||
DataFirst = DataLast = nullptr;
|
|
||||||
Count = 0;
|
Count = 0;
|
||||||
Capacity = 0;
|
Capacity = 0;
|
||||||
Arena = nullptr;
|
Arena = nullptr;
|
||||||
@@ -53,38 +32,33 @@ namespace Juliet
|
|||||||
|
|
||||||
void Reserve(size_t newCapacity)
|
void Reserve(size_t newCapacity)
|
||||||
{
|
{
|
||||||
if (newCapacity > Capacity)
|
Assert(Arena);
|
||||||
{
|
|
||||||
if (Data == nullptr)
|
if (Data == nullptr)
|
||||||
{
|
{
|
||||||
Data = ArenaPushArray<Type>(Arena, newCapacity JULIET_DEBUG_PARAM(Name));
|
Data = ArenaPushArray<Type>(Arena, newCapacity JULIET_DEBUG_PARAM(Name));
|
||||||
}
|
|
||||||
else if constexpr (AllowRealloc)
|
|
||||||
{
|
|
||||||
if (!InternalArena)
|
|
||||||
{
|
|
||||||
DataFirst = Data =
|
|
||||||
static_cast<Type*>(ArenaReallocate(Arena, Data, Capacity * sizeof(Type), newCapacity * sizeof(Type),
|
|
||||||
AlignOf(Type), true JULIET_DEBUG_PARAM("VectorRealloc")));
|
|
||||||
DataLast = Data + Count - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Capacity = newCapacity;
|
Capacity = newCapacity;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Assert(newCapacity <= Capacity && "VectorArena capacity exceeded! Reallocation is disabled.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Resize(size_t newCount)
|
void Resize(size_t newCount)
|
||||||
{
|
{
|
||||||
|
Assert(Arena);
|
||||||
if (newCount == Count)
|
if (newCount == Count)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newCount > Capacity)
|
if (Data == nullptr)
|
||||||
{
|
{
|
||||||
Reserve(newCount);
|
size_t initialCapacity = newCount > ReserveSize ? newCount : ReserveSize;
|
||||||
|
Reserve(initialCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Assert(newCount <= Capacity && "VectorArena capacity exceeded!");
|
||||||
Count = newCount;
|
Count = newCount;
|
||||||
|
|
||||||
if (Count > 0)
|
if (Count > 0)
|
||||||
@@ -101,20 +75,21 @@ namespace Juliet
|
|||||||
void PushBack(const Type* buffer, size_t amount)
|
void PushBack(const Type* buffer, size_t amount)
|
||||||
{
|
{
|
||||||
Assert(Arena);
|
Assert(Arena);
|
||||||
|
Assert(buffer || amount == 0);
|
||||||
|
|
||||||
if (Count + amount > Capacity)
|
if (amount == 0)
|
||||||
{
|
{
|
||||||
if (Capacity == 0 && Count + amount < ReserveSize)
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Data == nullptr)
|
||||||
{
|
{
|
||||||
Reserve(ReserveSize);
|
size_t initialCapacity = amount > ReserveSize ? amount : ReserveSize;
|
||||||
}
|
Reserve(initialCapacity);
|
||||||
else
|
|
||||||
{
|
|
||||||
size_t newCapacity = Max(Capacity * 2, AlignPow2(Capacity + amount, AlignOf(Type)));
|
|
||||||
Reserve(newCapacity);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Assert(Count + amount <= Capacity && "VectorArena capacity exceeded!");
|
||||||
|
|
||||||
Type* dst = Data + Count;
|
Type* dst = Data + Count;
|
||||||
MemCopy(dst, buffer, amount * sizeof(Type));
|
MemCopy(dst, buffer, amount * sizeof(Type));
|
||||||
|
|
||||||
@@ -122,7 +97,7 @@ namespace Juliet
|
|||||||
{
|
{
|
||||||
DataFirst = dst;
|
DataFirst = dst;
|
||||||
}
|
}
|
||||||
DataLast = dst + amount;
|
DataLast = dst + amount - 1;
|
||||||
Count += amount;
|
Count += amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,11 +105,13 @@ namespace Juliet
|
|||||||
{
|
{
|
||||||
Assert(Arena);
|
Assert(Arena);
|
||||||
|
|
||||||
if (Count + 1 > Capacity)
|
if (Data == nullptr)
|
||||||
{
|
{
|
||||||
Reserve(Capacity == 0 ? ReserveSize : Capacity * 2);
|
Reserve(ReserveSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Assert(Count + 1 <= Capacity && "VectorArena capacity exceeded!");
|
||||||
|
|
||||||
Type* entry = Data + Count;
|
Type* entry = Data + Count;
|
||||||
*entry = value;
|
*entry = value;
|
||||||
|
|
||||||
@@ -150,11 +127,13 @@ namespace Juliet
|
|||||||
{
|
{
|
||||||
Assert(Arena);
|
Assert(Arena);
|
||||||
|
|
||||||
if (Count + 1 > Capacity)
|
if (Data == nullptr)
|
||||||
{
|
{
|
||||||
Reserve(Capacity == 0 ? ReserveSize : Capacity * 2);
|
Reserve(ReserveSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Assert(Count + 1 <= Capacity && "VectorArena capacity exceeded!");
|
||||||
|
|
||||||
Type* entry = Data + Count;
|
Type* entry = Data + Count;
|
||||||
*entry = std::move(value);
|
*entry = std::move(value);
|
||||||
|
|
||||||
@@ -193,44 +172,37 @@ namespace Juliet
|
|||||||
{
|
{
|
||||||
Assert(Arena);
|
Assert(Arena);
|
||||||
|
|
||||||
if (InternalArena)
|
|
||||||
{
|
|
||||||
ArenaClear(Arena);
|
|
||||||
Data = nullptr;
|
|
||||||
Capacity = 0;
|
|
||||||
Reserve(ReserveSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
DataFirst = DataLast = nullptr;
|
DataFirst = DataLast = nullptr;
|
||||||
Count = 0;
|
Count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsEmpty() const { return Count == 0; }
|
[[nodiscard]] bool IsEmpty() const { return Count == 0; }
|
||||||
|
|
||||||
// C++ Accessors for loop supports and Index based access
|
// C++ Accessors for loop supports and Index based access
|
||||||
Type& operator[](size_t index) { return DataFirst[index]; }
|
[[nodiscard]] Type& operator[](size_t index) { return DataFirst[index]; }
|
||||||
const Type& operator[](size_t index) const { return DataFirst[index]; }
|
[[nodiscard]] const Type& operator[](size_t index) const { return DataFirst[index]; }
|
||||||
|
|
||||||
Type* begin() { return DataFirst; }
|
[[nodiscard]] Type* begin() { return DataFirst; }
|
||||||
Type* end() { return DataFirst + Count; }
|
[[nodiscard]] Type* end() { return DataFirst + Count; }
|
||||||
|
|
||||||
const Type* begin() const { return DataFirst; }
|
[[nodiscard]] const Type* begin() const { return DataFirst; }
|
||||||
const Type* end() const { return DataFirst + Count; }
|
[[nodiscard]] const Type* end() const { return DataFirst + Count; }
|
||||||
|
|
||||||
Type* First() { return DataFirst; }
|
[[nodiscard]] Type* First() { return DataFirst; }
|
||||||
Type* Front() { return DataFirst; }
|
[[nodiscard]] Type* Front() { return DataFirst; }
|
||||||
Type* Last() { return DataLast; }
|
[[nodiscard]] Type* Last() { return DataLast; }
|
||||||
Type* Back() { return DataLast; }
|
[[nodiscard]] Type* Back() { return DataLast; }
|
||||||
|
[[nodiscard]] Type* DataPtr() { return Data; }
|
||||||
|
[[nodiscard]] const Type* DataPtr() const { return Data; }
|
||||||
|
|
||||||
size_t Size() const { return Count; }
|
[[nodiscard]] size_t Size() const { return Count; }
|
||||||
|
|
||||||
Arena* Arena;
|
Arena* Arena = nullptr;
|
||||||
Type* DataFirst;
|
Type* DataFirst = nullptr;
|
||||||
Type* DataLast;
|
Type* DataLast = nullptr;
|
||||||
Type* Data;
|
Type* Data = nullptr;
|
||||||
size_t Count;
|
size_t Count = 0;
|
||||||
size_t Capacity;
|
size_t Capacity = 0;
|
||||||
bool InternalArena : 1;
|
|
||||||
JULIET_DEBUG_ONLY(const char* Name = "VectorArena";)
|
JULIET_DEBUG_ONLY(const char* Name = "VectorArena";)
|
||||||
};
|
};
|
||||||
static_assert(std::is_standard_layout_v<VectorArena<int>>,
|
static_assert(std::is_standard_layout_v<VectorArena<int>>,
|
||||||
|
|||||||
@@ -5,25 +5,20 @@
|
|||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
{
|
{
|
||||||
// TODO Use VectorArena
|
|
||||||
template <typename T>
|
|
||||||
class Vector : public std::vector<T>
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
class NetworkPacket
|
class NetworkPacket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NetworkPacket();
|
NetworkPacket();
|
||||||
|
NetworkPacket(Arena& arena);
|
||||||
virtual ~NetworkPacket();
|
virtual ~NetworkPacket();
|
||||||
NetworkPacket(NetworkPacket&);
|
NetworkPacket(NetworkPacket&);
|
||||||
NetworkPacket& operator=(const NetworkPacket&);
|
NetworkPacket& operator=(const NetworkPacket&);
|
||||||
NetworkPacket(NetworkPacket&&) noexcept;
|
NetworkPacket(NetworkPacket&&) noexcept;
|
||||||
NetworkPacket& operator=(NetworkPacket&&) noexcept;
|
NetworkPacket& operator=(NetworkPacket&&) noexcept;
|
||||||
|
|
||||||
ByteBuffer GetRawData();
|
void Create(Arena& arena);
|
||||||
|
|
||||||
// Unpack
|
[[nodiscard]] ByteBuffer GetRawData();
|
||||||
|
|
||||||
// Pack
|
// Pack
|
||||||
NetworkPacket& operator<<(uint32 value);
|
NetworkPacket& operator<<(uint32 value);
|
||||||
@@ -35,7 +30,7 @@ namespace Juliet
|
|||||||
friend class TcpSocket;
|
friend class TcpSocket;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Vector<Byte> Data;
|
VectorArena<Byte, 4096> Data;
|
||||||
size_t PartialSendIndex = 0;
|
size_t PartialSendIndex = 0;
|
||||||
};
|
};
|
||||||
} // namespace Juliet
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -30,11 +30,10 @@ namespace Juliet
|
|||||||
|
|
||||||
struct MeshRenderer
|
struct MeshRenderer
|
||||||
{
|
{
|
||||||
// Note we prevent realloc for now.
|
VectorArena<Mesh, kDefaultMeshNumber> Meshes;
|
||||||
VectorArena<Mesh, kDefaultMeshNumber, false> Meshes;
|
VectorArena<Vertex, kDefaultVertexCount> Vertices;
|
||||||
VectorArena<Vertex, kDefaultVertexCount, false> Vertices;
|
VectorArena<Index, kDefaultIndexCount> Indices;
|
||||||
VectorArena<Index, kDefaultIndexCount, false> Indices;
|
VectorArena<PointLight, kDefaultLightCount> PointLights;
|
||||||
VectorArena<PointLight, kDefaultLightCount, false> PointLights;
|
|
||||||
|
|
||||||
GraphicsBuffer* VertexBuffer;
|
GraphicsBuffer* VertexBuffer;
|
||||||
GraphicsBuffer* IndexBuffer;
|
GraphicsBuffer* IndexBuffer;
|
||||||
|
|||||||
@@ -7,17 +7,26 @@
|
|||||||
namespace Juliet
|
namespace Juliet
|
||||||
{
|
{
|
||||||
NetworkPacket::NetworkPacket() = default;
|
NetworkPacket::NetworkPacket() = default;
|
||||||
|
NetworkPacket::NetworkPacket(Arena& arena)
|
||||||
|
{
|
||||||
|
Data.Create(&arena);
|
||||||
|
}
|
||||||
NetworkPacket::~NetworkPacket() = default;
|
NetworkPacket::~NetworkPacket() = default;
|
||||||
NetworkPacket::NetworkPacket(NetworkPacket&) = default;
|
NetworkPacket::NetworkPacket(NetworkPacket&) = default;
|
||||||
NetworkPacket& NetworkPacket::operator=(const NetworkPacket&) = default;
|
NetworkPacket& NetworkPacket::operator=(const NetworkPacket&) = default;
|
||||||
NetworkPacket::NetworkPacket(NetworkPacket&&) noexcept = default;
|
NetworkPacket::NetworkPacket(NetworkPacket&&) noexcept = default;
|
||||||
NetworkPacket& NetworkPacket::operator=(NetworkPacket&&) noexcept = default;
|
NetworkPacket& NetworkPacket::operator=(NetworkPacket&&) noexcept = default;
|
||||||
|
|
||||||
|
void NetworkPacket::Create(Arena& arena)
|
||||||
|
{
|
||||||
|
Data.Create(&arena);
|
||||||
|
}
|
||||||
|
|
||||||
ByteBuffer NetworkPacket::GetRawData()
|
ByteBuffer NetworkPacket::GetRawData()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer{};
|
ByteBuffer buffer{};
|
||||||
buffer.Data = Data.data();
|
buffer.Data = Data.DataPtr();
|
||||||
buffer.Size = Data.size();
|
buffer.Size = Data.Size();
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
@@ -52,9 +61,7 @@ namespace Juliet
|
|||||||
{
|
{
|
||||||
if (buffer.Data && (buffer.Size > 0))
|
if (buffer.Data && (buffer.Size > 0))
|
||||||
{
|
{
|
||||||
const auto* begin = reinterpret_cast<const std::byte*>(buffer.Data);
|
Data.PushBack(TO_BUFFER(buffer.Data), buffer.Size);
|
||||||
const auto* end = begin + buffer.Size;
|
|
||||||
Data.insert(Data.end(), begin, end);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ namespace Juliet
|
|||||||
// Because of that we will send the size of the packet first before sending the data.
|
// Because of that we will send the size of the packet first before sending the data.
|
||||||
|
|
||||||
// TODO Use scratch allocator.
|
// TODO Use scratch allocator.
|
||||||
|
/*
|
||||||
Vector<Byte> scratchVector;
|
Vector<Byte> scratchVector;
|
||||||
scratchVector.resize(buffer.Size + sizeof(uint32));
|
scratchVector.resize(buffer.Size + sizeof(uint32));
|
||||||
|
|
||||||
@@ -52,6 +53,8 @@ namespace Juliet
|
|||||||
}
|
}
|
||||||
|
|
||||||
return messageStatus;
|
return messageStatus;
|
||||||
|
*/
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Socket::RequestStatus TcpSocket::Send(ByteBuffer buffer)
|
Socket::RequestStatus TcpSocket::Send(ByteBuffer buffer)
|
||||||
|
|||||||
@@ -40,13 +40,14 @@ namespace Juliet::Debug
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Static Vector for lookup
|
// Static Vector for lookup
|
||||||
VectorArena<PagedArenaStateEntry> s_PagedArenaStates;
|
VectorArena<PagedArenaStateEntry, Kilobytes(1024)> s_PagedArenaStates;
|
||||||
|
|
||||||
PagedArenaDebugState& GetPagedArenaState(const Arena* arena)
|
PagedArenaDebugState& GetPagedArenaState(const Arena* arena)
|
||||||
{
|
{
|
||||||
if (s_PagedArenaStates.Arena == nullptr)
|
if (s_PagedArenaStates.Arena == nullptr)
|
||||||
{
|
{
|
||||||
s_PagedArenaStates.Create(JULIET_DEBUG_ONLY("DebugState States"));
|
Arena* pagedArenaStates = ArenaAllocate({} JULIET_DEBUG_ONLY(, "DebugState States"));
|
||||||
|
s_PagedArenaStates.Create(pagedArenaStates);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& entry : s_PagedArenaStates)
|
for (auto& entry : s_PagedArenaStates)
|
||||||
@@ -104,7 +105,8 @@ namespace Juliet::Debug
|
|||||||
static VectorArena<const Arena*> blocks;
|
static VectorArena<const Arena*> blocks;
|
||||||
if (blocks.Arena == nullptr)
|
if (blocks.Arena == nullptr)
|
||||||
{
|
{
|
||||||
blocks.Create(JULIET_DEBUG_ONLY("DebugState Blocks"));
|
Arena* pagedArenaStates = ArenaAllocate({} JULIET_DEBUG_ONLY(, "DebugState Blocks"));
|
||||||
|
blocks.Create(pagedArenaStates);
|
||||||
}
|
}
|
||||||
blocks.Clear();
|
blocks.Clear();
|
||||||
|
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ namespace Juliet
|
|||||||
GraphicsBuffer* TransformsBuffer = nullptr;
|
GraphicsBuffer* TransformsBuffer = nullptr;
|
||||||
GraphicsTransferBuffer* LoadCopyBuffer = nullptr;
|
GraphicsTransferBuffer* LoadCopyBuffer = nullptr;
|
||||||
|
|
||||||
VectorArena<Mesh, kDefaultMeshNumber, false> Meshes;
|
VectorArena<Mesh, kDefaultMeshNumber> Meshes;
|
||||||
VectorArena<Vertex, kDefaultVertexCount, false> Vertices;
|
VectorArena<Vertex, kDefaultVertexCount> Vertices;
|
||||||
VectorArena<Index, kDefaultIndexCount, false> Indices;
|
VectorArena<Index, kDefaultIndexCount> Indices;
|
||||||
VectorArena<PointLight, kDefaultLightCount, false> PointLights;
|
VectorArena<PointLight, kDefaultLightCount> PointLights;
|
||||||
|
|
||||||
PointLight* MappedLights = nullptr;
|
PointLight* MappedLights = nullptr;
|
||||||
Matrix* MappedTransforms = nullptr;
|
Matrix* MappedTransforms = nullptr;
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ namespace Juliet::UnitTest
|
|||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
template <typename T, size_t ReserveSize, bool AllowRealloc>
|
template <typename T, size_t ReserveSize>
|
||||||
inline void VerifyVectorState(const VectorArena<T, ReserveSize, AllowRealloc>& vec, size_t expectedCount)
|
inline void VerifyVectorState(const VectorArena<T, ReserveSize>& vec, size_t expectedCount)
|
||||||
{
|
{
|
||||||
Assert(vec.Size() == expectedCount);
|
Assert(vec.Size() == expectedCount);
|
||||||
|
|
||||||
@@ -29,10 +29,13 @@ namespace Juliet::UnitTest
|
|||||||
|
|
||||||
void VectorUnitTest()
|
void VectorUnitTest()
|
||||||
{
|
{
|
||||||
|
ArenaParams params{};
|
||||||
|
Arena* testArena = ArenaAllocate(params JULIET_DEBUG_ONLY(, "VectorUnitTestArena"));
|
||||||
|
|
||||||
// Test 1: Integer VectorArena (Basic Operations)
|
// Test 1: Integer VectorArena (Basic Operations)
|
||||||
{
|
{
|
||||||
VectorArena<int> vec = {};
|
VectorArena<int> vec = {};
|
||||||
vec.Create();
|
vec.Create(testArena);
|
||||||
VerifyVectorState(vec, 0);
|
VerifyVectorState(vec, 0);
|
||||||
|
|
||||||
vec.PushBack(10);
|
vec.PushBack(10);
|
||||||
@@ -65,7 +68,7 @@ namespace Juliet::UnitTest
|
|||||||
// Test 2: RemoveAtFast
|
// Test 2: RemoveAtFast
|
||||||
{
|
{
|
||||||
VectorArena<int> vec = {};
|
VectorArena<int> vec = {};
|
||||||
vec.Create();
|
vec.Create(testArena);
|
||||||
|
|
||||||
vec.PushBack(10);
|
vec.PushBack(10);
|
||||||
vec.PushBack(20);
|
vec.PushBack(20);
|
||||||
@@ -95,7 +98,7 @@ namespace Juliet::UnitTest
|
|||||||
// Test 3: Clear and Reuse (Pointer State Check)
|
// Test 3: Clear and Reuse (Pointer State Check)
|
||||||
{
|
{
|
||||||
VectorArena<int> vec = {};
|
VectorArena<int> vec = {};
|
||||||
vec.Create();
|
vec.Create(testArena);
|
||||||
|
|
||||||
vec.PushBack(100);
|
vec.PushBack(100);
|
||||||
vec.PushBack(200);
|
vec.PushBack(200);
|
||||||
@@ -127,7 +130,7 @@ namespace Juliet::UnitTest
|
|||||||
};
|
};
|
||||||
|
|
||||||
VectorArena<TestItem> vec = {};
|
VectorArena<TestItem> vec = {};
|
||||||
vec.Create();
|
vec.Create(testArena);
|
||||||
|
|
||||||
VerifyVectorState(vec, 0);
|
VerifyVectorState(vec, 0);
|
||||||
|
|
||||||
@@ -145,39 +148,7 @@ namespace Juliet::UnitTest
|
|||||||
vec.Destroy();
|
vec.Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test 5: Reallocation Support (AllowRealloc = true)
|
// Test 5: Move Semantics
|
||||||
{
|
|
||||||
// Initial capacity 4, allow realloc
|
|
||||||
ArenaParams params{ .AllowRealloc = true };
|
|
||||||
Arena* externalArena = ArenaAllocate(params JULIET_DEBUG_ONLY(, "VectorTest"));
|
|
||||||
|
|
||||||
VectorArena<int, 4, true> vec = {};
|
|
||||||
vec.Create(externalArena);
|
|
||||||
|
|
||||||
Assert(vec.Capacity == 4);
|
|
||||||
|
|
||||||
vec.PushBack(1);
|
|
||||||
vec.PushBack(2);
|
|
||||||
vec.PushBack(3);
|
|
||||||
vec.PushBack(4);
|
|
||||||
Assert(vec.Capacity == 4);
|
|
||||||
|
|
||||||
// Trigger realloc
|
|
||||||
vec.PushBack(5);
|
|
||||||
Assert(vec.Capacity >= 5); // Should have grown (likely doubled to 8)
|
|
||||||
VerifyVectorState(vec, 5);
|
|
||||||
|
|
||||||
Assert(vec[0] == 1);
|
|
||||||
Assert(vec[1] == 2);
|
|
||||||
Assert(vec[2] == 3);
|
|
||||||
Assert(vec[3] == 4);
|
|
||||||
Assert(vec[4] == 5);
|
|
||||||
|
|
||||||
vec.Destroy();
|
|
||||||
ArenaRelease(externalArena);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test 6: Move Semantics
|
|
||||||
{
|
{
|
||||||
struct MoveOnly
|
struct MoveOnly
|
||||||
{
|
{
|
||||||
@@ -207,10 +178,8 @@ namespace Juliet::UnitTest
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
VectorArena<MoveOnly, 4, true> vec = {};
|
VectorArena<MoveOnly, 4> vec = {};
|
||||||
ArenaParams params{ .AllowRealloc = true };
|
NonNullPtr<Arena> validArena(testArena);
|
||||||
Arena* externalArena = ArenaAllocate(params JULIET_DEBUG_ONLY(, "VectorTest"));
|
|
||||||
NonNullPtr<Arena> validArena(externalArena);
|
|
||||||
vec.Create(validArena);
|
vec.Create(validArena);
|
||||||
|
|
||||||
MoveOnly item1(10);
|
MoveOnly item1(10);
|
||||||
@@ -222,16 +191,13 @@ namespace Juliet::UnitTest
|
|||||||
Assert(!vec[0].MovedFrom);
|
Assert(!vec[0].MovedFrom);
|
||||||
|
|
||||||
vec.Destroy();
|
vec.Destroy();
|
||||||
ArenaRelease(externalArena);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test 7: Resize Behavior
|
// Test 6: Resize Behavior
|
||||||
{
|
{
|
||||||
ArenaParams params{ .AllowRealloc = true };
|
NonNullPtr<Arena> validArena(testArena);
|
||||||
Arena* externalArena = ArenaAllocate(params JULIET_DEBUG_ONLY(, "VectorTest"));
|
|
||||||
NonNullPtr<Arena> validArena(externalArena);
|
|
||||||
|
|
||||||
VectorArena<int, 4, true> vec = {};
|
VectorArena<int, 4> vec = {};
|
||||||
vec.Create(validArena);
|
vec.Create(validArena);
|
||||||
|
|
||||||
vec.PushBack(1);
|
vec.PushBack(1);
|
||||||
@@ -243,42 +209,21 @@ namespace Juliet::UnitTest
|
|||||||
Assert(vec.Size() == 1);
|
Assert(vec.Size() == 1);
|
||||||
Assert(vec[0] == 1);
|
Assert(vec[0] == 1);
|
||||||
|
|
||||||
// Resize larger
|
// Resize larger up to max capacity
|
||||||
vec.Resize(4);
|
vec.Resize(4);
|
||||||
Assert(vec.Size() == 4);
|
Assert(vec.Size() == 4);
|
||||||
Assert(vec[0] == 1);
|
Assert(vec[0] == 1);
|
||||||
|
|
||||||
vec.Destroy();
|
vec.Destroy();
|
||||||
ArenaRelease(externalArena);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test 8: External Arena Usage
|
// Test 7: External Arena Usage & Volume Test within capacity
|
||||||
{
|
{
|
||||||
ArenaParams params{ .AllowRealloc = true };
|
NonNullPtr<Arena> validArena(testArena);
|
||||||
Arena* externalArena = ArenaAllocate(params JULIET_DEBUG_ONLY(, "VectorTest"));
|
|
||||||
NonNullPtr<Arena> validArena(externalArena);
|
|
||||||
|
|
||||||
VectorArena<int> vec = {};
|
VectorArena<int, 100> vec = {};
|
||||||
vec.Create(validArena); // Pass external arena
|
vec.Create(validArena); // Pass external arena
|
||||||
|
|
||||||
vec.PushBack(42);
|
|
||||||
Assert(vec.Size() == 1);
|
|
||||||
Assert(vec[0] == 42);
|
|
||||||
|
|
||||||
vec.Destroy();
|
|
||||||
ArenaRelease(externalArena);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test 9: Volume Test (100 items with Realloc)
|
|
||||||
{
|
|
||||||
ArenaParams params{ .AllowRealloc = true };
|
|
||||||
Arena* externalArena = ArenaAllocate(params JULIET_DEBUG_ONLY(, "VectorTest"));
|
|
||||||
NonNullPtr<Arena> validArena(externalArena);
|
|
||||||
|
|
||||||
VectorArena<int, 4, true> vec = {};
|
|
||||||
vec.Create(validArena);
|
|
||||||
|
|
||||||
// Push 100 items -> Should realloc multiple times
|
|
||||||
for (int i = 0; i < 100; ++i)
|
for (int i = 0; i < 100; ++i)
|
||||||
{
|
{
|
||||||
vec.PushBack(i);
|
vec.PushBack(i);
|
||||||
@@ -291,8 +236,9 @@ namespace Juliet::UnitTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
vec.Destroy();
|
vec.Destroy();
|
||||||
ArenaRelease(externalArena);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ArenaRelease(testArena);
|
||||||
}
|
}
|
||||||
} // namespace Juliet::UnitTest
|
} // namespace Juliet::UnitTest
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ namespace Romeo
|
|||||||
|
|
||||||
struct Database
|
struct Database
|
||||||
{
|
{
|
||||||
Juliet::VectorArena<FileEntry, 512, true> Entries = {};
|
Juliet::VectorArena<FileEntry, 512> Entries = {};
|
||||||
Juliet::Arena* DbArena = nullptr;
|
Juliet::Arena* DbArena = nullptr;
|
||||||
Juliet::Mutex Mutex;
|
Juliet::Mutex Mutex;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ namespace Romeo
|
|||||||
double NumVal = 0.0;
|
double NumVal = 0.0;
|
||||||
Juliet::String StrVal = {};
|
Juliet::String StrVal = {};
|
||||||
|
|
||||||
Juliet::VectorArena<JsonValue, 32, true> ArrayVal = {};
|
Juliet::VectorArena<JsonValue, 32> ArrayVal = {};
|
||||||
Juliet::VectorArena<JsonKeyValue, 32, true> ObjectVal = {};
|
Juliet::VectorArena<JsonKeyValue, 32> ObjectVal = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parses a JSON string. Memory is allocated on the provided arena.
|
// Parses a JSON string. Memory is allocated on the provided arena.
|
||||||
|
|||||||
@@ -410,7 +410,7 @@ namespace Romeo
|
|||||||
static void ParseSymbolsFromFile(
|
static void ParseSymbolsFromFile(
|
||||||
Juliet::Arena* arena,
|
Juliet::Arena* arena,
|
||||||
const Juliet::String& filePath,
|
const Juliet::String& filePath,
|
||||||
Juliet::VectorArena<ParsedSymbol, 128, true>& outSymbols
|
Juliet::VectorArena<ParsedSymbol, 128>& outSymbols
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Assert(arena != nullptr);
|
Assert(arena != nullptr);
|
||||||
@@ -726,7 +726,7 @@ namespace Romeo
|
|||||||
static void FormatAndWriteSymbols(StringBuilder& sb, Juliet::Arena* arena, const Juliet::String& filePath)
|
static void FormatAndWriteSymbols(StringBuilder& sb, Juliet::Arena* arena, const Juliet::String& filePath)
|
||||||
{
|
{
|
||||||
printf("Romeo: FormatAndWriteSymbols start for %.*s\n", static_cast<int>(filePath.Size), CStr(filePath));
|
printf("Romeo: FormatAndWriteSymbols start for %.*s\n", static_cast<int>(filePath.Size), CStr(filePath));
|
||||||
Juliet::VectorArena<ParsedSymbol, 128, true> symbols = {};
|
Juliet::VectorArena<ParsedSymbol, 128> symbols = {};
|
||||||
symbols.Create(arena JULIET_DEBUG_ONLY(, "ParsedSymbols"));
|
symbols.Create(arena JULIET_DEBUG_ONLY(, "ParsedSymbols"));
|
||||||
|
|
||||||
printf("Romeo: Calling ParseSymbolsFromFile...\n");
|
printf("Romeo: Calling ParseSymbolsFromFile...\n");
|
||||||
@@ -741,7 +741,7 @@ namespace Romeo
|
|||||||
|
|
||||||
// Collect all distinct namespaces
|
// Collect all distinct namespaces
|
||||||
printf("Romeo: Collecting namespaces...\n");
|
printf("Romeo: Collecting namespaces...\n");
|
||||||
Juliet::VectorArena<Juliet::String, 16, true> namespaces = {};
|
Juliet::VectorArena<Juliet::String, 16> namespaces = {};
|
||||||
namespaces.Create(arena JULIET_DEBUG_ONLY(, "NamespacesList"));
|
namespaces.Create(arena JULIET_DEBUG_ONLY(, "NamespacesList"));
|
||||||
|
|
||||||
for (const ParsedSymbol& sym : symbols)
|
for (const ParsedSymbol& sym : symbols)
|
||||||
|
|||||||
Reference in New Issue
Block a user