refactor: start to refactor project
This commit is contained in:
226
src/yycc/string/op.cpp
Normal file
226
src/yycc/string/op.cpp
Normal 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
156
src/yycc/string/op.hpp
Normal 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
|
33
src/yycc/string/reinterpret.cpp
Normal file
33
src/yycc/string/reinterpret.cpp
Normal 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());
|
||||
}
|
||||
|
||||
}
|
24
src/yycc/string/reinterpret.hpp
Normal file
24
src/yycc/string/reinterpret.hpp
Normal 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
|
Reference in New Issue
Block a user