feat: add new helper for scoped enum type.
- Add EnumHelper for bitwise operation of scoped enum type (copied from libcmo21) - Enrich the return value of ConfigManager load function to present more infomation of loading. - update testbench for new added feature and modification. - add document for new added feature.
This commit is contained in:
parent
50dd086b53
commit
21f7e7f786
35
doc/src/enum_helper.dox
Normal file
35
doc/src/enum_helper.dox
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
namespace YYCC::EnumHelper {
|
||||||
|
/**
|
||||||
|
|
||||||
|
\page enum_helper Scoped Enum Helper
|
||||||
|
|
||||||
|
\section enum_helper__intro Intro
|
||||||
|
|
||||||
|
C++ introduce a new enum called scoped enum.
|
||||||
|
It is better than legacy C enum because it will not leak name into namespace where it locate,
|
||||||
|
and also can specify an underlying type to it to make sure it is stored as specified size.
|
||||||
|
However, the shortcoming of it is that it lack bitwise operator comparing with legacy C enum.
|
||||||
|
Programmer must implement them for scoped enum one by one.
|
||||||
|
It is a hardship and inconvenient.
|
||||||
|
This is the reason why I invent this class
|
||||||
|
|
||||||
|
\section enum_helper__Usage Usage
|
||||||
|
|
||||||
|
In this namespace, we provide all bitwise functions related to scoped enum type which may be used.
|
||||||
|
See YYCC::EnumHelper for more detail (It is more clear to read function annotation than I introduce in there repeatedly).
|
||||||
|
|
||||||
|
\section enum_helper__why Why not Operator Overload
|
||||||
|
|
||||||
|
I have try it (and you even can see the relic of it in source code).
|
||||||
|
But it need a extra statement written in following to include it, otherwise compiler can not see it.
|
||||||
|
|
||||||
|
\code
|
||||||
|
using namespace YYCC::EnumHelper;
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
Another reason why I do not use this method is that
|
||||||
|
this overload strategy may be applied to some type which should not be applied by accient, such as non-scoped enum type.
|
||||||
|
So I gave up this solution.
|
||||||
|
|
||||||
|
*/
|
||||||
|
}
|
|
@ -45,6 +45,8 @@
|
||||||
|
|
||||||
\li \subpage std_patch
|
\li \subpage std_patch
|
||||||
|
|
||||||
|
\li \subpage enum_helper
|
||||||
|
|
||||||
<B>Advanced Features</B>
|
<B>Advanced Features</B>
|
||||||
|
|
||||||
\li \subpage constraints
|
\li \subpage constraints
|
||||||
|
|
|
@ -31,6 +31,7 @@ FILES
|
||||||
ConsoleHelper.hpp
|
ConsoleHelper.hpp
|
||||||
DialogHelper.hpp
|
DialogHelper.hpp
|
||||||
EncodingHelper.hpp
|
EncodingHelper.hpp
|
||||||
|
EnumHelper.hpp
|
||||||
ExceptionHelper.hpp
|
ExceptionHelper.hpp
|
||||||
StdPatch.hpp
|
StdPatch.hpp
|
||||||
IOHelper.hpp
|
IOHelper.hpp
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "EncodingHelper.hpp"
|
#include "EncodingHelper.hpp"
|
||||||
#include "IOHelper.hpp"
|
#include "IOHelper.hpp"
|
||||||
|
#include "EnumHelper.hpp"
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace YYCC::ConfigManager {
|
namespace YYCC::ConfigManager {
|
||||||
|
@ -33,7 +34,7 @@ namespace YYCC::ConfigManager {
|
||||||
m_CfgFilePath(cfg_file_path), m_VersionIdentifier(version_identifier), m_Settings() {
|
m_CfgFilePath(cfg_file_path), m_VersionIdentifier(version_identifier), m_Settings() {
|
||||||
// Mark: no need to check cfg file path
|
// Mark: no need to check cfg file path
|
||||||
// it will be checked at creating file handle
|
// it will be checked at creating file handle
|
||||||
|
|
||||||
// assign settings
|
// assign settings
|
||||||
for (auto* setting : settings) {
|
for (auto* setting : settings) {
|
||||||
auto result = m_Settings.try_emplace(setting->GetName(), setting);
|
auto result = m_Settings.try_emplace(setting->GetName(), setting);
|
||||||
|
@ -44,7 +45,10 @@ namespace YYCC::ConfigManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CoreManager::Load() {
|
ConfigLoadResult CoreManager::Load() {
|
||||||
|
// prepare result variables
|
||||||
|
ConfigLoadResult ret = ConfigLoadResult::OK;
|
||||||
|
|
||||||
// reset all settings first
|
// reset all settings first
|
||||||
Reset();
|
Reset();
|
||||||
|
|
||||||
|
@ -53,20 +57,27 @@ namespace YYCC::ConfigManager {
|
||||||
if (fs.get() == nullptr) {
|
if (fs.get() == nullptr) {
|
||||||
// if we fail to get, it means that we do not have corresponding cfg file.
|
// if we fail to get, it means that we do not have corresponding cfg file.
|
||||||
// all settings should be reset to default value.
|
// all settings should be reset to default value.
|
||||||
return true;
|
ret = ConfigLoadResult::Created;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetch version info
|
// fetch version info
|
||||||
uint64_t version_info;
|
uint64_t version_info;
|
||||||
if (std::fread(&version_info, 1u, sizeof(version_info), fs.get()) != sizeof(version_info))
|
if (std::fread(&version_info, 1u, sizeof(version_info), fs.get()) != sizeof(version_info)) {
|
||||||
return false;
|
ret = ConfigLoadResult::Created;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
// check version
|
// check version
|
||||||
// if read version is greater than we expected,
|
// if read version is greater than we expected,
|
||||||
// it means that this cfg file is created by the program higer than this.
|
// it means that this cfg file is created by the program higer than this.
|
||||||
// we should not read anything from it.
|
// we should not read anything from it.
|
||||||
// however, for compaitibility reason, we allow read old cfg data.
|
// however, for compaitibility reason, we allow read old cfg data.
|
||||||
if (version_info > m_VersionIdentifier)
|
if (version_info > m_VersionIdentifier) {
|
||||||
return true;
|
ret = ConfigLoadResult::ForwardNew;
|
||||||
|
return ret;
|
||||||
|
} else if (version_info < m_VersionIdentifier) {
|
||||||
|
EnumHelper::Add(ret, ConfigLoadResult::Migrated);
|
||||||
|
}
|
||||||
|
|
||||||
// fetch setting item from file
|
// fetch setting item from file
|
||||||
yycc_u8string name_cache;
|
yycc_u8string name_cache;
|
||||||
|
@ -77,37 +88,50 @@ namespace YYCC::ConfigManager {
|
||||||
if (std::fread(&name_length, 1u, sizeof(name_length), fs.get()) != sizeof(name_length)) {
|
if (std::fread(&name_length, 1u, sizeof(name_length), fs.get()) != sizeof(name_length)) {
|
||||||
// we also check whether reach EOF at there.
|
// we also check whether reach EOF at there.
|
||||||
if (std::feof(fs.get())) break;
|
if (std::feof(fs.get())) break;
|
||||||
else return false;
|
else {
|
||||||
|
EnumHelper::Add(ret, ConfigLoadResult::BrokenFile);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// fetch name body
|
// fetch name body
|
||||||
name_cache.resize(name_length);
|
name_cache.resize(name_length);
|
||||||
if (std::fread(name_cache.data(), 1u, name_length, fs.get()) != name_length)
|
if (std::fread(name_cache.data(), 1u, name_length, fs.get()) != name_length) {
|
||||||
return false;
|
EnumHelper::Add(ret, ConfigLoadResult::BrokenFile);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
// get setting data length
|
// get setting data length
|
||||||
size_t data_length;
|
size_t data_length;
|
||||||
if (std::fread(&data_length, 1u, sizeof(data_length), fs.get()) != sizeof(data_length))
|
if (std::fread(&data_length, 1u, sizeof(data_length), fs.get()) != sizeof(data_length)) {
|
||||||
return false;
|
EnumHelper::Add(ret, ConfigLoadResult::BrokenFile);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
// get matched setting first
|
// get matched setting first
|
||||||
const auto& found = m_Settings.find(name_cache);
|
const auto& found = m_Settings.find(name_cache);
|
||||||
if (found != m_Settings.end()) {
|
if (found != m_Settings.end()) {
|
||||||
// found. read data for it
|
// found. read data for it
|
||||||
found->second->ResizeData(data_length);
|
found->second->ResizeData(data_length);
|
||||||
if (std::fread(found->second->GetDataPtr(), 1u, data_length, fs.get()) != data_length)
|
if (std::fread(found->second->GetDataPtr(), 1u, data_length, fs.get()) != data_length) {
|
||||||
return false;
|
EnumHelper::Add(ret, ConfigLoadResult::BrokenFile);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
// call user defined load function
|
// call user defined load function
|
||||||
// if fail to parse, reset to default value
|
// if fail to parse, reset to default value
|
||||||
if (!found->second->UserLoad())
|
if (!found->second->UserLoad()) {
|
||||||
|
EnumHelper::Add(ret, ConfigLoadResult::ItemError);
|
||||||
found->second->UserReset();
|
found->second->UserReset();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// fail to find. skip this unknown setting
|
// fail to find. skip this unknown setting
|
||||||
if (fseek(fs.get(), static_cast<long>(data_length), SEEK_CUR) != 0)
|
if (fseek(fs.get(), static_cast<long>(data_length), SEEK_CUR) != 0) {
|
||||||
return false;
|
EnumHelper::Add(ret, ConfigLoadResult::BrokenFile);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CoreManager::Save() {
|
bool CoreManager::Save() {
|
||||||
|
|
|
@ -17,6 +17,19 @@
|
||||||
* @details For how to use this namespace, please see \ref config_manager.
|
* @details For how to use this namespace, please see \ref config_manager.
|
||||||
*/
|
*/
|
||||||
namespace YYCC::ConfigManager {
|
namespace YYCC::ConfigManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The load result of loading config.
|
||||||
|
*/
|
||||||
|
enum class ConfigLoadResult {
|
||||||
|
OK = 0, ///< Success load configs.
|
||||||
|
Created = 1 << 0, ///< Given file is not existing, we create all configs in default values.
|
||||||
|
ForwardNew = 1 << 1, ///< Detect the config file created by higher version. We create all configs in default values.
|
||||||
|
Migrated = 1 << 2, ///< Detect the config file created by lower version. We try migrate configs written in it.
|
||||||
|
BrokenFile = 1 << 3, ///< Given file has bad format. Thus some configs are kept as its default values.
|
||||||
|
ItemError = 1 << 4 ///< Some config can not be recognized from the data read from file so they are reset to default value.
|
||||||
|
};
|
||||||
|
using UnderlyingConfigLoadResult_t = std::underlying_type_t<ConfigLoadResult>;
|
||||||
|
|
||||||
/// @brief The base class of every setting.
|
/// @brief The base class of every setting.
|
||||||
/// @details Programmer can inherit this class and implement essential functions to create custom setting.
|
/// @details Programmer can inherit this class and implement essential functions to create custom setting.
|
||||||
|
@ -75,7 +88,7 @@ namespace YYCC::ConfigManager {
|
||||||
private:
|
private:
|
||||||
std::vector<uint8_t> m_RawData;
|
std::vector<uint8_t> m_RawData;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief Settings manager and config file reader writer.
|
/// @brief Settings manager and config file reader writer.
|
||||||
class CoreManager {
|
class CoreManager {
|
||||||
public:
|
public:
|
||||||
|
@ -96,8 +109,8 @@ namespace YYCC::ConfigManager {
|
||||||
public:
|
public:
|
||||||
/// @brief Load settings from file.
|
/// @brief Load settings from file.
|
||||||
/// @details Before loading, all settings will be reset to default value first.
|
/// @details Before loading, all settings will be reset to default value first.
|
||||||
/// @return True if success, otherwise false.
|
/// @return What happend when loading config. This function always success.
|
||||||
bool Load();
|
ConfigLoadResult Load();
|
||||||
/// @brief Save settings to file.
|
/// @brief Save settings to file.
|
||||||
/// @return True if success, otherwise false.
|
/// @return True if success, otherwise false.
|
||||||
bool Save();
|
bool Save();
|
||||||
|
|
177
src/EnumHelper.hpp
Normal file
177
src/EnumHelper.hpp
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
#pragma once
|
||||||
|
#include "YYCCInternal.hpp"
|
||||||
|
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The namespace for convenient C++ enum class logic operations.
|
||||||
|
* @details
|
||||||
|
* C++ enum class statement is a modern way to declare enum in C++.
|
||||||
|
* But it lack essential logic operations which is commonly used by programmer.
|
||||||
|
* So we create this helper to resolve this issue.
|
||||||
|
*/
|
||||||
|
namespace YYCC::EnumHelper {
|
||||||
|
|
||||||
|
//// Reference:
|
||||||
|
//// Enum operator overload: https://stackoverflow.com/a/71107019
|
||||||
|
//// Constexpr operator overload: https://stackoverflow.com/a/17746099
|
||||||
|
|
||||||
|
//template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
|
||||||
|
//inline constexpr TEnum operator|(TEnum lhs, TEnum rhs) {
|
||||||
|
// using ut = std::underlying_type_t<TEnum>;
|
||||||
|
// return static_cast<TEnum>(static_cast<ut>(lhs) | static_cast<ut>(rhs));
|
||||||
|
//}
|
||||||
|
//template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
|
||||||
|
//inline constexpr TEnum operator|=(TEnum& lhs, TEnum rhs) {
|
||||||
|
// using ut = std::underlying_type_t<TEnum>;
|
||||||
|
// lhs = lhs | rhs;
|
||||||
|
// return lhs;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
|
||||||
|
//inline constexpr TEnum operator&(TEnum lhs, TEnum rhs) {
|
||||||
|
// using ut = std::underlying_type_t<TEnum>;
|
||||||
|
// return static_cast<TEnum>(static_cast<ut>(lhs) & static_cast<ut>(rhs));
|
||||||
|
//}
|
||||||
|
//template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
|
||||||
|
//inline constexpr TEnum operator&=(TEnum& lhs, TEnum rhs) {
|
||||||
|
// using ut = std::underlying_type_t<TEnum>;
|
||||||
|
// lhs = lhs & rhs;
|
||||||
|
// return lhs;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
|
||||||
|
//inline constexpr TEnum operator^(TEnum lhs, TEnum rhs) {
|
||||||
|
// using ut = std::underlying_type_t<TEnum>;
|
||||||
|
// return static_cast<TEnum>(static_cast<ut>(lhs) ^ static_cast<ut>(rhs));
|
||||||
|
//}
|
||||||
|
//template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
|
||||||
|
//inline constexpr TEnum operator^=(TEnum& lhs, TEnum rhs) {
|
||||||
|
// using ut = std::underlying_type_t<TEnum>;
|
||||||
|
// lhs = lhs ^ rhs;
|
||||||
|
// return lhs;
|
||||||
|
//}
|
||||||
|
|
||||||
|
//template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
|
||||||
|
//inline constexpr TEnum operator~(TEnum lhs) {
|
||||||
|
// using ut = std::underlying_type_t<TEnum>;
|
||||||
|
// return static_cast<TEnum>(~(static_cast<ut>(lhs)));
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
|
||||||
|
//inline constexpr bool operator bool(TEnum lhs) {
|
||||||
|
// using ut = std::underlying_type_t<TEnum>;
|
||||||
|
// return static_cast<bool>(static_cast<ut>(lhs));
|
||||||
|
//}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The helper struct to check all given template argument are the same enum type.
|
||||||
|
* @tparam TEnum The template parameter to be checked (first one).
|
||||||
|
* @tparam Ts The template parameter to be checked.
|
||||||
|
*/
|
||||||
|
template<typename TEnum, typename... Ts>
|
||||||
|
struct all_enum_values {
|
||||||
|
public:
|
||||||
|
// Please note it is std::is_same, not std::is_same_v!
|
||||||
|
// That's std::conjunction_v required.
|
||||||
|
static constexpr bool value = std::is_enum_v<std::remove_cv_t<TEnum>> && std::conjunction_v<std::is_same<std::remove_cv_t<TEnum>, std::remove_cv_t<Ts>>...>;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* @brief The convenient calling to all_enum_values::value to check enum template parameter.
|
||||||
|
* @tparam TEnum The template parameter to be checked (first one).
|
||||||
|
* @tparam Ts The template parameter to be checked.
|
||||||
|
*/
|
||||||
|
template<typename TEnum, typename... Ts>
|
||||||
|
inline constexpr bool all_enum_values_v = all_enum_values<TEnum, Ts...>::value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Merge given enum flags like performing <TT>e1 | e2 | ... | en</TT>
|
||||||
|
* @tparam TEnum Enum type for processing.
|
||||||
|
* @param[in] il The list of enum flags to be merged.
|
||||||
|
* @return The merged enum flag.
|
||||||
|
*/
|
||||||
|
template<typename TEnum, typename... Ts, std::enable_if_t<all_enum_values_v<TEnum, Ts...>, int> = 0>
|
||||||
|
constexpr TEnum Merge(TEnum val, Ts... val_left) {
|
||||||
|
using ut = std::underlying_type_t<TEnum>;
|
||||||
|
ut result = static_cast<ut>(val);
|
||||||
|
if constexpr (sizeof...(val_left) > 0) {
|
||||||
|
result |= static_cast<ut>(Merge(val_left...));
|
||||||
|
}
|
||||||
|
return static_cast<TEnum>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reverse given enum flags like performing <TT>~(e)</TT>
|
||||||
|
* @tparam TEnum Enum type for processing.
|
||||||
|
* @param[in] e The list of enum flags to be inversed.
|
||||||
|
* @return The inversed enum flag.
|
||||||
|
*/
|
||||||
|
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
|
||||||
|
constexpr TEnum Invert(TEnum e) {
|
||||||
|
using ut = std::underlying_type_t<TEnum>;
|
||||||
|
return static_cast<TEnum>(~(static_cast<ut>(e)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Use specified enum flags to mask given enum flags like performing <TT>e1 &= e2</TT>
|
||||||
|
* @tparam TEnum Enum type for processing.
|
||||||
|
* @param[in,out] e1 The enum flags to be masked.
|
||||||
|
* @param[in] e2 The mask enum flag.
|
||||||
|
*/
|
||||||
|
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
|
||||||
|
constexpr void Mask(TEnum& e1, TEnum e2) {
|
||||||
|
using ut = std::underlying_type_t<TEnum>;
|
||||||
|
e1 = static_cast<TEnum>(static_cast<ut>(e1) & static_cast<ut>(e2));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add specified enum flags to given enum flags like performing <TT>e1 = e1 | e2 | ... | en</TT>
|
||||||
|
* @tparam TEnum Enum type for processing.
|
||||||
|
* @param[in,out] e1 The enum flags to be processed.
|
||||||
|
* @param[in] e2 The enum flag to be added.
|
||||||
|
*/
|
||||||
|
template<typename TEnum, typename... Ts, std::enable_if_t<all_enum_values_v<TEnum, Ts...>, int> = 0>
|
||||||
|
constexpr void Add(TEnum& e1, Ts... vals) {
|
||||||
|
using ut = std::underlying_type_t<TEnum>;
|
||||||
|
e1 = static_cast<TEnum>(static_cast<ut>(e1) | static_cast<ut>(Merge(vals...)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Remove specified enum flags from given enum flags like performing <TT>e1 &= ~(e2 | e3 | ... | en)</TT>
|
||||||
|
* @tparam TEnum Enum type for processing.
|
||||||
|
* @param[in,out] e1 The enum flags to be processed.
|
||||||
|
* @param[in] e2 The enum flag to be removed.
|
||||||
|
*/
|
||||||
|
template<typename TEnum, typename... Ts, std::enable_if_t<all_enum_values_v<TEnum>, int> = 0>
|
||||||
|
constexpr void Remove(TEnum& e1, Ts... vals) {
|
||||||
|
using ut = std::underlying_type_t<TEnum>;
|
||||||
|
e1 = static_cast<TEnum>(static_cast<ut>(e1) & static_cast<ut>(Invert(Merge(vals...))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check whether given enum flags has specified enum flag like performing <TT>bool(e & probe)</TT>
|
||||||
|
* @tparam TEnum Enum type for processing.
|
||||||
|
* @param[in] e1 The enum flags to be checked.
|
||||||
|
* @param[in] e2 The enum flag for checking.
|
||||||
|
* @return True if it has, otherwise false.
|
||||||
|
*/
|
||||||
|
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
|
||||||
|
constexpr bool Has(TEnum e1, TEnum e2) {
|
||||||
|
using ut = std::underlying_type_t<TEnum>;
|
||||||
|
return static_cast<bool>(static_cast<ut>(e1) & static_cast<ut>(e2));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Cast given enum flags to its equvalent boolean value like performing <TT>bool(e)</TT>
|
||||||
|
* @tparam TEnum Enum type for processing.
|
||||||
|
* @param e The enum flags to be cast.
|
||||||
|
* @return The cast enum flag.
|
||||||
|
*/
|
||||||
|
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
|
||||||
|
constexpr bool Bool(TEnum e) {
|
||||||
|
using ut = std::underlying_type_t<TEnum>;
|
||||||
|
return static_cast<bool>(static_cast<ut>(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -11,6 +11,7 @@
|
||||||
#include "IOHelper.hpp"
|
#include "IOHelper.hpp"
|
||||||
#include "WinFctHelper.hpp"
|
#include "WinFctHelper.hpp"
|
||||||
#include "StdPatch.hpp"
|
#include "StdPatch.hpp"
|
||||||
|
#include "EnumHelper.hpp"
|
||||||
#include "ExceptionHelper.hpp"
|
#include "ExceptionHelper.hpp"
|
||||||
|
|
||||||
#include "ConfigManager.hpp"
|
#include "ConfigManager.hpp"
|
||||||
|
|
|
@ -402,7 +402,7 @@ namespace YYCCTestbench {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void StdPatch() {
|
static void StdPatchTestbench() {
|
||||||
|
|
||||||
// Std Path
|
// Std Path
|
||||||
|
|
||||||
|
@ -439,6 +439,51 @@ namespace YYCCTestbench {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class TestFlagEnum : uint8_t {
|
||||||
|
Test1 = 0b00000000,
|
||||||
|
Test2 = 0b00000001,
|
||||||
|
Test3 = 0b00000010,
|
||||||
|
Test4 = 0b00000100,
|
||||||
|
Test5 = 0b00001000,
|
||||||
|
Test6 = 0b00010000,
|
||||||
|
Test7 = 0b00100000,
|
||||||
|
Test8 = 0b01000000,
|
||||||
|
Test9 = 0b10000000,
|
||||||
|
Inverted = 0b01111111,
|
||||||
|
Merged = Test3 + Test5,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void EnumHelperTestbench() {
|
||||||
|
TestFlagEnum val;
|
||||||
|
|
||||||
|
Assert(YYCC::EnumHelper::Merge(TestFlagEnum::Test3, TestFlagEnum::Test5) == TestFlagEnum::Merged, YYCC_U8("YYCC::EnumHelper::Merge"));
|
||||||
|
|
||||||
|
Assert(YYCC::EnumHelper::Invert(TestFlagEnum::Test9) == TestFlagEnum::Inverted, YYCC_U8("YYCC::EnumHelper::Invert"));
|
||||||
|
|
||||||
|
val = YYCC::EnumHelper::Merge(TestFlagEnum::Test3, TestFlagEnum::Test5);
|
||||||
|
YYCC::EnumHelper::Mask(val, TestFlagEnum::Test3);
|
||||||
|
Assert(YYCC::EnumHelper::Bool(val), YYCC_U8("YYCC::EnumHelper::Mask"));
|
||||||
|
val = YYCC::EnumHelper::Merge(TestFlagEnum::Test3, TestFlagEnum::Test5);
|
||||||
|
YYCC::EnumHelper::Mask(val, TestFlagEnum::Test4);
|
||||||
|
Assert(!YYCC::EnumHelper::Bool(val), YYCC_U8("YYCC::EnumHelper::Mask"));
|
||||||
|
|
||||||
|
val = TestFlagEnum::Test3;
|
||||||
|
YYCC::EnumHelper::Add(val, TestFlagEnum::Test5);
|
||||||
|
Assert(val == TestFlagEnum::Merged, YYCC_U8("YYCC::EnumHelper::Add"));
|
||||||
|
|
||||||
|
val = TestFlagEnum::Merged;
|
||||||
|
YYCC::EnumHelper::Remove(val, TestFlagEnum::Test5);
|
||||||
|
Assert(val == TestFlagEnum::Test3, YYCC_U8("YYCC::EnumHelper::Remove"));
|
||||||
|
|
||||||
|
val = YYCC::EnumHelper::Merge(TestFlagEnum::Test3, TestFlagEnum::Test5);
|
||||||
|
Assert(YYCC::EnumHelper::Has(val, TestFlagEnum::Test3), YYCC_U8("YYCC::EnumHelper::Has"));
|
||||||
|
Assert(!YYCC::EnumHelper::Has(val, TestFlagEnum::Test4), YYCC_U8("YYCC::EnumHelper::Has"));
|
||||||
|
|
||||||
|
Assert(!YYCC::EnumHelper::Bool(TestFlagEnum::Test1), YYCC_U8("YYCC::EnumHelper::Bool"));
|
||||||
|
Assert(YYCC::EnumHelper::Bool(TestFlagEnum::Test2), YYCC_U8("YYCC::EnumHelper::Bool"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
enum class TestEnum : int8_t {
|
enum class TestEnum : int8_t {
|
||||||
Test1, Test2, Test3
|
Test1, Test2, Test3
|
||||||
};
|
};
|
||||||
|
@ -518,7 +563,11 @@ namespace YYCCTestbench {
|
||||||
Assert(test.m_EnumSetting.Get() == TestEnum::Test1, YYCC_U8("YYCC::ConfigManager::CoreManager::Reset"));
|
Assert(test.m_EnumSetting.Get() == TestEnum::Test1, YYCC_U8("YYCC::ConfigManager::CoreManager::Reset"));
|
||||||
|
|
||||||
// test load
|
// test load
|
||||||
Assert(test.m_CoreManager.Load(), YYCC_U8("YYCC::ConfigManager::CoreManager::Load"));
|
YYCC::ConfigManager::ConfigLoadResult wrong_result = YYCC::EnumHelper::Merge(
|
||||||
|
YYCC::ConfigManager::ConfigLoadResult::ItemError,
|
||||||
|
YYCC::ConfigManager::ConfigLoadResult::BrokenFile
|
||||||
|
);
|
||||||
|
Assert(!YYCC::EnumHelper::Has(test.m_CoreManager.Load(), wrong_result), YYCC_U8("YYCC::ConfigManager::CoreManager::Load"));
|
||||||
test.PrintSettings();
|
test.PrintSettings();
|
||||||
Assert(test.m_IntSetting.Get() == INT32_C(114), YYCC_U8("YYCC::ConfigManager::CoreManager::Load"));
|
Assert(test.m_IntSetting.Get() == INT32_C(114), YYCC_U8("YYCC::ConfigManager::CoreManager::Load"));
|
||||||
Assert(test.m_FloatSetting.Get() == 2.0f, YYCC_U8("YYCC::ConfigManager::CoreManager::Load"));
|
Assert(test.m_FloatSetting.Get() == 2.0f, YYCC_U8("YYCC::ConfigManager::CoreManager::Load"));
|
||||||
|
@ -655,7 +704,8 @@ int main(int argc, char* argv[]) {
|
||||||
YYCCTestbench::StringTestbench();
|
YYCCTestbench::StringTestbench();
|
||||||
YYCCTestbench::ParserTestbench();
|
YYCCTestbench::ParserTestbench();
|
||||||
YYCCTestbench::WinFctTestbench();
|
YYCCTestbench::WinFctTestbench();
|
||||||
YYCCTestbench::StdPatch();
|
YYCCTestbench::StdPatchTestbench();
|
||||||
|
YYCCTestbench::EnumHelperTestbench();
|
||||||
// advanced
|
// advanced
|
||||||
YYCCTestbench::ConfigManagerTestbench();
|
YYCCTestbench::ConfigManagerTestbench();
|
||||||
YYCCTestbench::ArgParserTestbench(argc, argv);
|
YYCCTestbench::ArgParserTestbench(argc, argv);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user