This commit is contained in:
2025-11-25 22:13:05 +05:30
parent 3c99d01f49
commit 39eb5c74d6
6 changed files with 278 additions and 81 deletions

View File

@ -1,5 +1,6 @@
set(SRC_FILES set(SRC_FILES
"imp/cpp/IACore.cpp" "imp/cpp/IACore.cpp"
"imp/cpp/Logger.cpp"
) )
add_library(IACore STATIC ${SRC_FILES}) add_library(IACore STATIC ${SRC_FILES})

View File

@ -0,0 +1,61 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <IACore/Logger.hpp>
#include <IACore/File.hpp>
namespace IACore
{
Logger::ELogLevel Logger::s_logLevel{Logger::ELogLevel::WARN};
HRTimePoint Logger::s_startTime{};
IACore::File *Logger::s_logFile{};
VOID Logger::Initialize()
{
s_startTime = HRClock::now();
}
VOID Logger::Terminate()
{
if (s_logFile)
{
s_logFile->Close();
delete s_logFile;
}
}
BOOL Logger::EnableLoggingToDisk(IN PCCHAR filePath)
{
if (s_logFile)
return true;
s_logFile = new IACore::File(filePath, IACore::File::EOpenFlags::Write);
return s_logFile->IsOpen();
}
VOID Logger::SetLogLevel(IN ELogLevel logLevel)
{
s_logLevel = logLevel;
}
VOID Logger::LogInternal(IN PCCHAR prefix, IN String&& msg)
{
std::chrono::duration<double> elapsed = HRClock::now() - s_startTime;
double timestamp = elapsed.count();
const auto outLine = std::format("[{:>8.3f}]: [{}]: {}\n", timestamp, prefix, msg);
const auto outStream = s_logFile ? s_logFile->GetStreamHandle() : &std::cout;
outStream->write(outLine.data(), outLine.size());
}
}

View File

