refactor: start to refactor project

This commit is contained in:
2025-06-20 23:38:34 +08:00
parent bec36b4b3c
commit df3b602110
70 changed files with 2093 additions and 779 deletions

View File

@ -1,7 +1,7 @@
# Configure version file
configure_file(
${CMAKE_CURRENT_LIST_DIR}/../cmake/YYCCVersion.hpp.in
${CMAKE_CURRENT_LIST_DIR}/YYCC/YYCCVersion.hpp
${CMAKE_CURRENT_LIST_DIR}/yycc/version.hpp.in
${CMAKE_CURRENT_LIST_DIR}/yycc/version.hpp
@ONLY
)
@ -11,48 +11,68 @@ add_library(YYCCommonplace STATIC "")
target_sources(YYCCommonplace
PRIVATE
# Sources
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>
yycc/string/reinterpret.cpp
yycc/string/op.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
FILE_SET HEADERS
FILES
# 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
yycc.hpp
yycc/version.hpp
yycc/prelude/core.hpp
yycc/prelude/rust.hpp
yycc/macro/version_cmp.hpp
yycc/macro/os_detector.hpp
yycc/macro/class_copy_move.hpp
yycc/string.hpp
yycc/string/reinterpret.hpp
yycc/string/op.hpp
yycc/rust/primitive.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
# # 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

16
src/yycc.hpp Normal file
View File

@ -0,0 +1,16 @@
#pragma once
// Library Version and Comparison Macros
#include "yycc/version.hpp"
#include "yycc/macro/version_cmp.hpp"
// Operating System Identifier Macros
#include "yycc/macro/os_detector.hpp"
// Windows Shitty Behavior Disable Macros
#include "yycc/windows/unsafe_suppressor.hpp"
// Batch Class Move / Copy Function Macros
#include "yycc/macro/class_copy_move.hpp"
namespace yycc {}

View File

0
src/yycc/clap/kernel.hpp Normal file
View File

78
src/yycc/constraint.hpp Normal file
View File

@ -0,0 +1,78 @@
#pragma once
#include "macro/class_copy_move.hpp"
#include <functional>
#include <stdexcept>
#include <algorithm>
/// @brief The namespace containing generic constraint concept used varied in other modules.
namespace yycc::constraint {
/// @brief Function prototype used in Constraint for checking whether given value is valid.
/// @details Analyze given value, and return true if value is legal, otherwise false.
template<typename T>
using FnCheck = std::function<bool(const T&)>;
/// @brief Function prototype used in Constraint for clamping given value into a valid value.
/// @details Analyze given value, return clamped value.
template<typename T>
using FnClamp = std::function<T(const T&)>;
/**
* @brief The constraint applied to settings to limit its stored value.
* @tparam T The data type this constraint need to be processed with.
* @details
* Constraint class contains various features:
* \li Check: Check whether given value is in range.
* \li Clamp: Clamp given value into valid value.
* Every instances of Constraint can have some, or none of these features.
* So it is essential to check whether instance has corresponding features before using it.
*/
template<typename T>
class Constraint {
public:
Constraint(FnCheck<T>&& fn_check, FnClamp<T>&& fn_clamp) :
fn_check(std::move(fn_check)), fn_clamp(std::move(fn_clamp)) {}
YYCC_DELETE_COPY(Constraint)
YYCC_DEFAULT_MOVE(Constraint)
/**
* @brief Perform Check feature.
* @param[in] value The valid for checking.
* @return True if valid is okey, otherwise false.
* @exception std::logic_error Raised if this feature is not supported.
*/
bool check(const T& value) const {
if (!support_check()) {
throw std::logic_error("this Constraint do not support check operation");
} else {
return fn_check(value);
}
}
/**
* @brief Perform Clamp feature.
* @param[in] value The valid for clamping.
* @return The result after clamping.
* @exception std::logic_error Raised if this feature is not supported.
*/
T clamp(const T& value) const {
if (!support_clamp()) {
throw std::logic_error("this Constraint do not support clamp operation");
} else {
return fn_clamp(value);
}
}
/// @brief Check whether this Constraint support Check feature.
/// @return True if it support, otherwise false.
bool support_check() const noexcept { return this->fn_check != nullptr; }
/// @brief Check whether this Constraint support Clamp feature.
/// @return True if it support, otherwise false.
bool support_clamp() const noexcept { return this->fn_clamp != nullptr; }
private:
/// @brief Pointer to Check feature function.
FnCheck<T> fn_check;
/// @brief Pointer to Clamp feature function.
FnClamp<T> fn_clamp;
};
} // namespace yycc::core::constraint

View File

@ -0,0 +1,67 @@
#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 {
/**
* @brief Build Constraint for arithmetic values by minimum and maximum value range.
* @tparam T An arithmetic or enum type (except bool) of underlying stored value.
* @param[in] min_value The minimum value of range (inclusive).
* @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>
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");
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));
}
/**
* @brief Get constraint for enum values by enumerating all possible values.
* @tparam T An enum type (except bool) of underlying stored value.
* @param[in] il An initializer list storing all possible values.
* @return The generated constraint instance which can be directly applied.
*/
template<typename T, std::enable_if_t<std::is_enum_v<T>, int> = 0>
Constraint<T> enum_constraint(const std::initializer_list<T>& il) {
std::set<T> data(il);
auto fn_check = [data](const T& val) -> bool { return data.find(val) != data.end(); };
return Constraint<T>(std::move(fn_check), nullptr);
}
/**
* @brief Get constraint for string values by enumerating all possible values.
* @param[in] il An initializer list storing all possible values.
* @return The generated constraint instance which can be directly applied.
* @remarks
* Caller must make sure that the string view passed in initializer list is valid until this Constraint life time gone.
* Becasue this generator will not copy your given string view into string.
*/
inline Constraint<NS_YYCC_STRING::u8string> GetStringEnumerationConstraint(
const std::initializer_list<NS_YYCC_STRING::u8string_view>& il) {
std::set<NS_YYCC_STRING::u8string_view> data(il);
auto fn_check = [data](const NS_YYCC_STRING::u8string& val) -> bool {
return data.find(NS_YYCC_STRING::u8string_view(val)) != data.end();
};
return Constraint<NS_YYCC_STRING::u8string>(std::move(fn_check), nullptr);
}
} // namespace yycc::constraint::builder
#undef NS_YYCC_STRING

