BigFile/Sasquatch #1
@@ -41,19 +41,19 @@ template<class SLOTMAP>
|
||||
class SlotMapAdaptor
|
||||
{
|
||||
public:
|
||||
using Key = SlotMapKey;
|
||||
using Key = SLOTMAP::SlotMapKey;
|
||||
|
||||
SlotMapKey Add(MyComplexStruct&& p_value)
|
||||
Key Add(MyComplexStruct&& p_value)
|
||||
{
|
||||
return m_container.Insert(std::move(p_value));
|
||||
}
|
||||
|
||||
const MyComplexStruct* Find(const SlotMapKey p_key) const
|
||||
const MyComplexStruct* Find(const Key p_key) const
|
||||
{
|
||||
return m_container.Get(p_key);
|
||||
}
|
||||
|
||||
void Remove(const SlotMapKey p_key)
|
||||
void Remove(const Key p_key)
|
||||
{
|
||||
m_container.Remove(p_key);
|
||||
}
|
||||
|
||||
@@ -119,6 +119,8 @@ class ContainerHandle
|
||||
|
||||
class AssetContainerBase
|
||||
{
|
||||
using SlotMap = StableSlotMap<ContainerHandle>;
|
||||
using SlotMapKey = SlotMap::SlotMapKey;
|
||||
public:
|
||||
virtual ~AssetContainerBase() = default;
|
||||
|
||||
@@ -245,7 +247,7 @@ class AssetContainerBase
|
||||
/*
|
||||
* HandleContainers
|
||||
*/
|
||||
StableSlotMap<ContainerHandle> m_handles;
|
||||
SlotMap m_handles;
|
||||
|
||||
/*
|
||||
* Every Asset added to the map
|
||||
@@ -258,6 +260,8 @@ class AssetContainerBase
|
||||
template<class ASSET>
|
||||
class AssetContainer: public AssetContainerBase
|
||||
{
|
||||
using SlotMap = StableSlotMap<ASSET>;
|
||||
using SlotMapKey = SlotMap::SlotMapKey;
|
||||
public:
|
||||
AssetContainer() = default;
|
||||
|
||||
@@ -343,7 +347,7 @@ class AssetContainer: public AssetContainerBase
|
||||
/*
|
||||
* The assets
|
||||
*/
|
||||
StableSlotMap<ASSET> m_assets;
|
||||
SlotMap m_assets;
|
||||
};
|
||||
} // namespace Bigfoot
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
// to delete when an actual source is in Engine
|
||||
@@ -1,95 +0,0 @@
|
||||
/*********************************************************************
|
||||
* \file EASTLFormatters.hpp
|
||||
*
|
||||
* \author Romain BOULLARD
|
||||
* \date December 2025
|
||||
*********************************************************************/
|
||||
#ifndef BIGFOOT_SYSTEM_EASTLFORMATTERS_HPP
|
||||
#define BIGFOOT_SYSTEM_EASTLFORMATTERS_HPP
|
||||
#include <Utils/TargetMacros.h>
|
||||
|
||||
#if defined(BIGFOOT_NOT_OPTIMIZED)
|
||||
#include <quill/DeferredFormatCodec.h>
|
||||
#endif
|
||||
|
||||
#include <format>
|
||||
|
||||
#include <EASTL/string.h>
|
||||
#include <EASTL/string_view.h>
|
||||
|
||||
// STRING
|
||||
|
||||
template<>
|
||||
struct std::formatter<eastl::string>
|
||||
{
|
||||
constexpr auto parse(std::format_parse_context& ctx)
|
||||
{
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template<typename FormatContext>
|
||||
auto format(const eastl::string& p_string, FormatContext& ctx) const
|
||||
{
|
||||
return std::format_to(ctx.out(), "{}", p_string.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
#if defined BIGFOOT_NOT_OPTIMIZED
|
||||
template<>
|
||||
struct fmtquill::formatter<eastl::string>
|
||||
{
|
||||
constexpr auto parse(format_parse_context& ctx)
|
||||
{
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
auto format(const eastl::string& p_string, format_context& ctx) const
|
||||
{
|
||||
return fmtquill::format_to(ctx.out(), "{}", p_string.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct quill::Codec<eastl::string>: quill::DeferredFormatCodec<eastl::string>
|
||||
{
|
||||
};
|
||||
#endif
|
||||
|
||||
// STRING_VIEW
|
||||
|
||||
template<>
|
||||
struct std::formatter<eastl::string_view>
|
||||
{
|
||||
constexpr auto parse(std::format_parse_context& ctx)
|
||||
{
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template<typename FormatContext>
|
||||
auto format(const eastl::string_view& p_stringView, FormatContext& ctx) const
|
||||
{
|
||||
return std::format_to(ctx.out(), "{}", p_stringView.data());
|
||||
}
|
||||
};
|
||||
|
||||
#if defined BIGFOOT_NOT_OPTIMIZED
|
||||
template<>
|
||||
struct fmtquill::formatter<eastl::string_view>
|
||||
{
|
||||
constexpr auto parse(format_parse_context& ctx)
|
||||
{
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
auto format(const eastl::string_view& p_stringView, format_context& ctx) const
|
||||
{
|
||||
return fmtquill::format_to(ctx.out(), "{}", p_stringView.data());
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct quill::Codec<eastl::string_view>: quill::DeferredFormatCodec<eastl::string_view>
|
||||
{
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,16 +0,0 @@
|
||||
namespace Bigfoot.Flat;
|
||||
|
||||
enum LogSinkType: byte
|
||||
{
|
||||
Console
|
||||
}
|
||||
|
||||
enum LogLevel: byte
|
||||
{
|
||||
Debug,
|
||||
Trace,
|
||||
Info,
|
||||
Warn,
|
||||
Error,
|
||||
Critical
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
/*********************************************************************
|
||||
* \file Log.hpp
|
||||
*
|
||||
* \author Romain BOULLARD
|
||||
* \date October 2025
|
||||
*********************************************************************/
|
||||
#ifndef BIGFOOT_SYSTEM_LOG_HPP
|
||||
#define BIGFOOT_SYSTEM_LOG_HPP
|
||||
#include <System/Log/EASTLFormatters.hpp>
|
||||
|
||||
#if defined BIGFOOT_NOT_OPTIMIZED
|
||||
#include <System/Log/Log_generated.hpp>
|
||||
|
||||
#include <Utils/Singleton.hpp>
|
||||
|
||||
#include <EASTL/array.h>
|
||||
|
||||
#ifdef BIGFOOT_WINDOWS
|
||||
#pragma warning(disable: 4702)
|
||||
#endif
|
||||
#include <quill/Backend.h>
|
||||
#include <quill/Frontend.h>
|
||||
#include <quill/LogMacros.h>
|
||||
#include <quill/Logger.h>
|
||||
#include <quill/sinks/ConsoleSink.h>
|
||||
#if defined BIGFOOT_WINDOWS
|
||||
#pragma warning(default: 4702)
|
||||
#endif
|
||||
|
||||
namespace Bigfoot
|
||||
{
|
||||
class Log
|
||||
{
|
||||
public:
|
||||
struct LoggerInfo
|
||||
{
|
||||
std::string m_name;
|
||||
Flat::LogLevel m_level;
|
||||
};
|
||||
|
||||
Log();
|
||||
|
||||
Log(const Log& p_logger) = delete;
|
||||
Log(Log&& p_logger) = delete;
|
||||
|
||||
/**
|
||||
* Register a logger.
|
||||
*
|
||||
* \param p_loggerInfo The logger to register
|
||||
*/
|
||||
[[nodiscard]]
|
||||
quill::Logger* RegisterLogger(const LoggerInfo& p_loggerInfo);
|
||||
|
||||
/**
|
||||
* Register a logger.
|
||||
*
|
||||
* \param p_loggerInfo The logger to get
|
||||
* \return The logger, nullptr if it does not exist
|
||||
*/
|
||||
[[nodiscard]]
|
||||
quill::Logger* GetLogger(const LoggerInfo& p_loggerInfo);
|
||||
|
||||
/**
|
||||
* Changes the loglevel of a Logger.
|
||||
*
|
||||
* \param p_loggerInfo The logger to change
|
||||
* \param p_level The new level
|
||||
*/
|
||||
void ChangeLoggerLogLevel(LoggerInfo& p_loggerInfo, const Flat::LogLevel p_level);
|
||||
|
||||
~Log();
|
||||
|
||||
Log& operator=(const Log& p_logger) = delete;
|
||||
Log& operator=(Log&& p_logger) = delete;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Set the LogLevel of a logger
|
||||
*
|
||||
* \param p_loggerInfo The logger to set
|
||||
*/
|
||||
void SetLoggerLevel(const LoggerInfo& p_loggerInfo);
|
||||
|
||||
/*
|
||||
* The sinks
|
||||
*/
|
||||
eastl::array<std::shared_ptr<quill::Sink>, 1> m_sinks;
|
||||
};
|
||||
} // namespace Bigfoot
|
||||
|
||||
#define BIGFOOT_LOG_DEBUG(loggerName, fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (quill::Logger* logger = Bigfoot::Singleton<Bigfoot::Log>::Instance().GetLogger(loggerName)) \
|
||||
{ \
|
||||
QUILL_LOG_DEBUG(logger, fmt __VA_OPT__(, ) __VA_ARGS__); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
QUILL_LOG_DEBUG(Bigfoot::Singleton<Bigfoot::Log>::Instance().RegisterLogger(loggerName), \
|
||||
fmt __VA_OPT__(, ) __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BIGFOOT_LOG_TRACE(loggerName, fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (quill::Logger* logger = Bigfoot::Singleton<Bigfoot::Log>::Instance().GetLogger(loggerName)) \
|
||||
{ \
|
||||
QUILL_LOG_TRACE_L3(logger, fmt __VA_OPT__(, ) __VA_ARGS__); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
QUILL_LOG_TRACE_L3(Bigfoot::Singleton<Bigfoot::Log>::Instance().RegisterLogger(loggerName), \
|
||||
fmt __VA_OPT__(, ) __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BIGFOOT_LOG_INFO(loggerName, fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (quill::Logger* logger = Bigfoot::Singleton<Bigfoot::Log>::Instance().GetLogger(loggerName)) \
|
||||
{ \
|
||||
QUILL_LOG_INFO(logger, fmt __VA_OPT__(, ) __VA_ARGS__); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
QUILL_LOG_INFO(Bigfoot::Singleton<Bigfoot::Log>::Instance().RegisterLogger(loggerName), \
|
||||
fmt __VA_OPT__(, ) __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BIGFOOT_LOG_WARN(loggerName, fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (quill::Logger* logger = Bigfoot::Singleton<Bigfoot::Log>::Instance().GetLogger(loggerName)) \
|
||||
{ \
|
||||
QUILL_LOG_WARNING(logger, fmt __VA_OPT__(, ) __VA_ARGS__); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
QUILL_LOG_WARNING(Bigfoot::Singleton<Bigfoot::Log>::Instance().RegisterLogger(loggerName), \
|
||||
fmt __VA_OPT__(, ) __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BIGFOOT_LOG_ERROR(loggerName, fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (quill::Logger* logger = Bigfoot::Singleton<Bigfoot::Log>::Instance().GetLogger(loggerName)) \
|
||||
{ \
|
||||
QUILL_LOG_ERROR(logger, fmt __VA_OPT__(, ) __VA_ARGS__); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
QUILL_LOG_ERROR(Bigfoot::Singleton<Bigfoot::Log>::Instance().RegisterLogger(loggerName), \
|
||||
fmt __VA_OPT__(, ) __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BIGFOOT_LOG_FATAL(loggerName, fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (quill::Logger* logger = Bigfoot::Singleton<Bigfoot::Log>::Instance().GetLogger(loggerName)) \
|
||||
{ \
|
||||
QUILL_LOG_CRITICAL(logger, fmt __VA_OPT__(, ) __VA_ARGS__); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
QUILL_LOG_CRITICAL(Bigfoot::Singleton<Bigfoot::Log>::Instance().RegisterLogger(loggerName), \
|
||||
fmt __VA_OPT__(, ) __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define BIGFOOT_LOG_DEBUG(loggerName, fmt, ...)
|
||||
#define BIGFOOT_LOG_TRACE(loggerName, fmt, ...)
|
||||
#define BIGFOOT_LOG_INFO(loggerName, fmt, ...)
|
||||
#define BIGFOOT_LOG_WARN(loggerName, fmt, ...)
|
||||
#define BIGFOOT_LOG_ERROR(loggerName, fmt, ...)
|
||||
#define BIGFOOT_LOG_FATAL(loggerName, fmt, ...)
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,133 +0,0 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
|
||||
|
||||
#ifndef FLATBUFFERS_GENERATED_LOG_BIGFOOT_FLAT_H_
|
||||
#define FLATBUFFERS_GENERATED_LOG_BIGFOOT_FLAT_H_
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
|
||||
// Ensure the included flatbuffers.h is the same version as when this file was
|
||||
// generated, otherwise it may not be compatible.
|
||||
static_assert(FLATBUFFERS_VERSION_MAJOR == 25 &&
|
||||
FLATBUFFERS_VERSION_MINOR == 12 &&
|
||||
FLATBUFFERS_VERSION_REVISION == 19,
|
||||
"Non-compatible flatbuffers version included");
|
||||
// Ensure the included flatbuffers.h is Bigfoot's fork - stock
|
||||
// flatbuffers (or a differently versioned Bigfoot fork) is not compatible.
|
||||
#ifndef FLATBUFFERS_BIGFOOT_VERSION
|
||||
#error "This file requires Bigfoot's flatbuffers fork - stock flatbuffers is not compatible"
|
||||
#endif
|
||||
static_assert(FLATBUFFERS_BIGFOOT_VERSION == 1,
|
||||
"Non-compatible Bigfoot flatbuffers fork version included");
|
||||
|
||||
#include "EASTL/unique_ptr.h"
|
||||
#include "EASTL/string.h"
|
||||
#include "EASTL/vector.h"
|
||||
|
||||
namespace Bigfoot {
|
||||
namespace Flat {
|
||||
|
||||
enum class LogSinkType : int8_t {
|
||||
Console = 0,
|
||||
MIN = Console,
|
||||
MAX = Console
|
||||
};
|
||||
|
||||
inline const LogSinkType (&EnumValuesLogSinkType())[1] {
|
||||
static const LogSinkType values[] = {
|
||||
LogSinkType::Console
|
||||
};
|
||||
return values;
|
||||
}
|
||||
|
||||
inline const char * const *EnumNamesLogSinkType() {
|
||||
static const char * const names[2] = {
|
||||
"Console",
|
||||
nullptr
|
||||
};
|
||||
return names;
|
||||
}
|
||||
|
||||
inline const char *EnumNameLogSinkType(LogSinkType e) {
|
||||
if (::flatbuffers::IsOutRange(e, LogSinkType::Console, LogSinkType::Console)) return "";
|
||||
const size_t index = static_cast<size_t>(e);
|
||||
return EnumNamesLogSinkType()[index];
|
||||
}
|
||||
|
||||
enum class LogLevel : int8_t {
|
||||
Debug = 0,
|
||||
Trace = 1,
|
||||
Info = 2,
|
||||
Warn = 3,
|
||||
Error = 4,
|
||||
Critical = 5,
|
||||
MIN = Debug,
|
||||
MAX = Critical
|
||||
};
|
||||
|
||||
inline const LogLevel (&EnumValuesLogLevel())[6] {
|
||||
static const LogLevel values[] = {
|
||||
LogLevel::Debug,
|
||||
LogLevel::Trace,
|
||||
LogLevel::Info,
|
||||
LogLevel::Warn,
|
||||
LogLevel::Error,
|
||||
LogLevel::Critical
|
||||
};
|
||||
return values;
|
||||
}
|
||||
|
||||
inline const char * const *EnumNamesLogLevel() {
|
||||
static const char * const names[7] = {
|
||||
"Debug",
|
||||
"Trace",
|
||||
"Info",
|
||||
"Warn",
|
||||
"Error",
|
||||
"Critical",
|
||||
nullptr
|
||||
};
|
||||
return names;
|
||||
}
|
||||
|
||||
inline const char *EnumNameLogLevel(LogLevel e) {
|
||||
if (::flatbuffers::IsOutRange(e, LogLevel::Debug, LogLevel::Critical)) return "";
|
||||
const size_t index = static_cast<size_t>(e);
|
||||
return EnumNamesLogLevel()[index];
|
||||
}
|
||||
|
||||
inline const ::flatbuffers::TypeTable *LogSinkTypeTypeTable() {
|
||||
static const ::flatbuffers::TypeCode type_codes[] = {
|
||||
{ ::flatbuffers::ET_CHAR, 0, 0 }
|
||||
};
|
||||
static const ::flatbuffers::TypeFunction type_refs[] = {
|
||||
Bigfoot::Flat::LogSinkTypeTypeTable
|
||||
};
|
||||
static const ::flatbuffers::TypeTable tt = {
|
||||
::flatbuffers::ST_ENUM, 1, type_codes, type_refs, nullptr, nullptr, nullptr
|
||||
};
|
||||
return &tt;
|
||||
}
|
||||
|
||||
inline const ::flatbuffers::TypeTable *LogLevelTypeTable() {
|
||||
static const ::flatbuffers::TypeCode type_codes[] = {
|
||||
{ ::flatbuffers::ET_CHAR, 0, 0 },
|
||||
{ ::flatbuffers::ET_CHAR, 0, 0 },
|
||||
{ ::flatbuffers::ET_CHAR, 0, 0 },
|
||||
{ ::flatbuffers::ET_CHAR, 0, 0 },
|
||||
{ ::flatbuffers::ET_CHAR, 0, 0 },
|
||||
{ ::flatbuffers::ET_CHAR, 0, 0 }
|
||||
};
|
||||
static const ::flatbuffers::TypeFunction type_refs[] = {
|
||||
Bigfoot::Flat::LogLevelTypeTable
|
||||
};
|
||||
static const ::flatbuffers::TypeTable tt = {
|
||||
::flatbuffers::ST_ENUM, 6, type_codes, type_refs, nullptr, nullptr, nullptr
|
||||
};
|
||||
return &tt;
|
||||
}
|
||||
|
||||
} // namespace Flat
|
||||
} // namespace Bigfoot
|
||||
|
||||
#endif // FLATBUFFERS_GENERATED_LOG_BIGFOOT_FLAT_H_
|
||||
@@ -1,21 +0,0 @@
|
||||
@AUTO_GENERATED_COMMENT@
|
||||
|
||||
/*********************************************************************
|
||||
* \file @LOGGER_FILENAME@.generated.hpp
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef BIGFOOT_@LOGGER_FILENAME_UPPER@_GENERATED_HPP
|
||||
#define BIGFOOT_@LOGGER_FILENAME_UPPER@_GENERATED_HPP
|
||||
#include <System/Log/Log.hpp>
|
||||
|
||||
#if defined BIGFOOT_NOT_OPTIMIZED
|
||||
|
||||
namespace Bigfoot
|
||||
{
|
||||
/*
|
||||
* Logger
|
||||
*/
|
||||
inline Log::LoggerInfo @LOGGER_NAME@ {"@LOGGER_NAME@", Flat::LogLevel::Trace};
|
||||
} // namespace Bigfoot
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,64 +0,0 @@
|
||||
/*********************************************************************
|
||||
* \file Profiler.hpp
|
||||
*
|
||||
* \author Romain BOULLARD
|
||||
* \date October 2025
|
||||
*********************************************************************/
|
||||
#ifndef BIGFOOT_CONCAT_PROFILER_HPP
|
||||
#define BIGFOOT_CONCAT_PROFILER_HPP
|
||||
|
||||
#ifdef TRACY
|
||||
#include <tracy/Tracy.hpp>
|
||||
#define BIGFOOT_PROFILER_THREADNAME(p_name) tracy::SetThreadName(p_name)
|
||||
|
||||
#define BIGFOOT_PROFILER_FRAME() FrameMark
|
||||
#define BIGFOOT_PROFILER_FRAME_START(p_name) FrameMarkStart(p_name)
|
||||
#define BIGFOOT_PROFILER_FRAME_STOP(p_name) FrameMarkEnd(p_name)
|
||||
|
||||
#define BIGFOOT_PROFILER_PROFILE_FUNCTION() ZoneScoped
|
||||
#define BIGFOOT_PROFILER_PROFILE(p_name) ZoneScopedN(p_name)
|
||||
|
||||
#define BIGFOOT_PROFILER_TEXT(p_text, p_size) ZoneText(p_text, p_size)
|
||||
|
||||
#define BIGFOOT_PROFILER_MEMORY_ALLOC(p_ptr, p_size) TracyAlloc(p_ptr, p_size)
|
||||
#define BIGFOOT_PROFILER_MEMORY_FREE(p_ptr) TracyFree(p_ptr)
|
||||
|
||||
#define BIGFOOT_PROFILER_LOCKABLE(p_type, p_name) TracyLockable(p_type, p_name)
|
||||
#define BIGFOOT_PROFILER_LOCK(p_name) LockMark(p_name)
|
||||
|
||||
#define BIGFOOT_PROFILER_APPINFO(p_text, p_size) TracyAppInfo(p_text, p_size)
|
||||
|
||||
#define BIGFOOT_PROFILER_ATTACH_FRAME_IMAGE(p_imageData, p_width, p_height, p_offset) \
|
||||
FrameImage(p_imageData, p_width, p_height, p_offset, false)
|
||||
|
||||
#define BIGFOOT_PROFILER
|
||||
|
||||
#define BIGFOOT_PROFILER_ONLY(...) __VA_ARGS__
|
||||
// TODO: profile GPU
|
||||
#else
|
||||
#define BIGFOOT_PROFILER_THREADNAME(p_name)
|
||||
|
||||
#define BIGFOOT_PROFILER_FRAME()
|
||||
#define BIGFOOT_PROFILER_FRAME_START(p_name)
|
||||
#define BIGFOOT_PROFILER_FRAME_STOP(p_name)
|
||||
|
||||
#define BIGFOOT_PROFILER_PROFILE_FUNCTION()
|
||||
#define BIGFOOT_PROFILER_PROFILE(p_name)
|
||||
|
||||
#define BIGFOOT_PROFILER_TEXT_FUNCTION(p_text, p_size)
|
||||
#define BIGFOOT_PROFILER_TEXT(p_text, p_size)
|
||||
|
||||
#define BIGFOOT_PROFILER_MEMORY_ALLOC(p_ptr, p_size)
|
||||
#define BIGFOOT_PROFILER_MEMORY_FREE(p_ptr)
|
||||
|
||||
#define BIGFOOT_PROFILER_LOCKABLE(p_type, p_name) p_type p_name
|
||||
#define BIGFOOT_PROFILER_LOCK(p_name)
|
||||
|
||||
#define BIGFOOT_PROFILER_APPINFO(p_text, p_size)
|
||||
|
||||
#define BIGFOOT_PROFILER_ATTACH_FRAME_IMAGE(p_imageData, p_width, p_height, p_offset)
|
||||
|
||||
#define BIGFOOT_PROFILER_ONLY(...)
|
||||
// TODO: profile GPU
|
||||
#endif
|
||||
#endif
|
||||
@@ -11,8 +11,8 @@
|
||||
|
||||
namespace flatbuffers
|
||||
{
|
||||
Bigfoot::Flat::UUID Pack(const Bigfoot::UUID& p_uuid);
|
||||
Bigfoot::UUID UnPack(const Bigfoot::Flat::UUID& p_flatUUID);
|
||||
Flat::Bigfoot::UUID Pack(const Bigfoot::UUID& p_uuid);
|
||||
Bigfoot::UUID UnPack(const Flat::Bigfoot::UUID& p_flatUUID);
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
/*******************************************************************
|
||||
* \file Log.cpp
|
||||
*
|
||||
* \author Romain BOULLARD
|
||||
* \date October 2025
|
||||
*********************************************************************/
|
||||
#include <System/Log/Log.hpp>
|
||||
|
||||
#if defined BIGFOOT_NOT_OPTIMIZED
|
||||
|
||||
namespace Bigfoot
|
||||
{
|
||||
Log::Log()
|
||||
{
|
||||
quill::Backend::start();
|
||||
|
||||
m_sinks[static_cast<std::size_t>(Flat::LogSinkType::Console)] =
|
||||
quill::Frontend::create_or_get_sink<quill::ConsoleSink>(
|
||||
std::string {Flat::EnumNameLogSinkType(Flat::LogSinkType::Console)});
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
quill::Logger* Log::RegisterLogger(const LoggerInfo& p_loggerInfo)
|
||||
{
|
||||
quill::Logger* logger = quill::Frontend::create_or_get_logger(
|
||||
p_loggerInfo.m_name,
|
||||
m_sinks[static_cast<std::size_t>(Flat::LogSinkType::Console)]);
|
||||
SetLoggerLevel(p_loggerInfo);
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
quill::Logger* Log::GetLogger(const LoggerInfo& p_loggerInfo)
|
||||
{
|
||||
return quill::Frontend::get_logger(p_loggerInfo.m_name);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
void Log::ChangeLoggerLogLevel(LoggerInfo& p_loggerInfo, const Flat::LogLevel p_level)
|
||||
{
|
||||
p_loggerInfo.m_level = p_level;
|
||||
SetLoggerLevel(p_loggerInfo);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
void Log::SetLoggerLevel(const LoggerInfo& p_loggerInfo)
|
||||
{
|
||||
constexpr auto logLevelToQuillLogLevel = [](const Flat::LogLevel p_level) constexpr -> quill::LogLevel
|
||||
{
|
||||
switch (p_level)
|
||||
{
|
||||
case Flat::LogLevel::Debug:
|
||||
return quill::LogLevel::Debug;
|
||||
case Flat::LogLevel::Trace:
|
||||
return quill::LogLevel::TraceL3;
|
||||
case Flat::LogLevel::Info:
|
||||
return quill::LogLevel::Info;
|
||||
case Flat::LogLevel::Warn:
|
||||
return quill::LogLevel::Warning;
|
||||
case Flat::LogLevel::Error:
|
||||
return quill::LogLevel::Error;
|
||||
case Flat::LogLevel::Critical:
|
||||
return quill::LogLevel::Critical;
|
||||
}
|
||||
|
||||
return quill::LogLevel::TraceL3;
|
||||
};
|
||||
|
||||
if (quill::Logger* logger = GetLogger(p_loggerInfo))
|
||||
{
|
||||
logger->set_log_level(logLevelToQuillLogLevel(p_loggerInfo.m_level));
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
Log::~Log()
|
||||
{
|
||||
for (quill::Logger* logger: quill::Frontend::get_all_loggers())
|
||||
{
|
||||
quill::Frontend::remove_logger(logger);
|
||||
}
|
||||
|
||||
quill::Backend::stop();
|
||||
}
|
||||
} // namespace Bigfoot
|
||||
#endif
|
||||
@@ -1,98 +0,0 @@
|
||||
/*********************************************************************
|
||||
* \file MimallocImpl.cpp
|
||||
*
|
||||
* \author Romain BOULLARD
|
||||
* \date October 2025
|
||||
*********************************************************************/
|
||||
#include <System/Profiler.hpp>
|
||||
|
||||
#if defined BIGFOOT_WINDOWS
|
||||
#pragma comment(linker, "/include:mi_version")
|
||||
#pragma warning(disable: 4100 4559)
|
||||
#elif defined BIGFOOT_LINUX
|
||||
#if defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
#else
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-parameter"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Taken from mimalloc-new-delete.h
|
||||
|
||||
// clang-format off
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// This header provides convenient overrides for the new and
|
||||
// delete operations in C++.
|
||||
//
|
||||
// This header should be included in only one source file!
|
||||
//
|
||||
// On Windows, or when linking dynamically with mimalloc, these
|
||||
// can be more performant than the standard new-delete operations.
|
||||
// See <https://en.cppreference.com/w/cpp/memory/new/operator_new>
|
||||
// ---------------------------------------------------------------------------
|
||||
#if defined(__cplusplus)
|
||||
#include <new>
|
||||
#include <mimalloc.h>
|
||||
|
||||
#if defined(_MSC_VER) && defined(_Ret_notnull_) && defined(_Post_writable_byte_size_)
|
||||
// stay consistent with VCRT definitions
|
||||
#define mi_decl_new(n) mi_decl_nodiscard mi_decl_restrict _Ret_notnull_ _Post_writable_byte_size_(n)
|
||||
#define mi_decl_new_nothrow(n) mi_decl_nodiscard mi_decl_restrict _Ret_maybenull_ _Success_(return != NULL) _Post_writable_byte_size_(n)
|
||||
#else
|
||||
#define mi_decl_new(n) mi_decl_nodiscard mi_decl_restrict
|
||||
#define mi_decl_new_nothrow(n) mi_decl_nodiscard mi_decl_restrict
|
||||
#endif
|
||||
|
||||
void operator delete(void* p) noexcept { mi_free(p); BIGFOOT_PROFILER_MEMORY_FREE(p); };
|
||||
void operator delete[](void* p) noexcept { mi_free(p); BIGFOOT_PROFILER_MEMORY_FREE(p); };
|
||||
|
||||
void operator delete (void* p, const std::nothrow_t&) noexcept { mi_free(p); BIGFOOT_PROFILER_MEMORY_FREE(p); }
|
||||
void operator delete[](void* p, const std::nothrow_t&) noexcept { mi_free(p); BIGFOOT_PROFILER_MEMORY_FREE(p); }
|
||||
|
||||
mi_decl_new(n) void* operator new(std::size_t n) noexcept(false) { void* p = mi_new(n); BIGFOOT_PROFILER_MEMORY_ALLOC(p, n); return p; }
|
||||
mi_decl_new(n) void* operator new[](std::size_t n) noexcept(false) { void* p = mi_new(n); BIGFOOT_PROFILER_MEMORY_ALLOC(p, n); return p; }
|
||||
|
||||
mi_decl_new_nothrow(n) void* operator new (std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); void* p = mi_new_nothrow(n); BIGFOOT_PROFILER_MEMORY_ALLOC(p, n); return p; }
|
||||
mi_decl_new_nothrow(n) void* operator new[](std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); void* p = mi_new_nothrow(n); BIGFOOT_PROFILER_MEMORY_ALLOC(p, n); return p; }
|
||||
|
||||
// Not from mimalloc-new-delete.h, but necessary for EASTL
|
||||
void* operator new[](size_t size, const char* name, int flags, unsigned debugFlags, const char* file, int line) noexcept(false) { void* p = mi_new(size); BIGFOOT_PROFILER_MEMORY_ALLOC(p, size); return p; }
|
||||
|
||||
#if (__cplusplus >= 201402L || _MSC_VER >= 1916)
|
||||
void operator delete (void* p, std::size_t n) noexcept { mi_free_size(p,n); BIGFOOT_PROFILER_MEMORY_FREE(p); };
|
||||
void operator delete[](void* p, std::size_t n) noexcept { mi_free_size(p,n); BIGFOOT_PROFILER_MEMORY_FREE(p); };
|
||||
#endif
|
||||
|
||||
#if (__cplusplus > 201402L || defined(__cpp_aligned_new))
|
||||
void operator delete (void* p, std::align_val_t al) noexcept { mi_free_aligned(p, static_cast<size_t>(al)); BIGFOOT_PROFILER_MEMORY_FREE(p); }
|
||||
void operator delete[](void* p, std::align_val_t al) noexcept { mi_free_aligned(p, static_cast<size_t>(al)); BIGFOOT_PROFILER_MEMORY_FREE(p); }
|
||||
void operator delete (void* p, std::size_t n, std::align_val_t al) noexcept { mi_free_size_aligned(p, n, static_cast<size_t>(al)); BIGFOOT_PROFILER_MEMORY_FREE(p); };
|
||||
void operator delete[](void* p, std::size_t n, std::align_val_t al) noexcept { mi_free_size_aligned(p, n, static_cast<size_t>(al)); BIGFOOT_PROFILER_MEMORY_FREE(p); };
|
||||
void operator delete (void* p, std::align_val_t al, const std::nothrow_t&) noexcept { mi_free_aligned(p, static_cast<size_t>(al)); BIGFOOT_PROFILER_MEMORY_FREE(p); }
|
||||
void operator delete[](void* p, std::align_val_t al, const std::nothrow_t&) noexcept { mi_free_aligned(p, static_cast<size_t>(al)); BIGFOOT_PROFILER_MEMORY_FREE(p); }
|
||||
|
||||
void* operator new (std::size_t n, std::align_val_t al) noexcept(false) { void* p = mi_new_aligned(n, static_cast<size_t>(al)); BIGFOOT_PROFILER_MEMORY_ALLOC(p, n); return p; }
|
||||
void* operator new[](std::size_t n, std::align_val_t al) noexcept(false) { void* p = mi_new_aligned(n, static_cast<size_t>(al)); BIGFOOT_PROFILER_MEMORY_ALLOC(p, n); return p; }
|
||||
void* operator new (std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept { void* p = mi_new_aligned_nothrow(n, static_cast<size_t>(al)); BIGFOOT_PROFILER_MEMORY_ALLOC(p, n); return p; }
|
||||
void* operator new[](std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept { void* p = mi_new_aligned_nothrow(n, static_cast<size_t>(al)); BIGFOOT_PROFILER_MEMORY_ALLOC(p, n); return p; }
|
||||
|
||||
// Not from mimalloc-new-delete.h, but necessary for EASTL
|
||||
void* operator new[](size_t size, size_t alignment, size_t alignmentOffset, const char* pName, int flags, unsigned debugFlags, const char* file, int line) noexcept(false) { void* p = mi_new_aligned(size, alignment); BIGFOOT_PROFILER_MEMORY_ALLOC(p, size); return p; }
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// clang-format on
|
||||
|
||||
#if defined BIGFOOT_WINDOWS
|
||||
#pragma warning(default: 4100 4559)
|
||||
#elif defined BIGFOOT_LINUX
|
||||
#if defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER)
|
||||
#pragma GCC diagnostic pop
|
||||
#else
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,121 +0,0 @@
|
||||
/*********************************************************************
|
||||
* \file Time.cpp
|
||||
*
|
||||
* \author Romain BOULLARD
|
||||
* \date December 2025
|
||||
*********************************************************************/
|
||||
#include <System/Time.hpp>
|
||||
|
||||
#include <System/SystemAssertHandler.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
[[nodiscard]]
|
||||
std::tm GetTimeInfo(const std::time_t& p_time)
|
||||
{
|
||||
std::tm timeInfo {};
|
||||
#ifdef BIGFOOT_WINDOWS
|
||||
[[maybe_unused]]
|
||||
const errno_t error = gmtime_s(&timeInfo, &p_time);
|
||||
if (error != 0)
|
||||
{
|
||||
char errnoStr[256];
|
||||
strerror_s(errnoStr, error);
|
||||
|
||||
CRITICAL_ASSERT(Bigfoot::SystemAssertHandler,
|
||||
false,
|
||||
"Failed to convert epoch time to calendar time. {}",
|
||||
errnoStr);
|
||||
}
|
||||
#elif BIGFOOT_LINUX
|
||||
[[maybe_unused]]
|
||||
const std::tm* error = gmtime_r(&p_time, &timeInfo);
|
||||
CRITICAL_ASSERT(Bigfoot::SystemAssertHandler, error, "Failed to convert epoch time to calendar time");
|
||||
#else
|
||||
static_assert(false, "not implemented");
|
||||
#endif
|
||||
|
||||
return timeInfo;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace Bigfoot
|
||||
{
|
||||
Time::Time(const std::uint64_t p_epoch):
|
||||
m_epoch(p_epoch),
|
||||
m_timeInfo(GetTimeInfo(std::chrono::system_clock::to_time_t(
|
||||
std::chrono::time_point<std::chrono::system_clock> {std::chrono::microseconds {m_epoch}}))),
|
||||
m_microseconds(std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::time_point<std::chrono::system_clock> {
|
||||
std::chrono::microseconds {m_epoch}}.time_since_epoch()) %
|
||||
std::chrono::seconds(1)))
|
||||
{
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
std::uint32_t Time::Year() const
|
||||
{
|
||||
return m_timeInfo.tm_year + 1900;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
std::uint32_t Time::Month() const
|
||||
{
|
||||
return m_timeInfo.tm_mon + 1;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
std::uint32_t Time::Day() const
|
||||
{
|
||||
return m_timeInfo.tm_mday;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
std::uint32_t Time::Hour() const
|
||||
{
|
||||
return m_timeInfo.tm_hour;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
std::uint32_t Time::Minute() const
|
||||
{
|
||||
return m_timeInfo.tm_min;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
std::uint32_t Time::Second() const
|
||||
{
|
||||
return m_timeInfo.tm_sec;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
std::uint32_t Time::Microsecond() const
|
||||
{
|
||||
return static_cast<std::uint32_t>(m_microseconds.count());
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
std::uint64_t Time::Epoch() const
|
||||
{
|
||||
return m_epoch;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
Time Time::Now()
|
||||
{
|
||||
const std::chrono::time_point<std::chrono::system_clock> time = std::chrono::system_clock::now();
|
||||
const std::uint64_t epochInMicroSeconds =
|
||||
std::chrono::duration_cast<std::chrono::microseconds>(time.time_since_epoch()).count();
|
||||
|
||||
return Time {epochInMicroSeconds};
|
||||
}
|
||||
} // namespace Bigfoot
|
||||
@@ -1,27 +0,0 @@
|
||||
/*********************************************************************
|
||||
* \file FlatUUID.cpp
|
||||
*
|
||||
* \author Romain BOULLARD
|
||||
* \date December 2025
|
||||
*********************************************************************/
|
||||
#include <System/UUID/FlatUUID.hpp>
|
||||
|
||||
namespace flatbuffers
|
||||
{
|
||||
Bigfoot::Flat::UUID Pack(const Bigfoot::UUID& p_uuid)
|
||||
{
|
||||
const std::span<const std::byte, Bigfoot::UUID::UUID_BYTE_SIZE> bytes = p_uuid;
|
||||
return Bigfoot::Flat::UUID {
|
||||
std::span<const std::uint8_t, Bigfoot::UUID::UUID_BYTE_SIZE> {reinterpret_cast<const std::uint8_t*>(bytes.data()),
|
||||
bytes.size()}};
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
Bigfoot::UUID UnPack(const Bigfoot::Flat::UUID& p_flatUUID)
|
||||
{
|
||||
const std::span<const std::uint8_t, Bigfoot::UUID::UUID_BYTE_SIZE> bytesView {p_flatUUID.bytes()->data(),
|
||||
p_flatUUID.bytes()->size()};
|
||||
return Bigfoot::UUID {std::as_bytes(bytesView)};
|
||||
}
|
||||
} // namespace flatbuffers
|
||||
@@ -13,12 +13,15 @@
|
||||
#include <EASTL/iterator.h>
|
||||
#include <EASTL/unique_ptr.h>
|
||||
#include <EASTL/vector.h>
|
||||
#include <EASTL/numeric.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace Bigfoot
|
||||
{
|
||||
@@ -331,12 +334,506 @@ class DenseSlotMap
|
||||
std::size_t m_freeListHead = SlotMapKey::MAX_INDEX;
|
||||
};
|
||||
|
||||
template<class T, class SLOT_MAP_KEY = SlotMapKey<>>
|
||||
template<class T, class SLOT_MAP_KEY_TYPE = SlotMapKey<>>
|
||||
class StableSlotMap
|
||||
{
|
||||
private:
|
||||
static constexpr std::size_t PAGE_SIZE = 64;
|
||||
|
||||
struct AlignedSlot
|
||||
{
|
||||
alignas(T) std::byte m_bytes[sizeof(T)];
|
||||
};
|
||||
|
||||
|
||||
struct Page
|
||||
{
|
||||
Page() = default;
|
||||
|
||||
Page(const Page& p_page) = delete;
|
||||
Page(Page&& p_page) = delete;
|
||||
|
||||
~Page()
|
||||
{
|
||||
for (std::size_t offset = m_occupied.find_first(); offset != PAGE_SIZE;
|
||||
offset = m_occupied.find_next(offset))
|
||||
{
|
||||
std::destroy_at(Get(offset));
|
||||
}
|
||||
}
|
||||
|
||||
Page& operator=(const Page& p_page) = delete;
|
||||
Page& operator=(Page&& p_page) = delete;
|
||||
|
||||
[[nodiscard]]
|
||||
T* Get(const std::size_t p_offset)
|
||||
{
|
||||
return std::launder(reinterpret_cast<T*>(m_data[p_offset].m_bytes));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const T* Get(const std::size_t p_offset) const
|
||||
{
|
||||
return std::launder(reinterpret_cast<const T*>(m_data[p_offset].m_bytes));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
std::size_t Size() const
|
||||
{
|
||||
return m_occupied.count();
|
||||
}
|
||||
|
||||
eastl::array<AlignedSlot, PAGE_SIZE> m_data;
|
||||
eastl::bitset<PAGE_SIZE> m_occupied;
|
||||
};
|
||||
|
||||
public:
|
||||
using SlotMapKey = SLOT_MAP_KEY_TYPE;
|
||||
|
||||
template<class VALUE_TYPE>
|
||||
class IteratorImpl
|
||||
{
|
||||
private:
|
||||
using PagesVector = eastl::vector<eastl::unique_ptr<Page>>;
|
||||
using PageIterator =
|
||||
std::conditional_t<std::is_const_v<VALUE_TYPE>, typename PagesVector::const_iterator, typename PagesVector::iterator>;
|
||||
using MapType = std::conditional_t<std::is_const_v<VALUE_TYPE>, const StableSlotMap, StableSlotMap>;
|
||||
using PageType = std::conditional_t<std::is_const_v<VALUE_TYPE>, const Page, Page>;
|
||||
|
||||
public:
|
||||
using iterator_category = eastl::bidirectional_iterator_tag;
|
||||
using value_type = std::remove_const_t<VALUE_TYPE>;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = VALUE_TYPE*;
|
||||
using reference = VALUE_TYPE&;
|
||||
|
||||
IteratorImpl() = default;
|
||||
|
||||
// Allows an iterator to be implicitly used as a const_iterator.
|
||||
template<class OTHER_VALUE_TYPE, class = std::enable_if_t<std::is_same_v<VALUE_TYPE, const OTHER_VALUE_TYPE>>>
|
||||
IteratorImpl(const IteratorImpl<OTHER_VALUE_TYPE>& p_other):
|
||||
m_map(p_other.m_map),
|
||||
m_pageIt(p_other.m_pageIt),
|
||||
m_page(p_other.m_page),
|
||||
m_offset(p_other.m_offset),
|
||||
m_current(p_other.m_current)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
reference operator*() const
|
||||
{
|
||||
return *m_current;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
pointer operator->() const
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
|
||||
IteratorImpl& operator++()
|
||||
{
|
||||
Increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
IteratorImpl operator++(int)
|
||||
{
|
||||
const IteratorImpl temp = *this;
|
||||
++(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
IteratorImpl& operator--()
|
||||
{
|
||||
Decrement();
|
||||
return *this;
|
||||
}
|
||||
|
||||
IteratorImpl operator--(int)
|
||||
{
|
||||
const IteratorImpl temp = *this;
|
||||
--(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool operator==(const IteratorImpl& p_other) const
|
||||
{
|
||||
return m_map == p_other.m_map && m_current == p_other.m_current;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class StableSlotMap;
|
||||
template<class>
|
||||
friend class IteratorImpl;
|
||||
|
||||
explicit IteratorImpl(MapType* p_map):
|
||||
m_map(p_map)
|
||||
{
|
||||
}
|
||||
|
||||
void SeekFirstFrom(PageIterator p_pageIt)
|
||||
{
|
||||
for (; p_pageIt != m_map->m_pages.end(); ++p_pageIt)
|
||||
{
|
||||
PageType* const page = p_pageIt->get();
|
||||
const std::size_t offset = page->m_occupied.find_first();
|
||||
if (offset != PAGE_SIZE)
|
||||
{
|
||||
m_pageIt = p_pageIt;
|
||||
m_page = page;
|
||||
m_offset = offset;
|
||||
m_current = page->Get(offset);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_pageIt = p_pageIt;
|
||||
m_page = nullptr;
|
||||
m_offset = 0;
|
||||
m_current = nullptr;
|
||||
}
|
||||
|
||||
void SeekLastFrom(PageIterator p_pageIt)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
PageType* const page = p_pageIt->get();
|
||||
const std::size_t offset = page->m_occupied.find_last();
|
||||
if (offset != PAGE_SIZE)
|
||||
{
|
||||
m_pageIt = p_pageIt;
|
||||
m_page = page;
|
||||
m_offset = offset;
|
||||
m_current = page->Get(offset);
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_pageIt == m_map->m_pages.begin())
|
||||
{
|
||||
return;
|
||||
}
|
||||
--p_pageIt;
|
||||
}
|
||||
}
|
||||
|
||||
void Increment()
|
||||
{
|
||||
const std::size_t offset = m_page->m_occupied.find_next(m_offset);
|
||||
if (offset != PAGE_SIZE)
|
||||
{
|
||||
m_offset = offset;
|
||||
m_current = m_page->Get(offset);
|
||||
return;
|
||||
}
|
||||
|
||||
SeekFirstFrom(eastl::next(m_pageIt));
|
||||
}
|
||||
|
||||
void Decrement()
|
||||
{
|
||||
if (m_current == nullptr)
|
||||
{
|
||||
SeekLastFrom(eastl::prev(m_map->m_pages.end()));
|
||||
return;
|
||||
}
|
||||
|
||||
const std::size_t offset = m_page->m_occupied.find_prev(m_offset);
|
||||
if (offset != PAGE_SIZE)
|
||||
{
|
||||
m_offset = offset;
|
||||
m_current = m_page->Get(offset);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_pageIt == m_map->m_pages.begin())
|
||||
{
|
||||
return;
|
||||
}
|
||||
SeekLastFrom(eastl::prev(m_pageIt));
|
||||
}
|
||||
|
||||
MapType* m_map = nullptr;
|
||||
PageIterator m_pageIt {};
|
||||
PageType* m_page = nullptr;
|
||||
std::size_t m_offset = 0;
|
||||
pointer m_current = nullptr;
|
||||
};
|
||||
|
||||
using iterator = IteratorImpl<T>;
|
||||
using const_iterator = IteratorImpl<const T>;
|
||||
using reverse_iterator = eastl::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = eastl::reverse_iterator<const_iterator>;
|
||||
|
||||
StableSlotMap() = default;
|
||||
|
||||
StableSlotMap(const StableSlotMap& p_map) = default;
|
||||
StableSlotMap(StableSlotMap&& p_map) = default;
|
||||
|
||||
~StableSlotMap() = default;
|
||||
|
||||
[[nodiscard]]
|
||||
bool Has(const SlotMapKey p_key) const
|
||||
{
|
||||
return p_key.Valid() &&
|
||||
(p_key.GetIndex() < m_keys.size() && p_key.GetVersion() == m_keys[p_key.GetIndex()].GetVersion());
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
std::size_t Size() const
|
||||
{
|
||||
return eastl::accumulate(m_pages.begin(),
|
||||
m_pages.end(),
|
||||
0,
|
||||
[](const std::size_t p_value, const eastl::unique_ptr<Page>& p_page)
|
||||
{
|
||||
return p_value + p_page->Size();
|
||||
});
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
std::size_t Capacity() const
|
||||
{
|
||||
return m_pages.size() * PAGE_SIZE;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool Empty() const
|
||||
{
|
||||
return Size() == 0;
|
||||
}
|
||||
|
||||
template<class... ARGS>
|
||||
[[nodiscard]]
|
||||
SlotMapKey Insert(ARGS&&... p_args)
|
||||
{
|
||||
ASSERT(UtilsAssertHandler,
|
||||
Size() < SlotMapKey::MAX_INDEX,
|
||||
"Can't store more than {} elements",
|
||||
SlotMapKey::MAX_INDEX);
|
||||
|
||||
SlotMapKey key;
|
||||
if (HasFreeSlots())
|
||||
{
|
||||
const std::size_t indexToRecyclingKey = m_freeListHead;
|
||||
|
||||
m_freeListHead = m_keys[indexToRecyclingKey].GetIndex();
|
||||
m_keys[indexToRecyclingKey] = SlotMapKey {m_keys[indexToRecyclingKey].GetVersion(),
|
||||
static_cast<SlotMapKey::IndexType>(indexToRecyclingKey)};
|
||||
|
||||
key = m_keys[indexToRecyclingKey];
|
||||
}
|
||||
else
|
||||
{
|
||||
m_keys.emplace_back(1, static_cast<SlotMapKey::IndexType>(m_keys.size()));
|
||||
key = m_keys.back();
|
||||
}
|
||||
|
||||
const std::size_t pageIndex = GetPageIndex(key);
|
||||
if (pageIndex >= m_pages.size())
|
||||
{
|
||||
m_pages.push_back(eastl::make_unique<Page>());
|
||||
}
|
||||
|
||||
Page* const page = GetPageAt(pageIndex);
|
||||
const std::size_t offsetInPage = GetDataOffset(key);
|
||||
new (page->m_data[offsetInPage].m_bytes) T(std::forward<ARGS>(p_args)...);
|
||||
page->m_occupied.set(offsetInPage);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
void Remove(const SlotMapKey p_key)
|
||||
{
|
||||
if (!Has(p_key))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Page* const page = GetPageAt(GetPageIndex(p_key));
|
||||
const std::size_t offsetInPage = GetDataOffset(p_key);
|
||||
std::destroy_at(page->Get(offsetInPage));
|
||||
page->m_occupied.reset(offsetInPage);
|
||||
|
||||
RecycleKey(p_key);
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
for (eastl::unique_ptr<Page>& page: m_pages)
|
||||
{
|
||||
page = eastl::make_unique<Page>();
|
||||
}
|
||||
m_keys.clear();
|
||||
m_freeListHead = SlotMapKey::MAX_INDEX;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
std::size_t pageIndex = 0;
|
||||
for (const eastl::unique_ptr<Page>& page: m_pages)
|
||||
{
|
||||
for (std::size_t offset = page->m_occupied.find_first(); offset != PAGE_SIZE;
|
||||
offset = page->m_occupied.find_next(offset))
|
||||
{
|
||||
std::destroy_at(page->Get(offset));
|
||||
|
||||
const std::size_t keyIndex = pageIndex * PAGE_SIZE + offset;
|
||||
RecycleKey(SlotMapKey {m_keys[keyIndex].GetVersion(), static_cast<SlotMapKey::IndexType>(keyIndex)});
|
||||
}
|
||||
page->m_occupied.reset();
|
||||
++pageIndex;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const T* Get(const SlotMapKey p_key) const
|
||||
{
|
||||
return Has(p_key) ? GetPageAt(GetPageIndex(p_key))->Get(GetDataOffset(p_key)) : nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
T* Get(const SlotMapKey p_key)
|
||||
{
|
||||
return const_cast<T*>(std::as_const(*this).Get(p_key));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
iterator begin()
|
||||
{
|
||||
iterator it {this};
|
||||
it.SeekFirstFrom(m_pages.begin());
|
||||
return it;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
iterator end()
|
||||
{
|
||||
return iterator {this};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const_iterator begin() const
|
||||
{
|
||||
const_iterator it {this};
|
||||
it.SeekFirstFrom(m_pages.begin());
|
||||
return it;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const_iterator end() const
|
||||
{
|
||||
return const_iterator {this};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
reverse_iterator rbegin()
|
||||
{
|
||||
return reverse_iterator {end()};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
reverse_iterator rend()
|
||||
{
|
||||
return reverse_iterator {begin()};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const_reverse_iterator rbegin() const
|
||||
{
|
||||
return const_reverse_iterator {end()};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const_reverse_iterator rend() const
|
||||
{
|
||||
return const_reverse_iterator {begin()};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const_iterator cbegin() const
|
||||
{
|
||||
return begin();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const_iterator cend() const
|
||||
{
|
||||
return end();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const_reverse_iterator crbegin() const
|
||||
{
|
||||
return rbegin();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const_reverse_iterator crend() const
|
||||
{
|
||||
return rend();
|
||||
}
|
||||
|
||||
StableSlotMap& operator=(const StableSlotMap& p_map) = default;
|
||||
StableSlotMap& operator=(StableSlotMap&& p_map) = default;
|
||||
|
||||
private:
|
||||
[[nodiscard]]
|
||||
bool HasFreeSlots() const
|
||||
{
|
||||
return m_freeListHead != SlotMapKey::MAX_INDEX;
|
||||
}
|
||||
|
||||
void RecycleKey(const SlotMapKey p_key)
|
||||
{
|
||||
const typename SlotMapKey::VersionType nextVersion = static_cast<SlotMapKey::VersionType>(p_key.GetVersion() +
|
||||
1);
|
||||
|
||||
if (nextVersion == SlotMapKey::INVALID_VERSION)
|
||||
{
|
||||
// Mark it dead, we've exhausted all versions for this key
|
||||
m_keys[p_key.GetIndex()] = SlotMapKey {SlotMapKey::INVALID_VERSION, 0};
|
||||
return;
|
||||
}
|
||||
|
||||
m_keys[p_key.GetIndex()] = SlotMapKey {nextVersion, static_cast<SlotMapKey::IndexType>(m_freeListHead)};
|
||||
m_freeListHead = p_key.GetIndex();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
static std::size_t GetPageIndex(const SlotMapKey p_key)
|
||||
{
|
||||
return p_key.GetIndex() / PAGE_SIZE;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
static std::size_t GetDataOffset(const SlotMapKey p_key)
|
||||
{
|
||||
return p_key.GetIndex() % PAGE_SIZE;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const Page* GetPageAt(const std::size_t p_pageIndex) const
|
||||
{
|
||||
return m_pages[p_pageIndex].get();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
Page* GetPageAt(const std::size_t p_pageIndex)
|
||||
{
|
||||
return m_pages[p_pageIndex].get();
|
||||
}
|
||||
|
||||
private:
|
||||
eastl::vector<eastl::unique_ptr<Page>> m_pages;
|
||||
eastl::vector<SlotMapKey> m_keys;
|
||||
|
||||
/**
|
||||
* Index to a key that can be recycled
|
||||
*/
|
||||
std::size_t m_freeListHead = SlotMapKey::MAX_INDEX;
|
||||
};
|
||||
} // namespace Bigfoot
|
||||
|
||||
|
||||
@@ -90,8 +90,8 @@ TEST_F(AssetContainerFixture, Get_ShouldReturnTheAssetWithTheSlotKey)
|
||||
|
||||
TEST_F(AssetContainerFixture, Get_ShouldReturnNullptrIfSlotKeyNotInContainer)
|
||||
{
|
||||
EXPECT_EQ(m_containerA.Get(SlotMapKey {1, 0}), nullptr);
|
||||
EXPECT_EQ(const_cast<const AssetContainer<AssetA>&>(m_containerA).Get(SlotMapKey {1, 0}), nullptr);
|
||||
EXPECT_EQ(m_containerA.Get(SlotMapKey<> {1, 0}), nullptr);
|
||||
EXPECT_EQ(const_cast<const AssetContainer<AssetA>&>(m_containerA).Get(SlotMapKey<> {1, 0}), nullptr);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
// to delete when an actual test is in EngineTests
|
||||
@@ -1,21 +0,0 @@
|
||||
// AUTO-GENERATED DO NOT TOUCH
|
||||
|
||||
/*********************************************************************
|
||||
* \file SystemTestsLogger.generated.hpp
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef BIGFOOT_SYSTEMTESTSLOGGER_GENERATED_HPP
|
||||
#define BIGFOOT_SYSTEMTESTSLOGGER_GENERATED_HPP
|
||||
#include <System/Log/Log.hpp>
|
||||
|
||||
#if defined BIGFOOT_NOT_OPTIMIZED
|
||||
|
||||
namespace Bigfoot
|
||||
{
|
||||
/*
|
||||
* Logger
|
||||
*/
|
||||
inline Log::LoggerInfo SYSTEMTESTS_LOGGER {"SYSTEMTESTS_LOGGER", Flat::LogLevel::Trace};
|
||||
} // namespace Bigfoot
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,138 +0,0 @@
|
||||
/*********************************************************************
|
||||
* \file Log.cpp
|
||||
*
|
||||
* \author Romain BOULLARD
|
||||
* \date December 2022
|
||||
*********************************************************************/
|
||||
#include <System/Log/Log.hpp>
|
||||
|
||||
#include <Utils/Singleton.hpp>
|
||||
|
||||
#include <SystemTests/SystemTestsLogger_generated.hpp>
|
||||
|
||||
#if defined BIGFOOT_NOT_OPTIMIZED
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace Bigfoot
|
||||
{
|
||||
class LogFixture: public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
SYSTEMTESTS_LOGGER = {"UTILSTESTS_LOGGER", Flat::LogLevel::Trace};
|
||||
}
|
||||
|
||||
static constexpr Flat::LogLevel QuillLogLevelToLogLevel(const quill::LogLevel p_level)
|
||||
{
|
||||
switch (p_level)
|
||||
{
|
||||
case quill::LogLevel::Debug:
|
||||
return Flat::LogLevel::Debug;
|
||||
case quill::LogLevel::TraceL3:
|
||||
return Flat::LogLevel::Trace;
|
||||
case quill::LogLevel::Info:
|
||||
return Flat::LogLevel::Info;
|
||||
case quill::LogLevel::Warning:
|
||||
return Flat::LogLevel::Warn;
|
||||
case quill::LogLevel::Error:
|
||||
return Flat::LogLevel::Error;
|
||||
case quill::LogLevel::Critical:
|
||||
return Flat::LogLevel::Critical;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return Flat::LogLevel::Trace;
|
||||
}
|
||||
|
||||
Log m_log;
|
||||
};
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(LogFixture, RegisterLogger_ShouldRegisterTheLogger)
|
||||
{
|
||||
const quill::Logger* logger = m_log.RegisterLogger(SYSTEMTESTS_LOGGER);
|
||||
EXPECT_TRUE(logger);
|
||||
EXPECT_EQ(logger, m_log.GetLogger(SYSTEMTESTS_LOGGER));
|
||||
EXPECT_EQ(logger->get_logger_name(), SYSTEMTESTS_LOGGER.m_name);
|
||||
EXPECT_EQ(QuillLogLevelToLogLevel(logger->get_log_level()), SYSTEMTESTS_LOGGER.m_level);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(LogFixture, GetLogger_ShouldReturnNullptrIfTheLoggerDoesNotExist)
|
||||
{
|
||||
EXPECT_FALSE(m_log.GetLogger(SYSTEMTESTS_LOGGER));
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(LogFixture, GetLogger_ShouldReturnTheLoggerIfItExists)
|
||||
{
|
||||
[[maybe_unused]]
|
||||
const quill::Logger* logger = m_log.RegisterLogger(SYSTEMTESTS_LOGGER);
|
||||
EXPECT_TRUE(m_log.GetLogger(SYSTEMTESTS_LOGGER));
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(LogFixture, ChangeLoggerLogLevel_ShouldChangeTheLoggerLogLevel)
|
||||
{
|
||||
const quill::Logger* logger = m_log.RegisterLogger(SYSTEMTESTS_LOGGER);
|
||||
|
||||
m_log.ChangeLoggerLogLevel(SYSTEMTESTS_LOGGER, Flat::LogLevel::Critical);
|
||||
EXPECT_EQ(QuillLogLevelToLogLevel(logger->get_log_level()), Flat::LogLevel::Critical);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(LogFixture, LogDebug)
|
||||
{
|
||||
Singleton<Log>::Lifetime singletonLifetime;
|
||||
BIGFOOT_LOG_DEBUG(SYSTEMTESTS_LOGGER, "Hello");
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(LogFixture, LogTrace)
|
||||
{
|
||||
Singleton<Log>::Lifetime singletonLifetime;
|
||||
BIGFOOT_LOG_TRACE(SYSTEMTESTS_LOGGER, "Hello");
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(LogFixture, LogInfo)
|
||||
{
|
||||
Singleton<Log>::Lifetime singletonLifetime;
|
||||
BIGFOOT_LOG_INFO(SYSTEMTESTS_LOGGER, "Hello");
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(LogFixture, LogWarn)
|
||||
{
|
||||
Singleton<Log>::Lifetime singletonLifetime;
|
||||
BIGFOOT_LOG_WARN(SYSTEMTESTS_LOGGER, "Hello");
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(LogFixture, LogError)
|
||||
{
|
||||
Singleton<Log>::Lifetime singletonLifetime;
|
||||
BIGFOOT_LOG_ERROR(SYSTEMTESTS_LOGGER, "Hello");
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(LogFixture, LogFatal)
|
||||
{
|
||||
Singleton<Log>::Lifetime singletonLifetime;
|
||||
BIGFOOT_LOG_FATAL(SYSTEMTESTS_LOGGER, "Hello");
|
||||
}
|
||||
} // namespace Bigfoot
|
||||
#endif
|
||||
@@ -1,67 +0,0 @@
|
||||
/*********************************************************************
|
||||
* \file Time.cpp
|
||||
*
|
||||
* \author Romain BOULLARD
|
||||
* \date December 2025
|
||||
*********************************************************************/
|
||||
#include <System/Time.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace Bigfoot
|
||||
{
|
||||
class TimeFixture: public ::testing::Test
|
||||
{
|
||||
public:
|
||||
Time m_time {1'767'643'746'680'609};
|
||||
};
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(TimeFixture, Year_ShouldReturnTheYear)
|
||||
{
|
||||
EXPECT_EQ(m_time.Year(), 2026);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(TimeFixture, Month_ShouldReturnTheMonth)
|
||||
{
|
||||
EXPECT_EQ(m_time.Month(), 1);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(TimeFixture, Day_ShouldReturnTheDay)
|
||||
{
|
||||
EXPECT_EQ(m_time.Day(), 5);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(TimeFixture, Hour_ShouldReturnTheHour)
|
||||
{
|
||||
EXPECT_EQ(m_time.Hour(), 20);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(TimeFixture, Minute_ShouldReturnTheMinute)
|
||||
{
|
||||
EXPECT_EQ(m_time.Minute(), 9);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(TimeFixture, Second_ShouldReturnTheSecond)
|
||||
{
|
||||
EXPECT_EQ(m_time.Second(), 6);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(TimeFixture, Microsecond_ShouldReturnTheMicrosecond)
|
||||
{
|
||||
EXPECT_EQ(m_time.Microsecond(), 680'609);
|
||||
}
|
||||
} // namespace Bigfoot
|
||||
@@ -148,14 +148,14 @@ class SlotMapNameGenerator
|
||||
{
|
||||
return "DenseSlotMap";
|
||||
}
|
||||
// if constexpr (std::is_same_v<T, StableSlotMap<SlotMapValue>>)
|
||||
// {
|
||||
// return "StableSlotMap";
|
||||
// }
|
||||
if constexpr (std::is_same_v<T, StableSlotMap<SlotMapValue, SlotMapKey<std::uint8_t, std::uint8_t>>>)
|
||||
{
|
||||
return "StableSlotMap";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using SlotMapTypes = ::testing::Types<DenseSlotMap<SlotMapValue, SlotMapKey<std::uint8_t, std::uint8_t>>>;
|
||||
using SlotMapTypes = ::testing::Types<DenseSlotMap<SlotMapValue, SlotMapKey<std::uint8_t, std::uint8_t>>, StableSlotMap<SlotMapValue, SlotMapKey<std::uint8_t, std::uint8_t>>>;
|
||||
TYPED_TEST_SUITE(SlotMapFixture, SlotMapTypes, SlotMapNameGenerator);
|
||||
|
||||
/****************************************************************************************/
|
||||
@@ -1114,49 +1114,51 @@ TYPED_TEST(SlotMapFixture, ConstReverseIterator)
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
// class StableSlotMapFixture: public ::testing::Test
|
||||
// {
|
||||
// protected:
|
||||
// StableSlotMap<std::uint32_t> m_slotMap;
|
||||
// };
|
||||
//
|
||||
// /****************************************************************************************/
|
||||
//
|
||||
// TEST_F(StableSlotMapFixture, PointersAreStable)
|
||||
// {
|
||||
// const SlotMapKey key = m_slotMap.Insert(42);
|
||||
// const std::uint32_t* const pointer = m_slotMap.Get(key);
|
||||
//
|
||||
// // Inserting enough elements to span multiple pages (PAGE_SIZE is 64) must not move already
|
||||
// // -inserted data: unlike DenseSlotMap's contiguous eastl::vector, growth only appends new
|
||||
// // Page objects (each individually heap-allocated), it never reallocates existing ones.
|
||||
// constexpr std::uint32_t elementCount = 200;
|
||||
// eastl::array<SlotMapKey, elementCount> keys;
|
||||
// for (std::uint32_t value = 0; value < elementCount; ++value)
|
||||
// {
|
||||
// keys[value] = m_slotMap.Insert(value);
|
||||
// }
|
||||
//
|
||||
// EXPECT_EQ(m_slotMap.Get(key), pointer);
|
||||
// EXPECT_EQ(*pointer, 42);
|
||||
//
|
||||
// // Removing unrelated elements, including ones sharing the same page as key, must not move it
|
||||
// // either: Remove() only destroys that slot in place, it never compacts the page's array.
|
||||
// for (std::uint32_t value = 0; value < elementCount; value += 2)
|
||||
// {
|
||||
// m_slotMap.Remove(keys[value]);
|
||||
// }
|
||||
//
|
||||
// EXPECT_EQ(m_slotMap.Get(key), pointer);
|
||||
// EXPECT_EQ(*pointer, 42);
|
||||
//
|
||||
// // Re-inserting into the freed slots must not move it either
|
||||
// for (std::uint32_t value = 0; value < elementCount / 2; ++value)
|
||||
// {
|
||||
// std::ignore = m_slotMap.Insert(value);
|
||||
// }
|
||||
//
|
||||
// EXPECT_EQ(m_slotMap.Get(key), pointer);
|
||||
// EXPECT_EQ(*pointer, 42);
|
||||
// }
|
||||
class StableSlotMapFixture: public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
StableSlotMap<std::uint32_t> m_slotMap;
|
||||
|
||||
using SlotMapKey = StableSlotMap<std::uint32_t>::SlotMapKey;
|
||||
};
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(StableSlotMapFixture, PointersAreStable)
|
||||
{
|
||||
const SlotMapKey key = m_slotMap.Insert(42);
|
||||
const std::uint32_t* const pointer = m_slotMap.Get(key);
|
||||
|
||||
// Inserting enough elements to span multiple pages (PAGE_SIZE is 64) must not move already
|
||||
// -inserted data: unlike DenseSlotMap's contiguous eastl::vector, growth only appends new
|
||||
// Page objects (each individually heap-allocated), it never reallocates existing ones.
|
||||
constexpr std::uint32_t elementCount = 200;
|
||||
eastl::array<SlotMapKey, elementCount> keys;
|
||||
for (std::uint32_t value = 0; value < elementCount; ++value)
|
||||
{
|
||||
keys[value] = m_slotMap.Insert(value);
|
||||
}
|
||||
|
||||
EXPECT_EQ(m_slotMap.Get(key), pointer);
|
||||
EXPECT_EQ(*pointer, 42);
|
||||
|
||||
// Removing unrelated elements, including ones sharing the same page as key, must not move it
|
||||
// either: Remove() only destroys that slot in place, it never compacts the page's array.
|
||||
for (std::uint32_t value = 0; value < elementCount; value += 2)
|
||||
{
|
||||
m_slotMap.Remove(keys[value]);
|
||||
}
|
||||
|
||||
EXPECT_EQ(m_slotMap.Get(key), pointer);
|
||||
EXPECT_EQ(*pointer, 42);
|
||||
|
||||
// Re-inserting into the freed slots must not move it either
|
||||
for (std::uint32_t value = 0; value < elementCount / 2; ++value)
|
||||
{
|
||||
std::ignore = m_slotMap.Insert(value);
|
||||
}
|
||||
|
||||
EXPECT_EQ(m_slotMap.Get(key), pointer);
|
||||
EXPECT_EQ(*pointer, 42);
|
||||
}
|
||||
} // namespace Bigfoot
|
||||
|
||||
Reference in New Issue
Block a user