refactor: refactor old IOHelper.
- move pointer left padding macro into single header file. - move utf8 fopen into single header but not finished. - add testbench for pointer left padding macro. - add system pointer size detector according to new migrated features requested.
This commit is contained in:
@ -13,6 +13,7 @@ PRIVATE
|
|||||||
# Sources
|
# Sources
|
||||||
yycc/string/reinterpret.cpp
|
yycc/string/reinterpret.cpp
|
||||||
yycc/string/op.cpp
|
yycc/string/op.cpp
|
||||||
|
yycc/patch/fopen.cpp
|
||||||
yycc/rust/panic.cpp
|
yycc/rust/panic.cpp
|
||||||
yycc/encoding/stlcvt.cpp
|
yycc/encoding/stlcvt.cpp
|
||||||
yycc/encoding/windows.cpp
|
yycc/encoding/windows.cpp
|
||||||
@ -31,10 +32,13 @@ FILES
|
|||||||
yycc/macro/stl_detector.hpp
|
yycc/macro/stl_detector.hpp
|
||||||
yycc/macro/endian_detector.hpp
|
yycc/macro/endian_detector.hpp
|
||||||
yycc/macro/compiler_detector.hpp
|
yycc/macro/compiler_detector.hpp
|
||||||
|
yycc/macro/ptr_size_detector.hpp
|
||||||
yycc/macro/class_copy_move.hpp
|
yycc/macro/class_copy_move.hpp
|
||||||
yycc/flag_enum.hpp
|
yycc/flag_enum.hpp
|
||||||
yycc/string/reinterpret.hpp
|
yycc/string/reinterpret.hpp
|
||||||
yycc/string/op.hpp
|
yycc/string/op.hpp
|
||||||
|
yycc/patch/ptr_pad.hpp
|
||||||
|
yycc/patch/fopen.hpp
|
||||||
yycc/num/parse.hpp
|
yycc/num/parse.hpp
|
||||||
yycc/num/stringify.hpp
|
yycc/num/stringify.hpp
|
||||||
yycc/rust/prelude.hpp
|
yycc/rust/prelude.hpp
|
||||||
@ -85,6 +89,9 @@ PUBLIC
|
|||||||
# Endian macro
|
# Endian macro
|
||||||
$<$<STREQUAL:${CMAKE_CXX_BYTE_ORDER},LITTLE_ENDIAN>:YYCC_ENDIAN_LITTLE>
|
$<$<STREQUAL:${CMAKE_CXX_BYTE_ORDER},LITTLE_ENDIAN>:YYCC_ENDIAN_LITTLE>
|
||||||
$<$<STREQUAL:${CMAKE_CXX_BYTE_ORDER},BIG_ENDIAN>:YYCC_ENDIAN_BIG>
|
$<$<STREQUAL:${CMAKE_CXX_BYTE_ORDER},BIG_ENDIAN>:YYCC_ENDIAN_BIG>
|
||||||
|
# Pointer size macro
|
||||||
|
$<$<EQUAL:${CMAKE_SIZEOF_VOID_P},4>:YYCC_PTRSIZE_32>
|
||||||
|
$<$<EQUAL:${CMAKE_SIZEOF_VOID_P},8>:YYCC_PTRSIZE_64>
|
||||||
# Use Unicode charset on MSVC
|
# Use Unicode charset on MSVC
|
||||||
$<$<CXX_COMPILER_ID:MSVC>:UNICODE>
|
$<$<CXX_COMPILER_ID:MSVC>:UNICODE>
|
||||||
$<$<CXX_COMPILER_ID:MSVC>:_UNICODE>
|
$<$<CXX_COMPILER_ID:MSVC>:_UNICODE>
|
||||||
|
@ -1,73 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
Copyright (c) Microsoft Corporation, yyc12345.
|
|
||||||
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
-->
|
|
||||||
|
|
||||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
|
||||||
|
|
||||||
<!-- Following XML are copied from Visual Studio embedded Natvis files. -->
|
|
||||||
<!-- <Microsoft Visual Studio Install Directory>\Common7\Packages\Debugger\Visualizers\stl.natvis -->
|
|
||||||
|
|
||||||
<!-- VC 2013 -->
|
|
||||||
<Type Name="std::basic_string<YYCC::yycc_char8_t,*>" Priority="MediumLow">
|
|
||||||
<AlternativeType Name="std::basic_string<char8_t,*>" />
|
|
||||||
<AlternativeType Name="std::basic_string<unsigned char,*>" />
|
|
||||||
<DisplayString Condition="_Myres < _BUF_SIZE">{_Bx._Buf,s8}</DisplayString>
|
|
||||||
<DisplayString Condition="_Myres >= _BUF_SIZE">{_Bx._Ptr,s8}</DisplayString>
|
|
||||||
<StringView Condition="_Myres < _BUF_SIZE">_Bx._Buf,s8</StringView>
|
|
||||||
<StringView Condition="_Myres >= _BUF_SIZE">_Bx._Ptr,s8</StringView>
|
|
||||||
<Expand>
|
|
||||||
<Item Name="[size]" ExcludeView="simple">_Mysize</Item>
|
|
||||||
<Item Name="[capacity]" ExcludeView="simple">_Myres</Item>
|
|
||||||
<ArrayItems>
|
|
||||||
<Size>_Mysize</Size>
|
|
||||||
<ValuePointer Condition="_Myres < _BUF_SIZE">_Bx._Buf</ValuePointer>
|
|
||||||
<ValuePointer Condition="_Myres >= _BUF_SIZE">_Bx._Ptr</ValuePointer>
|
|
||||||
</ArrayItems>
|
|
||||||
</Expand>
|
|
||||||
</Type>
|
|
||||||
|
|
||||||
<!-- VC 2015+ ABI basic_string -->
|
|
||||||
<Type Name="std::basic_string<YYCC::yycc_char8_t,*>">
|
|
||||||
<AlternativeType Name="std::basic_string<char8_t,*>" />
|
|
||||||
<AlternativeType Name="std::basic_string<unsigned char,*>" />
|
|
||||||
<Intrinsic Name="size" Expression="_Mypair._Myval2._Mysize" />
|
|
||||||
<Intrinsic Name="capacity" Expression="_Mypair._Myval2._Myres" />
|
|
||||||
<!-- _BUF_SIZE = 16 / sizeof(char) < 1 ? 1 : 16 / sizeof(char) == 16 -->
|
|
||||||
<Intrinsic Name="bufSize" Expression="16" />
|
|
||||||
<Intrinsic Name="isShortString" Expression="capacity() < bufSize()" />
|
|
||||||
<Intrinsic Name="isLongString" Expression="capacity() >= bufSize()" />
|
|
||||||
<DisplayString Condition="isShortString()">{_Mypair._Myval2._Bx._Buf,s8}</DisplayString>
|
|
||||||
<DisplayString Condition="isLongString()">{_Mypair._Myval2._Bx._Ptr,s8}</DisplayString>
|
|
||||||
<StringView Condition="isShortString()">_Mypair._Myval2._Bx._Buf,s8</StringView>
|
|
||||||
<StringView Condition="isLongString()">_Mypair._Myval2._Bx._Ptr,s8</StringView>
|
|
||||||
<Expand>
|
|
||||||
<Item Name="[size]" ExcludeView="simple">size()</Item>
|
|
||||||
<Item Name="[capacity]" ExcludeView="simple">capacity()</Item>
|
|
||||||
<Item Name="[allocator]" ExcludeView="simple">_Mypair</Item>
|
|
||||||
<ArrayItems>
|
|
||||||
<Size>_Mypair._Myval2._Mysize</Size>
|
|
||||||
<ValuePointer Condition="isShortString()">_Mypair._Myval2._Bx._Buf</ValuePointer>
|
|
||||||
<ValuePointer Condition="isLongString()">_Mypair._Myval2._Bx._Ptr</ValuePointer>
|
|
||||||
</ArrayItems>
|
|
||||||
</Expand>
|
|
||||||
</Type>
|
|
||||||
|
|
||||||
<Type Name="std::basic_string_view<YYCC::yycc_char8_t,*>">
|
|
||||||
<AlternativeType Name="std::basic_string_view<char8_t,*>" />
|
|
||||||
<AlternativeType Name="std::basic_string_view<unsigned char,*>" />
|
|
||||||
<Intrinsic Name="size" Expression="_Mysize" />
|
|
||||||
<Intrinsic Name="data" Expression="_Mydata" />
|
|
||||||
<DisplayString>{_Mydata,[_Mysize],s8}</DisplayString>
|
|
||||||
<StringView>_Mydata,[_Mysize],s8</StringView>
|
|
||||||
<Expand>
|
|
||||||
<Item Name="[size]" ExcludeView="simple">size()</Item>
|
|
||||||
<ArrayItems>
|
|
||||||
<Size>size()</Size>
|
|
||||||
<ValuePointer>data()</ValuePointer>
|
|
||||||
</ArrayItems>
|
|
||||||
</Expand>
|
|
||||||
</Type>
|
|
||||||
|
|
||||||
</AutoVisualizer>
|
|
@ -1,182 +0,0 @@
|
|||||||
#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] 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<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 flag to mask given enum flag 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 multiple enum flags to given enum flag like performing <TT>e1 |= (e2 | e3 | ... | en)</TT>
|
|
||||||
* @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<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 multiple enum flags from given enum flag like performing <TT>e1 &= ~(e2 | e3 | ... | en)</TT>
|
|
||||||
* @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<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 flag has any of specified multiple enum flags (OR) like performing <TT>bool(e1 & (e2 | e3 | ... | en))</TT>
|
|
||||||
* @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<typename TEnum, typename... Ts, std::enable_if_t<std::is_enum_v<TEnum>, int> = 0>
|
|
||||||
constexpr bool Has(TEnum e1, Ts... vals) {
|
|
||||||
using ut = std::underlying_type_t<TEnum>;
|
|
||||||
return static_cast<bool>(static_cast<ut>(e1) & static_cast<ut>(Merge(vals...)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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 equvalent bool value of given 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,23 +11,6 @@
|
|||||||
*/
|
*/
|
||||||
namespace YYCC::IOHelper {
|
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*
|
/// @brief C++ standard deleter for std::FILE*
|
||||||
class StdFileDeleter {
|
class StdFileDeleter {
|
||||||
public:
|
public:
|
||||||
|
@ -1,221 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "YYCCInternal.hpp"
|
|
||||||
|
|
||||||
#include "EncodingHelper.hpp"
|
|
||||||
#include "StringHelper.hpp"
|
|
||||||
#include <string>
|
|
||||||
#include <cinttypes>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <charconv>
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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<typename _Ty, std::enable_if_t<std::is_floating_point_v<_Ty>, 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<typename _Ty, std::enable_if_t<std::is_integral_v<_Ty> && !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<typename _Ty, std::enable_if_t<std::is_same_v<_Ty, bool>, 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<typename _Ty, std::enable_if_t<std::is_floating_point_v<_Ty>, 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<typename _Ty, std::enable_if_t<std::is_integral_v<_Ty> && !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<typename _Ty, std::enable_if_t<std::is_same_v<_Ty, bool>, 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<typename _Ty, std::enable_if_t<std::is_floating_point_v<_Ty>, 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<yycc_char8_t, 64> 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<typename _Ty, std::enable_if_t<std::is_integral_v<_Ty> && !std::is_same_v<_Ty, bool>, int> = 0>
|
|
||||||
yycc_u8string ToString(_Ty num, int base = 10) {
|
|
||||||
std::array<yycc_char8_t, 64> 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<typename _Ty, std::enable_if_t<std::is_same_v<_Ty, bool>, int> = 0>
|
|
||||||
yycc_u8string ToString(_Ty num) {
|
|
||||||
if (num) return yycc_u8string(YYCC_U8("true"));
|
|
||||||
else return yycc_u8string(YYCC_U8("false"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
10
src/yycc.hpp
10
src/yycc.hpp
@ -8,9 +8,8 @@
|
|||||||
* They are crucial before using YYCC.
|
* They are crucial before using YYCC.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Library Version and Comparison Macros
|
// Library version
|
||||||
#include "yycc/version.hpp"
|
#include "yycc/version.hpp"
|
||||||
#include "yycc/macro/version_cmp.hpp"
|
|
||||||
|
|
||||||
// Detect essential macros
|
// Detect essential macros
|
||||||
// Operating System macros
|
// Operating System macros
|
||||||
@ -19,8 +18,9 @@
|
|||||||
#include "yycc/macro/compiler_detector.hpp"
|
#include "yycc/macro/compiler_detector.hpp"
|
||||||
// Endian macros
|
// Endian macros
|
||||||
#include "yycc/macro/endian_detector.hpp"
|
#include "yycc/macro/endian_detector.hpp"
|
||||||
|
// Pointer size macros
|
||||||
// Batch Class Move / Copy Function Macros
|
#include "yycc/macro/ptr_size_detector.hpp"
|
||||||
#include "yycc/macro/class_copy_move.hpp"
|
// STL macros
|
||||||
|
#include "yycc/macro/stl_detector.hpp"
|
||||||
|
|
||||||
namespace yycc {}
|
namespace yycc {}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Check OS macro
|
// 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!"
|
#error "Current operating system is not supported!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -11,6 +11,7 @@ namespace yycc::macro::os {
|
|||||||
enum class OsKind {
|
enum class OsKind {
|
||||||
Windows, ///< Microsoft Windows
|
Windows, ///< Microsoft Windows
|
||||||
Linux, ///< GNU/Linux
|
Linux, ///< GNU/Linux
|
||||||
|
MacOs, ///< Apple macOS
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -20,8 +21,10 @@ namespace yycc::macro::os {
|
|||||||
inline constexpr OsKind get_os() {
|
inline constexpr OsKind get_os() {
|
||||||
#if defined(YYCC_OS_WINDOWS)
|
#if defined(YYCC_OS_WINDOWS)
|
||||||
return OsKind::Windows;
|
return OsKind::Windows;
|
||||||
#else
|
#elif defined(YYCC_OS_LINUX)
|
||||||
return OsKind::Linux;
|
return OsKind::Linux;
|
||||||
|
#else
|
||||||
|
return OsKind::MacOs;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
6
src/yycc/macro/ptr_size_detector.hpp
Normal file
6
src/yycc/macro/ptr_size_detector.hpp
Normal file
@ -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
|
35
src/yycc/patch/fopen.cpp
Normal file
35
src/yycc/patch/fopen.cpp
Normal file
@ -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 <Windows.h>
|
||||||
|
#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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
30
src/yycc/patch/fopen.hpp
Normal file
30
src/yycc/patch/fopen.hpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
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<std::FILE, StdFileDeleter>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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);
|
||||||
|
|
||||||
|
}
|
20
src/yycc/patch/ptr_pad.hpp
Normal file
20
src/yycc/patch/ptr_pad.hpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../macro/ptr_size_detector.hpp"
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
@ -5,5 +5,5 @@
|
|||||||
// YYC MARK:
|
// YYC MARK:
|
||||||
// Since YYCC 2.0 version, we use CMake to handle Windows shitty macros,
|
// 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.
|
// 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.
|
// although it do nothing.
|
||||||
|
@ -6,11 +6,11 @@
|
|||||||
|
|
||||||
#if defined(YYCC_OS_WINDOWS)
|
#if defined(YYCC_OS_WINDOWS)
|
||||||
|
|
||||||
// Windows also will generate following macros
|
// Windows also will generate following macros which may cause
|
||||||
// which may cause the function sign is different in Windows and other platforms.
|
// the function sign is different in Windows and other platforms.
|
||||||
// So we simply remove them.
|
// So we simply remove them.
|
||||||
// Because #undef will not throw error if there are no matched macro,
|
// At the same time, because `#undef` will not throw error if there are no matched macro,
|
||||||
// so we simply #undef them directly.
|
// we can simply use `#undef` to remove them directly.
|
||||||
#undef GetObject
|
#undef GetObject
|
||||||
#undef GetClassName
|
#undef GetClassName
|
||||||
#undef LoadImage
|
#undef LoadImage
|
||||||
|
@ -8,6 +8,7 @@ PRIVATE
|
|||||||
yycc/flag_enum.cpp
|
yycc/flag_enum.cpp
|
||||||
yycc/constraint.cpp
|
yycc/constraint.cpp
|
||||||
yycc/constraint/builder.cpp
|
yycc/constraint/builder.cpp
|
||||||
|
yycc/patch/ptr_pad.cpp
|
||||||
yycc/string/op.cpp
|
yycc/string/op.cpp
|
||||||
yycc/string/reinterpret.cpp
|
yycc/string/reinterpret.cpp
|
||||||
yycc/num/parse.cpp
|
yycc/num/parse.cpp
|
||||||
|
22
testbench/yycc/patch/ptr_pad.cpp
Normal file
22
testbench/yycc/patch/ptr_pad.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <yycc.hpp>
|
||||||
|
#include <yycc/string/op.hpp>
|
||||||
|
#include <yycc/patch/ptr_pad.hpp>
|
||||||
|
#include <cinttypes>
|
||||||
|
|
||||||
|
#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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user