View File

@ -0,0 +1,31 @@
#pragma once
/// @brief Explicitly remove copy (\c constructor and \c operator\=) for given class.
#define YYCC_DELETE_COPY(CLSNAME) \
CLSNAME(const CLSNAME&) = delete; \
CLSNAME& operator=(const CLSNAME&) = delete;
/// @brief Explicitly remove move (\c constructor and \c operator\=) for given class.
#define YYCC_DELETE_MOVE(CLSNAME) \
CLSNAME(CLSNAME&&) = delete; \
CLSNAME& operator=(CLSNAME&&) = delete;
/// @brief Explicitly remove (copy and move) (\c constructor and \c operator\=) for given class.
#define YYCC_DELETE_COPY_MOVE(CLSNAME) \
YYCC_DELETE_COPY(CLSNAME) \
YYCC_DELETE_MOVE(CLSNAME)
/// @brief Explicitly set default copy (\c constructor and \c operator\=) for given class.
#define YYCC_DEFAULT_COPY(CLSNAME) \
CLSNAME(const CLSNAME&) = default; \
CLSNAME& operator=(const CLSNAME&) = default;
/// @brief Explicitly set default move (\c constructor and \c operator\=) for given class.
#define YYCC_DEFAULT_MOVE(CLSNAME) \
CLSNAME(CLSNAME&&) = default; \
CLSNAME& operator=(CLSNAME&&) = default;
/// @brief Explicitly set default (copy and move) (\c constructor and \c operator\=) for given class.
#define YYCC_DEFAULT_COPY_MOVE(CLSNAME) \
YYCC_DEFAULT_COPY(CLSNAME) \
YYCC_DEFAULT_MOVE(CLSNAME)

View File

@ -0,0 +1,11 @@
#pragma once
// Define operating system macros
#define YYCC_OS_WINDOWS 2
#define YYCC_OS_LINUX 3
// Check current operating system.
#if defined(_WIN32)
#define YYCC_OS YYCC_OS_WINDOWS
#else
#define YYCC_OS YYCC_OS_LINUX
#endif

View File