@ -21,14 +21,17 @@
#include <fstream> #include <fstream>
#include <filesystem> #include <filesystem>
namespace IACore { namespace IACore
{
namespace fs = std::filesystem; namespace fs = std::filesystem;
class File { class File
{
public: public:
// Modern mapping of flags to standard IO streams // Modern mapping of flags to standard IO streams
enum class EOpenFlags : UINT32 { enum class EOpenFlags : UINT32
{
Read = 1 << 0, // std::ios::in Read = 1 << 0, // std::ios::in
Write = 1 << 1, // std::ios::out Write = 1 << 1, // std::ios::out
Binary = 1 << 2, // std::ios::binary Binary = 1 << 2, // std::ios::binary
@ -42,18 +45,22 @@ namespace IACore {
// Reads entire file into a binary vector // Reads entire file into a binary vector
NO_DISCARD("Handle the error") NO_DISCARD("Handle the error")
STATIC tl::expected<Vector<UINT8>, String> ReadToVector(CONST String& path) {
STATIC tl::expected<Vector<UINT8>, String> ReadToVector(CONST String &path)
{
// 1. Check File Existence & Size // 1. Check File Existence & Size
std::error_code ec; std::error_code ec;
auto fileSize = fs::file_size(path, ec); auto fileSize = fs::file_size(path, ec);
if (ec) { if (ec)
{
return tl::make_unexpected(String("File not found or inaccessible: ") + path); return tl::make_unexpected(String("File not found or inaccessible: ") + path);
} }
// 2. Open Stream // 2. Open Stream
std::ifstream file(path, std::ios::binary); std::ifstream file(path, std::ios::binary);
if (!file.is_open()) { if (!file.is_open())
{
return tl::make_unexpected(String("Failed to open file handle: ") + path); return tl::make_unexpected(String("Failed to open file handle: ") + path);
} }
@ -69,10 +76,13 @@ namespace IACore {
// Reads entire file into a String // Reads entire file into a String
NO_DISCARD("Handle the error") NO_DISCARD("Handle the error")
STATIC tl::expected<String, String> ReadToString(CONST String& path) {
STATIC tl::expected<String, String> ReadToString(CONST String &path)
{
// Reuse the binary logic to avoid code duplication, then cast // Reuse the binary logic to avoid code duplication, then cast
auto result = ReadToVector(path); auto result = ReadToVector(path);
if (!result) { if (!result)
{
return tl::make_unexpected(result.error()); return tl::make_unexpected(result.error());
} }
@ -89,23 +99,28 @@ namespace IACore {
// Old: ExtractFilenameFromPath<true/false> // Old: ExtractFilenameFromPath<true/false>
// New: true -> filename(), false -> stem() // New: true -> filename(), false -> stem()
template<BOOL includeExtension = true> template<BOOL includeExtension = true> STATIC String ExtractFilename(CONST String &pathStr)
STATIC String ExtractFilename(CONST String& pathStr) { {
fs::path p(pathStr); fs::path p(pathStr);
if CONSTEXPR (includeExtension) { if CONSTEXPR (includeExtension)
{
return p.filename().string(); // "sprite.png" return p.filename().string(); // "sprite.png"
} else { }
else
{
return p.stem().string(); // "sprite" return p.stem().string(); // "sprite"
} }
} }
// Old: ExtractDirectoryFromPath // Old: ExtractDirectoryFromPath
STATIC String ExtractDirectory(CONST String& pathStr) { STATIC String ExtractDirectory(CONST String &pathStr)
{
fs::path p(pathStr); fs::path p(pathStr);
return p.parent_path().string(); // "assets/textures" return p.parent_path().string(); // "assets/textures"
} }
STATIC BOOL Exists(CONST String& pathStr) { STATIC BOOL Exists(CONST String &pathStr)
{
std::error_code ec; std::error_code ec;
return fs::exists(pathStr, ec); return fs::exists(pathStr, ec);
} }
@ -117,58 +132,84 @@ namespace IACore {
File() = default; File() = default;
// RAII Constructor #ifdef __cplusplus
File(CONST String& path, UINT32 flags) { File(CONST String &path, EOpenFlags flags)
#else
File(CONST String &path, UINT32 flags)
#endif
{
UNUSED(Open(path, flags)); UNUSED(Open(path, flags));
} }
~File() { ~File()
{
Close(); Close();
} }
// Returns void (success) or error String #ifdef __cplusplus
tl::expected<void, String> Open(CONST String& path, UINT32 flags) { tl::expected<void, String> Open(CONST String &path, EOpenFlags flags)
#else
tl::expected<void, String> Open(CONST String &path, UINT32 flags)
#endif
{
Close(); // Ensure previous handle is closed Close(); // Ensure previous handle is closed
std::ios_base::openmode mode = static_cast<std::ios_base::openmode>(0); std::ios_base::openmode mode = static_cast<std::ios_base::openmode>(0);
if (flags & (UINT32)EOpenFlags::Read) mode |= std::ios::in; if ((UINT32) flags & (UINT32) EOpenFlags::Read)
if (flags & (UINT32)EOpenFlags::Write) mode |= std::ios::out; mode |= std::ios::in;
if (flags & (UINT32)EOpenFlags::Binary) mode |= std::ios::binary; if ((UINT32) flags & (UINT32) EOpenFlags::Write)
if (flags & (UINT32)EOpenFlags::Append) mode |= std::ios::app; mode |= std::ios::out;
if (flags & (UINT32)EOpenFlags::Trunc) mode |= std::ios::trunc; if ((UINT32) flags & (UINT32) EOpenFlags::Binary)
mode |= std::ios::binary;
if ((UINT32) flags & (UINT32) EOpenFlags::Append)
mode |= std::ios::app;
if ((UINT32) flags & (UINT32) EOpenFlags::Trunc)
mode |= std::ios::trunc;
m_fs.open(path, mode); m_fs.open(path, mode);
if (!m_fs.is_open()) { if (!m_fs.is_open())
{
return tl::make_unexpected(String("Failed to open file: ") + path); return tl::make_unexpected(String("Failed to open file: ") + path);
} }
return {}; return {};
} }
VOID Close() { VOID Close()
if (m_fs.is_open()) { {
if (m_fs.is_open())
{
m_fs.close(); m_fs.close();
} }
} }
BOOL IsOpen() CONST { BOOL IsOpen() CONST
{
return m_fs.is_open(); return m_fs.is_open();
} }
// Returns number of bytes read // Returns number of bytes read
SIZE_T Read(PVOID buffer, SIZE_T size) { SIZE_T Read(PVOID buffer, SIZE_T size)
if (!m_fs.is_open()) return 0; {
if B_UNLIKELY (!m_fs.is_open())
return 0;
m_fs.read(REINTERPRET(buffer, char *), size); m_fs.read(REINTERPRET(buffer, char *), size);
return static_cast<SIZE_T>(m_fs.gcount()); return static_cast<SIZE_T>(m_fs.gcount());
} }
VOID Write(CONST PVOID buffer, SIZE_T size) { VOID Write(CONST PVOID buffer, SIZE_T size)
if (m_fs.is_open()) { {
if B_UNLIKELY (!m_fs.is_open())
return;
m_fs.write(REINTERPRET(buffer, const char *), size); m_fs.write(REINTERPRET(buffer, const char *), size);
} }
std::fstream *GetStreamHandle()
{
return &m_fs;
} }
private: private:
std::fstream m_fs; std::fstream m_fs;
}; };
} } // namespace IACore

View File

@ -22,29 +22,6 @@
namespace IACore namespace IACore
{ {
template<typename... Args>
VOID LogInfo(Args... args)
{
StringStream ss;
UNUSED((ss << ... << args));
printf( __CC_WHITE "[INFO]: %s" __CC_DEFAULT "\n", ss.str().c_str());
}
template<typename... Args>
VOID LogWarn(Args... args)
{
StringStream ss;
UNUSED((ss << ... << args));
printf( __CC_YELLOW "[WARN]: %s" __CC_DEFAULT "\n", ss.str().c_str());
}
template<typename... Args>
VOID LogError(Args... args)
{
StringStream ss;
UNUSED((ss << ... << args));
printf( __CC_RED "[ERROR]: %s" __CC_DEFAULT "\n", ss.str().c_str());
}
} // namespace IACore } // namespace IACore
#endif #endif

View File

@ -0,0 +1,117 @@
// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2025 IAS (ias@iasoft.dev)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
#include <IACore/PCH.hpp>
namespace IACore
{
class File;
class Logger
{
public:
enum class ELogLevel
{
VERBOSE,
INFO,
WARN,
ERROR
};
public:
STATIC VOID Initialize();
STATIC VOID Terminate();
STATIC BOOL EnableLoggingToDisk(IN PCCHAR filePath);
STATIC VOID SetLogLevel(IN ELogLevel logLevel);
template<typename... Args> STATIC VOID Status(FormatterString<Args...> fmt, Args &&...args)
{
LogStatus(std::vformat(fmt.get(), std::make_format_args(args...)));
}
template<typename... Args> STATIC VOID Info(FormatterString<Args...> fmt, Args &&...args)
{
LogInfo(std::vformat(fmt.get(), std::make_format_args(args...)));
}
template<typename... Args> STATIC VOID Warn(FormatterString<Args...> fmt, Args &&...args)
{
LogWarn(std::vformat(fmt.get(), std::make_format_args(args...)));
}
template<typename... Args> STATIC VOID Error(FormatterString<Args...> fmt, Args &&...args)
{
LogError(std::vformat(fmt.get(), std::make_format_args(args...)));
}
private:
#if IA_ENABLE_LOGGING > 0
STATIC VOID LogStatus(IN String &&msg)
{
if (s_logLevel <= ELogLevel::VERBOSE)
LogInternal("STATUS", IA_MOVE(msg));
}
STATIC VOID LogInfo(IN String &&msg)
{
if (s_logLevel <= ELogLevel::INFO)
LogInternal("INFO", IA_MOVE(msg));
}
STATIC VOID LogWarn(IN String &&msg)
{
if (s_logLevel <= ELogLevel::WARN)
LogInternal("WARN", IA_MOVE(msg));
}
STATIC VOID LogError(IN String &&msg)
{
if (s_logLevel <= ELogLevel::ERROR)
LogInternal("ERROR", IA_MOVE(msg));
}
#else
STATIC VOID LogStatus(IN String &&msg)
{
UNUSED(msg);
}
STATIC VOID LogInfo(IN String &&msg)
{
UNUSED(msg);
}
STATIC VOID LogWarn(IN String &&msg)
{
UNUSED(msg);
}
STATIC VOID LogError(IN String &&msg)
{
UNUSED(msg);
}
#endif
STATIC VOID LogInternal(IN PCCHAR prefix, IN String &&msg);
private:
STATIC ELogLevel s_logLevel;
STATIC HRTimePoint s_startTime;
STATIC IACore::File *s_logFile;
};
}

View File

@ -29,6 +29,8 @@
# include <limits> # include <limits>
# include <cstring> # include <cstring>
# include <cstddef> # include <cstddef>
# include <chrono>
# include <iostream>
# include <concepts> # include <concepts>
# include <functional> # include <functional>
# include <type_traits> # include <type_traits>
@ -526,11 +528,9 @@ using String = std::string;
using StringView = std::string_view; using StringView = std::string_view;
using StringStream = std::stringstream; using StringStream = std::stringstream;
template<typename... Args> STATIC String BuildString(Args &&...args) using HRClock = std::chrono::high_resolution_clock;
{ using HRTimePoint = std::chrono::time_point<HRClock>;
std::stringstream ss;
(ss << ... << args); template<typename... Args> using FormatterString = std::format_string<Args...>;
return ss.str();
}
#endif #endif