V1 (#2)
Some checks failed
Conan Packaging / Package Bin2CPP/1.0.0 (push) Has been cancelled
Bin2CPP / Build & Test Debug with ./ConanProfiles/clangd (Unity Build: OFF) (push) Has been cancelled
Bin2CPP / Build & Test Debug with ./ConanProfiles/clangd (Unity Build: ON) (push) Has been cancelled
Bin2CPP / Build & Test Debug with ./ConanProfiles/clangd_asan (Unity Build: OFF) (push) Has been cancelled
Bin2CPP / Build & Test Debug with ./ConanProfiles/clangd_asan (Unity Build: ON) (push) Has been cancelled
Bin2CPP / Build & Test RelWithDebInfo with ./ConanProfiles/clang (Unity Build: OFF) (push) Has been cancelled
Bin2CPP / Build & Test RelWithDebInfo with ./ConanProfiles/clang (Unity Build: ON) (push) Has been cancelled
Bin2CPP / Build & Test RelWithDebInfo with ./ConanProfiles/clangd (Unity Build: OFF) (push) Has been cancelled
Bin2CPP / Build & Test RelWithDebInfo with ./ConanProfiles/clangd (Unity Build: ON) (push) Has been cancelled
Bin2CPP / Build & Test RelWithDebInfo with ./ConanProfiles/clangd_asan (Unity Build: OFF) (push) Has been cancelled
Bin2CPP / Build & Test Release with ./ConanProfiles/clangd (Unity Build: ON) (push) Has been cancelled
Bin2CPP / Build & Test Release with ./ConanProfiles/clangd_asan (Unity Build: OFF) (push) Has been cancelled
Bin2CPP / Build & Test Debug with ./ConanProfiles/clang (Unity Build: ON) (push) Has been cancelled
Bin2CPP / Build & Test RelWithDebInfo with ./ConanProfiles/clangd_asan (Unity Build: ON) (push) Has been cancelled
Bin2CPP / Build & Test Release with ./ConanProfiles/clang (Unity Build: OFF) (push) Has been cancelled
Bin2CPP / Build & Test Release with ./ConanProfiles/clang (Unity Build: ON) (push) Has been cancelled
Bin2CPP / Build & Test Release with ./ConanProfiles/clangd (Unity Build: OFF) (push) Has been cancelled
Bin2CPP / Build & Test Release with ./ConanProfiles/clangd_asan (Unity Build: ON) (push) Has been cancelled
Bin2CPP / Clang Format Checks (push) Has been cancelled
Bin2CPP / Build & Test Debug with ./ConanProfiles/clang (Unity Build: OFF) (push) Has been cancelled
Bin2CPP / Sonarqube (push) Has been cancelled
Some checks failed
Conan Packaging / Package Bin2CPP/1.0.0 (push) Has been cancelled
Bin2CPP / Build & Test Debug with ./ConanProfiles/clangd (Unity Build: OFF) (push) Has been cancelled
Bin2CPP / Build & Test Debug with ./ConanProfiles/clangd (Unity Build: ON) (push) Has been cancelled
Bin2CPP / Build & Test Debug with ./ConanProfiles/clangd_asan (Unity Build: OFF) (push) Has been cancelled
Bin2CPP / Build & Test Debug with ./ConanProfiles/clangd_asan (Unity Build: ON) (push) Has been cancelled
Bin2CPP / Build & Test RelWithDebInfo with ./ConanProfiles/clang (Unity Build: OFF) (push) Has been cancelled
Bin2CPP / Build & Test RelWithDebInfo with ./ConanProfiles/clang (Unity Build: ON) (push) Has been cancelled
Bin2CPP / Build & Test RelWithDebInfo with ./ConanProfiles/clangd (Unity Build: OFF) (push) Has been cancelled
Bin2CPP / Build & Test RelWithDebInfo with ./ConanProfiles/clangd (Unity Build: ON) (push) Has been cancelled
Bin2CPP / Build & Test RelWithDebInfo with ./ConanProfiles/clangd_asan (Unity Build: OFF) (push) Has been cancelled
Bin2CPP / Build & Test Release with ./ConanProfiles/clangd (Unity Build: ON) (push) Has been cancelled
Bin2CPP / Build & Test Release with ./ConanProfiles/clangd_asan (Unity Build: OFF) (push) Has been cancelled
Bin2CPP / Build & Test Debug with ./ConanProfiles/clang (Unity Build: ON) (push) Has been cancelled
Bin2CPP / Build & Test RelWithDebInfo with ./ConanProfiles/clangd_asan (Unity Build: ON) (push) Has been cancelled
Bin2CPP / Build & Test Release with ./ConanProfiles/clang (Unity Build: OFF) (push) Has been cancelled
Bin2CPP / Build & Test Release with ./ConanProfiles/clang (Unity Build: ON) (push) Has been cancelled
Bin2CPP / Build & Test Release with ./ConanProfiles/clangd (Unity Build: OFF) (push) Has been cancelled
Bin2CPP / Build & Test Release with ./ConanProfiles/clangd_asan (Unity Build: ON) (push) Has been cancelled
Bin2CPP / Clang Format Checks (push) Has been cancelled
Bin2CPP / Build & Test Debug with ./ConanProfiles/clang (Unity Build: OFF) (push) Has been cancelled
Bin2CPP / Sonarqube (push) Has been cancelled
Reviewed-on: #2 Co-authored-by: Romain BOULLARD <romain.boullard@protonmail.com> Co-committed-by: Romain BOULLARD <romain.boullard@protonmail.com>
This commit was merged in pull request #2.
This commit is contained in:
56
Bin2CPP/Sources/Bin2CPP/CMakeLists.txt
Normal file
56
Bin2CPP/Sources/Bin2CPP/CMakeLists.txt
Normal file
@@ -0,0 +1,56 @@
|
||||
get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||
project(${PackageName})
|
||||
|
||||
add_executable(${PROJECT_NAME})
|
||||
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20)
|
||||
|
||||
file(GLOB_RECURSE BIN2CPPEXE_SOURCES
|
||||
CONFIGURE_DEPENDS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
|
||||
)
|
||||
|
||||
file(GLOB_RECURSE BIN2CPPEXE_HEADERS
|
||||
CONFIGURE_DEPENDS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/*.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/*.hpp
|
||||
)
|
||||
|
||||
target_sources(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
${BIN2CPPEXE_SOURCES}
|
||||
PRIVATE
|
||||
FILE_SET HEADERS
|
||||
BASE_DIRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Include
|
||||
FILES
|
||||
${BIN2CPPEXE_HEADERS}
|
||||
)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
Bin2CPPCompileAndLinkFlags
|
||||
Bin2CPPLib
|
||||
CLI11::CLI11
|
||||
${CMAKE_DL_LIBS})
|
||||
|
||||
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX Src FILES ${BIN2CPPEXE_SOURCES} ${BIN2CPPEXE_HEADERS})
|
||||
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER Bin2CPP/${ParentFolder})
|
||||
|
||||
##################ASAN SETUP###################
|
||||
|
||||
if(${ASAN})
|
||||
if (MSVC)
|
||||
get_filename_component(MSVC_BIN_DIR "${CMAKE_CXX_COMPILER}" DIRECTORY)
|
||||
set(ASAN_DLL "${MSVC_BIN_DIR}/clang_rt.asan_dynamic-x86_64.dll")
|
||||
|
||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Copying ASan DLL: ${ASAN_DLL} to $<TARGET_FILE_DIR:${PROJECT_NAME}>"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${ASAN_DLL}" "$<TARGET_FILE_DIR:${PROJECT_NAME}>"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
########INSTALL
|
||||
|
||||
install(TARGETS ${PROJECT_NAME} DESTINATION bin)
|
||||
68
Bin2CPP/Sources/Bin2CPP/main.cpp
Normal file
68
Bin2CPP/Sources/Bin2CPP/main.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
#include <Generator.hpp>
|
||||
#include <Log.hpp>
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
CLI::App app {"Bin2CPP allows you to generate a C++ header containing the binary content of an input file"};
|
||||
argv = app.ensure_utf8(argv);
|
||||
|
||||
std::string input;
|
||||
app.add_option("-f,--input", input, "The input file")->required();
|
||||
std::string output;
|
||||
app.add_option("-o,--output", output, "The output file")->required();
|
||||
std::optional<std::string> arrayType;
|
||||
app.add_option("--arrayType", arrayType, "The type of the array");
|
||||
std::optional<std::string> arrayInclude;
|
||||
app.add_option("--arrayInclude", arrayInclude, "Include for the array type");
|
||||
std::optional<std::string> arrayName;
|
||||
app.add_option("--arrayName", arrayName, "The array name");
|
||||
std::optional<std::string> customNamespace;
|
||||
app.add_option("--namespace", customNamespace, "The namespace");
|
||||
bool verbose = false;
|
||||
app.add_option("--verbose", verbose, "Activate logging");
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
std::unique_ptr<Bin2CPP::Singleton<Bin2CPP::Log>::Lifetime> loggerLifetime =
|
||||
verbose ? std::make_unique<Bin2CPP::Singleton<Bin2CPP::Log>::Lifetime>() : nullptr;
|
||||
|
||||
Bin2CPP::Generator generator(input);
|
||||
if (arrayType)
|
||||
{
|
||||
generator.SetMapping(Bin2CPP::MappingKey::ARRAY_TYPE, arrayType.value());
|
||||
}
|
||||
if (arrayInclude)
|
||||
{
|
||||
generator.SetMapping(Bin2CPP::MappingKey::ARRAY_TYPE_INCLUDE, arrayInclude.value());
|
||||
}
|
||||
if (arrayName)
|
||||
{
|
||||
generator.SetMapping(Bin2CPP::MappingKey::ARRAY_NAME, arrayName.value());
|
||||
}
|
||||
if (customNamespace)
|
||||
{
|
||||
generator.SetMapping(Bin2CPP::MappingKey::NAMESPACE, customNamespace.value());
|
||||
}
|
||||
|
||||
if (!generator.Generate())
|
||||
{
|
||||
BIN2CPP_LOG_ERROR("Failed to generate '{}'", input);
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::ofstream out(output);
|
||||
if (!out)
|
||||
{
|
||||
BIN2CPP_LOG_ERROR("Failed to open '{}'", output);
|
||||
return 1;
|
||||
}
|
||||
|
||||
out << generator.Get();
|
||||
out.close();
|
||||
|
||||
BIN2CPP_LOG_INFO("'{}' Generated !", output);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||
project(${PackageName})
|
||||
|
||||
add_executable(${PROJECT_NAME})
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/Include)
|
||||
|
||||
# collect sources (reconfigure when files are added/removed)
|
||||
file(GLOB_RECURSE SOURCES
|
||||
CONFIGURE_DEPENDS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/*.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/*.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
|
||||
)
|
||||
|
||||
target_sources(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
${SOURCES}
|
||||
)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC CLI11::CLI11 Bin2CPPLib)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE ${CMAKE_DL_LIBS})
|
||||
|
||||
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX Src FILES ${SOURCES})
|
||||
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER Bin2CPP/${ParentFolder})
|
||||
|
||||
bin2cpp_setup_dependencies("Bin2CPPExe")
|
||||
@@ -1,4 +0,0 @@
|
||||
int main([[maybe_unused]] int argc, [[maybe_unused]] char** argv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -2,27 +2,51 @@ get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||
project(${PackageName})
|
||||
|
||||
add_library(${PROJECT_NAME} STATIC)
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX)
|
||||
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/Include)
|
||||
file(GLOB_RECURSE BIN2CPPLIB_SOURCES
|
||||
CONFIGURE_DEPENDS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
|
||||
)
|
||||
|
||||
# collect sources (reconfigure when files are added/removed)
|
||||
file(GLOB_RECURSE SOURCES
|
||||
file(GLOB_RECURSE BIN2CPPLIB_HEADERS
|
||||
CONFIGURE_DEPENDS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/*.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/*.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
|
||||
)
|
||||
|
||||
file(GLOB_RECURSE BIN2CPPLIB_OTHERS
|
||||
CONFIGURE_DEPENDS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/*.hpp.in
|
||||
)
|
||||
|
||||
target_sources(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
${SOURCES}
|
||||
${BIN2CPPLIB_SOURCES}
|
||||
PUBLIC
|
||||
FILE_SET HEADERS
|
||||
BASE_DIRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Include
|
||||
FILES
|
||||
${BIN2CPPLIB_HEADERS}
|
||||
)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC EASTL::EASTL rapidhash::rapidhash mimalloc)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE ${CMAKE_DL_LIBS})
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE $<$<CONFIG:Debug,RelWithDebInfo>:cpptrace::cpptrace> quill::quill)
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
Bin2CPPCompileAndLinkFlags
|
||||
PUBLIC
|
||||
$<IF:$<BOOL:${ASAN}>,mimalloc-asan,mimalloc-static>
|
||||
quill::quill
|
||||
$<$<CONFIG:Debug,RelWithDebInfo>:cpptrace::cpptrace>
|
||||
magic_enum::magic_enum)
|
||||
|
||||
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX Src FILES ${SOURCES})
|
||||
target_compile_definitions(${PROJECT_NAME}
|
||||
PUBLIC
|
||||
QUILL_NO_EXCEPTIONS
|
||||
QUILL_DISABLE_NON_PREFIXED_MACROS)
|
||||
|
||||
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/MimallocImpl.cpp PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
|
||||
|
||||
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX Src FILES ${BIN2CPPLIB_SOURCES} ${BIN2CPPLIB_HEADERS} ${BIN2CPPLIB_OTHERS})
|
||||
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER Bin2CPP/${ParentFolder})
|
||||
280
Bin2CPP/Sources/Bin2CPPLib/Generator.cpp
Normal file
280
Bin2CPP/Sources/Bin2CPPLib/Generator.cpp
Normal file
@@ -0,0 +1,280 @@
|
||||
/*********************************************************************
|
||||
* \file Generator.cpp
|
||||
*
|
||||
* \author Romain BOULLARD
|
||||
* \date February 2026
|
||||
*********************************************************************/
|
||||
#include <Generator.hpp>
|
||||
|
||||
#include <Assert.hpp>
|
||||
#include <GeneratedTemplate.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace Bin2CPP
|
||||
{
|
||||
Generator::Generator(const std::string_view p_inputFile):
|
||||
m_inputFile(p_inputFile)
|
||||
{
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
void Generator::SetMapping(const MappingKey p_key, const std::string_view p_value)
|
||||
{
|
||||
const std::optional<std::size_t> index = magic_enum::enum_index(p_key);
|
||||
BIN2CPP_CRITICAL_ASSERT(index.has_value(), "Incorrect mapping key! Got {}", magic_enum::enum_integer(p_key));
|
||||
|
||||
m_mappingTable[index.value()] = p_value;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
bool Generator::Generate()
|
||||
{
|
||||
if (!ComputeMappings())
|
||||
{
|
||||
BIN2CPP_LOG_ERROR("Invalid mappings! Can't generate file!");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_result = g_generatedTemplate;
|
||||
|
||||
for (std::uint32_t i = 0; i < m_mappingTable.size(); ++i)
|
||||
{
|
||||
const std::string KEY = magic_enum::enum_name(magic_enum::enum_value<MappingKey>(i)).data();
|
||||
const std::string& VALUE = m_mappingTable[i];
|
||||
|
||||
const std::string pattern = "\\{\\{" + KEY + "\\}\\}";
|
||||
std::regex placeholderRegex(pattern);
|
||||
m_result = std::regex_replace(m_result, placeholderRegex, VALUE);
|
||||
}
|
||||
|
||||
return Validate();
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
std::string_view Generator::Get() const
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
bool Generator::ComputeMappings()
|
||||
{
|
||||
std::filesystem::path file {m_inputFile.data()};
|
||||
if (!std::filesystem::exists(file))
|
||||
{
|
||||
BIN2CPP_LOG_ERROR("File '{}' does not exists!", m_inputFile);
|
||||
return false;
|
||||
}
|
||||
if (std::filesystem::is_directory(file))
|
||||
{
|
||||
BIN2CPP_LOG_ERROR("'{}' is not a file!", m_inputFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ComputeFilename())
|
||||
{
|
||||
BIN2CPP_LOG_ERROR("Failed to compute filename");
|
||||
return false;
|
||||
}
|
||||
if (!ComputeGuardName())
|
||||
{
|
||||
BIN2CPP_LOG_ERROR("Failed to compute GuardName");
|
||||
return false;
|
||||
}
|
||||
if (!ComputeArrayTypeInclude())
|
||||
{
|
||||
BIN2CPP_LOG_ERROR("Failed to compute ArrayTypeInclude");
|
||||
return false;
|
||||
}
|
||||
if (!ComputeArrayType())
|
||||
{
|
||||
BIN2CPP_LOG_ERROR("Failed to compute ArrayType");
|
||||
return false;
|
||||
}
|
||||
if (!ComputeArrayName())
|
||||
{
|
||||
BIN2CPP_LOG_ERROR("Failed to compute ArrayName");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ifstream in {m_inputFile.data(), std::ios::binary};
|
||||
if (!in)
|
||||
{
|
||||
BIN2CPP_LOG_ERROR("Failed to open '{}'", m_inputFile);
|
||||
return false;
|
||||
}
|
||||
in.seekg(0, std::ios::end);
|
||||
const size_t fileSize = static_cast<size_t>(in.tellg());
|
||||
in.seekg(0, std::ios::beg);
|
||||
|
||||
std::vector<std::byte> data(fileSize);
|
||||
in.read(std::bit_cast<char*>(data.data()), fileSize);
|
||||
|
||||
if (!ComputeArraySize(data))
|
||||
{
|
||||
BIN2CPP_LOG_ERROR("Failed to compute ArraySize");
|
||||
return false;
|
||||
}
|
||||
if (!ComputeData(data))
|
||||
{
|
||||
BIN2CPP_LOG_ERROR("Failed to compute Data");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
bool Generator::ComputeFilename()
|
||||
{
|
||||
std::filesystem::path file {m_inputFile.data()};
|
||||
m_mappingTable[magic_enum::enum_index(MappingKey::FILENAME).value()] = file.filename().string().c_str();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
bool Generator::ComputeGuardName()
|
||||
{
|
||||
std::filesystem::path file {m_inputFile.data()};
|
||||
std::string guardName = file.filename().string();
|
||||
|
||||
std::transform(guardName.begin(),
|
||||
guardName.end(),
|
||||
guardName.begin(),
|
||||
[](const char c)
|
||||
{
|
||||
if (!std::isalnum(c))
|
||||
{
|
||||
return static_cast<int>('_');
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::toupper(c);
|
||||
}
|
||||
});
|
||||
m_mappingTable[magic_enum::enum_index(MappingKey::GUARD_NAME).value()] = std::format("{}_HPP", guardName);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
bool Generator::ComputeArrayTypeInclude()
|
||||
{
|
||||
std::string& value = m_mappingTable[magic_enum::enum_index(MappingKey::ARRAY_TYPE_INCLUDE).value()];
|
||||
if (value.empty())
|
||||
{
|
||||
value = "<array>";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
bool Generator::ComputeArrayType()
|
||||
{
|
||||
std::string& value = m_mappingTable[magic_enum::enum_index(MappingKey::ARRAY_TYPE).value()];
|
||||
if (value.empty())
|
||||
{
|
||||
value = "std::array";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
bool Generator::ComputeArrayName()
|
||||
{
|
||||
std::string& value = m_mappingTable[magic_enum::enum_index(MappingKey::ARRAY_NAME).value()];
|
||||
if (value.empty())
|
||||
{
|
||||
std::filesystem::path file {m_inputFile.data()};
|
||||
value = std::format("g_{}", file.filename().string());
|
||||
|
||||
std::transform(value.begin(),
|
||||
value.end(),
|
||||
value.begin(),
|
||||
[](const char c)
|
||||
{
|
||||
if (!std::isalnum(c))
|
||||
{
|
||||
return static_cast<int>('_');
|
||||
}
|
||||
else
|
||||
{
|
||||
return static_cast<int>(c);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
bool Generator::ComputeArraySize(const std::span<std::byte> p_data)
|
||||
{
|
||||
m_mappingTable[magic_enum::enum_index(MappingKey::ARRAY_SIZE).value()] = std::to_string(p_data.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
bool Generator::ComputeData(const std::span<std::byte> p_data)
|
||||
{
|
||||
std::string& value = m_mappingTable[magic_enum::enum_index(MappingKey::DATA).value()];
|
||||
value.clear();
|
||||
|
||||
constexpr std::size_t bytesPerLine = 16;
|
||||
constexpr std::string_view linePrefix = "\n ";
|
||||
|
||||
for (std::size_t i = 0; i < p_data.size(); ++i)
|
||||
{
|
||||
if (i > 0 && i % bytesPerLine == 0)
|
||||
{
|
||||
value.append(linePrefix.data(), linePrefix.size());
|
||||
}
|
||||
|
||||
const std::string element = std::format("std::byte{{0x{:02X}}}", std::to_integer<std::uint8_t>(p_data[i]));
|
||||
value.append(element.data(), element.size());
|
||||
|
||||
if (i + 1 < p_data.size())
|
||||
{
|
||||
value.append(", ");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
bool Generator::Validate()
|
||||
{
|
||||
std::regex unreplacedRegex(R"(\{\{[A-Z_]+\}\})");
|
||||
std::smatch match;
|
||||
|
||||
if (std::regex_search(m_result, match, unreplacedRegex))
|
||||
{
|
||||
BIN2CPP_LOG_ERROR("Warning: Unreplaced placeholder found: {}", match.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace Bin2CPP
|
||||
134
Bin2CPP/Sources/Bin2CPPLib/Include/Assert.hpp
Normal file
134
Bin2CPP/Sources/Bin2CPPLib/Include/Assert.hpp
Normal file
@@ -0,0 +1,134 @@
|
||||
/*********************************************************************
|
||||
* \file Assert.hpp
|
||||
*
|
||||
* \author Romain BOULLARD
|
||||
* \date October 2025
|
||||
*********************************************************************/
|
||||
#ifndef BIN2CPP_ASSERT_HPP
|
||||
#define BIN2CPP_ASSERT_HPP
|
||||
#include <Log.hpp>
|
||||
|
||||
#if defined BIN2CPP_NOT_OPTIMIZED
|
||||
|
||||
#include <cpptrace/cpptrace.hpp>
|
||||
|
||||
#include <source_location>
|
||||
#include <string>
|
||||
|
||||
#if defined BIN2CPP_LINUX
|
||||
#include <csignal>
|
||||
#endif
|
||||
|
||||
namespace Bin2CPP
|
||||
{
|
||||
class AssertHandler
|
||||
{
|
||||
public:
|
||||
AssertHandler() = delete;
|
||||
|
||||
AssertHandler(const AssertHandler& p_handler) = delete;
|
||||
AssertHandler(AssertHandler&& p_handler) = delete;
|
||||
|
||||
~AssertHandler() = delete;
|
||||
|
||||
/**
|
||||
* Handle an assertion.
|
||||
*
|
||||
* \param p_location Location of the assertion.
|
||||
* \param p_stacktrace The stack trace
|
||||
* \param p_format Format string for the assertion message.
|
||||
* \param p_args Arguments for the format string.
|
||||
*/
|
||||
template<typename... ARGS>
|
||||
static void Handle(const std::source_location& p_location,
|
||||
const std::string_view p_stacktrace,
|
||||
std::format_string<ARGS...> p_format,
|
||||
ARGS&&... p_args)
|
||||
{
|
||||
BIN2CPP_LOG_FATAL("Assert: {} (File:{}, Line:{}, Function:{})\n{}",
|
||||
std::format(p_format, std::forward<ARGS>(p_args)...),
|
||||
p_location.file_name(),
|
||||
p_location.line(),
|
||||
p_location.function_name(),
|
||||
p_stacktrace);
|
||||
}
|
||||
|
||||
AssertHandler& operator=(const AssertHandler& p_handler) = delete;
|
||||
AssertHandler& operator=(AssertHandler&& p_handler) = delete;
|
||||
};
|
||||
} // namespace Bin2CPP
|
||||
|
||||
#if defined BIN2CPP_WINDOWS
|
||||
#define BIN2CPP_BREAK \
|
||||
do \
|
||||
{ \
|
||||
__debugbreak(); \
|
||||
} while (false)
|
||||
#elif defined BIN2CPP_LINUX
|
||||
#define BIN2CPP_BREAK \
|
||||
do \
|
||||
{ \
|
||||
std::raise(SIGTRAP); \
|
||||
} while (false)
|
||||
#endif
|
||||
|
||||
#define BIN2CPP_ASSERT(p_assert, p_message, ...) \
|
||||
do \
|
||||
{ \
|
||||
constexpr std::source_location location = std::source_location::current(); \
|
||||
if (!(p_assert)) [[unlikely]] \
|
||||
{ \
|
||||
Bin2CPP::AssertHandler::Handle(location, \
|
||||
cpptrace::generate_trace().to_string(), \
|
||||
p_message __VA_OPT__(, ) __VA_ARGS__); \
|
||||
if (Bin2CPP::Singleton<Bin2CPP::Log>::HasInstance()) \
|
||||
{ \
|
||||
Bin2CPP::Singleton<Bin2CPP::Log>::Instance().Flush(); \
|
||||
} \
|
||||
BIN2CPP_BREAK; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define BIN2CPP_SOFT_ASSERT(p_assert, p_message, ...) \
|
||||
do \
|
||||
{ \
|
||||
constexpr std::source_location location = std::source_location::current(); \
|
||||
if (!(p_assert)) [[unlikely]] \
|
||||
{ \
|
||||
Bin2CPP::AssertHandler::Handle(location, \
|
||||
cpptrace::generate_trace().to_string(), \
|
||||
p_message __VA_OPT__(, ) __VA_ARGS__); \
|
||||
if (Bin2CPP::Singleton<Bin2CPP::Log>::HasInstance()) \
|
||||
{ \
|
||||
Bin2CPP::Singleton<Bin2CPP::Log>::Instance().Flush(); \
|
||||
} \
|
||||
BIN2CPP_BREAK; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define BIN2CPP_CRITICAL_ASSERT(p_assert, p_message, ...) \
|
||||
do \
|
||||
{ \
|
||||
constexpr std::source_location location = std::source_location::current(); \
|
||||
if (!(p_assert)) [[unlikely]] \
|
||||
{ \
|
||||
Bin2CPP::AssertHandler::Handle(location, \
|
||||
cpptrace::generate_trace().to_string(), \
|
||||
p_message __VA_OPT__(, ) __VA_ARGS__); \
|
||||
if (Bin2CPP::Singleton<Bin2CPP::Log>::HasInstance()) \
|
||||
{ \
|
||||
Bin2CPP::Singleton<Bin2CPP::Log>::Instance().Flush(); \
|
||||
} \
|
||||
BIN2CPP_BREAK; \
|
||||
std::abort(); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#else
|
||||
#define BIN2CPP_ASSERT(p_assert, p_message, ...)
|
||||
|
||||
#define BIN2CPP_SOFT_ASSERT(p_assert, p_message, ...)
|
||||
|
||||
#define BIN2CPP_CRITICAL_ASSERT(p_assert, p_message, ...)
|
||||
#endif
|
||||
#endif
|
||||
36
Bin2CPP/Sources/Bin2CPPLib/Include/GeneratedTemplate.hpp
Normal file
36
Bin2CPP/Sources/Bin2CPPLib/Include/GeneratedTemplate.hpp
Normal file
@@ -0,0 +1,36 @@
|
||||
/*********************************************************************
|
||||
* \file GeneratedTemplate.hpp
|
||||
*
|
||||
* \author Romain BOULLARD
|
||||
* \date March 2026
|
||||
*********************************************************************/
|
||||
#ifndef BIN2CPP_GENERATED_TEMPLATE_HPP
|
||||
#define BIN2CPP_GENERATED_TEMPLATE_HPP
|
||||
#include <string_view>
|
||||
|
||||
namespace Bin2CPP
|
||||
{
|
||||
constexpr std::string_view g_generatedTemplate = R"(/**
|
||||
* Auto-generated header from: {{FILENAME}}
|
||||
* Generated by Bin2CPP
|
||||
*
|
||||
* DO NOT TOUCH
|
||||
*/
|
||||
#ifndef {{GUARD_NAME}}
|
||||
#define {{GUARD_NAME}}
|
||||
#include {{ARRAY_TYPE_INCLUDE}}
|
||||
#include <cstddef>
|
||||
|
||||
namespace {{NAMESPACE}}
|
||||
{
|
||||
inline constexpr {{ARRAY_TYPE}}<std::byte, {{ARRAY_SIZE}}> {{ARRAY_NAME}} = {
|
||||
{{DATA}}
|
||||
};
|
||||
|
||||
} // namespace {{NAMESPACE}}
|
||||
|
||||
#endif // {{GUARD_NAME}}
|
||||
)";
|
||||
} // namespace Bin2CPP
|
||||
|
||||
#endif
|
||||
157
Bin2CPP/Sources/Bin2CPPLib/Include/Generator.hpp
Normal file
157
Bin2CPP/Sources/Bin2CPPLib/Include/Generator.hpp
Normal file
@@ -0,0 +1,157 @@
|
||||
/*********************************************************************
|
||||
* \file Generator.hpp
|
||||
*
|
||||
* \author Romain BOULLARD
|
||||
* \date February 2026
|
||||
*********************************************************************/
|
||||
#ifndef BIN2CPP_GENERATOR_HPP
|
||||
#define BIN2CPP_GENERATOR_HPP
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <span>
|
||||
#include <string>
|
||||
|
||||
namespace Bin2CPP
|
||||
{
|
||||
enum class MappingKey
|
||||
{
|
||||
FILENAME,
|
||||
GUARD_NAME,
|
||||
NAMESPACE,
|
||||
ARRAY_TYPE_INCLUDE,
|
||||
ARRAY_TYPE,
|
||||
ARRAY_SIZE,
|
||||
ARRAY_NAME,
|
||||
DATA
|
||||
};
|
||||
|
||||
class Generator
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param p_inputFile the Input file
|
||||
*/
|
||||
Generator(const std::string_view p_inputFile);
|
||||
|
||||
Generator(const Generator& p_generator) = default;
|
||||
Generator(Generator&& p_generator) = default;
|
||||
|
||||
/**
|
||||
* Set a mapping
|
||||
*
|
||||
*/
|
||||
void SetMapping(const MappingKey p_key, const std::string_view p_value);
|
||||
|
||||
/**
|
||||
* Generate
|
||||
*
|
||||
* \return True if successful, false otherwise
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool Generate();
|
||||
|
||||
/**
|
||||
* Get
|
||||
*
|
||||
*/
|
||||
[[nodiscard]]
|
||||
std::string_view Get() const;
|
||||
|
||||
~Generator() = default;
|
||||
|
||||
Generator& operator=(const Generator& p_generator) = default;
|
||||
Generator& operator=(Generator&& p_generator) = default;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Compute the mappings
|
||||
*
|
||||
* \return True if all mappings have valid values, false otherwise
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool ComputeMappings();
|
||||
|
||||
/**
|
||||
* Compute the filename mapping
|
||||
*
|
||||
* \return True if success, false otherwise
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool ComputeFilename();
|
||||
|
||||
/**
|
||||
* Compute the guardName mapping
|
||||
*
|
||||
* \return True if success, false otherwise
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool ComputeGuardName();
|
||||
|
||||
/**
|
||||
* Compute the arrayTypeInclude mapping
|
||||
*
|
||||
* \return True if success, false otherwise
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool ComputeArrayTypeInclude();
|
||||
|
||||
/**
|
||||
* Compute the arrayType mapping
|
||||
*
|
||||
* \return True if success, false otherwise
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool ComputeArrayType();
|
||||
|
||||
/**
|
||||
* Compute the arrayName mapping
|
||||
*
|
||||
* \return True if success, false otherwise
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool ComputeArrayName();
|
||||
|
||||
/**
|
||||
* Compute the arraySize mapping
|
||||
*
|
||||
* \return True if success, false otherwise
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool ComputeArraySize(const std::span<std::byte> p_data);
|
||||
|
||||
/**
|
||||
* Compute the data mapping
|
||||
*
|
||||
* \return True if success, false otherwise
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool ComputeData(const std::span<std::byte> p_data);
|
||||
|
||||
/**
|
||||
* Validate generated is correct (no remaining tags)
|
||||
*
|
||||
* \return True if valid, false otherwise
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool Validate();
|
||||
|
||||
/**
|
||||
* The mapping table
|
||||
*/
|
||||
std::array<std::string, magic_enum::enum_count<MappingKey>()> m_mappingTable;
|
||||
|
||||
/**
|
||||
* The input file
|
||||
*/
|
||||
std::string m_inputFile;
|
||||
|
||||
/**
|
||||
* The result
|
||||
*/
|
||||
std::string m_result;
|
||||
};
|
||||
} // namespace Bin2CPP
|
||||
#endif
|
||||
127
Bin2CPP/Sources/Bin2CPPLib/Include/Log.hpp
Normal file
127
Bin2CPP/Sources/Bin2CPPLib/Include/Log.hpp
Normal file
@@ -0,0 +1,127 @@
|
||||
/*********************************************************************
|
||||
* \file Log.hpp
|
||||
*
|
||||
* \author Romain BOULLARD
|
||||
* \date February 2026
|
||||
*********************************************************************/
|
||||
#ifndef BIN2CPP_LOG_HPP
|
||||
#define BIN2CPP_LOG_HPP
|
||||
#include <Singleton.hpp>
|
||||
|
||||
#include <array>
|
||||
|
||||
#ifdef BIN2CPP_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 BIN2CPP_WINDOWS
|
||||
#pragma warning(default: 4702)
|
||||
#endif
|
||||
|
||||
namespace Bin2CPP
|
||||
{
|
||||
class Log
|
||||
{
|
||||
public:
|
||||
Log();
|
||||
|
||||
Log(const Log& p_logger) = delete;
|
||||
Log(Log&& p_logger) = delete;
|
||||
|
||||
/**
|
||||
* Register a logger.
|
||||
*
|
||||
* \return The logger, nullptr if it does not exist
|
||||
*/
|
||||
[[nodiscard]]
|
||||
quill::Logger* GetLogger();
|
||||
|
||||
/*
|
||||
* Flush all the loggers
|
||||
*
|
||||
*/
|
||||
void Flush();
|
||||
|
||||
~Log();
|
||||
|
||||
Log& operator=(const Log& p_logger) = delete;
|
||||
Log& operator=(Log&& p_logger) = delete;
|
||||
|
||||
private:
|
||||
/*
|
||||
* The sinks
|
||||
*/
|
||||
std::array<std::shared_ptr<quill::Sink>, 1> m_sinks;
|
||||
};
|
||||
} // namespace Bin2CPP
|
||||
|
||||
#define BIN2CPP_LOG_DEBUG(fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (quill::Logger* logger = Bin2CPP::Singleton<Bin2CPP::Log>::Instance().GetLogger()) \
|
||||
{ \
|
||||
QUILL_LOG_DEBUG(logger, fmt __VA_OPT__(, ) __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BIN2CPP_LOG_TRACE(fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (quill::Logger* logger = Bin2CPP::Singleton<Bin2CPP::Log>::Instance().GetLogger()) \
|
||||
{ \
|
||||
QUILL_LOG_TRACE_L3(logger, fmt __VA_OPT__(, ) __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BIN2CPP_LOG_INFO(fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (Bin2CPP::Singleton<Bin2CPP::Log>::HasInstance()) \
|
||||
{ \
|
||||
if (quill::Logger* logger = Bin2CPP::Singleton<Bin2CPP::Log>::Instance().GetLogger()) \
|
||||
{ \
|
||||
QUILL_LOG_INFO(logger, fmt __VA_OPT__(, ) __VA_ARGS__); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BIN2CPP_LOG_WARN(fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (Bin2CPP::Singleton<Bin2CPP::Log>::HasInstance()) \
|
||||
{ \
|
||||
if (quill::Logger* logger = Bin2CPP::Singleton<Bin2CPP::Log>::Instance().GetLogger()) \
|
||||
{ \
|
||||
QUILL_LOG_WARNING(logger, fmt __VA_OPT__(, ) __VA_ARGS__); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BIN2CPP_LOG_ERROR(fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (Bin2CPP::Singleton<Bin2CPP::Log>::HasInstance()) \
|
||||
{ \
|
||||
if (quill::Logger* logger = Bin2CPP::Singleton<Bin2CPP::Log>::Instance().GetLogger()) \
|
||||
{ \
|
||||
QUILL_LOG_ERROR(logger, fmt __VA_OPT__(, ) __VA_ARGS__); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BIN2CPP_LOG_FATAL(fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (Bin2CPP::Singleton<Bin2CPP::Log>::HasInstance()) \
|
||||
{ \
|
||||
if (quill::Logger* logger = Bin2CPP::Singleton<Bin2CPP::Log>::Instance().GetLogger()) \
|
||||
{ \
|
||||
QUILL_LOG_CRITICAL(logger, fmt __VA_OPT__(, ) __VA_ARGS__); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
104
Bin2CPP/Sources/Bin2CPPLib/Include/Singleton.hpp
Normal file
104
Bin2CPP/Sources/Bin2CPPLib/Include/Singleton.hpp
Normal file
@@ -0,0 +1,104 @@
|
||||
/*********************************************************************
|
||||
* \file Singleton.hpp
|
||||
*
|
||||
* \author Romain BOULLARD
|
||||
* \date February 2026
|
||||
*********************************************************************/
|
||||
#ifndef BIN2CPP_SINGLETON_HPP
|
||||
#define BIN2CPP_SINGLETON_HPP
|
||||
#include <optional>
|
||||
|
||||
namespace Bin2CPP
|
||||
{
|
||||
template<class TYPE>
|
||||
class Singleton
|
||||
{
|
||||
public:
|
||||
Singleton() = delete;
|
||||
|
||||
Singleton(const Singleton& p_singleton) = delete;
|
||||
Singleton(Singleton&& p_singleton) = delete;
|
||||
|
||||
~Singleton() = delete;
|
||||
|
||||
/**
|
||||
* Get the instance.
|
||||
*
|
||||
* \return The instance
|
||||
*/
|
||||
static TYPE& Instance()
|
||||
{
|
||||
return ms_instance.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the instance initialized
|
||||
*
|
||||
* \return True if initialized, false otherwise
|
||||
*/
|
||||
static bool HasInstance()
|
||||
{
|
||||
return ms_instance.has_value();
|
||||
}
|
||||
|
||||
class Lifetime
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* \param p_args Arguments for the singleton
|
||||
*/
|
||||
template<typename... ARGS>
|
||||
explicit Lifetime(ARGS&&... p_args)
|
||||
{
|
||||
Initialize(std::forward<ARGS>(p_args)...);
|
||||
}
|
||||
|
||||
Lifetime(const Lifetime& p_lifetime) = delete;
|
||||
Lifetime(Lifetime&& p_lifetime) = delete;
|
||||
|
||||
~Lifetime()
|
||||
{
|
||||
Finalize();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
Lifetime& operator=(const Lifetime& p_lifetime) = delete;
|
||||
[[nodiscard]]
|
||||
Lifetime& operator=(Lifetime&& p_lifetime) = delete;
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
Singleton& operator=(const Singleton& p_singleton) = delete;
|
||||
[[nodiscard]]
|
||||
Singleton& operator=(Singleton&& p_singleton) = delete;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Initialize the singleton.
|
||||
*
|
||||
* \param p_args Arguments for the singleton
|
||||
*/
|
||||
template<typename... ARGS>
|
||||
static void Initialize(ARGS&&... p_args)
|
||||
{
|
||||
ms_instance.emplace(std::forward<ARGS>(p_args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize the singleton.
|
||||
*
|
||||
*/
|
||||
static void Finalize()
|
||||
{
|
||||
ms_instance.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* The singleton.
|
||||
*/
|
||||
inline static std::optional<TYPE> ms_instance;
|
||||
};
|
||||
} // namespace Bin2CPP
|
||||
#endif
|
||||
49
Bin2CPP/Sources/Bin2CPPLib/Log.cpp
Normal file
49
Bin2CPP/Sources/Bin2CPPLib/Log.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
/*******************************************************************
|
||||
* \file Log.cpp
|
||||
*
|
||||
* \author Romain BOULLARD
|
||||
* \date February 2026
|
||||
*********************************************************************/
|
||||
#include <Log.hpp>
|
||||
|
||||
namespace Bin2CPP
|
||||
{
|
||||
Log::Log()
|
||||
{
|
||||
quill::Backend::start();
|
||||
|
||||
m_sinks[0] = quill::Frontend::create_or_get_sink<quill::ConsoleSink>("ConsoleSink");
|
||||
|
||||
quill::Logger* logger = quill::Frontend::create_or_get_logger("Bin2CPP", m_sinks[0]);
|
||||
logger->set_log_level(quill::LogLevel::TraceL3);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
quill::Logger* Log::GetLogger()
|
||||
{
|
||||
return quill::Frontend::get_logger("Bin2CPP");
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
void Log::Flush()
|
||||
{
|
||||
for (quill::Logger* logger: quill::Frontend::get_all_loggers())
|
||||
{
|
||||
logger->flush_log();
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
Log::~Log()
|
||||
{
|
||||
for (quill::Logger* logger: quill::Frontend::get_all_loggers())
|
||||
{
|
||||
quill::Frontend::remove_logger(logger);
|
||||
}
|
||||
|
||||
quill::Backend::stop();
|
||||
}
|
||||
} // namespace Bin2CPP
|
||||
96
Bin2CPP/Sources/Bin2CPPLib/MimallocImpl.cpp
Normal file
96
Bin2CPP/Sources/Bin2CPPLib/MimallocImpl.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
/*********************************************************************
|
||||
* \file MimallocImpl.cpp
|
||||
*
|
||||
* \author Romain BOULLARD
|
||||
* \date February 2026
|
||||
*********************************************************************/
|
||||
#if defined BIN2CPP_WINDOWS
|
||||
#pragma comment(linker, "/include:mi_version")
|
||||
#pragma warning(disable: 4100 4559)
|
||||
#elif defined BIN2CPP_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); };
|
||||
void operator delete[](void* p) noexcept { mi_free(p); };
|
||||
|
||||
void operator delete (void* p, const std::nothrow_t&) noexcept { mi_free(p); }
|
||||
void operator delete[](void* p, const std::nothrow_t&) noexcept { mi_free(p); }
|
||||
|
||||
mi_decl_new(n) void* operator new(std::size_t n) noexcept(false) { return mi_new(n); }
|
||||
mi_decl_new(n) void* operator new[](std::size_t n) noexcept(false) { return mi_new(n); }
|
||||
|
||||
mi_decl_new_nothrow(n) void* operator new (std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); return mi_new_nothrow(n); }
|
||||
mi_decl_new_nothrow(n) void* operator new[](std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); return mi_new_nothrow(n); }
|
||||
|
||||
// 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) { return mi_new(size); }
|
||||
|
||||
#if (__cplusplus >= 201402L || _MSC_VER >= 1916)
|
||||
void operator delete (void* p, std::size_t n) noexcept { mi_free_size(p,n); };
|
||||
void operator delete[](void* p, std::size_t n) noexcept { mi_free_size(p,n); };
|
||||
#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)); }
|
||||
void operator delete[](void* p, std::align_val_t al) noexcept { mi_free_aligned(p, static_cast<size_t>(al)); }
|
||||
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)); };
|
||||
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)); };
|
||||
void operator delete (void* p, std::align_val_t al, const std::nothrow_t&) noexcept { mi_free_aligned(p, static_cast<size_t>(al)); }
|
||||
void operator delete[](void* p, std::align_val_t al, const std::nothrow_t&) noexcept { mi_free_aligned(p, static_cast<size_t>(al)); }
|
||||
|
||||
void* operator new (std::size_t n, std::align_val_t al) noexcept(false) { return mi_new_aligned(n, static_cast<size_t>(al)); }
|
||||
void* operator new[](std::size_t n, std::align_val_t al) noexcept(false) { return mi_new_aligned(n, static_cast<size_t>(al)); }
|
||||
void* operator new (std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept { return mi_new_aligned_nothrow(n, static_cast<size_t>(al)); }
|
||||
void* operator new[](std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept { return mi_new_aligned_nothrow(n, static_cast<size_t>(al)); }
|
||||
|
||||
// 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) { return mi_new_aligned(size, alignment); }
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// clang-format on
|
||||
|
||||
#if defined BIN2CPP_WINDOWS
|
||||
#pragma warning(default: 4100 4559)
|
||||
#elif defined BIN2CPP_LINUX
|
||||
#if defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER)
|
||||
#pragma GCC diagnostic pop
|
||||
#else
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,2 +1,2 @@
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Bin2CPPLib)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Bin2CPPExe)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Bin2CPP)
|
||||
@@ -2,52 +2,64 @@ get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||
project(${PackageName}Tests)
|
||||
|
||||
add_executable(${PROJECT_NAME})
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX)
|
||||
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/Include)
|
||||
file(GLOB_RECURSE BIN2CPPLIBTESTS_SOURCES
|
||||
CONFIGURE_DEPENDS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
|
||||
)
|
||||
|
||||
file(GLOB_RECURSE TEST_SOURCES
|
||||
file(GLOB_RECURSE BIN2CPPLIBTESTS_HEADERS
|
||||
CONFIGURE_DEPENDS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/*.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/*.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
|
||||
)
|
||||
|
||||
target_sources(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
${TEST_SOURCES}
|
||||
${BIN2CPPLIBTESTS_SOURCES}
|
||||
PRIVATE
|
||||
FILE_SET HEADERS
|
||||
BASE_DIRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Include
|
||||
FILES
|
||||
${BIN2CPPLIBTESTS_HEADERS}
|
||||
)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE gtest::gtest Bin2CPPLib)
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
Bin2CPPCompileAndLinkFlags
|
||||
Bin2CPPLib
|
||||
gtest::gtest)
|
||||
|
||||
include(GoogleTest)
|
||||
gtest_discover_tests(${PROJECT_NAME} XML_OUTPUT_DIR ${CMAKE_BINARY_DIR}/TestResults/)
|
||||
|
||||
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX Src/ FILES ${TEST_SOURCES})
|
||||
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX Src/ FILES ${BIN2CPPLIBTESTS_SOURCES} ${BIN2CPPLIBTESTS_HEADERS})
|
||||
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER Tests/Bin2CPP/${ParentFolder})
|
||||
|
||||
##################ASAN SETUP###################
|
||||
|
||||
if(${ASAN})
|
||||
if (MSVC)
|
||||
get_filename_component(MSVC_BIN_DIR "${CMAKE_CXX_COMPILER}" DIRECTORY)
|
||||
set(ASAN_DLL "${MSVC_BIN_DIR}/clang_rt.asan_dynamic-x86_64.dll")
|
||||
|
||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Copying ASan DLL: ${ASAN_DLL} to $<TARGET_FILE_DIR:${PROJECT_NAME}>"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${ASAN_DLL}" "$<TARGET_FILE_DIR:${PROJECT_NAME}>"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
##################COPY FIXTURE FOLDER###################
|
||||
|
||||
if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/Fixture)
|
||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Fixture)
|
||||
endif()
|
||||
|
||||
# Track all fixture files
|
||||
file(GLOB_RECURSE FIXTURE_FILES
|
||||
CONFIGURE_DEPENDS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Fixture/*
|
||||
)
|
||||
|
||||
add_custom_target(${PROJECT_NAME}Fixture
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory $<TARGET_FILE_DIR:${PROJECT_NAME}>/Fixture
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/Fixture $<TARGET_FILE_DIR:${PROJECT_NAME}>/Fixture
|
||||
DEPENDS ${FIXTURE_FILES}
|
||||
COMMENT "Copying Fixture folder for ${PROJECT_NAME}"
|
||||
)
|
||||
|
||||
add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}Fixture)
|
||||
|
||||
set_target_properties(${PROJECT_NAME}Fixture PROPERTIES FOLDER UtilityTargets/Tests/Bin2CPP/${ParentFolder})
|
||||
|
||||
bin2cpp_setup_dependencies("Tests/Bin2CPP")
|
||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_CURRENT_SOURCE_DIR}/Fixture $<TARGET_FILE_DIR:${PROJECT_NAME}>/Fixture
|
||||
COMMENT "Copying Fixture folder ${CMAKE_CURRENT_SOURCE_DIR}/Fixture to $<TARGET_FILE_DIR:${PROJECT_NAME}>/Fixture"
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
Hello World
|
||||
139
Bin2CPP/Tests/Bin2CPPLib/Generator.cpp
Normal file
139
Bin2CPP/Tests/Bin2CPPLib/Generator.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
/*********************************************************************
|
||||
* \file Generator.cpp
|
||||
*
|
||||
* \author Romain BOULLARD
|
||||
* \date February 2026
|
||||
*********************************************************************/
|
||||
#include <Generator.hpp>
|
||||
|
||||
#include <Log.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace Bin2CPP
|
||||
{
|
||||
class GeneratorFixture: public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
Singleton<Log>::Lifetime m_lifetime;
|
||||
};
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(GeneratorFixture, GenerateDefault)
|
||||
{
|
||||
Generator generator("Fixture/toto.txt");
|
||||
EXPECT_TRUE(generator.Generate());
|
||||
|
||||
constexpr std::string_view expectedResult = R"(/**
|
||||
* Auto-generated header from: toto.txt
|
||||
* Generated by Bin2CPP
|
||||
*
|
||||
* DO NOT TOUCH
|
||||
*/
|
||||
#ifndef TOTO_TXT_HPP
|
||||
#define TOTO_TXT_HPP
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
|
||||
namespace
|
||||
{
|
||||
inline constexpr std::array<std::byte, 11> g_toto_txt = {
|
||||
std::byte{0x48}, std::byte{0x65}, std::byte{0x6C}, std::byte{0x6C}, std::byte{0x6F},
|
||||
std::byte{0x20}, std::byte{0x57}, std::byte{0x6F}, std::byte{0x72}, std::byte{0x6C},
|
||||
std::byte{0x64}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // TOTO_TXT_HPP
|
||||
)";
|
||||
EXPECT_STREQ(expectedResult.data(), generator.Get().data());
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(GeneratorFixture, GenerateNamespace)
|
||||
{
|
||||
Generator generator("Fixture/toto.txt");
|
||||
generator.SetMapping(MappingKey::NAMESPACE, "Test");
|
||||
EXPECT_TRUE(generator.Generate());
|
||||
|
||||
constexpr std::string_view expectedResult = R"(/**
|
||||
* Auto-generated header from: toto.txt
|
||||
* Generated by Bin2CPP
|
||||
*
|
||||
* DO NOT TOUCH
|
||||
*/
|
||||
#ifndef TOTO_TXT_HPP
|
||||
#define TOTO_TXT_HPP
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
|
||||
namespace Test
|
||||
{
|
||||
inline constexpr std::array<std::byte, 11> g_toto_txt = {
|
||||
std::byte{0x48}, std::byte{0x65}, std::byte{0x6C}, std::byte{0x6C}, std::byte{0x6F},
|
||||
std::byte{0x20}, std::byte{0x57}, std::byte{0x6F}, std::byte{0x72}, std::byte{0x6C},
|
||||
std::byte{0x64}
|
||||
};
|
||||
|
||||
} // namespace Test
|
||||
|
||||
#endif // TOTO_TXT_HPP
|
||||
)";
|
||||
EXPECT_STREQ(expectedResult.data(), generator.Get().data());
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(GeneratorFixture, GenerateCustomArray)
|
||||
{
|
||||
Generator generator("Fixture/toto.txt");
|
||||
generator.SetMapping(MappingKey::ARRAY_TYPE, "eastl::array");
|
||||
generator.SetMapping(MappingKey::ARRAY_TYPE_INCLUDE, "<EASTL/array.h>");
|
||||
generator.SetMapping(MappingKey::ARRAY_NAME, "g_myArray");
|
||||
EXPECT_TRUE(generator.Generate());
|
||||
|
||||
constexpr std::string_view expectedResult = R"(/**
|
||||
* Auto-generated header from: toto.txt
|
||||
* Generated by Bin2CPP
|
||||
*
|
||||
* DO NOT TOUCH
|
||||
*/
|
||||
#ifndef TOTO_TXT_HPP
|
||||
#define TOTO_TXT_HPP
|
||||
#include <EASTL/array.h>
|
||||
#include <cstddef>
|
||||
|
||||
namespace
|
||||
{
|
||||
inline constexpr eastl::array<std::byte, 11> g_myArray = {
|
||||
std::byte{0x48}, std::byte{0x65}, std::byte{0x6C}, std::byte{0x6C}, std::byte{0x6F},
|
||||
std::byte{0x20}, std::byte{0x57}, std::byte{0x6F}, std::byte{0x72}, std::byte{0x6C},
|
||||
std::byte{0x64}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // TOTO_TXT_HPP
|
||||
)";
|
||||
EXPECT_STREQ(expectedResult.data(), generator.Get().data());
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(GeneratorFixture, NonExistentFile)
|
||||
{
|
||||
Generator generator("Fixture/tata.txt");
|
||||
EXPECT_FALSE(generator.Generate());
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(GeneratorFixture, Directory)
|
||||
{
|
||||
Generator generator("Fixture/");
|
||||
EXPECT_FALSE(generator.Generate());
|
||||
}
|
||||
} // namespace Bin2CPP
|
||||
76
Bin2CPP/Tests/Bin2CPPLib/Log.cpp
Normal file
76
Bin2CPP/Tests/Bin2CPPLib/Log.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
/*********************************************************************
|
||||
* \file Log.cpp
|
||||
*
|
||||
* \author Romain BOULLARD
|
||||
* \date February 2026
|
||||
*********************************************************************/
|
||||
#include <Log.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <Assert.hpp>
|
||||
|
||||
namespace Bin2CPP
|
||||
{
|
||||
class LogFixture: public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
Log m_log;
|
||||
};
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(LogFixture, GetLogger_ShouldReturnTheLogger)
|
||||
{
|
||||
EXPECT_TRUE(m_log.GetLogger());
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(LogFixture, LogDebug)
|
||||
{
|
||||
Singleton<Log>::Lifetime singletonLifetime;
|
||||
BIN2CPP_LOG_DEBUG("Hello");
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(LogFixture, LogTrace)
|
||||
{
|
||||
Singleton<Log>::Lifetime singletonLifetime;
|
||||
|
||||
BIN2CPP_LOG_TRACE("Hello");
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(LogFixture, LogInfo)
|
||||
{
|
||||
Singleton<Log>::Lifetime singletonLifetime;
|
||||
BIN2CPP_LOG_INFO("Hello");
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(LogFixture, LogWarn)
|
||||
{
|
||||
Singleton<Log>::Lifetime singletonLifetime;
|
||||
BIN2CPP_LOG_WARN("Hello");
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(LogFixture, LogError)
|
||||
{
|
||||
Singleton<Log>::Lifetime singletonLifetime;
|
||||
BIN2CPP_LOG_ERROR("Hello");
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(LogFixture, LogFatal)
|
||||
{
|
||||
Singleton<Log>::Lifetime singletonLifetime;
|
||||
BIN2CPP_LOG_FATAL("Hello");
|
||||
}
|
||||
} // namespace Bin2CPP
|
||||
39
Bin2CPP/Tests/Bin2CPPLib/Singleton.cpp
Normal file
39
Bin2CPP/Tests/Bin2CPPLib/Singleton.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
/*********************************************************************
|
||||
* \file Singleton.cpp
|
||||
*
|
||||
* \author Romain BOULLARD
|
||||
* \date February 2026
|
||||
*********************************************************************/
|
||||
#include <Singleton.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace Bin2CPP
|
||||
{
|
||||
class SingletonFixture: public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
Singleton<std::uint8_t>::Lifetime m_lifetime {8};
|
||||
};
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(SingletonFixture, HasInstance_ShouldReturnTrueIfSingletonIsInitialized)
|
||||
{
|
||||
EXPECT_TRUE(Singleton<std::uint8_t>::HasInstance());
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(SingletonFixture, HasInstance_ShouldReturnFaleIfSingletonIsNotInitialized)
|
||||
{
|
||||
EXPECT_FALSE(Singleton<std::uint32_t>::HasInstance());
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(SingletonFixture, Instance_ShouldReturnTheInstance)
|
||||
{
|
||||
EXPECT_EQ(Singleton<std::uint8_t>::Instance(), 8);
|
||||
}
|
||||
} // namespace Bin2CPP
|
||||
Reference in New Issue
Block a user