@ -0,0 +1,26 @@
#pragma once
/// @brief Return true if left version number is equal to right version number, otherwise false.
#define YYCC_VERCMP_E(av1, av2, av3, bv1, bv2, bv3) ((av1) == (bv1) && (av2) == (bv2) && (av3) == (bv3))
/// @brief Return true if left version number is not equal to right version number, otherwise false.
#define YYCC_VERCMP_NE(av1, av2, av3, bv1, bv2, bv3) (!YYCC_VERCMP_E(av1, av2, av3, bv1, bv2, bv3))
/// @brief Return true if left version number is greater than right version number, otherwise false.
#define YYCC_VERCMP_G(av1, av2, av3, bv1, bv2, bv3) ( \
((av1) > (bv1)) || \
((av1) == (bv1) && (av2) > (bv2)) || \
((av1) == (bv1) && (av2) == (bv2) && (av3) > (bv3)) \
)
/// @brief Return true if left version number is greater than or equal to right version number, otherwise false.
#define YYCC_VERCMP_GE(av1, av2, av3, bv1, bv2, bv3) (YYCC_VERCMP_G(av1, av2, av3, bv1, bv2, bv3) || YYCC_VERCMP_E(av1, av2, av3, bv1, bv2, bv3))
/// @brief Return true if left version number is not lower than right version number, otherwise false.
#define YYCC_VERCMP_NL(av1, av2, av3, bv1, bv2, bv3) YYCC_VERCMP_GE(av1, av2, av3, bv1, bv2, bv3)
/// @brief Return true if left version number is lower than right version number, otherwise false.
#define YYCC_VERCMP_L(av1, av2, av3, bv1, bv2, bv3) ( \
((av1) < (bv1)) || \
((av1) == (bv1) && (av2) < (bv2)) || \
((av1) == (bv1) && (av2) == (bv2) && (av3) < (bv3)) \
)
/// @brief Return true if left version number is lower than or equal to right version number, otherwise false.
#define YYCC_VERCMP_LE(av1, av2, av3, bv1, bv2, bv3) (YYCC_VERCMP_L(av1, av2, av3, bv1, bv2, bv3) || YYCC_VERCMP_E(av1, av2, av3, bv1, bv2, bv3))
/// @brief Return true if left version number is not greater than right version number, otherwise false.
#define YYCC_VERCMP_NG(av1, av2, av3, bv1, bv2, bv3) YYCC_VERCMP_LE(av1, av2, av3, bv1, bv2, bv3)

View File

0
src/yycc/patch/path.hpp Normal file
View File

View File

18
src/yycc/prelude/core.hpp Normal file
View File

@ -0,0 +1,18 @@
#pragma once
// Prelude section
#include "../string.hpp"
namespace yycc::prelude {
#define NS_YYCC_STRING ::yycc::string
using u8char = NS_YYCC_STRING::u8char;
using u8string = NS_YYCC_STRING::u8string;
using u8string_view = NS_YYCC_STRING::u8string_view;
#undef NS_YYCC_STRING
} // namespace yycc::prelude
// Expose all members
using namespace yycc::prelude;

41
src/yycc/prelude/rust.hpp Normal file
View File

@ -0,0 +1,41 @@
#pragma once
// Include YYCC prelude first
#include "core.hpp"
// Rust prelude section
#include "../rust/primitive.hpp"
#include <vector>
namespace yycc::prelude::rust {
// Include primitive types
#define NS_RUST_PRIMITIVE ::yycc::rust::primitive
using i8 = NS_RUST_PRIMITIVE::i8;
using i16 = NS_RUST_PRIMITIVE::i16;
using i32 = NS_RUST_PRIMITIVE::i32;
using i64 = NS_RUST_PRIMITIVE::i64;
using u8 = NS_RUST_PRIMITIVE::u8;
using u16 = NS_RUST_PRIMITIVE::u16;
using u32 = NS_RUST_PRIMITIVE::u32;
using u64 = NS_RUST_PRIMITIVE::u64;
using isize = NS_RUST_PRIMITIVE::isize;
using usize = NS_RUST_PRIMITIVE::usize;
using f32 = NS_RUST_PRIMITIVE::f32;
using f64 = NS_RUST_PRIMITIVE::f64;
using str = NS_RUST_PRIMITIVE::str;
#undef NS_RUST_PRIMITIVE
// Other types
using String = ::yycc::string::u8string;
template<typename T>
using Vec = std::vector<T>;
} // namespace yycc::prelude::rust
// Expose all members
using namespace yycc::prelude::rust;

0
src/yycc/rust/parse.hpp Normal file
View File

View File

@ -0,0 +1,28 @@
#pragma once
#include <cinttypes>
#include <cstddef>
#include "../string.hpp"
namespace yycc::rust::primitive {
// `bool` is keyword so should not declare it anymore.
// `char` is keyword so should not declare it anymore.
using i8 = std::int8_t;
using i16 = std::int16_t;
using i32 = std::int32_t;
using i64 = std::int64_t;
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
using isize = std::ptrdiff_t;
using usize = std::size_t;
using f32 = float;
using f64 = double;
using str = ::yycc::string::u8string_view;
}

