11 #include <initializer_list> 14 #include <string_view> 17 #include <fcitx-utils/fcitxutils_export.h> 25 concatPieces(std::initializer_list<std::pair<const char *, std::size_t>> list) {
27 for (
auto pair : list) {
32 for (
const auto &pair : list) {
33 result.append(pair.first, pair.first + pair.second);
35 assert(result.size() == size);
39 std::string concatPathPieces(
40 std::initializer_list<std::pair<const char *, std::size_t>> list) {
46 bool firstPieceIsSlash =
false;
48 for (
const auto &pair : list) {
50 if (pair.first[pair.second - 1] ==
'/') {
51 firstPieceIsSlash =
true;
59 if (list.size() > 1 && firstPieceIsSlash) {
65 for (
auto pair : list) {
68 }
else if (firstPieceIsSlash) {
69 firstPieceIsSlash =
false;
74 result.append(pair.first, pair.first + pair.second);
76 assert(result.size() == size);
81 FCITXUTILS_DEPRECATED_EXPORT
bool startsWith(
const std::string &str,
82 const std::string &prefix) {
83 return startsWith(std::string_view(str), std::string_view(prefix));
86 bool startsWith(std::string_view str, std::string_view prefix) {
87 if (str.size() < prefix.size()) {
91 return (str.compare(0, prefix.size(), prefix) == 0);
94 FCITXUTILS_DEPRECATED_EXPORT
bool endsWith(
const std::string &str,
95 const std::string &suffix) {
96 return endsWith(std::string_view(str), std::string_view(suffix));
99 bool endsWith(std::string_view str, std::string_view suffix) {
100 if (str.size() < suffix.size()) {
104 return (str.compare(str.size() - suffix.size(), suffix.size(), suffix) ==
108 inline std::pair<std::string::size_type, std::string::size_type>
109 trimInplaceImpl(std::string_view str) {
110 auto start = str.find_first_not_of(FCITX_WHITESPACE);
111 if (start == std::string::npos) {
112 return {str.size(), str.size()};
115 auto end = str.size();
116 while (end > start && charutils::isspace(str[end - 1])) {
123 FCITXUTILS_DEPRECATED_EXPORT
124 std::pair<std::string::size_type, std::string::size_type>
126 return trimInplaceImpl(str);
129 std::pair<std::string::size_type, std::string::size_type>
131 return trimInplaceImpl(str);
134 FCITXUTILS_DEPRECATED_EXPORT
135 std::string
trim(
const std::string &str) {
return trim(std::string_view(str)); }
137 std::string
trim(std::string_view str) {
138 auto pair = trimInplaceImpl(str);
139 return {str.begin() + pair.first, str.begin() + pair.second};
144 return str.substr(pair.first, pair.second - pair.first);
147 FCITXUTILS_DEPRECATED_EXPORT
148 std::vector<std::string>
split(
const std::string &str,
const std::string &delim,
149 SplitBehavior behavior) {
150 return split(std::string_view(str), std::string_view(delim), behavior);
153 std::vector<std::string>
split(std::string_view str, std::string_view delim,
154 SplitBehavior behavior) {
155 std::vector<std::string> strings;
156 std::string::size_type lastPos;
157 std::string::size_type pos;
158 if (behavior == SplitBehavior::SkipEmpty) {
159 lastPos = str.find_first_not_of(delim, 0);
163 pos = str.find_first_of(delim, lastPos);
165 while (std::string::npos != pos || std::string::npos != lastPos) {
166 strings.push_back(std::string(str.substr(lastPos, pos - lastPos)));
167 if (behavior == SplitBehavior::SkipEmpty) {
168 lastPos = str.find_first_not_of(delim, pos);
170 if (pos == std::string::npos) {
175 pos = str.find_first_of(delim, lastPos);
181 FCITXUTILS_DEPRECATED_EXPORT std::vector<std::string>
182 split(
const std::string &str,
const std::string &delim) {
183 return split(std::string_view(str), std::string_view(delim));
186 std::vector<std::string>
split(std::string_view str, std::string_view delim) {
187 return split(str, delim, SplitBehavior::SkipEmpty);
190 std::string
replaceAll(std::string str,
const std::string &before,
191 const std::string &after) {
192 if (before.empty()) {
196 constexpr
int MAX_REPLACE_INDICES_NUM = 128;
199 std::string newString;
201 size_t indices[MAX_REPLACE_INDICES_NUM];
203 size_t newStringPos = 0;
204 size_t oldStringPos = 0;
206 auto copyAndMoveOn = [&newString, &newStringPos](std::string_view source,
213 newString.replace(newStringPos,
length, source, pos,
length);
220 while (nIndices < MAX_REPLACE_INDICES_NUM) {
221 pivot = str.find(before, pivot);
222 if (pivot == std::string::npos) {
226 indices[nIndices++] = pivot;
227 pivot += before.size();
232 lastLen = str.size() + nIndices * after.size() -
233 nIndices * before.size();
234 newString.resize(lastLen);
236 size_t newLen = lastLen + nIndices * after.size() -
237 nIndices * before.size();
239 newString.resize(newLen);
246 copyAndMoveOn(str, oldStringPos, indices[0] - oldStringPos);
247 copyAndMoveOn(after, 0, after.size());
249 for (
int i = 1; i < nIndices; i++) {
250 copyAndMoveOn(str, indices[i - 1] + before.size(),
251 indices[i] - (indices[i - 1] + before.size()));
252 copyAndMoveOn(after, 0, after.size());
255 oldStringPos = indices[nIndices - 1] + before.size();
257 }
while (pivot != std::string::npos);
263 copyAndMoveOn(str, oldStringPos, str.size() - oldStringPos);
264 newString.resize(newStringPos);
270 if (ol_minus_1 < sizeof(unsigned int) * CHAR_BIT) \ 271 hashHaystack -= (a) << ol_minus_1; \ 275 size_t ol,
size_t from) {
279 size_t delta = l - ol;
287 const char *end = haystack;
289 const unsigned int ol_minus_1 = ol - 1;
290 const char *n = needle + ol_minus_1;
291 const char *h = haystack + ol_minus_1;
292 unsigned int hashNeedle = 0;
293 unsigned int hashHaystack = 0;
295 for (idx = 0; idx < ol; ++idx) {
296 hashNeedle = ((hashNeedle << 1) + *(n - idx));
297 hashHaystack = ((hashHaystack << 1) + *(h - idx));
299 hashHaystack -= *haystack;
300 while (haystack >= end) {
301 hashHaystack += *haystack;
302 if (hashHaystack == hashNeedle && memcmp(needle, haystack, ol) == 0) {
306 REHASH(*(haystack + ol));
314 static_cast<const char *>(haystack), l, needle, ol, from));
319 const auto *cstr = haystack.c_str();
320 const auto *result =
backwardSearch(cstr, haystack.size(), needle.c_str(),
321 needle.size(), from);
323 return result - cstr;
325 return std::string::npos;
328 enum class UnescapeState { NORMAL, ESCAPE };
330 bool unescape(std::string &str,
bool unescapeQuote) {
337 UnescapeState state = UnescapeState::NORMAL;
340 case UnescapeState::NORMAL:
341 if (str[i] ==
'\\') {
342 state = UnescapeState::ESCAPE;
348 case UnescapeState::ESCAPE:
349 if (str[i] ==
'\\') {
352 }
else if (str[i] ==
'n') {
355 }
else if (str[i] ==
'\"' && unescapeQuote) {
361 state = UnescapeState::NORMAL;
370 bool unescapeQuote =
false;
372 if (str.size() >= 2 && str.front() ==
'"' && str.back() ==
'"') {
373 unescapeQuote =
true;
374 str = str.substr(1, str.size() - 2);
377 return std::string();
380 std::string value(str);
389 value.reserve(str.size());
390 const bool needQuote =
391 str.find_first_of(
"\f\r\t\v \"") != std::string::npos;
393 value.push_back(
'"');
398 value.append(
"\\\\");
404 value.append(
"\\\"");
412 value.push_back(
'"');
420 str = str.substr(prefix.size());
std::vector< std::string > split(std::string_view str, std::string_view delim)
Split the string by delim.
std::optional< std::string > unescapeForValue(std::string_view str)
unescape a string, that is potentially quoted.
bool unescape(std::string &str, bool unescapeQuote)
Inplace unescape a string contains slash, new line, optionally quote.
bool endsWith(std::string_view str, std::string_view suffix)
Check if a string ends with a suffix.
bool consumePrefix(std::string_view &str, std::string_view prefix)
Return a substring of input str if str starts with given prefix.
size_t length(Iter start, Iter end)
Return the number UTF-8 characters in the string iterator range.
std::pair< std::string::size_type, std::string::size_type > trimInplace(std::string_view str)
Trim the whitespace by returning start end end of first and list non whitespace character position...
std::string_view trimView(std::string_view str)
Trim the white space in string view.
std::string replaceAll(std::string str, const std::string &before, const std::string &after)
Replace all substring appearance of before with after.
bool startsWith(std::string_view str, std::string_view prefix)
Check if a string starts with a prefix.
std::string escapeForValue(std::string_view str)
escape a string, add quote if needed.
size_t backwardSearch(const std::string &haystack, const std::string &needle, size_t from)
Fast backward substring search.
std::string trim(std::string_view str)
Trim the white space in str.
Local independent API to detect character type.