libcmo21/LibCmo/VTUtils.hpp
yyc12345 f870d4dde3 refactor: update project
- add documentation CMake build script. re-organise document layout for future changes.
- move LIBCMO_EXPORT to BMap and rename it to BMAP_EXPORT because only BMap need to use this macro.
- fully refactor VTEncoding to make it more like Python
	- Now language name is platform independent.
	- Hide implementation detail as possible as I can.
	- Language mapping are still work in progress.
- add code gen for new added universal encoding feature to generate language name mapping in Windows and Iconv respectively.
- remove old code of CMake build script.
- update VTUtils for new requirement.
	- remove useless functions.
	- create LibCmo specific custom exception classes.
2024-08-16 22:07:23 +08:00

130 lines
4.0 KiB
C++

#pragma once
// Check LibCmo build type first.
#if !(defined(LIBCMO_BUILD_DEBUG) ^ defined(LIBCMO_BUILD_RELEASE))
#error "You must define ONE of LIBCMO_BUILD_DEBUG and LIBCMO_BUILD_RELEASE to indicate build type!"
#endif
// Include YYCC helper library
#include <YYCCommonplace.hpp>
// Header for this namespace implementation
#include <string>
#include <type_traits>
#include <initializer_list>
namespace LibCmo {
#pragma region LibCmo Exceptions
/**
* @brief The exception raised when library entering unreachable scope.
* @details This exception usually used in \c switch syntax.
* It means that program enter the scope which it definitely can not enter.
*/
class UnreachableException : public std::exception {
public:
UnreachableException(const char* msg) : message(msg ? msg : "") {}
UnreachableException(const UnreachableException& rhs) : message(rhs.message) {}
virtual ~UnreachableException() {}
[[nodiscard]] virtual const char* what() const override { return message.c_str(); }
private:
std::string message;
};
/**
* @brief The exception raised when library entering logic error.
* @details In theory, this exception can be found by reading code.
* It usually caused by programmer use functions in a wrong way.
* For example, pass invalid argument to function and etc.
*/
class LogicException : public std::exception {
public:
LogicException(const char* msg) : message(msg ? msg : "") {}
LogicException(const LogicException& rhs) : message(rhs.message) {}
virtual ~LogicException() {}
[[nodiscard]] virtual const char* what() const override { return message.c_str(); }
private:
std::string message;
};
/**
* @brief The exception raised when library entering runtime error.
* @details In theory, this exception can not be found by reading code.
* It may caused by user input or anything else.
*/
class RuntimeException : public std::exception {
public:
RuntimeException(const char* msg) : message(msg ? msg : "") {}
RuntimeException(const RuntimeException& rhs) : message(rhs.message) {}
virtual ~RuntimeException() {}
[[nodiscard]] virtual const char* what() const override { return message.c_str(); }
private:
std::string message;
};
#pragma endregion
namespace EnumsHelper {
/**
* @brief Return 'e1 | e2 | ... | en'
*/
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
inline TEnum Merge(std::initializer_list<TEnum> il) {
using ut = std::underlying_type_t<TEnum>;
ut result = 0;
for (auto it = il.begin(); it != il.end(); ++it) {
result |= static_cast<ut>(*it);
}
return static_cast<TEnum>(result);
}
/**
* @brief Return '~(e)'
*/
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
inline TEnum Inv(TEnum e) {
using ut = std::underlying_type_t<TEnum>;
return static_cast<TEnum>(~(static_cast<ut>(e)));
}
/**
* @brief Operate e1 &= (~e2)
*/
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
inline void Rm(TEnum& e1, TEnum e2) {
using ut = std::underlying_type_t<TEnum>;
e1 = static_cast<TEnum>(static_cast<ut>(e1) & static_cast<ut>(Inv(e2)));
}
/**
* @brief Operate e1 &= e2
*/
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
inline 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 Operate e1 |= e2
*/
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
inline void Add(TEnum& e1, TEnum e2) {
using ut = std::underlying_type_t<TEnum>;
e1 = static_cast<TEnum>(static_cast<ut>(e1) | static_cast<ut>(e2));
}
/**
* @brief Return 'bool(e1 & e2)'
*/
template<typename TEnum, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
inline bool Has(TEnum e, TEnum probe) {
using ut = std::underlying_type_t<TEnum>;
return static_cast<bool>(static_cast<ut>(e) & static_cast<ut>(probe));
}
}
}