41
src/yycc/string.hpp Normal file
View File

@ -0,0 +1,41 @@
#pragma once
// Define the UTF8 char type we used.
// And do a polyfill if no embedded char8_t type.
#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(__cpp_char8_t)
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
} // namespace yycc::string

226
src/yycc/string/op.cpp Normal file
View File

@ -0,0 +1,226 @@
#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;
}
bool vprintf(NS_YYCC_STRING::u8string& strl, const NS_YYCC_STRING::u8char* format, va_list argptr) {
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,
NS_YYCC_STRING_REINTERPRET::as_ordinary(format),
args1
);
if (count < 0) {
// invalid length returned by vsnprintf.
return false;
}
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(
NS_YYCC_STRING_REINTERPRET::as_ordinary(strl.data()),
strl.size() + 1,
NS_YYCC_STRING_REINTERPRET::as_ordinary(format),
args2
);
va_end(args2);
if (write_result < 0 || write_result > count) {
// invalid write result in vsnprintf.
return false;
}
return true;
}
NS_YYCC_STRING::u8string printf(const NS_YYCC_STRING::u8char* format, ...) {
NS_YYCC_STRING::u8string ret;
va_list argptr;
va_start(argptr, format);
vprintf(ret, format, argptr);
va_end(argptr);
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;
}
#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
// 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;
// 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'
}
}
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;
}
#pragma endregion
#pragma region Join
NS_YYCC_STRING::u8string join(JoinDataProvider fct_data, const NS_YYCC_STRING::u8string_view& decilmer) {
NS_YYCC_STRING::u8string ret;
bool is_first = true;
NS_YYCC_STRING::u8string_view element;
// fetch element
while (fct_data(element)) {
// insert decilmer
if (is_first) is_first = false;
else {
// append decilmer.
ret.append(decilmer);
}
// insert element if it is not empty
if (!element.empty())
ret.append(element);
}
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);
}
);
}
void lower(NS_YYCC_STRING::u8string& strl) {
generic_lower_upper<true>(strl);
}
NS_YYCC_STRING::u8string lower(const NS_YYCC_STRING::u8string_view& strl) {
NS_YYCC_STRING::u8string ret(strl);
lower(ret);
return ret;
}
void upper(NS_YYCC_STRING::u8string& strl) {
generic_lower_upper<false>(strl);
}
NS_YYCC_STRING::u8string 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;
}
#pragma endregion
#pragma region Split
std::vector<NS_YYCC_STRING::u8string> split(const NS_YYCC_STRING::u8string_view& strl, const NS_YYCC_STRING::u8string_view& _decilmer) {
// call split view
auto view_result = split_view(strl, _decilmer);
// 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;
}
std::vector<NS_YYCC_STRING::u8string_view> split_view(const NS_YYCC_STRING::u8string_view& strl, const NS_YYCC_STRING::u8string_view& _decilmer) {
// 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;
// if string need to be splitted is empty, return original string (empty string).
// if decilmer is empty, return original string.
NS_YYCC_STRING::u8string decilmer(_decilmer);
if (strl.empty() || decilmer.empty()) {
elems.emplace_back(strl);
return elems;
}
// start spliting
std::size_t previous = 0, current;
while ((current = strl.find(decilmer.c_str(), previous)) != NS_YYCC_STRING::u8string::npos) {
elems.emplace_back(strl.substr(previous, current - previous));
previous = current + decilmer.size();
}
// try insert last part but prevent possible out of range exception
if (previous <= strl.size()) {
elems.emplace_back(strl.substr(previous));
}
return elems;
}
#pragma endregion
}

156
src/yycc/string/op.hpp Normal file
View File

