copying code over from alphane engine

This commit is contained in:
2026-08-14 06:09:53 +00:00
parent 108341158e
commit 263b6da528
13 changed files with 1203 additions and 0 deletions
+111
View File
@@ -0,0 +1,111 @@
#pragma once
#include <functional>
#include <memory>
#include <stdexcept>
#include <string>
#include <typeinfo>
#include <vector>
#include "util/logger.hpp"
#define DEFAULT_DELEGATE_FUNCTOR_ALLOC 5
namespace hep {
class expired_weak_object : public std::runtime_error {
public:
explicit expired_weak_object(const std::string& message)
: std::runtime_error(message) {}
};
/**
* Creates a weak function that safely calls a method if the
* object is alive.
*
* @tparam O Class owning the method
* @tparam A Variadic template parameters for the method arguments
*
* @param method Pointer to the static method to be called
* @param obj Shared pointer to the object instance
* @returns std::function that calls method on obj if alive, or throws if
* expired
* @throws std::invalid_argument If obj is null.
* @throws expired_weak_object If the object has expired when called
*
* @note Could investigate removing throwing exceptions, and instead return a
* bool if the weak pointer is alive. This may improve performance
*/
template <class O, typename... A>
std::function<void(A...)> createWeakFunction(void (O::*method)(A...),
std::shared_ptr<O> obj) {
if (!obj) { throw std::invalid_argument("method and obj must not be null"); }
std::weak_ptr<O> weakObj = obj;
return std::function<void(A...)>([method = std::move(method),
weakObj = std::move(weakObj)](A... args) {
if (auto lockedObj = weakObj.lock()) {
(lockedObj.get()->*method)(std::forward<A>(args)...);
} else {
throw expired_weak_object("Attempting to call function of a dead class");
}
});
}
template <typename... A>
class Delegate {
public:
using Functor = std::function<void(A...)>;
Delegate() { this->functors.reserve(DEFAULT_DELEGATE_FUNCTOR_ALLOC); }
void add(const Functor& func) { functors.push_back(func); }
template <class O>
void addMethod(void (O::*memberFn)(A...), std::shared_ptr<O> obj) {
functors.push_back(createWeakFunction(memberFn, obj));
}
void clear() { this->functors.clear(); }
void invoke(A... args) {
if (this->functors.empty()) {
log::warning("invoking empty delegate");
return;
}
std::vector<size_t> deadFunctorIndexs;
for (size_t i = 0; i < functors.size(); i++) {
if (this->functors[i]) {
try {
this->functors[i](std::forward<A>(args)...);
} catch (const expired_weak_object& e) {
log::error("delegate invoke error: ", e.what());
deadFunctorIndexs.push_back(i);
}
}
}
for (auto it = deadFunctorIndexs.rbegin(); it != deadFunctorIndexs.rend();
++it) {
functors.erase(functors.begin() + *it);
}
}
void operator=(Functor c) {
clear();
if (c != nullptr) { add(c); }
}
void operator+=(Functor c) { add(c); }
void operator()() { invoke(); }
private:
std::vector<Functor> functors;
};
} // namespace hep
+140
View File
@@ -0,0 +1,140 @@
/**
* Lots of work still needs to be done in here.
*
* Usage:
* using namespace hep;
* log::fatal("fatal message")
* log::info("Infomation message")
*
* TODO Impl some form of log error handling
*/
#pragma once
#include <iostream>
#include <utility>
#include "types.hpp"
namespace hep
{
namespace log
{
enum class LEVEL
{
NONE,
FATAL,
ERROR,
WARNING,
INFO,
VERBOSE,
DEBUGGING,
TRACE,
};
// Helper print functions
#define LOG_PRINT_HELPER(MSG) std::cout << MSG
#define LOG_PREFIX_FATAL LOG_PRINT_HELPER("\033[1;91m[FATAL]\033[0m ")
#define LOG_PREFIX_ERROR LOG_PRINT_HELPER("\033[1;31m[ERROR]\033[0m ")
#define LOG_PREFIX_WARNING LOG_PRINT_HELPER("\033[1;33m[WARNING]\033[0m ")
#define LOG_PREFIX_INFO LOG_PRINT_HELPER("\033[32m[INFO]\033[0m ")
#define LOG_PREFIX_VERBOSE LOG_PRINT_HELPER("\033[36m[VERBOSE]\033[0m ")
#define LOG_PREFIX_DEBUG LOG_PRINT_HELPER("\033[1;34m[DEBUG]\033[0m ")
#define LOG_PREFIX_TRACE LOG_PRINT_HELPER("\033[1;90m[TRACE]\033[0m ")
template <typename... Args>
void log(LEVEL level = LEVEL::NONE, Args... args)
{
#ifndef NDEBUG
switch (level)
{
case LEVEL::FATAL:
LOG_PREFIX_FATAL;
break;
case LEVEL::ERROR:
LOG_PREFIX_ERROR;
break;
case LEVEL::WARNING:
LOG_PREFIX_WARNING;
break;
case LEVEL::INFO:
LOG_PREFIX_INFO;
break;
case LEVEL::VERBOSE:
LOG_PREFIX_VERBOSE;
break;
// case LEVEL::DEBUGGING:
// LOG_PREFIX_DEBUG;
// break;
case LEVEL::TRACE:
LOG_PREFIX_TRACE;
break;
default:
std::cout << "\033[1;90m[LOG]\033[0m ";
break;
}
((std::cout << ' ' << std::forward<Args>(args)), ...);
std::cout << std::endl;
#else
(void)level;
(void)std::initializer_list<int>{((void)args, 0)...};
#endif // !NDEBUG
}
template <typename... Args>
void fatal(Args... args)
{
log(LEVEL::FATAL, args...);
}
template <typename... Args>
void error(Args... args)
{
log(LEVEL::ERROR, args...);
}
template <typename... Args>
void warning(Args... args)
{
log(LEVEL::WARNING, args...);
}
template <typename... Args>
void info(Args... args)
{
log(LEVEL::INFO, args...);
}
template <typename... Args>
void verbose(Args... args)
{
log(LEVEL::VERBOSE, args...);
}
template <typename... Args>
void debug(const char *file, u16 line, Args... args)
{
#ifndef NDEBUG
LOG_PREFIX_DEBUG;
std::cout << file << "::" << line;
((std::cout << ' ' << std::forward<Args>(args)), ...);
std::cout << std::endl;
#else
(void)file;
(void)line;
(void)std::initializer_list<int>{((void)args, 0)...};
#endif // !NDEBUG
}
// trick
#define debug(...) debug(__FILE__, __LINE__, __VA_ARGS__)
template <typename... Args>
void trace(Args... args)
{
log(LEVEL::TRACE, args...);
}
} // namespace log
} // namespace hep