refactor: update C++ from 17 to 23
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,6 +1,6 @@
|
||||
# -------------------- Output --------------------
|
||||
out/
|
||||
src/YYCC/YYCCVersion.hpp
|
||||
src/yycc/version.hpp
|
||||
CMakeSettings.json
|
||||
|
||||
# -------------------- VSCode --------------------
|
||||
|
@ -4,11 +4,15 @@ project(YYCC
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
||||
# Setup C++ standard
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
# Provide options
|
||||
option(YYCC_BUILD_TESTBENCH "Build testbench of YYCCommonplace." OFF)
|
||||
option(YYCC_BUILD_DOC "Build document of YYCCommonplace." OFF)
|
||||
option(YYCC_ENFORCE_ICONV "Enforce iconv support for this library (e.g. in MSYS2 environment)." OFF)
|
||||
option(YYCC_DEBUG_UE_FILTER "YYCC developer used switch for testing Windows unhandled exception filter. Should not set to ON!!!" OFF)
|
||||
|
||||
# Setup install path from CMake provided install path for convenient use.
|
||||
include(GNUInstallDirs)
|
||||
|
@ -14,24 +14,10 @@ PRIVATE
|
||||
yycc/string/reinterpret.cpp
|
||||
yycc/string/op.cpp
|
||||
yycc/rust/panic.cpp
|
||||
yycc/patch/path.cpp
|
||||
yycc/encoding/stlcvt.cpp
|
||||
yycc/encoding/windows.cpp
|
||||
yycc/encoding/iconv.cpp
|
||||
yycc/encoding/pycodec.cpp
|
||||
# YYCC/COMHelper.cpp
|
||||
# YYCC/ArgParser.cpp
|
||||
# YYCC/ConfigManager.cpp
|
||||
# YYCC/ConsoleHelper.cpp
|
||||
# YYCC/DialogHelper.cpp
|
||||
# YYCC/EncodingHelper.cpp
|
||||
# YYCC/ExceptionHelper.cpp
|
||||
# YYCC/StdPatch.cpp
|
||||
# YYCC/IOHelper.cpp
|
||||
# YYCC/StringHelper.cpp
|
||||
# YYCC/WinFctHelper.cpp
|
||||
# # Natvis (only for MSVC)
|
||||
# $<$<CXX_COMPILER_ID:MSVC>:YYCC.natvis>
|
||||
)
|
||||
target_sources(YYCCommonplace
|
||||
PUBLIC
|
||||
@ -40,63 +26,29 @@ FILES
|
||||
# Headers
|
||||
yycc.hpp
|
||||
yycc/version.hpp
|
||||
yycc/primitive.hpp
|
||||
yycc/prelude/core.hpp
|
||||
yycc/prelude/rust.hpp
|
||||
yycc/macro/version_cmp.hpp
|
||||
yycc/macro/feature_probe.hpp
|
||||
yycc/macro/os_detector.hpp
|
||||
yycc/macro/endian_detector.hpp
|
||||
yycc/macro/compiler_detector.hpp
|
||||
yycc/macro/class_copy_move.hpp
|
||||
yycc/string.hpp
|
||||
yycc/string/reinterpret.hpp
|
||||
yycc/string/op.hpp
|
||||
yycc/num/parse.hpp
|
||||
yycc/num/stringify.hpp
|
||||
yycc/rust/primitive.hpp
|
||||
yycc/rust/panic.hpp
|
||||
yycc/rust/option.hpp
|
||||
yycc/rust/result.hpp
|
||||
yycc/rust/num/parse.hpp
|
||||
yycc/rust/num/stringify.hpp
|
||||
yycc/windows/unsafe_suppressor.hpp
|
||||
yycc/windows/import_guard_head.hpp
|
||||
yycc/windows/import_guard_tail.hpp
|
||||
yycc/constraint.hpp
|
||||
yycc/constraint/builder.hpp
|
||||
yycc/patch/path.hpp
|
||||
yycc/patch/contains.hpp
|
||||
yycc/patch/starts_ends_with.hpp
|
||||
yycc/patch/expected.hpp
|
||||
yycc/encoding/stlcvt.hpp
|
||||
yycc/encoding/windows.hpp
|
||||
yycc/encoding/iconv.hpp
|
||||
yycc/encoding/pycodec.hpp
|
||||
|
||||
# # Headers
|
||||
# # Common headers
|
||||
# YYCC/Constraints.hpp
|
||||
# YYCC/COMHelper.hpp
|
||||
# YYCC/ArgParser.hpp
|
||||
# YYCC/ConfigManager.hpp
|
||||
# YYCC/ConsoleHelper.hpp
|
||||
# YYCC/DialogHelper.hpp
|
||||
# YYCC/EncodingHelper.hpp
|
||||
# YYCC/EnumHelper.hpp
|
||||
# YYCC/ExceptionHelper.hpp
|
||||
# YYCC/StdPatch.hpp
|
||||
# YYCC/IOHelper.hpp
|
||||
# YYCC/ParserHelper.hpp
|
||||
# YYCC/StringHelper.hpp
|
||||
# YYCC/WinFctHelper.hpp
|
||||
# # Windows including guard pair
|
||||
# YYCC/WinImportPrefix.hpp
|
||||
# YYCC/WinImportSuffix.hpp
|
||||
# # Internal
|
||||
# YYCC/YYCCVersion.hpp
|
||||
# YYCC/YYCCInternal.hpp
|
||||
# # Exposed
|
||||
# YYCCommonplace.hpp
|
||||
)
|
||||
# Setup header infomations
|
||||
target_include_directories(YYCCommonplace
|
||||
@ -116,14 +68,9 @@ target_link_libraries(YYCCommonplace
|
||||
PRIVATE
|
||||
$<$<BOOL:${WIN32}>:DbgHelp.lib>
|
||||
)
|
||||
# Setup C++ standard
|
||||
target_compile_features(YYCCommonplace PUBLIC cxx_std_17)
|
||||
set_target_properties(YYCCommonplace PROPERTIES CXX_EXTENSION OFF)
|
||||
# Setup macros
|
||||
target_compile_definitions(YYCCommonplace
|
||||
PUBLIC
|
||||
# Debug macro. And it should populate to child projects
|
||||
$<$<BOOL:${YYCC_DEBUG_UE_FILTER}>:YYCC_DEBUG_UE_FILTER>
|
||||
# Iconv environment macro
|
||||
$<$<BOOL:${YYCC_ENFORCE_ICONV}>:YYCC_FEAT_ICONV>
|
||||
# OS macro
|
||||
@ -136,14 +83,21 @@ PUBLIC
|
||||
# Endian macro
|
||||
$<$<STREQUAL:${CMAKE_CXX_BYTE_ORDER},LITTLE_ENDIAN>:YYCC_ENDIAN_LITTLE>
|
||||
$<$<STREQUAL:${CMAKE_CXX_BYTE_ORDER},BIG_ENDIAN>:YYCC_ENDIAN_BIG>
|
||||
PRIVATE
|
||||
# Unicode charset for private using
|
||||
# Use Unicode charset on MSVC
|
||||
$<$<CXX_COMPILER_ID:MSVC>:UNICODE>
|
||||
$<$<CXX_COMPILER_ID:MSVC>:_UNICODE>
|
||||
# Fix MSVC shit
|
||||
$<$<CXX_COMPILER_ID:MSVC>:_CRT_SECURE_NO_WARNINGS>
|
||||
$<$<CXX_COMPILER_ID:MSVC>:_CRT_SECURE_NO_DEPRECATE>
|
||||
$<$<CXX_COMPILER_ID:MSVC>:_CRT_NONSTDC_NO_WARNINGS>
|
||||
$<$<CXX_COMPILER_ID:MSVC>:_CRT_NONSTDC_NO_DEPRECATE>
|
||||
# Fix Windows header file shit
|
||||
$<$<BOOL:${WIN32}>:WIN32_LEAN_AND_MEAN>
|
||||
$<$<BOOL:${WIN32}>:NOMINMAX>
|
||||
)
|
||||
target_compile_options(YYCCommonplace
|
||||
# Order build as UTF-8 in MSVC
|
||||
PRIVATE
|
||||
PUBLIC
|
||||
# Order build as UTF-8 in MSVC
|
||||
$<$<CXX_COMPILER_ID:MSVC>:/utf-8>
|
||||
)
|
||||
|
||||
|
10
src/yycc.hpp
10
src/yycc.hpp
@ -4,11 +4,13 @@
|
||||
#include "yycc/version.hpp"
|
||||
#include "yycc/macro/version_cmp.hpp"
|
||||
|
||||
// Operating System Identifier Macros
|
||||
// Detect essential macros
|
||||
// Operating System macros
|
||||
#include "yycc/macro/os_detector.hpp"
|
||||
|
||||
// Windows Shitty Behavior Disable Macros
|
||||
#include "yycc/windows/unsafe_suppressor.hpp"
|
||||
// Compiler macros
|
||||
#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"
|
||||
|
@ -1,10 +1,7 @@
|
||||
#pragma once
|
||||
#include "../constraint.hpp"
|
||||
#include "../string.hpp"
|
||||
#include <set>
|
||||
|
||||
#define NS_YYCC_STRING ::yycc::string
|
||||
|
||||
/// @brief The namespace containing convenient function building common used Constraint instance.
|
||||
namespace yycc::constraint::builder {
|
||||
|
||||
@ -15,18 +12,12 @@ namespace yycc::constraint::builder {
|
||||
* @param[in] max_value The maximum value of range (inclusive).
|
||||
* @return The generated constraint instance which can be directly applied.
|
||||
*/
|
||||
template<typename T,
|
||||
std::enable_if_t<std::is_arithmetic_v<T> && !std::is_same_v<T, bool>, int> = 0>
|
||||
template<typename T, std::enable_if_t<std::is_arithmetic_v<T> && !std::is_same_v<T, bool>, int> = 0>
|
||||
Constraint<T> min_max_constraint(T min_value, T max_value) {
|
||||
if (min_value > max_value)
|
||||
throw std::invalid_argument("the max value must be equal or greater than min value");
|
||||
if (min_value > max_value) throw std::invalid_argument("the max value must be equal or greater than min value");
|
||||
|
||||
auto fn_check = [min_value, max_value](const T& val) -> bool {
|
||||
return (val <= max_value) && (val >= min_value);
|
||||
};
|
||||
auto fn_clamp = [min_value, max_value](const T& val) -> T {
|
||||
return std::clamp(val, min_value, max_value);
|
||||
};
|
||||
auto fn_check = [min_value, max_value](const T& val) -> bool { return (val <= max_value) && (val >= min_value); };
|
||||
auto fn_clamp = [min_value, max_value](const T& val) -> T { return std::clamp(val, min_value, max_value); };
|
||||
return Constraint<T>(std::move(fn_check), std::move(fn_clamp));
|
||||
}
|
||||
|
||||
@ -39,16 +30,13 @@ namespace yycc::constraint::builder {
|
||||
*/
|
||||
template<typename T, std::enable_if_t<std::is_enum_v<T>, int> = 0>
|
||||
Constraint<T> enum_constraint(const std::initializer_list<T>& il, size_t default_index = 0u) {
|
||||
if (default_index >= il.size())
|
||||
throw std::invalid_argument("the default index must be a valid index in given list");
|
||||
if (default_index >= il.size()) throw std::invalid_argument("the default index must be a valid index in given list");
|
||||
|
||||
T default_entry = il.begin()[default_index];
|
||||
std::set<T> entries(il);
|
||||
|
||||
// TODO: modify it as `contain` once we finish patch namespace.
|
||||
auto fn_check = [entries](const T& val) -> bool {
|
||||
return entries.find(val) != entries.end();
|
||||
};
|
||||
auto fn_check = [entries](const T& val) -> bool { return entries.find(val) != entries.end(); };
|
||||
auto fn_clamp = [entries, default_entry](const T& val) -> T {
|
||||
if (entries.find(val) != entries.end()) {
|
||||
return val;
|
||||
@ -65,30 +53,21 @@ namespace yycc::constraint::builder {
|
||||
* @param[in] default_index The index of default value in given list.
|
||||
* @return The generated constraint instance which can be directly applied.
|
||||
*/
|
||||
inline Constraint<NS_YYCC_STRING::u8string> strenum_constraint(
|
||||
const std::initializer_list<NS_YYCC_STRING::u8string_view>& il, size_t default_index = 0u) {
|
||||
if (default_index >= il.size())
|
||||
throw std::invalid_argument("the default index must be a valid index in given list");
|
||||
inline Constraint<std::u8string> strenum_constraint(const std::initializer_list<std::u8string_view>& il, size_t default_index = 0u) {
|
||||
if (default_index >= il.size()) throw std::invalid_argument("the default index must be a valid index in given list");
|
||||
|
||||
NS_YYCC_STRING::u8string default_entry = NS_YYCC_STRING::u8string(il.begin()[default_index]);
|
||||
std::set<NS_YYCC_STRING::u8string> entries;
|
||||
std::u8string default_entry = std::u8string(il.begin()[default_index]);
|
||||
std::set<std::u8string> entries;
|
||||
for (const auto& i : il) {
|
||||
entries.emplace(i);
|
||||
}
|
||||
|
||||
// TODO: modify it as `contain` once we finish patch namespace.
|
||||
auto fn_check = [entries](const NS_YYCC_STRING::u8string& val) -> bool {
|
||||
return entries.find(val) != entries.end();
|
||||
auto fn_check = [entries](const std::u8string& val) -> bool { return entries.contains(val); };
|
||||
auto fn_clamp = [entries, default_entry](const std::u8string& val) -> std::u8string {
|
||||
if (entries.contains(val)) return val;
|
||||
else return default_entry;
|
||||
};
|
||||
auto fn_clamp = [entries, default_entry](
|
||||
const NS_YYCC_STRING::u8string& val) -> NS_YYCC_STRING::u8string {
|
||||
if (entries.find(val) != entries.end()) {
|
||||
return val;
|
||||
} else {
|
||||
return default_entry;
|
||||
}
|
||||
};
|
||||
return Constraint<NS_YYCC_STRING::u8string>(std::move(fn_check), fn_clamp);
|
||||
return Constraint<std::u8string>(std::move(fn_check), fn_clamp);
|
||||
}
|
||||
|
||||
} // namespace yycc::constraint::builder
|
||||
|
@ -1,54 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Hint for C++ feature detection:
|
||||
// __cplusplus macro need special compiler switch enabled when compiling.
|
||||
// So we use _MSVC_LANG check it instead.
|
||||
|
||||
// ===== C++ Version =====
|
||||
|
||||
// Detect C++ 20
|
||||
#if __cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
|
||||
#define YYCC_CPPFEAT_GE_CPP20
|
||||
#endif
|
||||
|
||||
// Detect C++ 23
|
||||
#if __cplusplus >= 202302L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202302L)
|
||||
#define YYCC_CPPFEAT_GE_CPP23
|
||||
#endif
|
||||
|
||||
// ===== C++ Features =====
|
||||
|
||||
// Check whether there is support of UTF8 string system.
|
||||
#if defined(__cpp_char8_t) || defined(YYCC_CPPFEAT_GE_CPP20)
|
||||
#define YYCC_CPPFEAT_UTF8
|
||||
#endif
|
||||
|
||||
// Check whether there is support of `contains` for `set` and `map` including their varients.
|
||||
#if defined(YYCC_CPPFEAT_GE_CPP20)
|
||||
#define YYCC_CPPFEAT_CONTAINS
|
||||
#endif
|
||||
|
||||
// Check whether there is support of `starts_with` and `ends_with` for `basic_string`.
|
||||
#if defined(__cpp_lib_starts_ends_with) || defined(YYCC_CPPFEAT_GE_CPP20)
|
||||
#define YYCC_CPPFEAT_STARTS_ENDS_WITH
|
||||
#endif
|
||||
|
||||
// Check whether there is support of `std::expected`.
|
||||
#if defined(__cpp_lib_expected) || defined(YYCC_CPPFEAT_GE_CPP23)
|
||||
#define YYCC_CPPFEAT_EXPECTED
|
||||
#endif
|
||||
|
||||
// Check whether there is support of `std::format`.
|
||||
#if defined(YYCC_CPPFEAT_GE_CPP20)
|
||||
#define YYCC_CPPFEAT_FORMAT
|
||||
#endif
|
||||
|
||||
// Check whether there is support of `__VA_OPT__`
|
||||
#if defined(YYCC_CPPFEAT_GE_CPP20)
|
||||
#define YYCC_CPPFEAT_VA_OPT
|
||||
#endif
|
||||
|
||||
// Check whether there is support of `std::stacktrace` and its formatter.
|
||||
#if (defined(__cpp_lib_starts_ends_with) && defined(__cpp_lib_formatters)) || defined(YYCC_CPPFEAT_GE_CPP23)
|
||||
#define YYCC_CPPFEAT_STACKTRACE
|
||||
#endif
|
@ -1,15 +1,14 @@
|
||||
#pragma once
|
||||
#include "../patch/expected.hpp"
|
||||
#include "../string.hpp"
|
||||
#include "../string/op.hpp"
|
||||
#include "../string/reinterpret.hpp"
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <charconv>
|
||||
#include <stdexcept>
|
||||
#include <expected>
|
||||
|
||||
#define NS_YYCC_STRING ::yycc::string
|
||||
#define NS_YYCC_STRING_REINTERPRET ::yycc::string::reinterpret
|
||||
#define NS_YYCC_STRING_OP ::yycc::string::op
|
||||
#define NS_YYCC_PATCH_EXPECTED ::yycc::patch::expected
|
||||
|
||||
/**
|
||||
* @brief Provides string parsing utilities for converting strings to numeric and boolean values.
|
||||
@ -20,18 +19,16 @@
|
||||
*/
|
||||
namespace yycc::num::parse {
|
||||
|
||||
/// @private
|
||||
/// @brief The error kind when parsing string into number.
|
||||
enum class ParseError {
|
||||
PartiallyParsed, ///< Only a part of given string was parsed. The whole string may be invalid.
|
||||
InvalidString, ///< Given string is a invalid number string.
|
||||
OutOfRange, ///< Given string is valid but its value out of the range of given number type.
|
||||
OutOfRange, ///< Given string is valid but its value out of the range of given number type.
|
||||
};
|
||||
|
||||
/// @private
|
||||
/// @brief The return value of internal parse function which ape `std::expected`.
|
||||
template<typename T>
|
||||
using ParseResult = NS_YYCC_PATCH_EXPECTED::Expected<T, ParseError>;
|
||||
using ParseResult = std::expected<T, ParseError>;
|
||||
|
||||
/**
|
||||
* @private
|
||||
@ -41,8 +38,9 @@ namespace yycc::num::parse {
|
||||
* @param fmt The floating point format to use
|
||||
* @return ParseResult<T> containing either the parsed value or a ParseError
|
||||
*/
|
||||
template<typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
|
||||
ParseResult<T> priv_parse(const NS_YYCC_STRING::u8string_view& strl, std::chars_format fmt) {
|
||||
template<typename T>
|
||||
requires(std::is_floating_point_v<T>)
|
||||
ParseResult<T> parse(const std::u8string_view& strl, std::chars_format fmt) {
|
||||
namespace reinterpret = NS_YYCC_STRING_REINTERPRET;
|
||||
|
||||
T rv;
|
||||
@ -54,13 +52,13 @@ namespace yycc::num::parse {
|
||||
// Parse completely.
|
||||
// But we need to check whether the whole string was parsed.
|
||||
if (ptr == tail) return rv;
|
||||
else return ParseError::PartiallyParsed;
|
||||
else return std::unexpected(ParseError::PartiallyParsed);
|
||||
} else if (ec == std::errc::invalid_argument) {
|
||||
// Given string is invalid
|
||||
return ParseError::InvalidString;
|
||||
return std::unexpected(ParseError::InvalidString);
|
||||
} else if (ec == std::errc::result_out_of_range) {
|
||||
// Given string is out of range
|
||||
return ParseError::OutOfRange;
|
||||
return std::unexpected(ParseError::OutOfRange);
|
||||
} else {
|
||||
// Unreachable
|
||||
throw std::runtime_error("invalid ec.");
|
||||
@ -75,8 +73,9 @@ namespace yycc::num::parse {
|
||||
* @param base Numeric base (2-36)
|
||||
* @return ParseResult<T> containing either the parsed value or a ParseError
|
||||
*/
|
||||
template<typename T, std::enable_if_t<std::is_integral_v<T> && !std::is_same_v<T, bool>, int> = 0>
|
||||
ParseResult<T> priv_parse(const NS_YYCC_STRING::u8string_view& strl, int base) {
|
||||
template<typename T>
|
||||
requires(std::is_integral_v<T> && !std::is_same_v<T, bool>)
|
||||
ParseResult<T> parse(const std::u8string_view& strl, int base) {
|
||||
namespace reinterpret = NS_YYCC_STRING_REINTERPRET;
|
||||
|
||||
T rv;
|
||||
@ -88,13 +87,13 @@ namespace yycc::num::parse {
|
||||
// Parse completely.
|
||||
// But we need to check whether the whole string was parsed.
|
||||
if (ptr == tail) return rv;
|
||||
else return ParseError::PartiallyParsed;
|
||||
else return std::unexpected(ParseError::PartiallyParsed);
|
||||
} else if (ec == std::errc::invalid_argument) {
|
||||
// Given string is invalid
|
||||
return ParseError::InvalidString;
|
||||
return std::unexpected(ParseError::InvalidString);
|
||||
} else if (ec == std::errc::result_out_of_range) {
|
||||
// Given string is out of range
|
||||
return ParseError::OutOfRange;
|
||||
return std::unexpected(ParseError::OutOfRange);
|
||||
} else {
|
||||
// Unreachable
|
||||
throw std::runtime_error("invalid ec.");
|
||||
@ -108,139 +107,18 @@ namespace yycc::num::parse {
|
||||
* @param strl The UTF-8 string view to parse ("true" or "false", case insensitive)
|
||||
* @return ParseResult<bool> containing either the parsed value or a ParseError
|
||||
*/
|
||||
template<typename T, std::enable_if_t<std::is_same_v<T, bool>, int> = 0>
|
||||
ParseResult<T> priv_parse(const NS_YYCC_STRING::u8string_view& strl) {
|
||||
template<typename T>
|
||||
requires(std::is_same_v<T, bool>)
|
||||
ParseResult<T> parse(const std::u8string_view& strl) {
|
||||
// Get lower case
|
||||
auto lower_case = NS_YYCC_STRING_OP::to_lower(strl);
|
||||
// Compare result
|
||||
if (lower_case == YYCC_U8("true")) return true;
|
||||
else if (lower_case == YYCC_U8("false")) return false;
|
||||
if (lower_case == u8"true") return true;
|
||||
else if (lower_case == u8"false") return false;
|
||||
else return ParseError::InvalidString;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Try parsing given string to floating point types.
|
||||
* @tparam T 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 T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
|
||||
bool try_parse(const NS_YYCC_STRING::u8string_view& strl,
|
||||
T& num,
|
||||
std::chars_format fmt = std::chars_format::general) {
|
||||
namespace expected = NS_YYCC_PATCH_EXPECTED;
|
||||
|
||||
auto rv = priv_parse<T>(strl, fmt);
|
||||
if (expected::is_value(rv)) {
|
||||
num = expected::get_value(rv);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Try parsing given string to integral types.
|
||||
* @tparam T 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 T, std::enable_if_t<std::is_integral_v<T> && !std::is_same_v<T, bool>, int> = 0>
|
||||
bool try_parse(const NS_YYCC_STRING::u8string_view& strl, T& num, int base = 10) {
|
||||
namespace expected = NS_YYCC_PATCH_EXPECTED;
|
||||
|
||||
auto rv = priv_parse<T>(strl, base);
|
||||
if (expected::is_value(rv)) {
|
||||
num = expected::get_value(rv);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Try parsing given string to bool types.
|
||||
* @tparam T 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 T, std::enable_if_t<std::is_same_v<T, bool>, int> = 0>
|
||||
bool try_parse(const NS_YYCC_STRING::u8string_view& strl, T& num) {
|
||||
namespace expected = NS_YYCC_PATCH_EXPECTED;
|
||||
|
||||
auto rv = priv_parse<T>(strl);
|
||||
if (expected::is_value(rv)) {
|
||||
num = expected::get_value(rv);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parse given string to floating point types.
|
||||
* @tparam T 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.
|
||||
* @exception std::invalid_argument Can not parse given string.
|
||||
*/
|
||||
template<typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
|
||||
T parse(const NS_YYCC_STRING::u8string_view& strl,
|
||||
std::chars_format fmt = std::chars_format::general) {
|
||||
T rv;
|
||||
if (try_parse(strl, rv, fmt)) return rv;
|
||||
else throw std::invalid_argument("can not parse given string");
|
||||
}
|
||||
/**
|
||||
* @brief Parse given string to integral type types.
|
||||
* @tparam T 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.
|
||||
* @exception std::invalid_argument Can not parse given string.
|
||||
*/
|
||||
template<typename T, std::enable_if_t<std::is_integral_v<T> && !std::is_same_v<T, bool>, int> = 0>
|
||||
T parse(const NS_YYCC_STRING::u8string_view& strl, int base = 10) {
|
||||
T rv;
|
||||
if (try_parse(strl, rv, base)) return rv;
|
||||
else throw std::invalid_argument("can not parse given string");
|
||||
}
|
||||
/**
|
||||
* @brief Parse given string to bool types.
|
||||
* @tparam T 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.
|
||||
* @exception std::invalid_argument Can not parse given string.
|
||||
*/
|
||||
template<typename T, std::enable_if_t<std::is_same_v<T, bool>, int> = 0>
|
||||
T parse(const NS_YYCC_STRING::u8string_view& strl) {
|
||||
T rv;
|
||||
if (try_parse(strl, rv)) return rv;
|
||||
else throw std::invalid_argument("can not parse given string");
|
||||
}
|
||||
|
||||
} // namespace yycc::num::parse
|
||||
|
||||
#undef NS_YYCC_PATCH_EXPECTED
|
||||
#undef NS_YYCC_STRING_OP
|
||||
#undef NS_YYCC_STRING_REINTERPRET
|
||||
#undef NS_YYCC_STRING
|
||||
|
@ -1,12 +1,11 @@
|
||||
#pragma once
|
||||
#include "../string.hpp"
|
||||
#include "../string/reinterpret.hpp"
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include <type_traits>
|
||||
#include <charconv>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
|
||||
#define NS_YYCC_STRING ::yycc::string
|
||||
#define NS_YYCC_STRING_REINTERPRET ::yycc::string::reinterpret
|
||||
|
||||
/**
|
||||
@ -25,7 +24,7 @@ namespace yycc::num::stringify {
|
||||
inline constexpr size_t STRINGIFY_BUFFER_SIZE = 64u;
|
||||
/// @private
|
||||
/// @brief Type alias for the buffer used in string conversion.
|
||||
using StringifyBuffer = std::array<NS_YYCC_STRING::u8char, STRINGIFY_BUFFER_SIZE>;
|
||||
using StringifyBuffer = std::array<char8_t, STRINGIFY_BUFFER_SIZE>;
|
||||
|
||||
/**
|
||||
* @brief Return the string representation of given floating point value.
|
||||
@ -35,10 +34,9 @@ namespace yycc::num::stringify {
|
||||
* @param[in] precision The floating point precision used when getting string representation.
|
||||
* @return The string representation of given value.
|
||||
*/
|
||||
template<typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
|
||||
NS_YYCC_STRING::u8string stringify(T num,
|
||||
std::chars_format fmt = std::chars_format::general,
|
||||
int precision = 6) {
|
||||
template<typename T>
|
||||
requires(std::is_floating_point_v<T>)
|
||||
std::u8string stringify(T num, std::chars_format fmt = std::chars_format::general, int precision = 6) {
|
||||
namespace reinterpret = NS_YYCC_STRING_REINTERPRET;
|
||||
|
||||
StringifyBuffer buffer;
|
||||
@ -48,8 +46,7 @@ namespace yycc::num::stringify {
|
||||
fmt,
|
||||
precision);
|
||||
if (ec == std::errc()) {
|
||||
return NS_YYCC_STRING::u8string(buffer.data(),
|
||||
reinterpret::as_utf8(ptr) - buffer.data());
|
||||
return std::u8string(buffer.data(), reinterpret::as_utf8(ptr) - buffer.data());
|
||||
} else if (ec == std::errc::value_too_large) {
|
||||
// Too short buffer. This should not happen.
|
||||
throw std::out_of_range("stringify() buffer is not sufficient.");
|
||||
@ -65,18 +62,18 @@ namespace yycc::num::stringify {
|
||||
* @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 T, std::enable_if_t<std::is_integral_v<T> && !std::is_same_v<T, bool>, int> = 0>
|
||||
NS_YYCC_STRING::u8string stringify(T num, int base = 10) {
|
||||
template<typename T>
|
||||
requires(std::is_integral_v<T> && !std::is_same_v<T, bool>)
|
||||
std::u8string stringify(T num, int base = 10) {
|
||||
namespace reinterpret = NS_YYCC_STRING_REINTERPRET;
|
||||
|
||||
|
||||
StringifyBuffer buffer;
|
||||
auto [ptr, ec] = std::to_chars(reinterpret::as_ordinary(buffer.data()),
|
||||
reinterpret::as_ordinary(buffer.data() + buffer.size()),
|
||||
num,
|
||||
base);
|
||||
if (ec == std::errc()) {
|
||||
return NS_YYCC_STRING::u8string(buffer.data(),
|
||||
reinterpret::as_utf8(ptr) - buffer.data());
|
||||
return std::u8string(buffer.data(), reinterpret::as_utf8(ptr) - buffer.data());
|
||||
} else if (ec == std::errc::value_too_large) {
|
||||
// Too short buffer. This should not happen.
|
||||
throw std::out_of_range("stringify() buffer is not sufficient.");
|
||||
@ -91,13 +88,13 @@ namespace yycc::num::stringify {
|
||||
* @param[in] num The value need to get string representation.
|
||||
* @return The string representation of given value ("true" or "false").
|
||||
*/
|
||||
template<typename T, std::enable_if_t<std::is_same_v<T, bool>, int> = 0>
|
||||
NS_YYCC_STRING::u8string stringify(T num) {
|
||||
if (num) return NS_YYCC_STRING::u8string(YYCC_U8("true"));
|
||||
else return NS_YYCC_STRING::u8string(YYCC_U8("false"));
|
||||
template<typename T>
|
||||
requires(std::is_same_v<T, bool>)
|
||||
std::u8string stringify(T num) {
|
||||
if (num) return std::u8string(u8"true");
|
||||
else return std::u8string(u8"false");
|
||||
}
|
||||
|
||||
} // namespace yycc::string::stringify
|
||||
} // namespace yycc::num::stringify
|
||||
|
||||
#undef NS_YYCC_STRING_REINTERPRET
|
||||
#undef NS_YYCC_STRING
|
||||
|
@ -1,45 +0,0 @@
|
||||
#pragma once
|
||||
#include "../macro/feature_probe.hpp"
|
||||
|
||||
namespace yycc::patch::contains {
|
||||
|
||||
/**
|
||||
* @brief Checks if there is an element with key equivalent to key in the container.
|
||||
* @details
|
||||
* The polyfill to \c contains() function of unordered and ordered associative container.
|
||||
* Because this function only present after C++ 20.
|
||||
* This function will use our custom polyfill if the version of C++ standard you are using lower than C++ 20.
|
||||
* Otherwise it will fallback to vanilla standard library function.
|
||||
* @tparam TContainer
|
||||
* The type of container. This container must have \c find() and \c end() member functions.
|
||||
* @tparam TKey
|
||||
* The type of key of container.
|
||||
* If the container is a set, this type is the type of item in set.
|
||||
* If the container is a map, this type is the key type of map.
|
||||
* @param[in] container The reference to container to find.
|
||||
* @param[in] key Key value of the element to search for
|
||||
* @return True if there is such an element, otherwise false.
|
||||
* @remarks
|
||||
* This template function do not have constraint check.
|
||||
* If container type has \c find() and \c end() member functions, this template function will be created without any error.
|
||||
* However, this function should be used for standard library associative container according to its original purpose.
|
||||
* It means that the type of container usually and should be one of following types:
|
||||
* \li \c std::set
|
||||
* \li \c std::multiset
|
||||
* \li \c std::map
|
||||
* \li \c std::multimap
|
||||
* \li \c std::unordered_set
|
||||
* \li \c std::unordered_multiset
|
||||
* \li \c std::unordered_map
|
||||
* \li \c std::unordered_multimap
|
||||
*/
|
||||
template<class TContainer, class TKey>
|
||||
bool contains(const TContainer& container, const TKey& key) {
|
||||
#if defined(YYCC_CPPFEAT_CONTAINS)
|
||||
return container.contains(key);
|
||||
#else
|
||||
return container.find(key) != container.end();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace yycc::patch::container
|
@ -1,40 +0,0 @@
|
||||
#pragma once
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
|
||||
/**
|
||||
* @brief A stupid polyfill for std::expected,
|
||||
*
|
||||
* For those C++ standard which do not support std::expected,
|
||||
* we provide this namespace with a pretty bad but at least working std::expected pplyfill.
|
||||
*
|
||||
* The polyfill was done by std::variant.
|
||||
*
|
||||
* This namespace is used by this project because this framework must support C++ 17.
|
||||
*/
|
||||
namespace yycc::patch::expected {
|
||||
|
||||
template<typename TValue, typename TError, std::enable_if_t<!std::is_same_v<TValue, TError>, int> = 0>
|
||||
using Expected = std::variant<TValue, TError>;
|
||||
|
||||
template<typename TValue, typename TError>
|
||||
bool is_value(const Expected<TValue, TError>& exp) {
|
||||
return exp.index() == 0u;
|
||||
}
|
||||
|
||||
template<typename TValue, typename TError>
|
||||
bool is_error(const Expected<TValue, TError>& exp) {
|
||||
return exp.index() == 1u;
|
||||
}
|
||||
|
||||
template<typename TValue, typename TError>
|
||||
const TValue& get_value(const Expected<TValue, TError>& exp) {
|
||||
return std::get<0>(exp);
|
||||
}
|
||||
|
||||
template<typename TValue, typename TError>
|
||||
const TError& get_error(const Expected<TValue, TError>& exp) {
|
||||
return std::get<1>(exp);
|
||||
}
|
||||
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
#include "path.hpp"
|
||||
#include "../macro/os_detector.hpp"
|
||||
#include <stdexcept>
|
||||
|
||||
#define NS_YYCC_STRING ::yycc::string
|
||||
|
||||
namespace yycc::patch::path {
|
||||
|
||||
// TODO: Fix this after finish encoding parts.
|
||||
|
||||
// TODO: Add native implementation if C++ support it.
|
||||
// So we need add feature test macro at the same time.
|
||||
|
||||
std::filesystem::path to_std_path(const NS_YYCC_STRING::u8string_view& u8_path) {
|
||||
// #if defined(YYCC_OS_WINDOWS)
|
||||
|
||||
// // convert path to wchar
|
||||
// std::wstring wpath;
|
||||
// if (!YYCC::EncodingHelper::UTF8ToWchar(u8_path, wpath))
|
||||
// throw std::invalid_argument("Fail to convert given UTF8 string.");
|
||||
// // return path with wchar_t ctor
|
||||
// return std::filesystem::path(wpath);
|
||||
|
||||
// #else
|
||||
// std::string cache = YYCC::EncodingHelper::ToOrdinary(u8_path);
|
||||
// return std::filesystem::path(cache.c_str());
|
||||
// #endif
|
||||
return std::filesystem::path();
|
||||
}
|
||||
|
||||
NS_YYCC_STRING::u8string to_u8string(const std::filesystem::path& path) {
|
||||
// #if defined(YYCC_OS_WINDOWS)
|
||||
|
||||
// // get and convert to utf8
|
||||
// NS_YYCC_STRING::u8string u8_path;
|
||||
// if (!YYCC::EncodingHelper::WcharToUTF8(path.c_str(), u8_path))
|
||||
// throw std::invalid_argument("Fail to convert to UTF8 string.");
|
||||
|
||||
// // return utf8 path
|
||||
// return u8_path;
|
||||
|
||||
// #else
|
||||
// return EncodingHelper::ToUTF8(path.string());
|
||||
// #endif
|
||||
return NS_YYCC_STRING::u8string();
|
||||
}
|
||||
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
#pragma once
|
||||
#include "../string.hpp"
|
||||
#include <filesystem>
|
||||
|
||||
#define NS_YYCC_STRING ::yycc::string
|
||||
|
||||
/**
|
||||
* @brief \c Standard library related patches for UTF8 compatibility and the limitation of C++ standard version.
|
||||
* @details
|
||||
* See also \ref std_patch.
|
||||
*/
|
||||
namespace yycc::patch::path {
|
||||
|
||||
/**
|
||||
* @brief Constructs \c std::filesystem::path from UTF8 path.
|
||||
* @param[in] u8_path UTF8 path string for building.
|
||||
* @return \c std::filesystem::path instance.
|
||||
* @exception std::invalid_argument Fail to parse given UTF8 string (maybe invalid?).
|
||||
*/
|
||||
std::filesystem::path to_std_path(const NS_YYCC_STRING::u8string_view& u8_path);
|
||||
|
||||
/**
|
||||
* @brief Returns the UTF8 representation of given \c std::filesystem::path.
|
||||
* @param[in] path The \c std::filesystem::path instance converting to UTF8 path.
|
||||
* @return The UTF8 representation of given \c std::filesystem::path.
|
||||
* @exception std::invalid_argument Fail to convert to UTF8 string.
|
||||
*/
|
||||
NS_YYCC_STRING::u8string to_u8string(const std::filesystem::path& path);
|
||||
|
||||
} // namespace yycc::patch::path
|
||||
|
||||
#undef NS_YYCC_STRING
|
@ -1,203 +0,0 @@
|
||||
#pragma once
|
||||
#include "../macro/feature_probe.hpp"
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace yycc::patch::starts_ends_with {
|
||||
|
||||
// Reference:
|
||||
// https://en.cppreference.com/w/cpp/string/basic_string_view/starts_with
|
||||
// https://en.cppreference.com/w/cpp/string/basic_string_view/ends_with
|
||||
// https://en.cppreference.com/w/cpp/string/basic_string/starts_with
|
||||
// https://en.cppreference.com/w/cpp/string/basic_string/ends_with
|
||||
|
||||
#pragma region For String View
|
||||
|
||||
/**
|
||||
* @brief Checks if the string view begins with the given prefix
|
||||
* @param[in] that The string view to find.
|
||||
* @param[in] sv A string view which may be a result of implicit conversion from \c std::basic_string.
|
||||
* @return True if the string view begins with the provided prefix, false otherwise.
|
||||
*/
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
bool starts_with(const std::basic_string_view<CharT, Traits>& that,
|
||||
std::basic_string_view<CharT, Traits> sv) noexcept {
|
||||
#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH)
|
||||
return that.starts_with(sv);
|
||||
#else
|
||||
return std::basic_string_view<CharT, Traits>(that.data(), std::min(that.size(), sv.size()))
|
||||
== sv;
|
||||
#endif
|
||||
}
|
||||
/**
|
||||
* @brief Checks if the string view begins with the given prefix
|
||||
* @param[in] that The string view to find.
|
||||
* @param[in] ch A single character.
|
||||
* @return True if the string view begins with the provided prefix, false otherwise.
|
||||
*/
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
bool starts_with(const std::basic_string_view<CharT, Traits>& that, CharT ch) noexcept {
|
||||
#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH)
|
||||
return that.starts_with(ch);
|
||||
#else
|
||||
return !that.empty() && Traits::eq(that.front(), ch);
|
||||
#endif
|
||||
}
|
||||
/**
|
||||
* @brief Checks if the string view begins with the given prefix
|
||||
* @param[in] that The string view to find.
|
||||
* @param[in] s A null-terminated character string.
|
||||
* @return True if the string view begins with the provided prefix, false otherwise.
|
||||
*/
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
bool starts_with(const std::basic_string_view<CharT, Traits>& that, const CharT* s) noexcept {
|
||||
#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH)
|
||||
return that.starts_with(s);
|
||||
#else
|
||||
return starts_with(that, std::basic_string_view(s));
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the string view ends with the given suffix
|
||||
* @param[in] that The string view to find.
|
||||
* @param[in] sv A string view which may be a result of implicit conversion from \c std::basic_string.
|
||||
* @return True if the string view ends with the provided suffix, false otherwise.
|
||||
*/
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
bool ends_with(const std::basic_string_view<CharT, Traits>& that,
|
||||
std::basic_string_view<CharT, Traits> sv) noexcept {
|
||||
#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH)
|
||||
return that.ends_with(sv);
|
||||
#else
|
||||
return that.size() >= sv.size()
|
||||
&& that.compare(that.size() - sv.size(),
|
||||
std::basic_string_view<CharT, Traits>::npos,
|
||||
sv)
|
||||
== 0;
|
||||
#endif
|
||||
}
|
||||
/**
|
||||
* @brief Checks if the string view ends with the given suffix
|
||||
* @param[in] that The string view to find.
|
||||
* @param[in] ch A single character.
|
||||
* @return True if the string view ends with the provided suffix, false otherwise.
|
||||
*/
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
bool ends_with(const std::basic_string_view<CharT, Traits>& that, CharT ch) noexcept {
|
||||
#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH)
|
||||
return that.ends_with(ch);
|
||||
#else
|
||||
return !that.empty() && Traits::eq(that.back(), ch);
|
||||
#endif
|
||||
}
|
||||
/**
|
||||
* @brief Checks if the string view ends with the given suffix
|
||||
* @param[in] that The string view to find.
|
||||
* @param[in] s A null-terminated character string.
|
||||
* @return True if the string view ends with the provided suffix, false otherwise.
|
||||
*/
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
bool ends_with(const std::basic_string_view<CharT, Traits>& that, const CharT* s) noexcept {
|
||||
#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH)
|
||||
return that.ends_with(s);
|
||||
#else
|
||||
return ends_with(that, std::basic_string_view(s));
|
||||
#endif
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region For String
|
||||
|
||||
/**
|
||||
* @brief Checks if the string begins with the given prefix
|
||||
* @param[in] that The string to find.
|
||||
* @param[in] sv A string view which may be a result of implicit conversion from \c std::basic_string.
|
||||
* @return True if the string view begins with the provided prefix, false otherwise.
|
||||
*/
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
bool starts_with(const std::basic_string<CharT, Traits>& that,
|
||||
std::basic_string_view<CharT, Traits> sv) noexcept {
|
||||
#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH)
|
||||
return that.starts_with(sv);
|
||||
#else
|
||||
return starts_with(std::basic_string_view<CharT, Traits>(that.data(), that.size()), sv);
|
||||
#endif
|
||||
}
|
||||
/**
|
||||
* @brief Checks if the string begins with the given prefix
|
||||
* @param[in] that The string to find.
|
||||
* @param[in] ch A single character.
|
||||
* @return True if the string view begins with the provided prefix, false otherwise.
|
||||
*/
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
bool starts_with(const std::basic_string<CharT, Traits>& that, CharT ch) noexcept {
|
||||
#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH)
|
||||
return that.starts_with(ch);
|
||||
#else
|
||||
return starts_with(std::basic_string_view<CharT, Traits>(that.data(), that.size()), ch);
|
||||
#endif
|
||||
}
|
||||
/**
|
||||
* @brief Checks if the string begins with the given prefix
|
||||
* @param[in] that The string to find.
|
||||
* @param[in] s A null-terminated character string.
|
||||
* @return True if the string view begins with the provided prefix, false otherwise.
|
||||
*/
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
bool starts_with(const std::basic_string<CharT, Traits>& that, const CharT* s) noexcept {
|
||||
#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH)
|
||||
return that.starts_with(s);
|
||||
#else
|
||||
return starts_with(std::basic_string_view<CharT, Traits>(that.data(), that.size()), s);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the string ends with the given suffix
|
||||
* @param[in] that The string to find.
|
||||
* @param[in] sv A string view which may be a result of implicit conversion from \c std::basic_string.
|
||||
* @return True if the string view ends with the provided suffix, false otherwise.
|
||||
*/
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
bool ends_with(const std::basic_string<CharT, Traits>& that,
|
||||
std::basic_string_view<CharT, Traits> sv) noexcept {
|
||||
#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH)
|
||||
return that.ends_with(sv);
|
||||
#else
|
||||
return ends_with(std::basic_string_view<CharT, Traits>(that.data(), that.size()), sv);
|
||||
#endif
|
||||
}
|
||||
/**
|
||||
* @brief Checks if the string ends with the given suffix
|
||||
* @param[in] that The string to find.
|
||||
* @param[in] ch A single character.
|
||||
* @return True if the string view ends with the provided suffix, false otherwise.
|
||||
*/
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
bool ends_with(const std::basic_string<CharT, Traits>& that, CharT ch) noexcept {
|
||||
#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH)
|
||||
return that.ends_with(ch);
|
||||
#else
|
||||
return ends_with(std::basic_string_view<CharT, Traits>(that.data(), that.size()), ch);
|
||||
#endif
|
||||
}
|
||||
/**
|
||||
* @brief Checks if the string ends with the given suffix
|
||||
* @param[in] that The string to find.
|
||||
* @param[in] s A null-terminated character string.
|
||||
* @return True if the string view ends with the provided suffix, false otherwise.
|
||||
*/
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
bool ends_with(const std::basic_string<CharT, Traits>& that, const CharT* s) noexcept {
|
||||
#if defined(YYCC_CPPFEAT_STARTS_ENDS_WITH)
|
||||
return that.ends_with(s);
|
||||
#else
|
||||
return ends_with(std::basic_string_view<CharT, Traits>(that.data(), that.size()), s);
|
||||
#endif
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
} // namespace yycc::patch::starts_ends_with
|
@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include "../string.hpp"
|
||||
#include <string_view>
|
||||
|
||||
namespace yycc::rust::primitive {
|
||||
namespace yycc::primitive {
|
||||
|
||||
// `bool` is keyword so should not declare it anymore.
|
||||
// `char` is keyword so should not declare it anymore.
|
||||
@ -23,6 +23,6 @@ namespace yycc::rust::primitive {
|
||||
using f32 = float;
|
||||
using f64 = double;
|
||||
|
||||
using str = ::yycc::string::u8string_view;
|
||||
using str = std::u8string_view;
|
||||
}
|
||||
|
@ -1,97 +0,0 @@
|
||||
#pragma once
|
||||
#include "../../macro/feature_probe.hpp"
|
||||
#include "../../num/parse.hpp"
|
||||
#include "../result.hpp"
|
||||
|
||||
#define NS_YYCC_STRING ::yycc::string
|
||||
#define NS_YYCC_NUM_PARSE ::yycc::num::parse
|
||||
#define NS_YYCC_RUST_RESULT ::yycc::rust::result
|
||||
#define NS_YYCC_PATCH_EXPECTED ::yycc::patch::expected
|
||||
|
||||
/**
|
||||
* @namespace yycc::rust::parse
|
||||
* @brief Provides Rust-inspired parsing utilities for converting strings to various types.
|
||||
* @details
|
||||
* This namespace contains template functions for parsing strings into different types
|
||||
* (floating-point, integral, boolean) with Rust-like Result error handling.
|
||||
*/
|
||||
namespace yycc::rust::num::parse {
|
||||
|
||||
#if defined(YYCC_CPPFEAT_EXPECTED)
|
||||
|
||||
/// @brief The error type of parsing.
|
||||
using Error = NS_YYCC_NUM_PARSE::ParseError;
|
||||
|
||||
/// @brief The result type of parsing.
|
||||
/// @tparam T The expected value type in result.
|
||||
template<typename T>
|
||||
using Result = NS_YYCC_RUST_RESULT::Result<T, Error>;
|
||||
|
||||
/**
|
||||
* @brief Parses a string into a floating-point value.
|
||||
* @tparam T Floating-point type to parse into (float, double, etc.)
|
||||
* @param strl String view to parse
|
||||
* @param fmt Formatting flags for parsing (default: general)
|
||||
* @return Result<T> containing either the parsed value or an error
|
||||
*/
|
||||
template<typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
|
||||
Result<T> parse(const NS_YYCC_STRING::u8string_view& strl,
|
||||
std::chars_format fmt = std::chars_format::general) {
|
||||
namespace expected = NS_YYCC_PATCH_EXPECTED;
|
||||
namespace result = NS_YYCC_RUST_RESULT;
|
||||
|
||||
auto rv = NS_YYCC_NUM_PARSE::priv_parse<T>(strl, fmt);
|
||||
if (expected::is_value(rv)) {
|
||||
return result::Ok<Result<T>>(expected::get_value(rv));
|
||||
} else {
|
||||
return result::Err<Result<T>>(expected::get_error(rv));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parses a string into an integral value (excluding bool).
|
||||
* @tparam T Integral type to parse into (int, long, etc.)
|
||||
* @param strl String view to parse
|
||||
* @param base Numeric base for parsing (default: 10)
|
||||
* @return Result<T> containing either the parsed value or an error
|
||||
*/
|
||||
template<typename T, std::enable_if_t<std::is_integral_v<T> && !std::is_same_v<T, bool>, int> = 0>
|
||||
Result<T> parse(const NS_YYCC_STRING::u8string_view& strl, int base = 10) {
|
||||
namespace expected = NS_YYCC_PATCH_EXPECTED;
|
||||
namespace result = NS_YYCC_RUST_RESULT;
|
||||
|
||||
auto rv = NS_YYCC_NUM_PARSE::priv_parse<T>(strl, base);
|
||||
if (expected::is_value(rv)) {
|
||||
return result::Ok<Result<T>>(expected::get_value(rv));
|
||||
} else {
|
||||
return result::Err<Result<T>>(expected::get_error(rv));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parses a string into a boolean value.
|
||||
* @tparam T Must be bool type
|
||||
* @param strl String view to parse
|
||||
* @return Result<bool> containing either the parsed value or an error
|
||||
*/
|
||||
template<typename T, std::enable_if_t<std::is_same_v<T, bool>, int> = 0>
|
||||
Result<T> parse(const NS_YYCC_STRING::u8string_view& strl) {
|
||||
namespace expected = NS_YYCC_PATCH_EXPECTED;
|
||||
namespace result = NS_YYCC_RUST_RESULT;
|
||||
|
||||
auto rv = NS_YYCC_NUM_PARSE::priv_parse<T>(strl);
|
||||
if (expected::is_value(rv)) {
|
||||
return result::Ok<Result<T>>(expected::get_value(rv));
|
||||
} else {
|
||||
return result::Err<Result<T>>(expected::get_error(rv));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#undef NS_YYCC_PATCH_EXPECTED
|
||||
#undef NS_YYCC_RUST_RESULT
|
||||
#undef NS_YYCC_NUM_PARSE
|
||||
#undef NS_YYCC_STRING
|
@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
#include "../../num/stringify.hpp"
|
||||
|
||||
namespace yycc::rust::num::stringify {
|
||||
|
||||
// There is no modification for legacy "stringify" functions like "parse".
|
||||
// So we simply expose all functions into this namespace.
|
||||
using namespace ::yycc::num::stringify;
|
||||
|
||||
} // namespace yycc::rust::stringify
|
@ -1,47 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Define the UTF8 char type we used.
|
||||
// And do a polyfill if no embedded char8_t type.
|
||||
|
||||
#include "macro/feature_probe.hpp"
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace yycc::string {
|
||||
/**
|
||||
\typedef u8char_t
|
||||
\brief YYCC UTF8 char type.
|
||||
\details
|
||||
This char type is an alias to \c char8_t if your current C++ standard support it.
|
||||
Otherwise it is defined as <TT>unsigned char</TT> as C++ 20 stdandard does.
|
||||
*/
|
||||
/**
|
||||
\typedef u8string
|
||||
\brief YYCC UTF8 string container type.
|
||||
\details
|
||||
This type is defined as \c std::basic_string<yycc_char8_t>.
|
||||
It is equal to \c std::u8string if your current C++ standard support it.
|
||||
*/
|
||||
/**
|
||||
\typedef u8string_view
|
||||
\brief YYCC UTF8 string view type.
|
||||
\details
|
||||
This type is defined as \c std::basic_string_view<yycc_char8_t>.
|
||||
It is equal to \c std::u8string_view if your current C++ standard support it.
|
||||
*/
|
||||
|
||||
#if defined(YYCC_CPPFEAT_UTF8)
|
||||
using u8char = char8_t;
|
||||
using u8string = std::u8string;
|
||||
using u8string_view = std::u8string_view;
|
||||
#else
|
||||
using u8char = unsigned char;
|
||||
using u8string = std::basic_string<u8char>;
|
||||
using u8string_view = std::basic_string_view<u8char>;
|
||||
#endif
|
||||
|
||||
#define _YYCC_U8(strl) u8 ## strl ///< The assistant macro for YYCC_U8.
|
||||
#define YYCC_U8(strl) (reinterpret_cast<const ::yycc::string::u8char*>(_YYCC_U8(strl))) ///< The macro for creating UTF8 string literal. See \ref library_encoding.
|
||||
#define YYCC_U8_CHAR(chr) (static_cast<::yycc::string::u8char>(chr)) ///< The macro for casting ordinary char type into YYCC UTF8 char type.
|
||||
|
||||
} // namespace yycc::string
|
@ -1,196 +1,180 @@
|
||||
#include "op.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include "reinterpret.hpp"
|
||||
|
||||
#define NS_YYCC_STRING ::yycc::string
|
||||
#define NS_YYCC_STRING_REINTERPRET ::yycc::string::reinterpret
|
||||
|
||||
namespace yycc::string::op {
|
||||
|
||||
#pragma region Printf VPrintf
|
||||
|
||||
bool printf(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8char* format, ...) {
|
||||
va_list argptr;
|
||||
va_start(argptr, format);
|
||||
bool ret = vprintf(strl, format, argptr);
|
||||
va_end(argptr);
|
||||
return ret;
|
||||
}
|
||||
template<typename TChar>
|
||||
requires(sizeof(TChar) == sizeof(char))
|
||||
static FormatResult<std::basic_string<TChar>> generic_printf(const TChar* format, va_list argptr) {
|
||||
// Prepare result
|
||||
std::basic_string<TChar> rv;
|
||||
|
||||
bool vprintf(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8char* format, va_list argptr) {
|
||||
namespace reinterpret = NS_YYCC_STRING_REINTERPRET;
|
||||
// Check format
|
||||
if (format == nullptr) return std::unexpected(FormatError::NullFormat);
|
||||
|
||||
va_list args1;
|
||||
va_copy(args1, argptr);
|
||||
va_list args2;
|
||||
va_copy(args2, argptr);
|
||||
// Prepare variable arguments
|
||||
va_list args1;
|
||||
va_copy(args1, argptr);
|
||||
va_list args2;
|
||||
va_copy(args2, argptr);
|
||||
|
||||
// the return value is desired char count without NULL terminal.
|
||||
// minus number means error
|
||||
int count = std::vsnprintf(
|
||||
nullptr,
|
||||
0,
|
||||
reinterpret::as_ordinary(format),
|
||||
args1
|
||||
);
|
||||
if (count < 0) {
|
||||
// invalid length returned by vsnprintf.
|
||||
return false;
|
||||
}
|
||||
va_end(args1);
|
||||
// The return value is desired char count without NULL terminal.
|
||||
// Minus number means error.
|
||||
int count = std::vsnprintf(nullptr, 0, reinterpret_cast<const char*>(format), args1);
|
||||
// Check expected size.
|
||||
if (count < 0) {
|
||||
// Invalid length returned by vsnprintf.
|
||||
return std::unexpected(FormatError::NoExpSize);
|
||||
}
|
||||
va_end(args1);
|
||||
|
||||
// resize std::string to desired count.
|
||||
// and pass its length + 1 to std::vsnprintf,
|
||||
// because std::vsnprintf only can write "buf_size - 1" chars with a trailing NULL.
|
||||
// however std::vsnprintf already have a trailing NULL, so we plus 1 for it.
|
||||
strl.resize(count);
|
||||
int write_result = std::vsnprintf(
|
||||
reinterpret::as_ordinary(strl.data()),
|
||||
strl.size() + 1,
|
||||
reinterpret::as_ordinary(format),
|
||||
args2
|
||||
);
|
||||
va_end(args2);
|
||||
// Resize std::string to desired count, and pass its length + 1 to std::vsnprintf,
|
||||
// Because std::vsnprintf only can write "buf_size - 1" chars with a trailing NULL.
|
||||
// However std::vsnprintf already have a trailing NULL, so we plus 1 for it.
|
||||
rv.resize(count);
|
||||
int write_result = std::vsnprintf(reinterpret_cast<char*>(rv.data()), rv.size() + 1, reinterpret_cast<const char*>(format), args2);
|
||||
va_end(args2);
|
||||
// Check written size.
|
||||
if (write_result < 0 || write_result > count) {
|
||||
// Invalid write result in vsnprintf.
|
||||
return std::unexpected(FormatError::BadWrittenSize);
|
||||
}
|
||||
|
||||
if (write_result < 0 || write_result > count) {
|
||||
// invalid write result in vsnprintf.
|
||||
return false;
|
||||
}
|
||||
// Return value
|
||||
return rv;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
FormatResult<std::u8string> printf(const char8_t* format, ...) {
|
||||
va_list argptr;
|
||||
va_start(argptr, format);
|
||||
auto rv = vprintf(format, argptr);
|
||||
va_end(argptr);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_YYCC_STRING::u8string printf(const NS_YYCC_STRING::u8char* format, ...) {
|
||||
NS_YYCC_STRING::u8string ret;
|
||||
FormatResult<std::u8string> vprintf(const char8_t* format, va_list argptr) {
|
||||
return generic_printf(format, argptr);
|
||||
}
|
||||
|
||||
va_list argptr;
|
||||
va_start(argptr, format);
|
||||
vprintf(ret, format, argptr);
|
||||
va_end(argptr);
|
||||
FormatResult<std::string> printf(const char* format, ...) {
|
||||
va_list argptr;
|
||||
va_start(argptr, format);
|
||||
auto rv = vprintf(format, argptr);
|
||||
va_end(argptr);
|
||||
return rv;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
NS_YYCC_STRING::u8string vprintf(const NS_YYCC_STRING::u8char* format, va_list argptr) {
|
||||
NS_YYCC_STRING::u8string ret;
|
||||
|
||||
va_list argcpy;
|
||||
va_copy(argcpy, argptr);
|
||||
vprintf(ret, format, argcpy);
|
||||
va_end(argcpy);
|
||||
|
||||
return ret;
|
||||
}
|
||||
FormatResult<std::string> vprintf(const char* format, va_list argptr) {
|
||||
return generic_printf(format, argptr);
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Replace
|
||||
|
||||
void replace(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8string_view& _from_strl, const NS_YYCC_STRING::u8string_view& _to_strl) {
|
||||
// Reference: https://stackoverflow.com/questions/3418231/replace-part-of-a-string-with-another-string
|
||||
void replace(std::u8string& strl, const std::u8string_view& _from_strl, const std::u8string_view& _to_strl) {
|
||||
// Reference: https://stackoverflow.com/questions/3418231/replace-part-of-a-string-with-another-string
|
||||
|
||||
// check requirements
|
||||
// from string should not be empty
|
||||
NS_YYCC_STRING::u8string from_strl(_from_strl);
|
||||
NS_YYCC_STRING::u8string to_strl(_to_strl);
|
||||
if (from_strl.empty()) return;
|
||||
// check requirements
|
||||
// from string should not be empty
|
||||
std::u8string from_strl(_from_strl);
|
||||
std::u8string to_strl(_to_strl);
|
||||
if (from_strl.empty()) return;
|
||||
|
||||
// start replace one by one
|
||||
size_t start_pos = 0;
|
||||
while ((start_pos = strl.find(from_strl, start_pos)) != NS_YYCC_STRING::u8string::npos) {
|
||||
strl.replace(start_pos, from_strl.size(), to_strl);
|
||||
start_pos += to_strl.size(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
|
||||
}
|
||||
}
|
||||
// start replace one by one
|
||||
size_t start_pos = 0;
|
||||
while ((start_pos = strl.find(from_strl, start_pos)) != std::u8string::npos) {
|
||||
strl.replace(start_pos, from_strl.size(), to_strl);
|
||||
start_pos += to_strl.size(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
|
||||
}
|
||||
}
|
||||
|
||||
NS_YYCC_STRING::u8string replace(const NS_YYCC_STRING::u8string_view& _strl, const NS_YYCC_STRING::u8string_view& _from_strl, const NS_YYCC_STRING::u8string_view& _to_strl) {
|
||||
// prepare result
|
||||
NS_YYCC_STRING::u8string strl(_strl);
|
||||
replace(strl, _from_strl, _to_strl);
|
||||
// return value
|
||||
return strl;
|
||||
}
|
||||
std::u8string replace(const std::u8string_view& _strl, const std::u8string_view& _from_strl, const std::u8string_view& _to_strl) {
|
||||
// prepare result
|
||||
std::u8string strl(_strl);
|
||||
replace(strl, _from_strl, _to_strl);
|
||||
// return value
|
||||
return strl;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Join
|
||||
|
||||
NS_YYCC_STRING::u8string join(JoinDataProvider fct_data, const NS_YYCC_STRING::u8string_view& delimiter) {
|
||||
NS_YYCC_STRING::u8string ret;
|
||||
bool is_first = true;
|
||||
NS_YYCC_STRING::u8string_view element;
|
||||
std::u8string join(JoinDataProvider fct_data, const std::u8string_view& delimiter) {
|
||||
std::u8string ret;
|
||||
bool is_first = true;
|
||||
std::u8string_view element;
|
||||
|
||||
// fetch element
|
||||
while (fct_data(element)) {
|
||||
// insert delimiter
|
||||
if (is_first) is_first = false;
|
||||
else {
|
||||
// append delimiter.
|
||||
ret.append(delimiter);
|
||||
}
|
||||
// fetch element
|
||||
while (fct_data(element)) {
|
||||
// insert delimiter
|
||||
if (is_first) is_first = false;
|
||||
else {
|
||||
// append delimiter.
|
||||
ret.append(delimiter);
|
||||
}
|
||||
|
||||
// insert element if it is not empty
|
||||
if (!element.empty())
|
||||
ret.append(element);
|
||||
}
|
||||
// insert element if it is not empty
|
||||
if (!element.empty()) ret.append(element);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Upper Lower
|
||||
|
||||
template<bool BIsToLower>
|
||||
static void generic_lower_upper(NS_YYCC_STRING::u8string& strl) {
|
||||
// References:
|
||||
// https://en.cppreference.com/w/cpp/algorithm/transform
|
||||
// https://en.cppreference.com/w/cpp/string/byte/tolower
|
||||
std::transform(
|
||||
strl.cbegin(), strl.cend(), strl.begin(),
|
||||
[](unsigned char c) -> char {
|
||||
if constexpr (BIsToLower) return std::tolower(c);
|
||||
else return std::toupper(c);
|
||||
}
|
||||
);
|
||||
}
|
||||
template<bool BIsToLower>
|
||||
static void generic_lower_upper(std::u8string& strl) {
|
||||
// References:
|
||||
// https://en.cppreference.com/w/cpp/algorithm/transform
|
||||
// https://en.cppreference.com/w/cpp/string/byte/tolower
|
||||
std::transform(strl.cbegin(), strl.cend(), strl.begin(), [](unsigned char c) -> char {
|
||||
if constexpr (BIsToLower) return std::tolower(c);
|
||||
else return std::toupper(c);
|
||||
});
|
||||
}
|
||||
|
||||
void lower(NS_YYCC_STRING::u8string& strl) {
|
||||
generic_lower_upper<true>(strl);
|
||||
}
|
||||
void lower(std::u8string& strl) {
|
||||
generic_lower_upper<true>(strl);
|
||||
}
|
||||
|
||||
NS_YYCC_STRING::u8string to_lower(const NS_YYCC_STRING::u8string_view& strl) {
|
||||
NS_YYCC_STRING::u8string ret(strl);
|
||||
lower(ret);
|
||||
return ret;
|
||||
}
|
||||
std::u8string to_lower(const std::u8string_view& strl) {
|
||||
std::u8string ret(strl);
|
||||
lower(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void upper(NS_YYCC_STRING::u8string& strl) {
|
||||
generic_lower_upper<false>(strl);
|
||||
}
|
||||
void upper(std::u8string& strl) {
|
||||
generic_lower_upper<false>(strl);
|
||||
}
|
||||
|
||||
NS_YYCC_STRING::u8string to_upper(const NS_YYCC_STRING::u8string_view& strl) {
|
||||
// same as Lower, just replace char transform function.
|
||||
NS_YYCC_STRING::u8string ret(strl);
|
||||
upper(ret);
|
||||
return ret;
|
||||
}
|
||||
std::u8string to_upper(const std::u8string_view& strl) {
|
||||
// same as Lower, just replace char transform function.
|
||||
std::u8string ret(strl);
|
||||
upper(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Split
|
||||
|
||||
std::vector<NS_YYCC_STRING::u8string_view> split(const NS_YYCC_STRING::u8string_view& strl, const NS_YYCC_STRING::u8string_view& _delimiter) {
|
||||
std::vector<std::u8string_view> split(const std::u8string_view& strl, const std::u8string_view& _delimiter) {
|
||||
// Reference:
|
||||
// https://stackoverflow.com/questions/14265581/parse-split-a-string-in-c-using-string-delimiter-standard-c
|
||||
|
||||
// prepare return value
|
||||
std::vector<NS_YYCC_STRING::u8string_view> elems;
|
||||
std::vector<std::u8string_view> elems;
|
||||
|
||||
// if string need to be splitted is empty, return original string (empty string).
|
||||
// if delimiter is empty, return original string.
|
||||
NS_YYCC_STRING::u8string delimiter(_delimiter);
|
||||
std::u8string delimiter(_delimiter);
|
||||
if (strl.empty() || delimiter.empty()) {
|
||||
elems.emplace_back(strl);
|
||||
return elems;
|
||||
@ -198,7 +182,7 @@ namespace yycc::string::op {
|
||||
|
||||
// start spliting
|
||||
std::size_t previous = 0, current;
|
||||
while ((current = strl.find(delimiter.c_str(), previous)) != NS_YYCC_STRING::u8string::npos) {
|
||||
while ((current = strl.find(delimiter.c_str(), previous)) != std::u8string::npos) {
|
||||
elems.emplace_back(strl.substr(previous, current - previous));
|
||||
previous = current + delimiter.size();
|
||||
}
|
||||
@ -209,20 +193,20 @@ namespace yycc::string::op {
|
||||
return elems;
|
||||
}
|
||||
|
||||
std::vector<NS_YYCC_STRING::u8string> split_owned(const NS_YYCC_STRING::u8string_view& strl, const NS_YYCC_STRING::u8string_view& _delimiter) {
|
||||
// call split view
|
||||
std::vector<std::u8string> split_owned(const std::u8string_view& strl, const std::u8string_view& _delimiter) {
|
||||
// call split view
|
||||
auto view_result = split(strl, _delimiter);
|
||||
|
||||
// copy string view result to string
|
||||
std::vector<NS_YYCC_STRING::u8string> elems;
|
||||
elems.reserve(view_result.size());
|
||||
for (const auto& strl_view : view_result) {
|
||||
elems.emplace_back(NS_YYCC_STRING::u8string(strl_view));
|
||||
}
|
||||
// return copied result
|
||||
return elems;
|
||||
}
|
||||
// copy string view result to string
|
||||
std::vector<std::u8string> elems;
|
||||
elems.reserve(view_result.size());
|
||||
for (const auto& strl_view : view_result) {
|
||||
elems.emplace_back(std::u8string(strl_view));
|
||||
}
|
||||
// return copied result
|
||||
return elems;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
}
|
||||
} // namespace yycc::string::op
|
||||
|
@ -1,65 +1,68 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <cstdarg>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include "../string.hpp"
|
||||
|
||||
#define NS_YYCC_STRING ::yycc::string
|
||||
#include <expected>
|
||||
|
||||
namespace yycc::string::op {
|
||||
|
||||
/**
|
||||
* @brief Perform a string formatting operation.
|
||||
* @param[out] strl
|
||||
* The string container receiving the result.
|
||||
* There is no guarantee that the content is not modified when function failed.
|
||||
* @param[in] format The format string.
|
||||
* @param[in] ... Argument list of format string.
|
||||
* @return True if success, otherwise false.
|
||||
*/
|
||||
bool printf(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8char* format, ...);
|
||||
/**
|
||||
* @brief Perform a string formatting operation.
|
||||
* @param[out] strl
|
||||
* The string container receiving the result.
|
||||
* There is no guarantee that the content is not modified when function failed.
|
||||
* @param[in] format The format string.
|
||||
* @param[in] argptr Argument list of format string.
|
||||
* @return True if success, otherwise false.
|
||||
*/
|
||||
bool vprintf(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8char* format, va_list argptr);
|
||||
/**
|
||||
* @brief Perform a string formatting operation.
|
||||
* @param[in] format The format string.
|
||||
* @param[in] ... Argument list of format string.
|
||||
* @return The formatting result. Empty string if error happened.
|
||||
*/
|
||||
NS_YYCC_STRING::u8string printf(const NS_YYCC_STRING::u8char* format, ...);
|
||||
/**
|
||||
* @brief Perform a string formatting operation.
|
||||
* @param[in] format The format string.
|
||||
* @param[in] argptr Argument list of format string.
|
||||
* @return The formatting result. Empty string if error happened.
|
||||
*/
|
||||
NS_YYCC_STRING::u8string vprintf(const NS_YYCC_STRING::u8char* format, va_list argptr);
|
||||
enum class FormatError {
|
||||
NullFormat, ///< Given format string is nullptr.
|
||||
NoExpSize, ///< Fail to fetch the expected size of result.
|
||||
BadWrittenSize, ///< The written size is different with expected size.
|
||||
};
|
||||
|
||||
/**
|
||||
template<typename T>
|
||||
using FormatResult = std::expected<T, FormatError>;
|
||||
|
||||
/**
|
||||
* @brief Perform an UTF8 string formatting operation.
|
||||
* @param[in] format The format string.
|
||||
* @param[in] ... Argument list of format string.
|
||||
* @return The formatted result, or the fail reason.
|
||||
*/
|
||||
FormatResult<std::u8string> printf(const char8_t* format, ...);
|
||||
/**
|
||||
* @brief Perform an UTF8 string formatting operation.
|
||||
* @param[in] format The format string.
|
||||
* @param[in] argptr Argument list of format string.
|
||||
* @return The formatted result, or the fail reason.
|
||||
*/
|
||||
FormatResult<std::u8string> vprintf(const char8_t* format, va_list argptr);
|
||||
/**
|
||||
* @brief Perform an ordinary string formatting operation.
|
||||
* @param[in] format The format string.
|
||||
* @param[in] ... Argument list of format string.
|
||||
* @return The formatted result, or the fail reason.
|
||||
*/
|
||||
FormatResult<std::string> printf(const char* format, ...);
|
||||
/**
|
||||
* @brief Perform an ordinary string formatting operation.
|
||||
* @param[in] format The format string.
|
||||
* @param[in] argptr Argument list of format string.
|
||||
* @return The formatted result, or the fail reason.
|
||||
*/
|
||||
FormatResult<std::string> vprintf(const char* format, va_list argptr);
|
||||
|
||||
/**
|
||||
* @brief Modify given string with all occurrences of substring \e old replaced by \e new.
|
||||
* @param[in,out] strl The string for replacing
|
||||
* @param[in] _from_strl The \e old string.
|
||||
* @param[in] _to_strl The \e new string.
|
||||
*/
|
||||
void replace(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8string_view& _from_strl, const NS_YYCC_STRING::u8string_view& _to_strl);
|
||||
/**
|
||||
void replace(std::u8string& strl, const std::u8string_view& _from_strl, const std::u8string_view& _to_strl);
|
||||
/**
|
||||
* @brief Return a copy with all occurrences of substring \e old replaced by \e new.
|
||||
* @param[in] _strl The string for replacing
|
||||
* @param[in] _from_strl The \e old string.
|
||||
* @param[in] _to_strl The \e new string.
|
||||
* @return The result of replacement.
|
||||
*/
|
||||
NS_YYCC_STRING::u8string replace(const NS_YYCC_STRING::u8string_view& _strl, const NS_YYCC_STRING::u8string_view& _from_strl, const NS_YYCC_STRING::u8string_view& _to_strl);
|
||||
std::u8string replace(const std::u8string_view& _strl, const std::u8string_view& _from_strl, const std::u8string_view& _to_strl);
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief The data provider of general join function.
|
||||
* @details
|
||||
* For programmer using lambda to implement this function pointer:
|
||||
@ -68,8 +71,8 @@ namespace yycc::string::op {
|
||||
* \li Function return true to continue joining. otherwise return false to stop joining.
|
||||
* The argument content assigned in the calling returning false is not included in join process.
|
||||
*/
|
||||
using JoinDataProvider = std::function<bool(NS_YYCC_STRING::u8string_view&)>;
|
||||
/**
|
||||
using JoinDataProvider = std::function<bool(std::u8string_view&)>;
|
||||
/**
|
||||
* @brief Universal join function.
|
||||
* @details
|
||||
* This function use function pointer as a general data provider interface,
|
||||
@ -80,51 +83,56 @@ namespace yycc::string::op {
|
||||
* @param[in] delimiter The delimiter used for joining.
|
||||
* @return The result string of joining.
|
||||
*/
|
||||
NS_YYCC_STRING::u8string join(JoinDataProvider fct_data, const NS_YYCC_STRING::u8string_view& delimiter);
|
||||
/**
|
||||
std::u8string join(JoinDataProvider fct_data, const std::u8string_view& delimiter);
|
||||
/**
|
||||
* @brief Specialized join function for standard library container.
|
||||
* @tparam InputIt
|
||||
* Must meet the requirements of LegacyInputIterator.
|
||||
* It also can be dereferenced and then implicitly converted to NS_YYCC_STRING::u8string_view.
|
||||
* It also can be dereferenced and then implicitly converted to std::u8string_view.
|
||||
* @param[in] first The beginning of the range of elements to join.
|
||||
* @param[in] last The terminal of the range of elements to join (exclusive).
|
||||
* @param[in] delimiter The delimiter used for joining.
|
||||
* @return The result string of joining.
|
||||
*/
|
||||
template<class InputIt>
|
||||
NS_YYCC_STRING::u8string join(InputIt first, InputIt last, const NS_YYCC_STRING::u8string_view& delimiter) {
|
||||
return join([&first, &last](NS_YYCC_STRING::u8string_view& view) -> bool {
|
||||
// if we reach tail, return false to stop join process
|
||||
if (first == last) return false;
|
||||
// otherwise fetch data, inc iterator and return.
|
||||
view = *first;
|
||||
++first;
|
||||
return true;
|
||||
}, delimiter);
|
||||
}
|
||||
template<class InputIt>
|
||||
std::u8string join(InputIt first, InputIt last, const std::u8string_view& delimiter) {
|
||||
return join(
|
||||
[&first, &last](std::u8string_view& view) -> bool {
|
||||
// if we reach tail, return false to stop join process
|
||||
if (first == last) return false;
|
||||
// otherwise fetch data, inc iterator and return.
|
||||
view = *first;
|
||||
++first;
|
||||
return true;
|
||||
},
|
||||
delimiter);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Convert given string to lowercase.
|
||||
* @param[in,out] strl The string to be lowercase.
|
||||
*/
|
||||
void lower(NS_YYCC_STRING::u8string& strl);
|
||||
/**
|
||||
void lower(std::u8string& strl);
|
||||
/**
|
||||
* @brief Return a copy of the string converted to lowercase.
|
||||
* @param[in] strl The string to be lowercase.
|
||||
* @return The copy of the string converted to lowercase.
|
||||
*/
|
||||
NS_YYCC_STRING::u8string to_lower(const NS_YYCC_STRING::u8string_view& strl);
|
||||
/**
|
||||
std::u8string to_lower(const std::u8string_view& strl);
|
||||
/**
|
||||
* @brief Convert given string to uppercase.
|
||||
* @param[in,out] strl The string to be uppercase.
|
||||
*/
|
||||
void upper(NS_YYCC_STRING::u8string& strl);
|
||||
/**
|
||||
void upper(std::u8string& strl);
|
||||
/**
|
||||
* @brief Return a copy of the string converted to uppercase.
|
||||
* @param[in] strl The string to be uppercase.
|
||||
* @return The copy of the string converted to uppercase.
|
||||
*/
|
||||
NS_YYCC_STRING::u8string to_upper(const NS_YYCC_STRING::u8string_view& strl);
|
||||
std::u8string to_upper(const std::u8string_view& strl);
|
||||
|
||||
// TODO:
|
||||
// Add strip, lstrip and rstrip functions.
|
||||
|
||||
/**
|
||||
* @brief Split given string with specified delimiter as string view.
|
||||
@ -136,10 +144,10 @@ namespace yycc::string::op {
|
||||
* \par
|
||||
* If given string or delimiter are empty,
|
||||
* the result container will only contain 1 entry which is equal to given string.
|
||||
* @see Split(const NS_YYCC_STRING::u8string_view&, const NS_YYCC_STRING::u8char*)
|
||||
* @see Split(const std::u8string_view&, const char8_t*)
|
||||
*/
|
||||
std::vector<NS_YYCC_STRING::u8string_view> split(const NS_YYCC_STRING::u8string_view& strl, const NS_YYCC_STRING::u8string_view& _delimiter);
|
||||
/**
|
||||
std::vector<std::u8string_view> split(const std::u8string_view& strl, const std::u8string_view& _delimiter);
|
||||
/**
|
||||
* @brief Split given string with specified delimiter.
|
||||
* @param[in] strl The string need to be splitting.
|
||||
* @param[in] _delimiter The delimiter for splitting.
|
||||
@ -149,9 +157,10 @@ namespace yycc::string::op {
|
||||
* If given string or delimiter are empty,
|
||||
* the result container will only contain 1 entry which is equal to given string.
|
||||
*/
|
||||
std::vector<NS_YYCC_STRING::u8string> split_owned(const NS_YYCC_STRING::u8string_view& strl, const NS_YYCC_STRING::u8string_view& _delimiter);
|
||||
// undefined lazy_split(const NS_YYCC_STRING::u8string_view& strl, const NS_YYCC_STRING::u8string_view& _delimiter);
|
||||
std::vector<std::u8string> split_owned(const std::u8string_view& strl, const std::u8string_view& _delimiter);
|
||||
|
||||
}
|
||||
// TODO:
|
||||
// Add lazy_split(const std::u8string_view& strl, const std::u8string_view& _delimiter);
|
||||
// Once we add it, we need redirect all split function into it.
|
||||
|
||||
#undef NS_YYCC_STRING
|
||||
} // namespace yycc::string::op
|
||||
|
@ -1,33 +1,31 @@
|
||||
#include "reinterpret.hpp"
|
||||
|
||||
#define NS_YYCC_STRING ::yycc::string
|
||||
|
||||
namespace yycc::string::reinterpret {
|
||||
|
||||
const NS_YYCC_STRING::u8char* as_utf8(const char* src) {
|
||||
return reinterpret_cast<const NS_YYCC_STRING::u8char*>(src);
|
||||
}
|
||||
NS_YYCC_STRING::u8char* as_utf8(char* src) {
|
||||
return reinterpret_cast<NS_YYCC_STRING::u8char*>(src);
|
||||
}
|
||||
NS_YYCC_STRING::u8string as_utf8(const std::string_view& src) {
|
||||
return NS_YYCC_STRING::u8string(reinterpret_cast<const NS_YYCC_STRING::u8char*>(src.data()), src.size());
|
||||
}
|
||||
NS_YYCC_STRING::u8string_view as_utf8_view(const std::string_view& src) {
|
||||
return NS_YYCC_STRING::u8string_view(reinterpret_cast<const NS_YYCC_STRING::u8char*>(src.data()), src.size());
|
||||
}
|
||||
const char8_t* as_utf8(const char* src) {
|
||||
return reinterpret_cast<const char8_t*>(src);
|
||||
}
|
||||
char8_t* as_utf8(char* src) {
|
||||
return reinterpret_cast<char8_t*>(src);
|
||||
}
|
||||
std::u8string as_utf8(const std::string_view& src) {
|
||||
return std::u8string(reinterpret_cast<const char8_t*>(src.data()), src.size());
|
||||
}
|
||||
std::u8string_view as_utf8_view(const std::string_view& src) {
|
||||
return std::u8string_view(reinterpret_cast<const char8_t*>(src.data()), src.size());
|
||||
}
|
||||
|
||||
const char* as_ordinary(const NS_YYCC_STRING::u8char* src) {
|
||||
return reinterpret_cast<const char*>(src);
|
||||
}
|
||||
char* as_ordinary(NS_YYCC_STRING::u8char* src) {
|
||||
return reinterpret_cast<char*>(src);
|
||||
}
|
||||
std::string as_ordinary(const NS_YYCC_STRING::u8string_view& src) {
|
||||
return std::string(reinterpret_cast<const char*>(src.data()), src.size());
|
||||
}
|
||||
std::string_view as_ordinary_view(const NS_YYCC_STRING::u8string_view& src) {
|
||||
return std::string_view(reinterpret_cast<const char*>(src.data()), src.size());
|
||||
}
|
||||
const char* as_ordinary(const char8_t* src) {
|
||||
return reinterpret_cast<const char*>(src);
|
||||
}
|
||||
char* as_ordinary(char8_t* src) {
|
||||
return reinterpret_cast<char*>(src);
|
||||
}
|
||||
std::string as_ordinary(const std::u8string_view& src) {
|
||||
return std::string(reinterpret_cast<const char*>(src.data()), src.size());
|
||||
}
|
||||
std::string_view as_ordinary_view(const std::u8string_view& src) {
|
||||
return std::string_view(reinterpret_cast<const char*>(src.data()), src.size());
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace yycc::string::reinterpret
|
||||
|
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
#include "../string.hpp"
|
||||
|
||||
#define NS_YYCC_STRING ::yycc::string
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
/**
|
||||
* @brief Provides utilities for reinterpretation between UTF-8 and ordinary string types.
|
||||
@ -17,51 +16,49 @@ namespace yycc::string::reinterpret {
|
||||
* @param src Source ordinary string
|
||||
* @return Pointer to UTF-8 encoded string
|
||||
*/
|
||||
const NS_YYCC_STRING::u8char* as_utf8(const char* src);
|
||||
const char8_t* as_utf8(const char* src);
|
||||
/**
|
||||
* @brief Reinterpret ordinary C-string as an UTF-8 string (non-const version).
|
||||
* @param src Source ordinary string
|
||||
* @return Pointer to UTF-8 encoded string
|
||||
*/
|
||||
NS_YYCC_STRING::u8char* as_utf8(char* src);
|
||||
char8_t* as_utf8(char* src);
|
||||
/**
|
||||
* @brief Reinterpret ordinary string view to copied UTF-8 string.
|
||||
* @param src Source ordinary string view
|
||||
* @return UTF-8 encoded string
|
||||
*/
|
||||
NS_YYCC_STRING::u8string as_utf8(const std::string_view& src);
|
||||
std::u8string as_utf8(const std::string_view& src);
|
||||
/**
|
||||
* @brief Reinterpret ordinary string view to UTF-8 string view.
|
||||
* @param src Source ordinary string view
|
||||
* @return UTF-8 encoded string view
|
||||
*/
|
||||
NS_YYCC_STRING::u8string_view as_utf8_view(const std::string_view& src);
|
||||
std::u8string_view as_utf8_view(const std::string_view& src);
|
||||
|
||||
/**
|
||||
* @brief Reinterpret UTF-8 C-string to ordinary string (const version).
|
||||
* @param src Source UTF-8 string
|
||||
* @return Pointer to ordinary string
|
||||
*/
|
||||
const char* as_ordinary(const NS_YYCC_STRING::u8char* src);
|
||||
const char* as_ordinary(const char8_t* src);
|
||||
/**
|
||||
* @brief Reinterpret UTF-8 C-string to ordinary string (non-const version).
|
||||
* @param src Source UTF-8 string
|
||||
* @return Pointer to ordinary string
|
||||
*/
|
||||
char* as_ordinary(NS_YYCC_STRING::u8char* src);
|
||||
char* as_ordinary(char8_t* src);
|
||||
/**
|
||||
* @brief Reinterpret UTF-8 string view to ordinary string.
|
||||
* @param src Source UTF-8 string view
|
||||
* @return Ordinary string
|
||||
*/
|
||||
std::string as_ordinary(const NS_YYCC_STRING::u8string_view& src);
|
||||
std::string as_ordinary(const std::u8string_view& src);
|
||||
/**
|
||||
* @brief Reinterpret UTF-8 string view to ordinary string view
|
||||
* @param src Source UTF-8 string view
|
||||
* @return Ordinary string view
|
||||
*/
|
||||
std::string_view as_ordinary_view(const NS_YYCC_STRING::u8string_view& src);
|
||||
std::string_view as_ordinary_view(const std::u8string_view& src);
|
||||
|
||||
}
|
||||
|
||||
#undef NS_YYCC_STRING
|
||||
|
@ -1,16 +0,0 @@
|
||||
#pragma once
|
||||
#include "../macro/os_detector.hpp"
|
||||
|
||||
// If we are in Windows,
|
||||
// we need add 2 macros to disable Windows shitty warnings and errors of
|
||||
// depracted functions and not secure functions.
|
||||
#if defined(YYCC_OS_WINDOWS)
|
||||
|
||||
#if !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#if !defined(_CRT_NONSTDC_NO_DEPRECATE)
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||
#endif
|
||||
|
||||
#endif
|
@ -34,20 +34,6 @@ PRIVATE
|
||||
YYCCommonplace
|
||||
GTest::gtest_main
|
||||
)
|
||||
# Setup C++ standard
|
||||
target_compile_features(YYCCTestbench PUBLIC cxx_std_17)
|
||||
set_target_properties(YYCCTestbench PROPERTIES CXX_EXTENSION OFF)
|
||||
# Order Unicode charset for private using
|
||||
target_compile_definitions(YYCCTestbench
|
||||
PRIVATE
|
||||
$<$<CXX_COMPILER_ID:MSVC>:UNICODE>
|
||||
$<$<CXX_COMPILER_ID:MSVC>:_UNICODE>
|
||||
)
|
||||
# Order build as UTF-8 in MSVC
|
||||
target_compile_options(YYCCTestbench
|
||||
PRIVATE
|
||||
$<$<CXX_COMPILER_ID:MSVC>:/utf-8>
|
||||
)
|
||||
|
||||
# Discover all test
|
||||
include(GoogleTest)
|
||||
|
Reference in New Issue
Block a user