feat: add helper macro and new Win32 function.

- add IsValidCodePage in WinFctHelper to check whether code page number is valid.
- add 6 macros to batchly (add / set default) (move / copy) (constructor / assign operator).
- add default or delete (copy / move) (constructor / assign operator) for some classes.
This commit is contained in:
yyc12345 2024-08-04 11:57:56 +08:00
parent 6da990876e
commit e6c24b8b61
12 changed files with 185 additions and 74 deletions

View File

@ -29,7 +29,7 @@
\li \subpage intro \li \subpage intro
\li \subpage platform_checker \li \subpage library_macros
\li \subpage library_encoding \li \subpage library_encoding

View File

@ -0,0 +1,80 @@
namespace YYCC {
/**
\page library_macros Library Macros
In this page we will introduce the macros defined by this library
which can not be grouped in other topic.
\section library_macros__platform_checker Platform Checker
In many cross platform applications,
programmer usually write code adapted to different platforms in one source file
and enable them respectively by macros representing the target platform.
As a cross platform library,
YYCC also has this feature and you can utilize it if you don't have other ways to so the same things.
\subsection library_macros__platform_checker__values Values
YYCC always define a macro called \c YYCC_OS to indicate the system of target platform.
In implementation, it will check following list from top to bottom to set matched value for it.
\li \c YYCC_OS_WINDOWS: Windows environment. It is done by checking whether environment define \c _WIN32 macro.
\li \c YYCC_OS_LINUX: In current implementation, this means target platform is \b NOT Windows.
\subsection library_macros__platform_checker__usage Usage
Now you know any possible value of \c YYCC_OS.
The next step is how to use it to enable specified code in specific target platform.
We take Windows platform for example.
Assume \c blabla() function is Windows specific.
We have following example code:
\code
#if YYCC_OS == YYCC_OS_WINDOWS
blabla();
#endif
\endcode
It's enough and simple that use \c \#if to bracket the Windows specified code.
\section library_macros__batch_class_copy_move Batch Class Copy / Move Functions
YYCC provides 6 macros to batchly remove class copy constructor and move constructor,
or set default class copy constructor and move constructor.
<UL>
<LI>
\c YYCC_DEL_CLS_COPY: Declare following 2 statements which delete copy constrcutor and copy assign operator.
<UL>
<LI><TT>CLSNAME(const CLSNAME&) = delete;</TT></LI>
<LI><TT>CLSNAME& operator=(const CLSNAME&) = delete;</TT></LI>
</UL>
</LI>
<LI>
\c YYCC_DEL_CLS_MOVE: Declare following 2 statements which delete move constrcutor and move assign operator.
<UL>
<LI><TT>CLSNAME(CLSNAME&&) = delete;</TT></LI>
<LI><TT>CLSNAME& operator=(CLSNAME&&) = delete;</TT></LI>
</UL>
</LI>
<LI>\c YYCC_DEL_CLS_COPY_MOVE: The combination of \c YYCC_DEL_CLS_COPY and \c YYCC_DEL_CLS_MOVE.</LI>
<LI>
\c YYCC_DEF_CLS_COPY: Declare following 2 statements which set default copy constrcutor and copy assign operator.
<UL>
<LI><TT>CLSNAME(const CLSNAME&) = default;</TT></LI>
<LI><TT>CLSNAME& operator=(const CLSNAME&) = default;</TT></LI>
</UL>
</LI>
<LI>
\c YYCC_DEF_CLS_MOVE: Declare following 2 statements which set default move constrcutor and move assign operator.
<UL>
<LI><TT>CLSNAME(CLSNAME&&) = default;</TT></LI>
<LI><TT>CLSNAME& operator=(CLSNAME&&) = default;</TT></LI>
</UL>
</LI>
<LI>\c YYCC_DEF_CLS_COPY_MOVE: The combination of \c YYCC_DEF_CLS_COPY and \c YYCC_DEF_CLS_MOVE.</LI>
</UL>
*/
}

