diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 62533c6..b6a8949 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,6 +13,7 @@ PRIVATE # Sources yycc/string/reinterpret.cpp yycc/string/op.cpp + yycc/patch/fopen.cpp yycc/rust/panic.cpp yycc/encoding/stlcvt.cpp yycc/encoding/windows.cpp @@ -31,10 +32,13 @@ FILES yycc/macro/stl_detector.hpp yycc/macro/endian_detector.hpp yycc/macro/compiler_detector.hpp + yycc/macro/ptr_size_detector.hpp yycc/macro/class_copy_move.hpp yycc/flag_enum.hpp yycc/string/reinterpret.hpp yycc/string/op.hpp + yycc/patch/ptr_pad.hpp + yycc/patch/fopen.hpp yycc/num/parse.hpp yycc/num/stringify.hpp yycc/rust/prelude.hpp @@ -85,6 +89,9 @@ PUBLIC # Endian macro $<$:YYCC_ENDIAN_LITTLE> $<$:YYCC_ENDIAN_BIG> + # Pointer size macro + $<$:YYCC_PTRSIZE_32> + $<$:YYCC_PTRSIZE_64> # Use Unicode charset on MSVC $<$:UNICODE> $<$:_UNICODE> diff --git a/src/YYCC.natvis b/src/YYCC.natvis deleted file mode 100644 index 51fe2a4..0000000 --- a/src/YYCC.natvis +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - {_Bx._Buf,s8} - {_Bx._Ptr,s8} - _Bx._Buf,s8 - _Bx._Ptr,s8 - - _Mysize - _Myres - - _Mysize - _Bx._Buf - _Bx._Ptr - - - - - - - - - - - - - - - {_Mypair._Myval2._Bx._Buf,s8} - {_Mypair._Myval2._Bx._Ptr,s8} - _Mypair._Myval2._Bx._Buf,s8 - _Mypair._Myval2._Bx._Ptr,s8 - - size() - capacity() - _Mypair - - _Mypair._Myval2._Mysize - _Mypair._Myval2._Bx._Buf - _Mypair._Myval2._Bx._Ptr - - - - - - - - - - {_Mydata,[_Mysize],s8} - _Mydata,[_Mysize],s8 - - size() - - size() - data() - - - - - diff --git a/src/YYCCLegacy/EnumHelper.hpp b/src/YYCCLegacy/EnumHelper.hpp deleted file mode 100644 index 043b13a..0000000 --- a/src/YYCCLegacy/EnumHelper.hpp +++ /dev/null @@ -1,182 +0,0 @@ -#pragma once -#include "YYCCInternal.hpp" - -#include -#include - -/** - * @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, int> = 0> - //inline constexpr TEnum operator|(TEnum lhs, TEnum rhs) { - // using ut = std::underlying_type_t; - // return static_cast(static_cast(lhs) | static_cast(rhs)); - //} - //template, int> = 0> - //inline constexpr TEnum operator|=(TEnum& lhs, TEnum rhs) { - // using ut = std::underlying_type_t; - // lhs = lhs | rhs; - // return lhs; - //} - // - //template, int> = 0> - //inline constexpr TEnum operator&(TEnum lhs, TEnum rhs) { - // using ut = std::underlying_type_t; - // return static_cast(static_cast(lhs) & static_cast(rhs)); - //} - //template, int> = 0> - //inline constexpr TEnum operator&=(TEnum& lhs, TEnum rhs) { - // using ut = std::underlying_type_t; - // lhs = lhs & rhs; - // return lhs; - //} - // - //template, int> = 0> - //inline constexpr TEnum operator^(TEnum lhs, TEnum rhs) { - // using ut = std::underlying_type_t; - // return static_cast(static_cast(lhs) ^ static_cast(rhs)); - //} - //template, int> = 0> - //inline constexpr TEnum operator^=(TEnum& lhs, TEnum rhs) { - // using ut = std::underlying_type_t; - // lhs = lhs ^ rhs; - // return lhs; - //} - - //template, int> = 0> - //inline constexpr TEnum operator~(TEnum lhs) { - // using ut = std::underlying_type_t; - // return static_cast(~(static_cast(lhs))); - //} - // - //template, int> = 0> - //inline constexpr bool operator bool(TEnum lhs) { - // using ut = std::underlying_type_t; - // return static_cast(static_cast(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 - 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::conjunction_v, std::remove_cv_t>...>; - }; - /** - * @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 - inline constexpr bool all_enum_values_v = all_enum_values::value; - - /** - * @brief Merge given enum flags like performing e1 | e2 | ... | en - * @tparam TEnum Enum type for processing. - * @param[in] val The first enum flag to be merged. - * @param[in] val_left Left enum flags to be merged. - * @return The merged enum flag. - * @remarks - * This function use recursive expansion to get final merge result. - * So there is no difference of each arguments. - * We independ first argument just served for expansion. - */ - template, int> = 0> - constexpr TEnum Merge(TEnum val, Ts... val_left) { - using ut = std::underlying_type_t; - ut result = static_cast(val); - if constexpr (sizeof...(val_left) > 0) { - result |= static_cast(Merge(val_left...)); - } - return static_cast(result); - } - - /** - * @brief Reverse given enum flags like performing ~(e) - * @tparam TEnum Enum type for processing. - * @param[in] e The list of enum flags to be inversed. - * @return The inversed enum flag. - */ - template, int> = 0> - constexpr TEnum Invert(TEnum e) { - using ut = std::underlying_type_t; - return static_cast(~(static_cast(e))); - } - - /** - * @brief Use specified enum flag to mask given enum flag like performing e1 &= e2 - * @tparam TEnum Enum type for processing. - * @param[in,out] e1 The enum flags to be masked. - * @param[in] e2 The mask enum flag. - */ - template, int> = 0> - constexpr void Mask(TEnum& e1, TEnum e2) { - using ut = std::underlying_type_t; - e1 = static_cast(static_cast(e1) & static_cast(e2)); - } - - /** - * @brief Add multiple enum flags to given enum flag like performing e1 |= (e2 | e3 | ... | en) - * @tparam TEnum Enum type for processing. - * @param[in,out] e1 The enum flag which flags add on. - * @param[in] vals The enum flag to be added. - */ - template, int> = 0> - constexpr void Add(TEnum& e1, Ts... vals) { - using ut = std::underlying_type_t; - e1 = static_cast(static_cast(e1) | static_cast(Merge(vals...))); - } - - /** - * @brief Remove multiple enum flags from given enum flag like performing e1 &= ~(e2 | e3 | ... | en) - * @tparam TEnum Enum type for processing. - * @param[in,out] e1 The enum flag which flags removed from. - * @param[in] vals The enum flag to be removed. - */ - template, int> = 0> - constexpr void Remove(TEnum& e1, Ts... vals) { - using ut = std::underlying_type_t; - e1 = static_cast(static_cast(e1) & static_cast(Invert(Merge(vals...)))); - } - - /** - * @brief Check whether given enum flag has any of specified multiple enum flags (OR) like performing bool(e1 & (e2 | e3 | ... | en)) - * @tparam TEnum Enum type for processing. - * @param[in] e1 The enum flag where we check. - * @param[in] vals The enum flags for checking. - * @return True if it has any of given flags (OR), otherwise false. - */ - template, int> = 0> - constexpr bool Has(TEnum e1, Ts... vals) { - using ut = std::underlying_type_t; - return static_cast(static_cast(e1) & static_cast(Merge(vals...))); - } - - /** - * @brief Cast given enum flags to its equvalent boolean value like performing bool(e) - * @tparam TEnum Enum type for processing. - * @param e The enum flags to be cast. - * @return The equvalent bool value of given enum flag. - */ - template, int> = 0> - constexpr bool Bool(TEnum e) { - using ut = std::underlying_type_t; - return static_cast(static_cast(e)); - } - -} diff --git a/src/YYCCLegacy/IOHelper.hpp b/src/YYCCLegacy/IOHelper.hpp index 34a78fd..71547d3 100644 --- a/src/YYCCLegacy/IOHelper.hpp +++ b/src/YYCCLegacy/IOHelper.hpp @@ -10,24 +10,7 @@ * See also \ref io_helper. */ namespace YYCC::IOHelper { - -#if UINTPTR_MAX == UINT32_MAX -#define PRI_XPTR_LEFT_PADDING "08" -#elif UINTPTR_MAX == UINT64_MAX - /** - * @brief The left-padding zero format string of HEX-printed pointer type. - * @details - * When printing a pointer with HEX style, we always hope it can be left-padded with some zero for easy reading. - * In different architecture, the size of this padding is differnet too so we create this macro. - * - * In 32-bit environment, it will be "08" meaning left pad zero until 8 number position. - * In 64-bit environment, it will be "016" meaning left pad zero until 16 number position. - */ -#define PRI_XPTR_LEFT_PADDING "016" -#else -#error "Not supported pointer size." -#endif - + /// @brief C++ standard deleter for std::FILE* class StdFileDeleter { public: diff --git a/src/YYCCLegacy/ParserHelper.hpp b/src/YYCCLegacy/ParserHelper.hpp deleted file mode 100644 index a41d25e..0000000 --- a/src/YYCCLegacy/ParserHelper.hpp +++ /dev/null @@ -1,221 +0,0 @@ -#pragma once -#include "YYCCInternal.hpp" - -#include "EncodingHelper.hpp" -#include "StringHelper.hpp" -#include -#include -#include -#include -#include -#include - -/** - * @brief The helper involving convertion between arithmetic types (integral, floating point and bool) and string - * @details - * See also \ref parser_helper. -*/ -namespace YYCC::ParserHelper { - - // Reference: https://zh.cppreference.com/w/cpp/utility/from_chars - - /** - * @brief Try parsing given string to floating point types. - * @tparam _Ty The type derived from floating point type. - * @param[in] strl The string need to be parsed. - * @param[out] num - * The variable receiving result. - * There is no guarantee that the content is not modified when parsing failed. - * @param[in] fmt The floating point format used when try parsing. - * @return True if success, otherwise false. - */ - template, int> = 0> - bool TryParse(const yycc_u8string_view& strl, _Ty& num, std::chars_format fmt = std::chars_format::general) { - auto [ptr, ec] = std::from_chars( - EncodingHelper::ToOrdinary(strl.data()), - EncodingHelper::ToOrdinary(strl.data() + strl.size()), - num, fmt - ); - if (ec == std::errc()) { - // check whether the full string is matched - return ptr == EncodingHelper::ToOrdinary(strl.data() + strl.size()); - } else if (ec == std::errc::invalid_argument) { - // given string is invalid - return false; - } else if (ec == std::errc::result_out_of_range) { - // given string is out of range - return false; - } else { - // unreachable - throw std::runtime_error("unreachable code."); - } - } - /** - * @brief Try parsing given string to integral types. - * @tparam _Ty The type derived from integral type except bool type. - * @param[in] strl The string need to be parsed. - * @param[out] num - * The variable receiving result. - * There is no guarantee that the content is not modified when parsing failed. - * @param[in] base Integer base to use: a value between 2 and 36 (inclusive). - * @return True if success, otherwise false. - */ - template && !std::is_same_v<_Ty, bool>, int> = 0> - bool TryParse(const yycc_u8string_view& strl, _Ty& num, int base = 10) { - auto [ptr, ec] = std::from_chars( - EncodingHelper::ToOrdinary(strl.data()), - EncodingHelper::ToOrdinary(strl.data() + strl.size()), - num, base - ); - if (ec == std::errc()) { - // check whether the full string is matched - return ptr == EncodingHelper::ToOrdinary(strl.data() + strl.size()); - } else if (ec == std::errc::invalid_argument) { - // given string is invalid - return false; - } else if (ec == std::errc::result_out_of_range) { - // given string is out of range - return false; - } else { - // unreachable - throw std::runtime_error("unreachable code."); - } - } - /** - * @brief Try parsing given string to bool types. - * @tparam _Ty The type derived from bool type. - * @param[in] strl The string need to be parsed ("true" or "false", case insensitive). - * @param[out] num - * The variable receiving result. - * There is no guarantee that the content is not modified when parsing failed. - * @return True if success, otherwise false. - */ - template, int> = 0> - bool TryParse(const yycc_u8string_view& strl, _Ty& num) { - // get lower case - yycc_u8string lower_case(strl); - YYCC::StringHelper::Lower(lower_case); - // compare result - if (strl == YYCC_U8("true")) num = true; - else if (strl == YYCC_U8("false")) num = false; - else return false; - return true; - } - - /** - * @brief Parse given string to floating point types. - * @tparam _Ty The type derived from floating point type. - * @param[in] strl The string need to be parsed. - * @param[in] fmt The floating point format used when try parsing. - * @return - * The parsing result. - * There is no guarantee about the content of this return value when parsing failed. - * It may be any possible value but usually is its default value. - */ - template, int> = 0> - _Ty Parse(const yycc_u8string_view& strl, std::chars_format fmt = std::chars_format::general) { - _Ty ret; - TryParse(strl, ret, fmt); - return ret; - } - /** - * @brief Parse given string to integral type types. - * @tparam _Ty The type derived from integral type except bool type. - * @param[in] strl The string need to be parsed. - * @param[in] base Integer base to use: a value between 2 and 36 (inclusive). - * @return - * The parsing result. - * There is no guarantee about the content of this return value when parsing failed. - * It may be any possible value but usually is its default value. - */ - template && !std::is_same_v<_Ty, bool>, int> = 0> - _Ty Parse(const yycc_u8string_view& strl, int base = 10) { - _Ty ret; - TryParse(strl, ret, base); - return ret; - } - /** - * @brief Parse given string to bool types. - * @tparam _Ty The type derived from bool type. - * @param[in] strl The string need to be parsed ("true" or "false", case insensitive). - * @return - * The parsing result. - * There is no guarantee about the content of this return value when parsing failed. - * It may be any possible value but usually is its default value. - */ - template, int> = 0> - _Ty Parse(const yycc_u8string_view& strl) { - _Ty ret; - TryParse(strl, ret); - return ret; - } - - // Reference: https://en.cppreference.com/w/cpp/utility/to_chars - - /** - * @brief Return the string representation of given floating point value. - * @tparam _Ty The type derived from floating point type. - * @param[in] num The value need to get string representation. - * @param[in] fmt The floating point format used when getting string representation. - * @param[in] precision The floating point precision used when getting string representation. - * @return The string representation of given value. - */ - template, int> = 0> - yycc_u8string ToString(_Ty num, std::chars_format fmt = std::chars_format::general, int precision = 6) { - // default precision = 6 is gotten from: https://en.cppreference.com/w/c/io/fprintf - std::array buffer; - auto [ptr, ec] = std::to_chars( - EncodingHelper::ToOrdinary(buffer.data()), - EncodingHelper::ToOrdinary(buffer.data() + buffer.size()), - num, fmt, precision - ); - if (ec == std::errc()) { - return yycc_u8string(buffer.data(), EncodingHelper::ToUTF8(ptr) - buffer.data()); - } else if (ec == std::errc::value_too_large) { - // too short buffer - // this should not happened - throw std::out_of_range("ToString() buffer is not sufficient."); - } else { - // unreachable - throw std::runtime_error("unreachable code."); - } - } - /** - * @brief Return the string representation of given integral value. - * @tparam _Ty The type derived from integral type except bool type. - * @param[in] num The value need to get string representation. - * @param[in] base Integer base used when getting string representation: a value between 2 and 36 (inclusive). - * @return The string representation of given value. - */ - template && !std::is_same_v<_Ty, bool>, int> = 0> - yycc_u8string ToString(_Ty num, int base = 10) { - std::array buffer; - auto [ptr, ec] = std::to_chars( - EncodingHelper::ToOrdinary(buffer.data()), - EncodingHelper::ToOrdinary(buffer.data() + buffer.size()), - num, base - ); - if (ec == std::errc()) { - return yycc_u8string(buffer.data(), EncodingHelper::ToUTF8(ptr) - buffer.data()); - } else if (ec == std::errc::value_too_large) { - // too short buffer - // this should not happened - throw std::out_of_range("ToString() buffer is not sufficient."); - } else { - // unreachable - throw std::runtime_error("unreachable code."); - } - } - /** - * @brief Return the string representation of given bool value. - * @tparam _Ty The type derived from bool type. - * @param[in] num The value need to get string representation. - * @return The string representation of given value ("true" or "false"). - */ - template, int> = 0> - yycc_u8string ToString(_Ty num) { - if (num) return yycc_u8string(YYCC_U8("true")); - else return yycc_u8string(YYCC_U8("false")); - } - -} diff --git a/src/yycc.hpp b/src/yycc.hpp index 2057722..4ca7819 100644 --- a/src/yycc.hpp +++ b/src/yycc.hpp @@ -8,9 +8,8 @@ * They are crucial before using YYCC. */ -// Library Version and Comparison Macros +// Library version #include "yycc/version.hpp" -#include "yycc/macro/version_cmp.hpp" // Detect essential macros // Operating System macros @@ -19,8 +18,9 @@ #include "yycc/macro/compiler_detector.hpp" // Endian macros #include "yycc/macro/endian_detector.hpp" - -// Batch Class Move / Copy Function Macros -#include "yycc/macro/class_copy_move.hpp" +// Pointer size macros +#include "yycc/macro/ptr_size_detector.hpp" +// STL macros +#include "yycc/macro/stl_detector.hpp" namespace yycc {} diff --git a/src/yycc/macro/os_detector.hpp b/src/yycc/macro/os_detector.hpp index 98ec1cb..7fb3727 100644 --- a/src/yycc/macro/os_detector.hpp +++ b/src/yycc/macro/os_detector.hpp @@ -1,7 +1,7 @@ #pragma once // Check OS macro -#if (defined(YYCC_OS_WINDOWS) + defined(YYCC_OS_LINUX)) != 1 +#if (defined(YYCC_OS_WINDOWS) + defined(YYCC_OS_LINUX) + defined(YYCC_OS_MACOS)) != 1 #error "Current operating system is not supported!" #endif @@ -11,6 +11,7 @@ namespace yycc::macro::os { enum class OsKind { Windows, ///< Microsoft Windows Linux, ///< GNU/Linux + MacOs, ///< Apple macOS }; /** @@ -20,8 +21,10 @@ namespace yycc::macro::os { inline constexpr OsKind get_os() { #if defined(YYCC_OS_WINDOWS) return OsKind::Windows; -#else +#elif defined(YYCC_OS_LINUX) return OsKind::Linux; +#else + return OsKind::MacOs; #endif } diff --git a/src/yycc/macro/ptr_size_detector.hpp b/src/yycc/macro/ptr_size_detector.hpp new file mode 100644 index 0000000..15fad21 --- /dev/null +++ b/src/yycc/macro/ptr_size_detector.hpp @@ -0,0 +1,6 @@ +#pragma once + +// Check pointer size macro +#if (defined(YYCC_PTRSIZE_32) + defined(YYCC_PTRSIZE_64)) != 1 +#error "Current environment used pointer size is not supported!" +#endif diff --git a/src/yycc/patch/fopen.cpp b/src/yycc/patch/fopen.cpp new file mode 100644 index 0000000..ede83e4 --- /dev/null +++ b/src/yycc/patch/fopen.cpp @@ -0,0 +1,35 @@ +#include "fopen.hpp" +#include "../macro/os_detector.hpp" +#include "../string/reinterpret.hpp" + +#if defined(YYCC_OS_WINDOWS) +#include "../windows/import_guard_head.hpp" +#include +#include "../windows/import_guard_tail.hpp" +#endif + +#define REINTERPRET ::yycc::string::reinterpret + +namespace yycc::patch::fopen { + + std::FILE* fopen(const char8_t* u8_filepath, const char8_t* u8_mode) { + // TODO: Fix this after finish Windows encoding +// #if defined(YYCC_OS_WINDOWS) + +// // convert mode and file path to wchar +// std::wstring wmode, wpath; +// if (!YYCC::EncodingHelper::UTF8ToWchar(u8_mode, wmode)) +// return nullptr; +// if (!YYCC::EncodingHelper::UTF8ToWchar(u8_filepath, wpath)) +// return nullptr; + +// // call microsoft specified fopen which support wchar as argument. +// return _wfopen(wpath.c_str(), wmode.c_str()); + +// #else +// return std::fopen(REINTERPRET::as_ordinary(u8_filepath), REINTERPRET::as_ordinary(u8_mode)); +// #endif + return std::fopen(REINTERPRET::as_ordinary(u8_filepath), REINTERPRET::as_ordinary(u8_mode)); + } + +} diff --git a/src/yycc/patch/fopen.hpp b/src/yycc/patch/fopen.hpp new file mode 100644 index 0000000..f7a025c --- /dev/null +++ b/src/yycc/patch/fopen.hpp @@ -0,0 +1,30 @@ +#pragma once +#include + +namespace yycc::patch::fopen { + + /// @brief C++ standard deleter for std::FILE* + class StdFileDeleter { + public: + StdFileDeleter() {} + void operator() (std::FILE* ptr) { + if (ptr != nullptr) { + std::fclose(ptr); + } + } + }; + /// @brief Smart unique pointer of \c std::FILE* + using SmartStdFile = std::unique_ptr; + + /** + * @brief The UTF8 version of \c std::fopen. + * @param[in] u8_filepath The UTF8 encoded path to the file to be opened. + * @param[in] u8_mode UTF8 encoded mode string of the file to be opened. + * @remarks + * This function is suit for Windows because std::fopen do not support UTF8 on Windows. + * On other platforms, this function will delegate request directly to std::fopen. + * @return \c FILE* of the file to be opened, or nullptr if failed. + */ + std::FILE* fopen(const char8_t* u8_filepath, const char8_t* u8_mode); + +} diff --git a/src/yycc/patch/ptr_pad.hpp b/src/yycc/patch/ptr_pad.hpp new file mode 100644 index 0000000..a9f4dc4 --- /dev/null +++ b/src/yycc/patch/ptr_pad.hpp @@ -0,0 +1,20 @@ +#pragma once +#include "../macro/ptr_size_detector.hpp" +#include + +/** + * @def PRIXPTR_LPAD + * @brief The left-padding zero format string of HEX-printed pointer type. + * @details + * When printing a pointer with HEX style, we usually hope it can be left-padded with some zero for easy reading. + * In different architecture, the size of this padding is differnet too so we create this macro. + * + * In 32-bit environment, it will be "08" meaning left pad zero until 8 number position. + * In 64-bit environment, it will be "016" meaning left pad zero until 16 number position. +*/ + +#if defined(YYCC_PTRSIZE_32) +#define PRIXPTR_LPAD "08" +#else +#define PRIXPTR_LPAD "016" +#endif diff --git a/src/yycc/windows/import_guard_head.hpp b/src/yycc/windows/import_guard_head.hpp index b55a26b..2f79c00 100644 --- a/src/yycc/windows/import_guard_head.hpp +++ b/src/yycc/windows/import_guard_head.hpp @@ -5,5 +5,5 @@ // YYC MARK: // Since YYCC 2.0 version, we use CMake to handle Windows shitty macros, // so we do not need declare WIN32_LEAN_AND_MEAN or NOMINMAX in there. -// But for keep the pair of this guard, we still keep this header file, +// But for keeping the pair of this guard, we still keep this header file, // although it do nothing. diff --git a/src/yycc/windows/import_guard_tail.hpp b/src/yycc/windows/import_guard_tail.hpp index af28574..68177a8 100644 --- a/src/yycc/windows/import_guard_tail.hpp +++ b/src/yycc/windows/import_guard_tail.hpp @@ -6,11 +6,11 @@ #if defined(YYCC_OS_WINDOWS) -// Windows also will generate following macros -// which may cause the function sign is different in Windows and other platforms. +// Windows also will generate following macros which may cause +// the function sign is different in Windows and other platforms. // So we simply remove them. -// Because #undef will not throw error if there are no matched macro, -// so we simply #undef them directly. +// At the same time, because `#undef` will not throw error if there are no matched macro, +// we can simply use `#undef` to remove them directly. #undef GetObject #undef GetClassName #undef LoadImage diff --git a/testbench/CMakeLists.txt b/testbench/CMakeLists.txt index 50966c5..06cb9ec 100644 --- a/testbench/CMakeLists.txt +++ b/testbench/CMakeLists.txt @@ -8,6 +8,7 @@ PRIVATE yycc/flag_enum.cpp yycc/constraint.cpp yycc/constraint/builder.cpp + yycc/patch/ptr_pad.cpp yycc/string/op.cpp yycc/string/reinterpret.cpp yycc/num/parse.cpp diff --git a/testbench/yycc/patch/ptr_pad.cpp b/testbench/yycc/patch/ptr_pad.cpp new file mode 100644 index 0000000..0bc88aa --- /dev/null +++ b/testbench/yycc/patch/ptr_pad.cpp @@ -0,0 +1,22 @@ +#include +#include +#include +#include +#include + +#define OP ::yycc::string::op + +namespace yycctest::patch::ptr_pad { + + TEST(PatchPtrPad, Normal) { + auto rv = OP::printf(u8"0x%" PRIXPTR_LPAD PRIXPTR, nullptr); + EXPECT_TRUE(rv.has_value()); + +#if defined(YYCC_PTRSIZE_32) + EXPECT_EQ(rv.value(), u8"0x00000000"); +#else + EXPECT_EQ(rv.value(), u8"0x0000000000000000"); +#endif + } + +}