@ -0,0 +1,156 @@
#pragma once
#include <cstdarg>
#include <functional>
#include <vector>
#include "../string.hpp"
#define NS_YYCC_STRING ::yycc::string
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);
/**
* @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);
/**
* @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);
/**
* @brief The data provider of general join function.
* @details
* For programmer using lambda to implement this function pointer:
* \li During calling, implementation should assign the reference of string view passed in argument
* to the string which need to be joined.
* \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&)>;
/**
* @brief Universal join function.
* @details
* This function use function pointer as a general data provider interface,
* so this function suit for all types container.
* You can use this universal join function for any custom container by
* using C++ lambda syntax to create a code block adapted to this function pointer.
* @param[in] fct_data The function pointer in JoinDataProvider type prividing the data to be joined.
* @param[in] decilmer The decilmer used for joining.
* @return The result string of joining.
*/
NS_YYCC_STRING::u8string join(JoinDataProvider fct_data, const NS_YYCC_STRING::u8string_view& decilmer);
/**
* @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.
* @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] decilmer The decilmer 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& decilmer) {
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;
}, decilmer);
}
/**
* @brief Convert given string to lowercase.
* @param[in,out] strl The string to be lowercase.
*/
void lower(NS_YYCC_STRING::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 lower(const NS_YYCC_STRING::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);
/**
* @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 upper(const NS_YYCC_STRING::u8string_view& strl);
/**
* @brief Split given string with specified decilmer.
* @param[in] strl The string need to be splitting.
* @param[in] _decilmer The decilmer for splitting.
* @return
* The split result.
* \par
* If given string or decilmer are empty,
* the result container will only contain 1 entry which is equal to given string.
*/
std::vector<NS_YYCC_STRING::u8string> split(const NS_YYCC_STRING::u8string_view& strl, const NS_YYCC_STRING::u8string_view& _decilmer);
/**
* @brief Split given string with specified decilmer as string view.
* @param[in] strl The string need to be splitting.
* @param[in] _decilmer The decilmer for splitting.
* @return
* The split result with string view format.
* This will not produce any copy of original string.
* \par
* If given string or decilmer 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*)
*/
std::vector<NS_YYCC_STRING::u8string_view> split_view(const NS_YYCC_STRING::u8string_view& strl, const NS_YYCC_STRING::u8string_view& _decilmer);
}
#undef NS_YYCC_STRING

View File

@ -0,0 +1,33 @@
#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 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());
}
}

View File

@ -0,0 +1,24 @@
#pragma once
#include "../string.hpp"
#define NS_YYCC_STRING ::yycc::string
namespace yycc::string::reinterpret {
#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.
const NS_YYCC_STRING::u8char* as_utf8(const char* src);
NS_YYCC_STRING::u8char* as_utf8(char* src);
NS_YYCC_STRING::u8string as_utf8(const std::string_view& src);
NS_YYCC_STRING::u8string_view as_utf8_view(const std::string_view& src);
const char* as_ordinary(const NS_YYCC_STRING::u8char* src);
char* as_ordinary(NS_YYCC_STRING::u8char* src);
std::string as_ordinary(const NS_YYCC_STRING::u8string_view& src);
std::string_view as_ordinary_view(const NS_YYCC_STRING::u8string_view& src);
}
#undef NS_YYCC_STRING

5
src/yycc/version.hpp Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#define YYCC_VER_MAJOR 2
#define YYCC_VER_MINOR 0
#define YYCC_VER_PATCH 0

5
src/yycc/version.hpp.in Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#define YYCC_VER_MAJOR @PROJECT_VERSION_MAJOR@
#define YYCC_VER_MINOR @PROJECT_VERSION_MINOR@
#define YYCC_VER_PATCH @PROJECT_VERSION_PATCH@

0
src/yycc/windows/com.cpp Normal file
View File

0
src/yycc/windows/com.hpp Normal file
View File

View File

View File

View File

@ -0,0 +1,19 @@
// It is by design that no pragma once or #if to prevent deplicated including.
// Because this header is the part of wrapper, not a real header.
// #pragma once
#include "../macro/os_detector.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS
// Define 2 macros to disallow Windows generate MIN and MAX macros
// which cause std::min and std::max can not function as normal.
#if !defined(WIN32_LEAN_AND_MEAN)
#define WIN32_LEAN_AND_MEAN
#endif
#if !defined(NOMINMAX)
#define NOMINMAX
#endif
#endif

View File

@ -0,0 +1,23 @@
// It is by design that no pragma once or #if to prevent deplicated including.
// Because this header is the part of wrapper, not a real header.
// #pragma once
#include "../macro/os_detector.hpp"
#if YYCC_OS == YYCC_OS_WINDOWS
// Windows also will generate following macros
// which may cause the function sign is different in Windows and other platforms.
// So we simply remove them.
// Because #undef will not throw error if there are no matched macro,
// so we simply #undef them directly.
#undef GetObject
#undef GetClassName
#undef LoadImage
#undef GetTempPath
#undef GetModuleFileName
#undef CopyFile
#undef MoveFile
#undef DeleteFile
#endif

View File

@ -0,0 +1,16 @@
#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 YYCC_OS == 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