View File

@ -1,37 +0,0 @@
namespace YYCC {
/**
\page platform_checker Platform Checker
In many cross platform applications,
programmer usually write code adapted to different platforms in one source file
and enable them respectively by macros representing the target platform.
As a cross platform library,
YYCC also has this feature and you can utilize it if you don't have other ways to so the same things.
\section platform_checker__values Values
YYCC always define a macro called \c YYCC_OS to indicate the system of target platform.
In implementation, it will check following list from top to bottom to set matched value for it.
\li \c YYCC_OS_WINDOWS: Windows environment. It is done by checking whether environment define \c _WIN32 macro.
\li \c YYCC_OS_LINUX: In current implementation, this means target platform is \b NOT Windows.
\section platform_checker__usage Usage
Now you know any possible value of \c YYCC_OS.
The next step is how to use it to enable specified code in specific target platform.
We take Windows platform for example.
Assume \c blabla() function is Windows specific.
We have following example code:
\code
#if YYCC_OS == YYCC_OS_WINDOWS
blabla();
#endif
\endcode
It's enough and simple that use \c \#if to bracket the Windows specified code.
*/
}

View File

@ -14,6 +14,7 @@ Currently this namespace has following functions:
\li #GetTempDirectory: Get temporary directory in Windows. \li #GetTempDirectory: Get temporary directory in Windows.
\li #GetModuleFileName: Get the path to module in file system by given handle. \li #GetModuleFileName: Get the path to module in file system by given handle.
\li #GetLocalAppData: Get the path inside \%LOCALAPPDATA\% \li #GetLocalAppData: Get the path inside \%LOCALAPPDATA\%
\li #IsValidCodePage: Check whether given code page number is valid.
*/ */
} }

View File

