Implemented initial concept of Objects and GC

This commit is contained in:
Jordon Brooks 2025-05-06 23:21:04 +01:00
parent 1dca4a91d9
commit 76ffb658db
Signed by: jordon
GPG key ID: DBD9758CD53E786A
13 changed files with 599 additions and 140 deletions

83
.vscode/settings.json vendored
View file

@ -2,5 +2,86 @@
"C_Cpp.default.compileCommands": "d:\\FluxEngine\\builddir/compile_commands.json",
"C_Cpp.default.configurationProvider": "mesonbuild.mesonbuild",
"cmake.ignoreCMakeListsMissing": true,
"C_Cpp.errorSquiggles": "enabled"
"C_Cpp.errorSquiggles": "enabled",
"files.associations": {
"algorithm": "cpp",
"array": "cpp",
"atomic": "cpp",
"bit": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"charconv": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"compare": "cpp",
"complex": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"coroutine": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"exception": "cpp",
"expected": "cpp",
"filesystem": "cpp",
"format": "cpp",
"forward_list": "cpp",
"fstream": "cpp",
"functional": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"ios": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"iterator": "cpp",
"limits": "cpp",
"list": "cpp",
"locale": "cpp",
"map": "cpp",
"memory": "cpp",
"mutex": "cpp",
"new": "cpp",
"optional": "cpp",
"ostream": "cpp",
"ratio": "cpp",
"regex": "cpp",
"source_location": "cpp",
"span": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"string": "cpp",
"system_error": "cpp",
"thread": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"typeinfo": "cpp",
"unordered_map": "cpp",
"utility": "cpp",
"variant": "cpp",
"vector": "cpp",
"xfacet": "cpp",
"xhash": "cpp",
"xiosbase": "cpp",
"xlocale": "cpp",
"xlocbuf": "cpp",
"xlocinfo": "cpp",
"xlocmes": "cpp",
"xlocmon": "cpp",
"xlocnum": "cpp",
"xloctime": "cpp",
"xmemory": "cpp",
"xstring": "cpp",
"xtr1common": "cpp",
"xtree": "cpp",
"xutility": "cpp",
"*.rh": "cpp"
}
}

View file

@ -3,6 +3,9 @@ flux_inc = include_directories('src/public')
flux_sources = files(
'src/private/Engine/Engine.cpp',
'src/private/Log.cpp',
'src/private/Engine/GarbageCollector.cpp',
'src/private/Framework/BaseObject.cpp',
'src/private/Framework/Object.cpp',
)
# 1) Grab the active C++ compiler

View file

