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
"imp/cpp/IACore.cpp"
"imp/cpp/Logger.cpp"
)
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,19 +21,22 @@
#include <fstream>
#include <filesystem>
namespace IACore {
namespace IACore
{
namespace fs = std::filesystem;
class File {
public:
class File
{
public:
// Modern mapping of flags to standard IO streams
enum class EOpenFlags : UINT32 {
Read = 1 << 0, // std::ios::in
Write = 1 << 1, // std::ios::out
enum class EOpenFlags : UINT32
{
Read = 1 << 0, // std::ios::in
Write = 1 << 1, // std::ios::out
Binary = 1 << 2, // std::ios::binary
Append = 1 << 3, // std::ios::app
Trunc = 1 << 4 // std::ios::trunc
Trunc = 1 << 4 // std::ios::trunc
};
// ---------------------------------------------------------------------
@ -42,26 +45,30 @@ namespace IACore {
// Reads entire file into a binary vector
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
std::error_code ec;
auto fileSize = fs::file_size(path, ec);
if (ec) {
if (ec)
{
return tl::make_unexpected(String("File not found or inaccessible: ") + path);
}
// 2. Open Stream
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);
}
// 3. Read
Vector<UINT8> buffer;
buffer.resize(CAST(fileSize, SIZE_T));
file.read(REINTERPRET(buffer.data(), char*), fileSize);
if(file.fail())
file.read(REINTERPRET(buffer.data(), char *), fileSize);
if (file.fail())
return tl::make_unexpected(String("Read error: ") + path);
return buffer;
@ -69,10 +76,13 @@ namespace IACore {
// Reads entire file into a String
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
auto result = ReadToVector(path);
if (!result) {
if (!result)
{
return tl::make_unexpected(result.error());
}
@ -89,86 +99,117 @@ namespace IACore {
// Old: ExtractFilenameFromPath<true/false>
// New: true -> filename(), false -> stem()
template<BOOL includeExtension = true>
STATIC String ExtractFilename(CONST String& pathStr) {
template<BOOL includeExtension = true> STATIC String ExtractFilename(CONST String &pathStr)
{
fs::path p(pathStr);
if CONSTEXPR (includeExtension) {
if CONSTEXPR (includeExtension)
{
return p.filename().string(); // "sprite.png"
} else {
return p.stem().string(); // "sprite"
}
else
{
return p.stem().string(); // "sprite"
}
}
// Old: ExtractDirectoryFromPath
STATIC String ExtractDirectory(CONST String& pathStr) {
STATIC String ExtractDirectory(CONST String &pathStr)
{
fs::path p(pathStr);
return p.parent_path().string(); // "assets/textures"
}
STATIC BOOL Exists(CONST String& pathStr) {
STATIC BOOL Exists(CONST String &pathStr)
{
std::error_code ec;
return fs::exists(pathStr, ec);
}
public:
public:
// ---------------------------------------------------------------------
// Instance API (For streaming/partial reads)
// ---------------------------------------------------------------------
File() = default;
// RAII Constructor
File(CONST String& path, UINT32 flags) {
#ifdef __cplusplus
File(CONST String &path, EOpenFlags flags)
#else
File(CONST String &path, UINT32 flags)
#endif
{
UNUSED(Open(path, flags));
}
~File() {
~File()
{
Close();
}
// Returns void (success) or error String
tl::expected<void, String> Open(CONST String& path, UINT32 flags) {
#ifdef __cplusplus
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
std::ios_base::openmode mode = static_cast<std::ios_base::openmode>(0);
if (flags & (UINT32)EOpenFlags::Read) mode |= std::ios::in;
if (flags & (UINT32)EOpenFlags::Write) mode |= std::ios::out;
if (flags & (UINT32)EOpenFlags::Binary) mode |= std::ios::binary;
if (flags & (UINT32)EOpenFlags::Append) mode |= std::ios::app;
if (flags & (UINT32)EOpenFlags::Trunc) mode |= std::ios::trunc;
if ((UINT32) flags & (UINT32) EOpenFlags::Read)
mode |= std::ios::in;
if ((UINT32) flags & (UINT32) EOpenFlags::Write)
mode |= std::ios::out;
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);
if (!m_fs.is_open()) {
if (!m_fs.is_open())
{
return tl::make_unexpected(String("Failed to open file: ") + path);
}
return {};
}
VOID Close() {
if (m_fs.is_open()) {
VOID Close()
{
if (m_fs.is_open())
{
m_fs.close();
}
}
BOOL IsOpen() CONST {
BOOL IsOpen() CONST
{
return m_fs.is_open();
}
// Returns number of bytes read
SIZE_T Read(PVOID buffer, SIZE_T size) {
if (!m_fs.is_open()) return 0;
m_fs.read(REINTERPRET(buffer, char*), size);
SIZE_T Read(PVOID buffer, SIZE_T size)
{
if B_UNLIKELY (!m_fs.is_open())
return 0;
m_fs.read(REINTERPRET(buffer, char *), size);
return static_cast<SIZE_T>(m_fs.gcount());
}
VOID Write(CONST PVOID buffer, SIZE_T size) {
if (m_fs.is_open()) {
m_fs.write(REINTERPRET(buffer, const char*), size);
}
VOID Write(CONST PVOID buffer, SIZE_T size)
{
if B_UNLIKELY (!m_fs.is_open())
return;
m_fs.write(REINTERPRET(buffer, const char *), size);
}
private:
std::fstream *GetStreamHandle()
{
return &m_fs;
}
private:
std::fstream m_fs;
};
}
} // namespace IACore

View File

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