@ -51,22 +51,22 @@ namespace YYCC::ArgParser {
#endif #endif
ArgumentList::ArgumentList(std::vector<yycc_u8string>&& arguments) : ArgumentList::ArgumentList(std::vector<yycc_u8string>&& arguments) :
m_Arguments(arguments), m_ArgumentsIterator(m_Arguments.begin()) {} m_Arguments(arguments), m_ArgumentsCursor(0u) {}
void ArgumentList::Prev() { void ArgumentList::Prev() {
if (m_ArgumentsIterator == m_Arguments.begin()) if (m_ArgumentsCursor == 0u)
throw std::runtime_error("attempt to move on the head of iterator."); throw std::runtime_error("attempt to move on the head of iterator.");
--m_ArgumentsIterator; --m_ArgumentsCursor;
} }
void ArgumentList::Next() { void ArgumentList::Next() {
if (IsEOF()) throw std::runtime_error("attempt to move on the tail of iterator."); if (IsEOF()) throw std::runtime_error("attempt to move on the tail of iterator.");
++m_ArgumentsIterator; ++m_ArgumentsCursor;
} }
const yycc_u8string& ArgumentList::Argument() const { const yycc_u8string& ArgumentList::Argument() const {
if (IsEOF()) throw std::runtime_error("attempt to get data on the tail of iterator."); if (IsEOF()) throw std::runtime_error("attempt to get data on the tail of iterator.");
return *m_ArgumentsIterator; return m_Arguments[m_ArgumentsCursor];
} }
bool ArgumentList::IsSwitch(bool* is_long_name, yycc_u8string* long_name, yycc_char8_t* short_name) const { bool ArgumentList::IsSwitch(bool* is_long_name, yycc_u8string* long_name, yycc_char8_t* short_name) const {
@ -87,7 +87,7 @@ namespace YYCC::ArgParser {
bool ArgumentList::IsLongNameSwitch(yycc_u8string* name_part) const { bool ArgumentList::IsLongNameSwitch(yycc_u8string* name_part) const {
// fetch current parameter // fetch current parameter
if (IsEOF()) throw std::runtime_error("attempt to fetch data on the tail of iterator."); if (IsEOF()) throw std::runtime_error("attempt to fetch data on the tail of iterator.");
const yycc_u8string& param = *m_ArgumentsIterator; const yycc_u8string& param = m_Arguments[m_ArgumentsCursor];
// find double slash // find double slash
if (param.find(AbstractArgument::DOUBLE_DASH) != 0u) return false; if (param.find(AbstractArgument::DOUBLE_DASH) != 0u) return false;
// check gotten long name // check gotten long name
@ -101,7 +101,7 @@ namespace YYCC::ArgParser {
bool ArgumentList::IsShortNameSwitch(yycc_char8_t* name_part) const { bool ArgumentList::IsShortNameSwitch(yycc_char8_t* name_part) const {
// fetch current parameter // fetch current parameter
if (IsEOF()) throw std::runtime_error("attempt to fetch data on the tail of iterator."); if (IsEOF()) throw std::runtime_error("attempt to fetch data on the tail of iterator.");
const yycc_u8string& param = *m_ArgumentsIterator; const yycc_u8string& param = m_Arguments[m_ArgumentsCursor];
// if the length is not exactly equal to 2, // if the length is not exactly equal to 2,
// or it not starts with dash, // or it not starts with dash,
// it is impossible a short name // it is impossible a short name
@ -118,13 +118,13 @@ namespace YYCC::ArgParser {
bool ArgumentList::IsValue(yycc_u8string* val) const { bool ArgumentList::IsValue(yycc_u8string* val) const {
bool is_value = !IsSwitch(); bool is_value = !IsSwitch();
if (is_value && val != nullptr) if (is_value && val != nullptr)
*val = *m_ArgumentsIterator; *val = m_Arguments[m_ArgumentsCursor];
return is_value; return is_value;
} }
bool ArgumentList::IsEOF() const { return m_ArgumentsIterator == m_Arguments.end(); } bool ArgumentList::IsEOF() const { return m_ArgumentsCursor >= m_Arguments.size(); }
void ArgumentList::Reset() { m_ArgumentsIterator = m_Arguments.begin(); } void ArgumentList::Reset() { m_ArgumentsCursor = 0u; }
#pragma endregion #pragma endregion

View File

@ -61,14 +61,7 @@ namespace YYCC::ArgParser {
*/ */
ArgumentList(std::vector<yycc_u8string>&& arguments); ArgumentList(std::vector<yycc_u8string>&& arguments);
public: public:
/// @brief Default copy constructor YYCC_DEF_CLS_COPY_MOVE(ArgumentList);
ArgumentList(const ArgumentList&) = default;
/// @brief Default copy assigner
ArgumentList& operator=(const ArgumentList&) = default;
/// @brief Default move constructor
ArgumentList(ArgumentList&&) = default;
/// @brief Default move assigner
ArgumentList& operator=(ArgumentList&&) = default;
public: public:
/** /**
@ -151,7 +144,7 @@ namespace YYCC::ArgParser {
private: private:
std::vector<yycc_u8string> m_Arguments; std::vector<yycc_u8string> m_Arguments;
std::vector<yycc_u8string>::const_iterator m_ArgumentsIterator; size_t m_ArgumentsCursor;
}; };
/** /**
@ -209,6 +202,7 @@ namespace YYCC::ArgParser {
const yycc_char8_t* description = nullptr, const yycc_char8_t* argument_example = nullptr, const yycc_char8_t* description = nullptr, const yycc_char8_t* argument_example = nullptr,
bool is_optional = false); bool is_optional = false);
virtual ~AbstractArgument(); virtual ~AbstractArgument();
YYCC_DEL_CLS_COPY_MOVE(AbstractArgument);
// ===== User Implementation ===== // ===== User Implementation =====
protected: protected:
@ -296,6 +290,7 @@ namespace YYCC::ArgParser {
const yycc_char8_t* summary, const yycc_char8_t* description, const yycc_char8_t* summary, const yycc_char8_t* description,
std::initializer_list<AbstractArgument*> arguments); std::initializer_list<AbstractArgument*> arguments);
~OptionContext(); ~OptionContext();
YYCC_DEL_CLS_COPY_MOVE(OptionContext);
public: public:
/** /**
@ -350,6 +345,7 @@ namespace YYCC::ArgParser {
Constraints::Constraint<_Ty> constraint = Constraints::Constraint<_Ty> {}) : Constraints::Constraint<_Ty> constraint = Constraints::Constraint<_Ty> {}) :
AbstractArgument(long_name, short_name, description, argument_example, is_optional), m_Data(), m_Constraint(constraint) {} AbstractArgument(long_name, short_name, description, argument_example, is_optional), m_Data(), m_Constraint(constraint) {}
virtual ~NumberArgument() {} virtual ~NumberArgument() {}
YYCC_DEL_CLS_COPY_MOVE(NumberArgument);
public: public:
/// @brief Get stored data in argument. /// @brief Get stored data in argument.
@ -403,6 +399,7 @@ namespace YYCC::ArgParser {
// bool switch doesn't have argument, so it doesn't have example property. // bool switch doesn't have argument, so it doesn't have example property.
AbstractArgument(long_name, short_name, description, nullptr, true) {} AbstractArgument(long_name, short_name, description, nullptr, true) {}
virtual ~SwitchArgument() {} virtual ~SwitchArgument() {}
YYCC_DEL_CLS_COPY_MOVE(SwitchArgument);
protected: protected:
virtual bool Parse(ArgumentList& al) override { return true; } // simply return true because no value to store. virtual bool Parse(ArgumentList& al) override { return true; } // simply return true because no value to store.
@ -429,6 +426,7 @@ namespace YYCC::ArgParser {
Constraints::Constraint<yycc_u8string> constraint = Constraints::Constraint<yycc_u8string> {}) : Constraints::Constraint<yycc_u8string> constraint = Constraints::Constraint<yycc_u8string> {}) :
AbstractArgument(long_name, short_name, description, argument_example, is_optional), m_Data(), m_Constraint(constraint) {} AbstractArgument(long_name, short_name, description, argument_example, is_optional), m_Data(), m_Constraint(constraint) {}
virtual ~StringArgument() {} virtual ~StringArgument() {}
YYCC_DEL_CLS_COPY_MOVE(StringArgument);
public: public:
/// @brief Get stored data in argument. /// @brief Get stored data in argument.

View File

@ -30,6 +30,7 @@ namespace YYCC::ConfigManager {
*/ */
AbstractSetting(const yycc_u8string_view& name); AbstractSetting(const yycc_u8string_view& name);
virtual ~AbstractSetting(); virtual ~AbstractSetting();
YYCC_DEL_CLS_COPY_MOVE(AbstractSetting);
// Name interface // Name interface
public: public:
@ -89,6 +90,7 @@ namespace YYCC::ConfigManager {
uint64_t version_identifier, uint64_t version_identifier,
std::initializer_list<AbstractSetting*> settings); std::initializer_list<AbstractSetting*> settings);
~CoreManager() {} ~CoreManager() {}
YYCC_DEL_CLS_COPY_MOVE(CoreManager);
// Core functions // Core functions
public: public:
@ -129,6 +131,7 @@ namespace YYCC::ConfigManager {
Constraints::Constraint<_Ty> constraint = Constraints::Constraint<_Ty> {}) : Constraints::Constraint<_Ty> constraint = Constraints::Constraint<_Ty> {}) :
AbstractSetting(name), m_Data(default_value), m_DefaultData(default_value), m_Constraint(constraint) {} AbstractSetting(name), m_Data(default_value), m_DefaultData(default_value), m_Constraint(constraint) {}
virtual ~NumberSetting() {} virtual ~NumberSetting() {}
YYCC_DEL_CLS_COPY_MOVE(NumberSetting);
/// @brief Get stored data in setting. /// @brief Get stored data in setting.
_Ty Get() const { return m_Data; } _Ty Get() const { return m_Data; }
@ -189,6 +192,7 @@ namespace YYCC::ConfigManager {
m_DefaultData = default_value; m_DefaultData = default_value;
} }
virtual ~StringSetting() {} virtual ~StringSetting() {}
YYCC_DEL_CLS_COPY_MOVE(StringSetting);
/// @brief Get reference to stored string. /// @brief Get reference to stored string.
const yycc_u8string& Get() const { return m_Data; } const yycc_u8string& Get() const { return m_Data; }

View File

@ -31,6 +31,7 @@ namespace YYCC::DialogHelper {
friend class WinFileDialog; friend class WinFileDialog;
public: public:
WinFileFilters() : m_WinFilters(), m_WinDataStruct(nullptr) {} WinFileFilters() : m_WinFilters(), m_WinDataStruct(nullptr) {}
YYCC_DEL_CLS_COPY_MOVE(WinFileFilters);
/// @brief Get the count of available file filters /// @brief Get the count of available file filters
UINT GetFilterCount() const { UINT GetFilterCount() const {
@ -67,6 +68,7 @@ namespace YYCC::DialogHelper {
class FileFilters { class FileFilters {
public: public:
FileFilters() : m_Filters() {} FileFilters() : m_Filters() {}
YYCC_DEL_CLS_COPY_MOVE(FileFilters);
/** /**
* @brief Add a filter pair in file types list. * @brief Add a filter pair in file types list.
@ -123,6 +125,7 @@ namespace YYCC::DialogHelper {
m_WinFileTypes(), m_WinDefaultFileTypeIndex(0u), m_WinFileTypes(), m_WinDefaultFileTypeIndex(0u),
m_HasTitle(false), m_HasInitFileName(false), m_WinTitle(), m_WinInitFileName(), m_HasTitle(false), m_HasInitFileName(false), m_WinTitle(), m_WinInitFileName(),
m_WinInitDirectory(nullptr) {} m_WinInitDirectory(nullptr) {}
YYCC_DEL_CLS_COPY_MOVE(WinFileDialog);
/// @brief Get whether this dialog has owner. /// @brief Get whether this dialog has owner.
bool HasOwner() const { return m_WinOwner != NULL; } bool HasOwner() const { return m_WinOwner != NULL; }
@ -189,6 +192,7 @@ namespace YYCC::DialogHelper {
m_DefaultFileTypeIndex(0u), m_DefaultFileTypeIndex(0u),
m_Title(), m_InitFileName(), m_InitDirectory(), m_Title(), m_InitFileName(), m_InitDirectory(),
m_HasTitle(false), m_HasInitFileName(false), m_HasInitDirectory(false) {} m_HasTitle(false), m_HasInitFileName(false), m_HasInitDirectory(false) {}
YYCC_DEL_CLS_COPY_MOVE(FileDialog);
/** /**
* @brief Set the owner of dialog. * @brief Set the owner of dialog.

View File

@ -85,6 +85,11 @@ namespace YYCC::WinFctHelper {
return YYCC::EncodingHelper::WcharToUTF8(known_path.get(), ret); return YYCC::EncodingHelper::WcharToUTF8(known_path.get(), ret);
} }
bool IsValidCodePage(UINT code_page) {
CPINFOEXW cpinfo;
return GetCPInfoExW(code_page, 0, &cpinfo);
}
} }
#endif #endif

View File

@ -57,6 +57,13 @@ namespace YYCC::WinFctHelper {
*/ */
bool GetLocalAppData(yycc_u8string& ret); bool GetLocalAppData(yycc_u8string& ret);
/**
* @brief Check whether given code page number is a valid one.
* @param[in] code_page The code page number.
* @return True if it is valid, otherwise false.
*/
bool IsValidCodePage(UINT code_page);
} }
#endif #endif

View File

@ -1,5 +1,7 @@
#pragma once #pragma once
#pragma region Operating System Identifier Macros
// Define operating system macros // Define operating system macros
#define YYCC_OS_WINDOWS 2 #define YYCC_OS_WINDOWS 2
#define YYCC_OS_LINUX 3 #define YYCC_OS_LINUX 3
@ -10,6 +12,10 @@
#define YYCC_OS YYCC_OS_LINUX #define YYCC_OS YYCC_OS_LINUX
#endif #endif
#pragma endregion
#pragma region Windows Shitty Behavior Disable Macros
// If we are in Windows, // If we are in Windows,
// we need add 2 macros to disable Windows shitty warnings and errors of // we need add 2 macros to disable Windows shitty warnings and errors of
// depracted functions and not secure functions. // depracted functions and not secure functions.
@ -24,6 +30,10 @@
#endif #endif
#pragma endregion
#pragma region YYCC UTF8 Types
// Define the UTF8 char type we used. // Define the UTF8 char type we used.
// And do a polyfill if no embedded char8_t type. // And do a polyfill if no embedded char8_t type.
@ -67,4 +77,40 @@ namespace YYCC {
It is equal to \c std::u8string_view if your current C++ standard support it. It is equal to \c std::u8string_view if your current C++ standard support it.
*/ */
#pragma endregion
#pragma region Batch Class Move / Copy Function Macros
/// @brief Explicitly remove copy (\c constructor and \c operator\=) for given class.
#define YYCC_DEL_CLS_COPY(CLSNAME) \
CLSNAME(const CLSNAME&) = delete; \
CLSNAME& operator=(const CLSNAME&) = delete;
/// @brief Explicitly remove move (\c constructor and \c operator\=) for given class.
#define YYCC_DEL_CLS_MOVE(CLSNAME) \
CLSNAME(CLSNAME&&) = delete; \
CLSNAME& operator=(CLSNAME&&) = delete;
/// @brief Explicitly remove (copy and move) (\c constructor and \c operator\=) for given class.
#define YYCC_DEL_CLS_COPY_MOVE(CLSNAME) \
YYCC_DEL_CLS_COPY(CLSNAME) \
YYCC_DEL_CLS_MOVE(CLSNAME)
/// @brief Explicitly set default copy (\c constructor and \c operator\=) for given class.
#define YYCC_DEF_CLS_COPY(CLSNAME) \
CLSNAME(const CLSNAME&) = default; \
CLSNAME& operator=(const CLSNAME&) = default;
/// @brief Explicitly set default move (\c constructor and \c operator\=) for given class.
#define YYCC_DEF_CLS_MOVE(CLSNAME) \
CLSNAME(CLSNAME&&) = default; \
CLSNAME& operator=(CLSNAME&&) = default;
/// @brief Explicitly set default (copy and move) (\c constructor and \c operator\=) for given class.
#define YYCC_DEF_CLS_COPY_MOVE(CLSNAME) \
YYCC_DEF_CLS_COPY(CLSNAME) \
YYCC_DEF_CLS_MOVE(CLSNAME)
#pragma endregion

View File

@ -388,6 +388,9 @@ namespace YYCCTestbench {
Assert(YYCC::WinFctHelper::GetLocalAppData(test_localappdata_path), YYCC_U8("YYCC::WinFctHelper::GetLocalAppData")); Assert(YYCC::WinFctHelper::GetLocalAppData(test_localappdata_path), YYCC_U8("YYCC::WinFctHelper::GetLocalAppData"));
Console::FormatLine(YYCC_U8("Local AppData: %s"), test_localappdata_path.c_str()); Console::FormatLine(YYCC_U8("Local AppData: %s"), test_localappdata_path.c_str());
Assert(YYCC::WinFctHelper::IsValidCodePage(static_cast<UINT>(1252)) == true, YYCC_U8("YYCC::WinFctHelper::IsValidCodePage"));
Assert(YYCC::WinFctHelper::IsValidCodePage(static_cast<UINT>(114514)) == false, YYCC_U8("YYCC::WinFctHelper::IsValidCodePage"));
#endif #endif
} }