@ -1,58 +1,111 @@
#include "Engine/Engine.h"
#include "Log.h"
#include "Framework/Object.h"
#include "Engine/GarbageCollector.h"
namespace Flux
bool FluxEngine::GIsRunning = false;
FluxEngine* FluxEngine::GInstance = nullptr;
FluxEngine* FluxEngine::CreateInstance()
{
bool FluxEngine::GIsRunning = false;
FluxEngine* FluxEngine::GInstance = nullptr;
FluxEngine::FluxEngine() : _Logger(*new Logger())
if (GInstance != nullptr)
{
if (GIsRunning)
FluxEngine* Engine = GetInstance();
if (Engine)
{
GetLogger()->LogTrace("Engine already running!");
bErrorState = true;
return;
Engine->GetLogger()->LogTrace("Engine already running!");
return nullptr;
}
if (GInstance != nullptr)
{
FluxEngine* Engine = GetInstance();
if (Engine)
{
Engine->GetLogger()->LogTrace("Engine already running!");
}
return;
}
GInstance = this;
}
FluxEngine::~FluxEngine()
FluxEngine* Engine = new FluxEngine();
if (Engine == nullptr)
{
GetLogger()->LogTrace("Engine shutting down!");
GetLogger()->LogTrace("Failed to create engine instance!");
return nullptr;
}
void FluxEngine::Start()
{
if (bErrorState)
{
GetLogger()->LogTrace("Engine failed to start!");
return;
}
Engine->GetLogger()->LogTrace("Engine instance created!");
Engine->Init();
Engine->Start();
return Engine;
}
GetLogger()->LogTrace("Engine started!");
GIsRunning = true;
EngineLoop();
GarbageCollector& FluxEngine::GetGarbageCollector()
{
return _GarbageCollector;
}
void FluxEngine::Init()
{
}
FluxEngine::FluxEngine() : _Logger(*new Logger()), _GarbageCollector(*new GarbageCollector(this))
{
if (GIsRunning)
{
GetLogger()->LogTrace("Engine already running!");
bErrorState = true;
return;
}
void Flux::FluxEngine::EngineLoop()
if (GInstance != nullptr)
{
while (IsRunning())
FluxEngine* Engine = GetInstance();
if (Engine)
{
GetLogger()->LogTrace("Loop running!");
// Main engine loop
// Update, render, etc.
Engine->GetLogger()->LogTrace("Engine already running!");
}
return;
}
GInstance = this;
}
FluxEngine::~FluxEngine()
{
GetLogger()->LogTrace("Engine shutting down!");
}
int32_t FluxEngine::Start()
{
if (bErrorState)
{
GetLogger()->LogTrace("Engine failed to start!");
return -1;
}
GetLogger()->LogTrace("Engine started!");
GIsRunning = true;
EngineLoop();
return bErrorState ? -1 : 0;
}
Logger* FluxEngine::GetLogger()
{
if (GInstance != nullptr)
{
FluxEngine* Engine = GetInstance();
if (Engine)
{
return &Engine->_Logger;
}
}
static Logger DefaultLogger;
return &DefaultLogger;
}
void FluxEngine::EngineLoop()
{
while (IsRunning())
{
//GetLogger()->LogTrace("Loop running!");
// Main engine loop
// Update, render, etc.
}
}

View file

@ -0,0 +1,80 @@
#include "Engine/GarbageCollector.h"
#include "Engine/Engine.h"
#include <memory>
#include "Log.h"
#include "Framework/Object.h"
void GarbageCollector::Init()
{
BaseObject::Init();
LOG_INFO("Garbage Collector Initialized");
}
void GarbageCollector::CollectGarbage()
{
// Implement garbage collection logic here
// Create a iterator to traverse the list of objects and remove unreachable / nullptr objects
for (auto it = _RootObjects.begin(); it != _RootObjects.end();)
{
BaseObject* object = it->get();
if (!object || object->IsValid())
{
LOG_WARN("Removing unreachable object from Garbage Collector: " + object->GetName());
it = _RootObjects.erase(it);
}
else { ++it; }
}
}
GarbageCollector::GarbageCollector(FluxEngine* engine) : BaseObject(engine)
{
Init();
}
GarbageCollector::~GarbageCollector()
{
_RootObjects.clear();
}
void GarbageCollector::AddObject(std::shared_ptr<Object> ObjectToAdd)
{
if (ObjectToAdd && ObjectToAdd->IsValid())
{
_RootObjects.push_back(ObjectToAdd->shared_from_this());
LOG_INFO("Added object to Garbage Collector: " + ObjectToAdd->GetName());
}
else
{
LOG_ERROR("Failed to add object to Garbage Collector: " + (ObjectToAdd ? ObjectToAdd->GetName() : "nullptr"));
}
}
void GarbageCollector::RemoveObject(std::shared_ptr<Object> ObjectToRemove)
{
if (!ObjectToRemove)
{
LOG_ERROR("Failed to remove object from GC: nullptr");
return;
}
auto oldSize = _RootObjects.size();
auto newEnd = std::remove_if(
_RootObjects.begin(), _RootObjects.end(),
[ObjectToRemove](const std::shared_ptr<Object>& obj) {
return obj.get() == ObjectToRemove.get();
}
);
if (newEnd != _RootObjects.end())
{
_RootObjects.erase(newEnd, _RootObjects.end());
LOG_INFO("Removed object from GC: {0}", object->GetName());
}
else
{
LOG_ERROR("RemoveObject(): {0} not found in GC",
object->GetName());
}
}

View file

@ -0,0 +1,59 @@
#include "Framework/BaseObject.h"
#include "Engine/Engine.h"
#include "Log.h"
BaseObject::BaseObject(FluxEngine* Engine)
{
_CachedEngine = Engine;
}
BaseObject::~BaseObject()
{
LOG_INFO("Destroying object: {0}", GetName());
}
void BaseObject::Init()
{
if (bIsInitialized || bUnreachable)
{
return;
}
_Name = std::string(typeid(*this).name()) + "_" + std::to_string(reinterpret_cast<std::uintptr_t>(this));
bIsInitialized = true;
}
void BaseObject::Destroy()
{
if (bUnreachable)
{
return;
}
bUnreachable = true;
}
bool BaseObject::IsValid()
{
return bIsInitialized;
}
bool BaseObject::IsUnreachable(BaseObject* Object)
{
return Object && Object->IsValid();
}
std::string BaseObject::GetName() const
{
return _Name;
}
FluxEngine* BaseObject::GetEngine() const
{
if (_CachedEngine == nullptr)
{
_CachedEngine = FluxEngine::GetInstance();
}
return _CachedEngine;
}

View file

@ -0,0 +1,23 @@
#include "Framework/Object.h"
#include "Engine/Engine.h"
#include "Log.h"
#include <memory>
Object::~Object()
{
LOG_INFO("Destroying object: {0}", GetName());
}
void Object::Init()
{
BaseObject::Init();
FluxEngine* engine = GetEngine();
if (!engine)
{
LOG_ERROR("Failed to initialize object: {0}", GetName());
return;
}
engine->GetGarbageCollector().AddObject(shared_from_this());
}

View file

@ -3,48 +3,82 @@
#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h"
namespace Flux
struct LoggerImpl
{
struct LoggerImpl
{
LoggerImpl() = default;
~LoggerImpl() = default;
LoggerImpl() = default;
~LoggerImpl() = default;
std::shared_ptr<spdlog::logger> _logger;
};
std::shared_ptr<spdlog::logger> _logger;
};
Logger::~Logger() = default;
spdlog::logger *Logger::GetLogger() const
{
return _impl._logger.get();
}
spdlog::logger *Logger::GetLogger() const
{
return _impl._logger.get();
Logger::Logger() : _impl(* new LoggerImpl())
{
// Initialize the logger
if (GetLogger()) {
return;
}
Logger::Logger() : _impl(* new LoggerImpl())
{
// Initialize the logger
if (GetLogger()) {
return;
}
// Create a new logger instance
spdlog::set_pattern("%^[%T] %n: %v%$");
// Create a new logger instance
spdlog::set_pattern("%^[%T] %n: %v%$");
_impl._logger = spdlog::stdout_color_mt("FLUX");
_impl._logger->set_level(spdlog::level::trace);
LogTrace("Logger initialized!");
std::shared_ptr<spdlog::logger> logger = spdlog::get("FLUX");
if (logger) {
_impl._logger = logger;
return;
}
void Logger::LogTrace(const std::string &message)
_impl._logger = spdlog::stdout_color_mt("FLUX");
_impl._logger->set_level(spdlog::level::trace);
LogTrace("Logger initialized!");
}
Logger::~Logger()
{
}
void Logger::LogTrace(const std::string& message)
{
if (auto logger = GetLogger())
{
spdlog::logger* logger = GetLogger();
if (!logger)
{
return;
}
logger->trace(message);
}
}
void Logger::LogInfo(const std::string& message)
{
if (auto logger = GetLogger())
{
logger->info(message);
}
}
void Logger::LogWarn(const std::string& message)
{
if (auto logger = GetLogger())
{
logger->warn(message);
}
}
void Logger::LogError(const std::string& message)
{
if (auto logger = GetLogger())
{
logger->error(message);
}
}
void Logger::LogFatal(const std::string& message)
{
if (auto logger = GetLogger())
{
logger->critical(message);
}
}

View file

@ -1,56 +1,61 @@
#pragma once
#include "Core.h"
#include "Log.h"
#include <memory>
#include <vector>
#include "Framework/Object.h"
#include "Engine/GarbageCollector.h"
namespace Flux
class Logger;
class FLUX_API FluxEngine
{
class FLUX_API FluxEngine
public:
static FluxEngine* CreateInstance();
template<typename T, typename... Args>
static std::unique_ptr<T> CreateApplication(Args&&... args)
{
public:
FluxEngine();
~FluxEngine();
static_assert(std::is_base_of<FluxEngine, T>::value, "T must inherit from FluxEngine");
std::unique_ptr<T> app = std::make_unique<T>(std::forward<Args>(args)...);
app->Init();
return app;
}
void Start();
FluxEngine();
~FluxEngine();
static FluxEngine* GetInstance()
{
return GInstance;
}
virtual void Init();
static bool IsRunning()
{
return GIsRunning;
}
virtual int32_t Start();
static Logger* GetLogger()
{
if (GIsRunning || GInstance != nullptr)
{
FluxEngine* Engine = GetInstance();
if (Engine)
{
return &Engine->_Logger;
}
}
static FluxEngine* GetInstance()
{
return GInstance;
}
return nullptr;
}
static bool IsRunning()
{
return GIsRunning;
}
void RequestExit()
{
GIsRunning = false;
}
static Logger* GetLogger();
void EngineLoop();
void RequestExit()
{
GIsRunning = false;
}
private:
Flux::Logger& _Logger;
GarbageCollector& GetGarbageCollector();
static bool GIsRunning;
static FluxEngine* GInstance;
void EngineLoop();
bool bErrorState = false;
};
}
private:
Logger& _Logger;
GarbageCollector& _GarbageCollector;
static bool GIsRunning;
static FluxEngine* GInstance;
bool bErrorState = false;
};

View file

@ -0,0 +1,28 @@
#pragma once
#include "Core.h"
#include <memory>
#include <vector>
#include "Framework/BaseObject.h"
class FluxEngine;
class Object;
class GarbageCollector : public BaseObject
{
public:
FLUX_API explicit GarbageCollector(FluxEngine* engine);
FLUX_API ~GarbageCollector();
FLUX_API void AddObject(std::shared_ptr<Object> ObjectToAdd);
FLUX_API void RemoveObject(std::shared_ptr<Object> ObjectToRemove);
FLUX_API void CollectGarbage();
protected:
virtual void Init() override;
private:
std::vector<std::shared_ptr<Object>> _RootObjects;
};

View file

@ -0,0 +1,33 @@
#pragma once
#include "Core.h"
#include <string>
#include <memory>
class FluxEngine;
class FLUX_API BaseObject
{
public:
BaseObject(FluxEngine* Engine);
BaseObject() = default;
virtual ~BaseObject();
virtual void Destroy();
virtual void Init();
static bool IsUnreachable(BaseObject* Object);
virtual bool IsValid();
std::string GetName() const;
FluxEngine* GetEngine() const;
private:
mutable FluxEngine* _CachedEngine = nullptr;
bool bIsInitialized = false;
bool bUnreachable = false;
std::string _Name = "";
};

View file

@ -0,0 +1,39 @@
#pragma once
#include "Core.h"
#include <memory>
#include "Framework/BaseObject.h"
class FluxEngine;
class FLUX_API Object : public BaseObject, public std::enable_shared_from_this<Object>
{
public:
template<typename T, typename... Args>
static std::shared_ptr<T> NewObject(Args&&... args)
{
static_assert(std::is_base_of<Object,T>::value, "T must inherit from Object");
std::shared_ptr<T> ptr = std::make_shared<T>(std::forward<Args>(args)...);
ptr->Init();
return ptr;
}
Object() = default;
virtual ~Object();
// Copy constructor
Object(const Object& other) = default;
// Move constructor
Object(Object&& other) noexcept = default;
// Copy assignment operator
Object& operator=(const Object& other) = default;
// Move assignment operator
Object& operator=(Object&& other) noexcept = default;
virtual void Init() override;
};

View file

@ -10,34 +10,28 @@ namespace spdlog
class logger;
}
namespace Flux
{
struct LoggerImpl;
struct LoggerImpl;
class FLUX_API Logger
{
public:
class FLUX_API Logger
{
public:
Logger();
~Logger();
void LogTrace(const std::string& message);
private:
spdlog::logger* GetLogger() const;
void LogInfo(const std::string& message);
void LogWarn(const std::string& message);
void LogError(const std::string& message);
void LogFatal(const std::string& message);
Flux::LoggerImpl& _impl;
};
}
private:
spdlog::logger* GetLogger() const;
// Core log macros
/*#define FLUX_CORE_TRACE(...) ::Flux::Log::GetCoreLogger()->trace(__VA_ARGS__)
#define FLUX_CORE_INFO(...) ::Flux::Log::GetCoreLogger()->info(__VA_ARGS__)
#define FLUX_CORE_WARN(...) ::Flux::Log::GetCoreLogger()->warn(__VA_ARGS__)
#define FLUX_CORE_ERROR(...) ::Flux::Log::GetCoreLogger()->error(__VA_ARGS__)
#define FLUX_CORE_FATAL(...) ::Flux::Log::GetCoreLogger()->fatal(__VA_ARGS__)
LoggerImpl& _impl;
};
// Client log macros
#define FLUX_TRACE(...) ::Flux::Log::GetCoreLogger()->trace(__VA_ARGS__)
#define FLUX_INFO(...) ::Flux::Log::GetCoreLogger()->info(__VA_ARGS__)
#define FLUX_WARN(...) ::Flux::Log::GetCoreLogger()->warn(__VA_ARGS__)
#define FLUX_ERROR(...) ::Flux::Log::GetCoreLogger()->error(__VA_ARGS__)
#define FLUX_FATAL(...) ::Flux::Log::GetCoreLogger()->fatal(__VA_ARGS__)*/
#define LOG_TRACE(message) ::FluxEngine::GetLogger()->LogTrace(message)
#define LOG_INFO(message) ::FluxEngine::GetLogger()->LogInfo(message)
#define LOG_WARN(message) ::FluxEngine::GetLogger()->LogWarn(message)
#define LOG_ERROR(message) ::FluxEngine::GetLogger()->LogError(message)
#define LOG_FATAL(message) ::FluxEngine::GetLogger()->LogFatal(message)

View file

@ -1,9 +1,36 @@
#include "Flux.h"
#include "Framework/Object.h"
int main (int argc, char** argv)
class SandboxObject : public Object
{
Flux::FluxEngine engine;
engine.Start();
public:
SandboxObject() = default;
virtual ~SandboxObject() = default;
return 0;
virtual void Init() override
{
Object::Init();
LOG_INFO("SandboxObject Initialized: {0}", GetName());
}
};
class Sandbox : public FluxEngine
{
public:
Sandbox() = default;
virtual ~Sandbox() = default;
virtual void Init() override
{
FluxEngine::Init();
std::shared_ptr<SandboxObject> Obj = Object::NewObject<SandboxObject>();
}
};
int main(int argc, char** argv)
{
std::unique_ptr<Sandbox> app = FluxEngine::CreateApplication<Sandbox>();
app->Init();
return app->Start();
}