Compare commits

..

1 Commits

Author SHA1 Message Date
cat
2a2c435b88 Added Container Options for fine tuning, fine tuned hashmap for DKM 2026-03-03 00:16:17 +02:00
16 changed files with 139 additions and 260 deletions

View File

@@ -6,98 +6,33 @@
# obtain one at http://mozilla.org/MPL/2.0/.
cmake_minimum_required(VERSION 3.10)
cmake_policy(SET CMP0135 NEW)
project(Tourmaline VERSION 1)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fsanitize=address")
endif()
include(GNUInstallDirs)
include(FetchContent)
# Original - https://github.com/novelrt/NovelRT/blob/c877c1e870d62df98935489e9682d93b009fb2fd/ThirdParty/CMakeLists.txt#L6
# Modified version by williamjcm
macro(external_dependency name)
FetchContent_Declare(${name}
${ARGN}
EXCLUDE_FROM_ALL
PREFIX "${CMAKE_CURRENT_BINARY_DIR}/${name}"
TMP_DIR "${CMAKE_CURRENT_BINARY_DIR}/${name}/tmp"
STAMP_DIR "${CMAKE_CURRENT_BINARY_DIR}/${name}/stamp"
DOWNLOAD_DIR "${CMAKE_CURRENT_BINARY_DIR}/${name}/dl"
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/${name}/src"
SUBBUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/${name}/build"
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/${name}/bin"
INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/${name}/inst"
LOG_DIR "${CMAKE_CURRENT_BINARY_DIR}/${name}/log"
)
list(APPEND CMAKE_PREFIX_PATH "${CMAKE_BINARY_DIR}/cmake/${name}")
endmacro()
# Third Party Libraries
external_dependency(Corrade
URL https://github.com/mosra/corrade/archive/2b7251d8bd8833a12f0d9b8deffca7a290340d3c.zip
URL_HASH SHA256=77ed07d373792ce05a64b87c84e7d4687965d6040df4e17b6e9922ca1cbd88c8
)
foreach(dep
Corrade
)
message(STATUS "Fetching ${dep}...")
add_subdirectory(external/${dep})
endforeach()
# Building
add_library(${PROJECT_NAME} SHARED
"source/Systems/ECS/Components.cpp"
"source/Systems/ECS/World.cpp"
"source/Systems/Logging.cpp"
"source/Systems/Random.cpp"
"source/Types/UUID.cpp"
)
"source/Systems/ECS/Components.cpp"
"source/Systems/ECS/World.cpp"
"source/Systems/Logging.cpp"
"source/Systems/Random.cpp"
"source/Types/UUID.cpp")
# Actual linking
target_link_libraries(${PROJECT_NAME} PUBLIC
Corrade::Main
Corrade::Containers
Corrade::Utility
Corrade::PluginManager
)
# Module stuff
set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION})
# Nothing to link right now
target_link_libraries(${PROJECT_NAME})
target_include_directories(${PROJECT_NAME}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/headers>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/>
$<BUILD_INTERFACE:${corrade_SOURCE_DIR}/src>
$<INSTALL_INTERFACE:include/${PROJECT_NAME}>
$<INSTALL_INTERFACE:include/${PROJECT_NAME}External>
)
FetchContent_GetProperties(Corrade SOURCE_DIR corrade_SOURCE_DIR)
FetchContent_GetProperties(Corrade BINARY_DIR corrade_BINARY_DIR)
install(
DIRECTORY
"${corrade_SOURCE_DIR}/src/Corrade/"
"${corrade_BINARY_DIR}/src/Corrade/"
DESTINATION "include/${PROJECT_NAME}External/Corrade"
FILES_MATCHING
PATTERN "*.h"
PATTERN "*.hpp"
)
# A way to live forever
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND printf "Dedicated to my beloved Goma, I love you. - Dora" >> $<TARGET_FILE:${PROJECT_NAME}>
)
install(
@@ -105,14 +40,7 @@ install(
EXPORT ${PROJECT_NAME}Targets
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
INCLUDES DESTINATION include/${PROJECT_NAME}
)
install(
TARGETS CorradeMain CorradeUtility CorradeContainers CorradePluginManager
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
INCLUDES DESTINATION include/${PROJECT_NAME}External
INCLUDES DESTINATION include
)
install(DIRECTORY headers/ DESTINATION include/${PROJECT_NAME})

View File

@@ -1,5 +1,5 @@
# Tourmaline Engine
Tormaline Engine is a game engine created for C++23. [Source Code](https://git.thenight.club/cat/Tourmaline-Engine/).
Tormaline Engine is a game engine created for game development with C++23.
### Currently the project is still trying to incorporate following parts (in no particular order):
- [ ] ECS (Builtin)
@@ -17,20 +17,17 @@ Tormaline Engine is a game engine created for C++23. [Source Code](https://git.t
# Usability Status
Tourmaline is by no means currently usable. The project is incredible volatile with constant changes and improvements. Please wait until a release is made.
However if you cannot just help yourself you can compile a tourmaline demo by running
```
g++ program.cpp -std=c++23 -lTourmaline -lCorradeUtility -lCorradePluginManager -I/usr/local/include/TourmalineExternal -o program
```
# 3rd Party Libraries Credits
- [Corrade/Magnum](https://magnum.graphics/) - graphics middleware by Vladimír "Mosra" Vondruš.
- [miniaudio](https://miniaud.io/) - audio playback and capture library by David "Mackron" Reid.
- [Xohiro](https://github.com/david-cortes/xoshiro_cpp/blob/master/xoshiro.h) implementation by David Blackman and Sebastiano Vigna.
- [Xohiro](https://github.com/david-cortes/xoshiro_cpp/blob/master/xoshiro.h) implementation by David Blackman and Sebastiano Vigna
# Special Thanks
- [Lars "harmonyisdead"](https://github.com/larsl2005) for hosting the thenight.club services.
- [Vladimír "Mosra" Vondruš](https://github.com/mosra) for their mentorship of my C++ knowledge/projects, and the people at the [magnum gitter channel](https://matrix.to/#/#mosra_magnum:gitter.im), for their continous support and feedback of this project.
- [Kae "voxelfoxkae"](https://voxelfox.co.uk/) for mentorship.
- [Kae "voxelfoxkae"](https://voxelfox.co.uk/) for getting me into programming seriously and mentorship.
- The members of The Night Club discord server, for being there for me.
# Not-so frequently asked questions
### Version Scheming
@@ -44,3 +41,14 @@ From [Find Gemstone](https://www.findgemstone.com/blog/what-is-tourmaline-used-f
> Tourmaline has unique electric properties, including the ability to generate an electric charge as well as maintain electromagnetic radiation. These characteristics make tourmaline useful in the production of a range of electronics.
In short Tourmaline is a very versatile "Gem". This name is given to the third iteration of a project that once only concern itself with Video playback on Magnum graphics.
## Short History
Initially this project was called **MagnumVideo**, as goal was to allow video playback on [Magnum Graphics](https://magnum.graphics/). Due to Magnum Graphic's OpenAL wrapper being very poorly, made the project required me to include an audio engine with the video playback.
> Original MagnumVideo was able to implement basic video playback with static frame time
So the project grew into **Overcharged Toolset** (MagnumVideo -> ChargeVideo), with goal to extend Magnum with Seamless Video, Audio, ECS, Shader, Particle, etc... systems. Each package aimed to be independent out of the box and only require each other if desired. However this was incredibly unsustainable and made development enjoyability and API quality very poor.
> ChargeVideo improved upon MagnumVideo with more supported types and PTS based timing. ChargeAudio was added to allow audio playback with video synced.
Around the time that Overcharged has been having an identity crisis, a dear friend in a libera IRC chat has introduced me to the wonderful world of [Ruby](https://www.ruby-lang.org/en/). I spent few days trying to combine two of my favourite things ever (Ruby's ease, and C++'s speed & control), this has led me to finally ditch Overcharged and start with a clean slate.
Therefore the name is basically "Overcharged + Ruby (a gem) = Tourmaline (Gem used to make electronics)" )

View File

@@ -1,16 +0,0 @@
include(FetchContent)
# Building options
set(CORRADE_BUILD_STATIC OFF)
# Feature options
set(CORRADE_WITH_MAIN ON)
set(CORRADE_WITH_UTILITY ON)
set(CORRADE_WITH_PLUGINMANAGER ON)
set(CORRADE_WITH_INTERCONNECT OFF)
set(CORRADE_WITH_TESTSUITE OFF)
if(NOT CMAKE_CROSSCOMPILING)
set(CORRADE_WITH_RC ON)
endif()
FetchContent_MakeAvailable(Corrade)

View File

@@ -11,8 +11,6 @@
#define GUARD_TOURMALINE_CONCEPTS_H
#include <concepts>
#include <functional>
#include <tuple>
#include <type_traits>
namespace Tourmaline::Concepts {
template <typename T>
@@ -32,29 +30,5 @@ template <typename Base, typename Type1, typename Type2>
requires Either<Base, Type1, Type2>
using OppositeOf = _opposite_of<Base, Type1, Type2>::type;
// heavily inspired by
// https://github.com/aminroosta/sqlite_modern_cpp/blob/master/hdr/sqlite_modern_cpp/utility/function_traits.h
template <typename> struct FunctionTraits;
template <typename Function>
struct FunctionTraits
: public FunctionTraits<
decltype(&std::remove_reference_t<Function>::operator())> {};
template <typename Return, typename Class, typename... Arguments>
struct FunctionTraits<Return (Class::*)(Arguments...) const>
: FunctionTraits<Return (*)(Arguments...)> {};
template <typename Return, typename Class, typename... Arguments>
struct FunctionTraits<Return (Class::*)(Arguments...)>
: FunctionTraits<Return (*)(Arguments...)> {};
template <typename Return, typename... Arguments>
struct FunctionTraits<Return (*)(Arguments...)> {
using returnType = Return;
using arguments = std::tuple<Arguments...>;
template <std::size_t index>
using argument = std::tuple_element_t<index, arguments>;
static constexpr std::size_t argumentCount = sizeof...(Arguments);
};
} // namespace Tourmaline::Concepts
#endif

View File

@@ -13,9 +13,8 @@
#include "ContainerOptions.hpp"
#include "Hashmap.hpp"
#include "Corrade/Containers/Array.h"
#include <algorithm>
#include <array>
#include <cmath>
#include <cstddef>
#include <cstdint>
@@ -34,14 +33,14 @@ template <Concepts::Hashable AKey, Concepts::Hashable BKey, typename Value,
class DualkeyMap {
public:
// Return Types
template <typename OppositeKey>
template <typename OppositeKey, std::size_t keyCount>
requires Concepts::Either<OppositeKey, AKey, BKey>
struct MultiQueryResult {
// Having to use pointers here over references was not fun
// but it was for greater good
const OppositeKey *oppositeKey;
Corrade::Containers::Array<Value *> valueQueryResults;
std::size_t howManyFound = 1;
std::array<Value *, keyCount> valueQueryResults;
};
using QueryResult =
@@ -206,19 +205,19 @@ public:
}
template <typename Key,
typename OppositeKey = Concepts::OppositeOf<Key, AKey, BKey>>
typename OppositeKey = Concepts::OppositeOf<Key, AKey, BKey>,
std::size_t keyCount>
requires Concepts::Either<Key, AKey, BKey>
[[nodiscard("Discarding a very expensive query!")]]
std::vector<MultiQueryResult<OppositeKey>>
QueryWithAll(const Corrade::Containers::Array<Key> &keys) {
std::vector<MultiQueryResult<OppositeKey>> queryResult =
std::vector<MultiQueryResult<OppositeKey, keyCount>>
QueryWithAll(const Key (&keys)[keyCount]) {
std::vector<MultiQueryResult<OppositeKey, keyCount>> queryResult =
queryWithMany<Key>(keys);
std::erase_if(queryResult,
[keyCount = keys.size()](
const MultiQueryResult<OppositeKey> &queryRecord) {
return queryRecord.howManyFound != keyCount;
});
std::erase_if(
queryResult,
[](const MultiQueryResult<OppositeKey, keyCount> &queryRecord) {
return queryRecord.howManyFound != keyCount;
});
return queryResult;
}
@@ -270,14 +269,14 @@ private:
// Interal querying
template <typename Key,
typename OppositeKey = Concepts::OppositeOf<Key, AKey, BKey>>
inline std::vector<MultiQueryResult<OppositeKey>>
queryWithMany(const Corrade::Containers::Array<Key> &keys) {
typename OppositeKey = Concepts::OppositeOf<Key, AKey, BKey>,
std::size_t keyCount>
inline std::vector<MultiQueryResult<OppositeKey, keyCount>>
queryWithMany(const Key (&keys)[keyCount]) {
constexpr bool searchingInFirstKey = std::is_same_v<Key, AKey>;
std::size_t keyCount = keys.size();
// I really can't wait for C++26 contracts
if (keyCount == 0) {
if constexpr (keyCount == 0) {
Systems::Logging::Log("Failed to Query! QueryWithAll require at least 2 "
"key to be given, zero was given! Terminating",
"Dualkey Map",
@@ -285,7 +284,7 @@ private:
}
// Hoping this never ever gets triggered :sigh:
if (keyCount == 1) {
if constexpr (keyCount == 1) {
Systems::Logging::Log("QueryWithAll should not be used for single key "
"entry! Please use Query for this instead.",
"Dualkey Map", Systems::Logging::LogLevel::Error);
@@ -293,7 +292,7 @@ private:
// While we don't necessary need the hashes,
// it just helps us tremendously benefit from short circuit checks
Corrade::Containers::Array<std::size_t> keyHashes{keyCount};
std::array<std::size_t, keyCount> keyHashes;
for (uint64_t index = 0; index < keyCount; index++) {
keyHashes[index] = std::hash<Key>{}(keys[index]);
}
@@ -302,7 +301,7 @@ private:
Key *keyToCompare;
OppositeKey *oppositeKey;
Containers::Hashmap<OppositeKey, MultiQueryResult<OppositeKey>,
Containers::Hashmap<OppositeKey, MultiQueryResult<OppositeKey, keyCount>,
{8.0f, 0.01f, 2.5f, 2048, 8}> // Aggressive hashmap :o
queryResults;
@@ -335,9 +334,8 @@ private:
}
queryResults
.Insert(
*oppositeKey,
{oppositeKey, Corrade::Containers::Array<Value *>{keyCount}})
.Insert(*oppositeKey,
MultiQueryResult<OppositeKey, keyCount>(oppositeKey))
.valueQueryResults[index] = &hash->value;
}
}

View File

@@ -34,7 +34,8 @@ public:
if (!storage[keyHashPosition].empty()) {
// Throws
Systems::Logging::Log("Trying to insert the same key twice! Throwing...",
"Hashmap", Systems::Logging::Error, Has(key));
"Hashmap", Systems::Logging::LogLevel::Error,
Has(key));
} else {
storage[keyHashPosition].reserve(Options.reservedBucketSpace);
}
@@ -50,7 +51,7 @@ public:
// Throws
Systems::Logging::Log("Trying to remove a non-existant key! Throwing...",
"Hashmap", Systems::Logging::Error,
"Hashmap", Systems::Logging::LogLevel::Error,
storage[keyHashPosition].empty());
std::erase_if(storage[keyHashPosition],
[keyHash, &key](const hashStorage &hash) {
@@ -89,7 +90,8 @@ public:
Systems::Logging::Log(
"Trying to access a non-existant bucket for a key! Throwing...",
"Hashmap", Systems::Logging::Error, storage[keyHashPosition].empty());
"Hashmap", Systems::Logging::LogLevel::Error,
storage[keyHashPosition].empty());
for (hashStorage &hash : storage[keyHashPosition]) {
if (hash.hash == keyHash && hash.key == key) {
@@ -98,8 +100,7 @@ public:
}
Systems::Logging::Log("Trying to access a non-existant key! Throwing...",
"Hashmap", Systems::Logging::Error);
throw;
"Hashmap", Systems::Logging::LogLevel::Error);
}
[[nodiscard("Discarding an expensive operation!")]]
@@ -159,8 +160,8 @@ private:
// Repopulate and cleanup
for (bucket &entry : oldStorage) {
for (hashStorage &hash : entry) {
Insert(std::move(hash.key), std::move(hash.value));
for (const hashStorage &hash : entry) {
Insert(hash.key, hash.value);
}
entry.clear();

View File

@@ -10,60 +10,64 @@
#ifndef GUARD_TOURMALINE_ECS_H
#define GUARD_TOURMALINE_ECS_H
#include <any>
#include <format>
#include <typeindex>
#include "../Containers/DualkeyMap.hpp"
#include "../Containers/Hashmap.hpp"
#include "../Types.hpp"
#include "ECS/BuiltinComponents.hpp"
#include "Logging.hpp"
namespace Tourmaline::Systems::ECS {
using Entity = Tourmaline::Type::UUID;
using System = Tourmaline::Type::UUID;
class World;
class World {
public:
World() {}
// ====== World controls ======
void Step();
// ======== Entities ========
[[nodiscard]]
Entity CreateEntity();
[[nodiscard("Pointless call of EntityExists")]]
bool EntityExists(const Entity &entity) noexcept;
[[nodiscard("It is not guaranteed that an entity can always be destroyed, "
"please make sure by checking the returned bool")]]
bool DestroyEntity(Entity entity);
// ======== Components ========
template <isAComponent Component, typename... ComponentArgs>
Component &AddComponent(const Entity &entity, ComponentArgs &&...args) {
auto newComponent = entityComponentMap.Insert(entity, typeid(Component),
Component(args...));
template <isAComponent component, typename... Args>
component &AddComponent(const Entity &entity,
Args &&...constructionArguments) {
auto newComponent = entityComponentMap.Insert(
entity, typeid(component), component(constructionArguments...));
return std::any_cast<Component &>(std::get<2>(newComponent));
return std::any_cast<component &>(std::get<2>(newComponent));
}
template <isAComponent Component>
[[nodiscard("Pointless call of GetComponent")]]
Component &GetComponent(const Entity &entity) {
auto result = entityComponentMap.Query(entity, typeid(Component));
template <isAComponent component>
[[nodiscard("Discarding an expensive operation's result!")]]
component &GetComponent(const Entity &entity) {
auto result = entityComponentMap.Query(entity, typeid(component));
if (result.empty()) {
Logging::LogFormatted("Entity {} does not have component {}!",
"ECS/GetComponent", Logging::LogLevel::Error,
entity.asString(), typeid(Component).name());
Logging::Log(std::format("Entity {} does not have component {}!",
entity.asString(), typeid(component).name()),
"ECS/GetComponent", Logging::LogLevel::Error);
}
return std::any_cast<Component &>(result.begin()->second);
return std::any_cast<component &>(result.begin()->second);
}
template <isAComponent Component>
[[nodiscard("Pointless call of HasComponent")]]
template <isAComponent component>
[[nodiscard("Discarding an expensive operation's result!")]]
bool HasComponent(const Entity &entity) {
return entityComponentMap.Query(entity, typeid(Component)).size();
return entityComponentMap.Query(entity, typeid(component)).size();
}
template <isAComponent Component> bool RemoveComponent(const Entity &entity) {
return entityComponentMap.Remove(entity, typeid(Component));
template <isAComponent component>
[[nodiscard("It is not guaranteed that a component can always be removed, "
"please make sure by checking the returned bool")]]
bool RemoveComponent(const Entity &entity) {
return entityComponentMap.Remove(entity, typeid(component));
}
// Copying is not allowed since the ECS world is meant to be
@@ -72,11 +76,8 @@ public:
World &operator=(const World &) = delete;
private:
using systemFunction =
std::function<void(const Entity &, std::span<std::any *>)>;
Containers::DualkeyMap<Entity, std::type_index, std::any>
Tourmaline::Containers::DualkeyMap<Entity, std::type_index, std::any>
entityComponentMap{};
Containers::Hashmap<System, systemFunction> registeredSystems{};
// ======== Life-cycle ========
void preSystems();

View File

@@ -24,7 +24,7 @@ concept isAComponent = std::derived_from<T, ECS::Component>;
namespace Tourmaline::Systems::Components {
// Builtin
struct Base : public ECS::Component {
double x = 0, y = 0, z = 0;
Base() {}
};
} // namespace Tourmaline::Systems::Components
#endif

View File

@@ -8,36 +8,31 @@
*/
#ifndef GUARD_TOURMALINE_LOGGING_H
#define GUARD_TOURMALINE_LOGGING_H
#include "Corrade/Containers/String.h"
#include "Corrade/Containers/StringView.h"
#include "Corrade/Utility/Format.h"
#include <array>
#include <fstream>
#include <string_view>
namespace Tourmaline::Systems {
class Logging {
public:
enum LogLevel { Critical, Error, Warning, Info, Debug, Trace };
enum class LogLevel {
Critical = 0,
Error = 1,
Warning = 2,
Info = 3,
Debug = 4,
Trace = 5
};
static void LogToFile(Corrade::Containers::String File = "");
static void Log(Corrade::Containers::StringView message,
Corrade::Containers::StringView position = "Unknown",
static void LogToFile(std::string File = "");
static void Log(std::string_view message,
std::string_view position = "Unknown",
LogLevel severity = LogLevel::Info, bool assertion = true);
template <class... Args>
static void LogFormatted(const char *format, const char *position,
LogLevel severity, const Args &...args) {
static Corrade::Containers::String output{Corrade::ValueInit, 4096};
std::size_t size = Corrade::Utility::formatInto(output, format, args...);
Log(Corrade::Containers::StringView{output.begin(), size}, position,
severity);
}
private:
static std::fstream File;
static const char *LogLevelToColour[Trace + 1];
static const char *LogLevelToString[Trace + 1];
static std::array<std::pair<const std::string, const std::string>, 6>
LogLevelToString;
};
} // namespace Tourmaline::Systems
#endif

View File

@@ -10,7 +10,7 @@
#ifndef GUARD_TOURMALINE_RANDOM_H
#define GUARD_TOURMALINE_RANDOM_H
#include "../Types.hpp"
#include "TourmalineExternal/random/xoshiro.h"
#include <TourmalineExternal/random/xoshiro.h>
#include <type_traits>

View File

@@ -10,9 +10,7 @@
#ifndef GUARD_TOURMALINE_TYPES_H
#define GUARD_TOURMALINE_TYPES_H
#include "Corrade/Containers/String.h"
#include "TourmalineExternal/random/xoshiro.h"
#include <cstdint>
#include <functional>
#include <string>
@@ -21,7 +19,7 @@ namespace Tourmaline::Type {
class UUID {
public:
[[nodiscard]]
Corrade::Containers::String asString() const;
std::string asString() const;
bool operator==(const UUID &rhs) const;
UUID(uint64_t firstHalf, uint64_t secondHalf);

View File

@@ -7,7 +7,7 @@
* obtain one at http://mozilla.org/MPL/2.0/.
*/
#include "Systems/ECS.hpp"
#include "Systems/ECS/BuiltinComponents.hpp"
#include <Systems/ECS.hpp>
#include <Systems/ECS/BuiltinComponents.hpp>
// Empty until future use

View File

@@ -7,9 +7,9 @@
* obtain one at http://mozilla.org/MPL/2.0/.
*/
#include "Systems/ECS.hpp"
#include "Systems/ECS/BuiltinComponents.hpp"
#include "Systems/Random.hpp"
#include <Systems/ECS.hpp>
#include <Systems/ECS/BuiltinComponents.hpp>
#include <Systems/Random.hpp>
using namespace Tourmaline::Systems;
using namespace ECS;

View File

@@ -7,12 +7,7 @@
* obtain one at http://mozilla.org/MPL/2.0/.
*/
#include "Systems/Logging.hpp"
#include "Corrade/Containers/String.h"
#include "Corrade/Containers/StringView.h"
#include "Corrade/Tags.h"
#include "Corrade/Utility/Format.h"
#include "../../headers/Systems/Logging.hpp"
#include <cerrno>
#include <chrono>
@@ -21,63 +16,63 @@
#include <exception>
#include <format>
#include <fstream>
#include <iterator>
#include <print>
#include <stdexcept>
#include <string>
#include <string_view>
#include <utility>
using namespace Tourmaline::Systems;
using namespace Corrade::Containers;
using namespace Corrade::Utility;
// This is what happens when it takes you 50 years to implement
// reflections to a language
const char *Logging::LogLevelToColour[Logging::Trace + 1]{
"[0;31m", "[0;91m", "[0;33m", "[0;37m", "[0;92m", "[0;36m"};
const char *Logging::LogLevelToString[Logging::Trace + 1]{
"Critical", "Error", "Warning", "Info", "Debug", "Trace"};
std::array<std::pair<const std::string, const std::string>, 6>
Logging::LogLevelToString{std::pair{"Critical", "[0;31m"},
{"Error", "[0;91m"},
{"Warning", "[0;33m"},
{"Info", "[0;37m"},
{"Debug", "[0;92m"},
{"Trace", "[0;36m"}};
std::fstream Logging::File;
void Logging::LogToFile(String File) {
void Logging::LogToFile(std::string File) {
if (File == "") {
const auto now = std::chrono::system_clock::now();
std::chrono::year_month_day ymd{std::chrono::floor<std::chrono::days>(now)};
File = String{Corrade::ValueInit, 128};
formatInto(File, "Tourmaline-{}-{}-{}.txt", static_cast<int>(ymd.year()),
static_cast<unsigned>(ymd.month()),
static_cast<unsigned>(ymd.day()));
File = std::format("Tourmaline-{:%Y-%j}.txt", now);
}
Logging::File.open(File.data(), std::fstream::out);
Logging::File.open(File, std::fstream::out);
if (Logging::File.fail()) {
String error =
format("FAILED! Could not open or create the file: {}! Error: {}", File,
strerror(errno));
throw std::runtime_error(error.data());
throw std::runtime_error("FAILED! Could not open or create the file: " +
File + "!\n" + strerror(errno));
}
}
void Logging::Log(StringView message, StringView position,
void Logging::Log(std::string_view message, std::string_view position,
Logging::LogLevel severity, bool assertion) {
if (assertion) {
static String output{Corrade::ValueInit,
4096}; // This is done to stop allocations
std::size_t formattedSize = formatInto(
output, "[{}@{}] {}\n", LogLevelToString[severity], position, message);
if (assertion) [[likely]] {
static std::string
output; // This is done to stop allocations per std::format
const auto &loglevelData =
Logging::LogLevelToString[static_cast<size_t>(severity)];
std::format_to(std::back_inserter(output), "[{}@{}] {}\n",
loglevelData.first, position, message);
std::print(
"\033{} {}\033[0m", LogLevelToColour[severity],
std::string_view{output.begin(), output.begin() + formattedSize});
std::print("\033{} {}\033[0m", loglevelData.second, output);
if (Logging::File.is_open()) {
Logging::File.write(output.data(), formattedSize);
Logging::File.write(output.c_str(), output.size());
Logging::File.flush(); // Terrible but necessary sadly
}
if (severity == Logging::LogLevel::Error) {
throw std::runtime_error(output.data());
throw std::runtime_error(output);
}
if (severity == Logging::LogLevel::Critical) {
std::terminate();
}
output.clear();
}
}

View File

@@ -6,8 +6,7 @@
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/.
*/
#include "Systems/Random.hpp"
#include <Systems/Random.hpp>
#include <bit>
#include <cstdint>

View File

@@ -7,19 +7,17 @@
* obtain one at http://mozilla.org/MPL/2.0/.
*/
#include "Corrade/Utility/Format.h"
#include "Types.hpp"
#include <Types.hpp>
#include <charconv>
#include <cstdint>
#include <cstring>
#include <format>
#include <string>
using namespace Tourmaline::Type;
using namespace Corrade::Containers;
using namespace Corrade::Utility;
String UUID::asString() const {
return format("{:.16X}{:.16X}", firstHalf, secondHalf);
std::string UUID::asString() const {
return std::format("{:016X}{:016X}", firstHalf, secondHalf);
}
bool UUID::operator==(const UUID &rhs) const {