123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627 |
- #ifndef BASE_STRINGS_STRING_UTIL_INTERNAL_H_
- #define BASE_STRINGS_STRING_UTIL_INTERNAL_H_
- #include <algorithm>
- #include "base/logging.h"
- #include "base/notreached.h"
- #include "base/strings/string_piece.h"
- #include "base/third_party/icu/icu_utf.h"
- namespace base {
- namespace internal {
- struct ReplacementOffset {
- ReplacementOffset(uintptr_t parameter, size_t offset)
- : parameter(parameter), offset(offset) {}
-
- uintptr_t parameter;
-
- size_t offset;
- };
- static bool CompareParameter(const ReplacementOffset& elem1,
- const ReplacementOffset& elem2) {
- return elem1.parameter < elem2.parameter;
- }
- using MachineWord = uintptr_t;
- inline bool IsMachineWordAligned(const void* pointer) {
- return !(reinterpret_cast<MachineWord>(pointer) & (sizeof(MachineWord) - 1));
- }
- template <typename StringType>
- StringType ToLowerASCIIImpl(BasicStringPiece<StringType> str) {
- StringType ret;
- ret.reserve(str.size());
- for (size_t i = 0; i < str.size(); i++)
- ret.push_back(ToLowerASCII(str[i]));
- return ret;
- }
- template <typename StringType>
- StringType ToUpperASCIIImpl(BasicStringPiece<StringType> str) {
- StringType ret;
- ret.reserve(str.size());
- for (size_t i = 0; i < str.size(); i++)
- ret.push_back(ToUpperASCII(str[i]));
- return ret;
- }
- template <class StringType>
- int CompareCaseInsensitiveASCIIT(BasicStringPiece<StringType> a,
- BasicStringPiece<StringType> b) {
-
-
-
- size_t i = 0;
- while (i < a.length() && i < b.length()) {
- typename StringType::value_type lower_a = ToLowerASCII(a[i]);
- typename StringType::value_type lower_b = ToLowerASCII(b[i]);
- if (lower_a < lower_b)
- return -1;
- if (lower_a > lower_b)
- return 1;
- i++;
- }
-
-
- if (a.length() == b.length())
- return 0;
- if (a.length() < b.length())
- return -1;
- return 1;
- }
- template <typename Str>
- TrimPositions TrimStringT(BasicStringPiece<Str> input,
- BasicStringPiece<Str> trim_chars,
- TrimPositions positions,
- Str* output) {
-
-
-
-
- const size_t last_char = input.length() - 1;
- const size_t first_good_char =
- (positions & TRIM_LEADING) ? input.find_first_not_of(trim_chars) : 0;
- const size_t last_good_char = (positions & TRIM_TRAILING)
- ? input.find_last_not_of(trim_chars)
- : last_char;
-
-
-
- if (input.empty() || first_good_char == Str::npos ||
- last_good_char == Str::npos) {
- bool input_was_empty = input.empty();
- output->clear();
- return input_was_empty ? TRIM_NONE : positions;
- }
-
- output->assign(input.data() + first_good_char,
- last_good_char - first_good_char + 1);
-
- return static_cast<TrimPositions>(
- (first_good_char == 0 ? TRIM_NONE : TRIM_LEADING) |
- (last_good_char == last_char ? TRIM_NONE : TRIM_TRAILING));
- }
- template <typename Str>
- BasicStringPiece<Str> TrimStringPieceT(BasicStringPiece<Str> input,
- BasicStringPiece<Str> trim_chars,
- TrimPositions positions) {
- size_t begin =
- (positions & TRIM_LEADING) ? input.find_first_not_of(trim_chars) : 0;
- size_t end = (positions & TRIM_TRAILING)
- ? input.find_last_not_of(trim_chars) + 1
- : input.size();
- return input.substr(std::min(begin, input.size()), end - begin);
- }
- template <typename STR>
- STR CollapseWhitespaceT(BasicStringPiece<STR> text,
- bool trim_sequences_with_line_breaks) {
- STR result;
- result.resize(text.size());
-
-
- bool in_whitespace = true;
- bool already_trimmed = true;
- int chars_written = 0;
- for (auto c : text) {
- if (IsUnicodeWhitespace(c)) {
- if (!in_whitespace) {
-
- in_whitespace = true;
- result[chars_written++] = L' ';
- }
- if (trim_sequences_with_line_breaks && !already_trimmed &&
- ((c == '\n') || (c == '\r'))) {
-
- already_trimmed = true;
- --chars_written;
- }
- } else {
-
- in_whitespace = false;
- already_trimmed = false;
- result[chars_written++] = c;
- }
- }
- if (in_whitespace && !already_trimmed) {
-
- --chars_written;
- }
- result.resize(chars_written);
- return result;
- }
- template <class Char>
- bool DoIsStringASCII(const Char* characters, size_t length) {
-
-
- constexpr MachineWord NonASCIIMasks[] = {
- 0, MachineWord(0x8080808080808080ULL), MachineWord(0xFF80FF80FF80FF80ULL),
- 0, MachineWord(0xFFFFFF80FFFFFF80ULL),
- };
- if (!length)
- return true;
- constexpr MachineWord non_ascii_bit_mask = NonASCIIMasks[sizeof(Char)];
- static_assert(non_ascii_bit_mask, "Error: Invalid Mask");
- MachineWord all_char_bits = 0;
- const Char* end = characters + length;
-
- while (!IsMachineWordAligned(characters) && characters < end)
- all_char_bits |= *characters++;
- if (all_char_bits & non_ascii_bit_mask)
- return false;
-
- constexpr size_t chars_per_word = sizeof(MachineWord) / sizeof(Char);
- constexpr int batch_count = 16;
- while (characters <= end - batch_count * chars_per_word) {
- all_char_bits = 0;
- for (int i = 0; i < batch_count; ++i) {
- all_char_bits |= *(reinterpret_cast<const MachineWord*>(characters));
- characters += chars_per_word;
- }
- if (all_char_bits & non_ascii_bit_mask)
- return false;
- }
-
- all_char_bits = 0;
- while (characters <= end - chars_per_word) {
- all_char_bits |= *(reinterpret_cast<const MachineWord*>(characters));
- characters += chars_per_word;
- }
-
- while (characters < end)
- all_char_bits |= *characters++;
- return !(all_char_bits & non_ascii_bit_mask);
- }
- template <bool (*Validator)(uint32_t)>
- inline static bool DoIsStringUTF8(StringPiece str) {
- const char* src = str.data();
- int32_t src_len = static_cast<int32_t>(str.length());
- int32_t char_index = 0;
- while (char_index < src_len) {
- int32_t code_point;
- CBU8_NEXT(src, char_index, src_len, code_point);
- if (!Validator(code_point))
- return false;
- }
- return true;
- }
- template <typename Str>
- static inline bool DoLowerCaseEqualsASCII(BasicStringPiece<Str> str,
- StringPiece lowercase_ascii) {
- return std::equal(
- str.begin(), str.end(), lowercase_ascii.begin(), lowercase_ascii.end(),
- [](auto lhs, auto rhs) { return ToLowerASCII(lhs) == rhs; });
- }
- template <typename Str>
- bool StartsWithT(BasicStringPiece<Str> str,
- BasicStringPiece<Str> search_for,
- CompareCase case_sensitivity) {
- if (search_for.size() > str.size())
- return false;
- BasicStringPiece<Str> source = str.substr(0, search_for.size());
- switch (case_sensitivity) {
- case CompareCase::SENSITIVE:
- return source == search_for;
- case CompareCase::INSENSITIVE_ASCII:
- return std::equal(
- search_for.begin(), search_for.end(), source.begin(),
- CaseInsensitiveCompareASCII<typename Str::value_type>());
- default:
- NOTREACHED();
- return false;
- }
- }
- template <typename Str>
- bool EndsWithT(BasicStringPiece<Str> str,
- BasicStringPiece<Str> search_for,
- CompareCase case_sensitivity) {
- if (search_for.size() > str.size())
- return false;
- BasicStringPiece<Str> source =
- str.substr(str.size() - search_for.size(), search_for.size());
- switch (case_sensitivity) {
- case CompareCase::SENSITIVE:
- return source == search_for;
- case CompareCase::INSENSITIVE_ASCII:
- return std::equal(
- source.begin(), source.end(), search_for.begin(),
- CaseInsensitiveCompareASCII<typename Str::value_type>());
- default:
- NOTREACHED();
- return false;
- }
- }
- template <class StringType>
- struct SubstringMatcher {
- BasicStringPiece<StringType> find_this;
- size_t Find(const StringType& input, size_t pos) {
- return input.find(find_this.data(), pos, find_this.length());
- }
- size_t MatchSize() { return find_this.length(); }
- };
- template <class StringType>
- struct CharacterMatcher {
- BasicStringPiece<StringType> find_any_of_these;
- size_t Find(const StringType& input, size_t pos) {
- return input.find_first_of(find_any_of_these.data(), pos,
- find_any_of_these.length());
- }
- constexpr size_t MatchSize() { return 1; }
- };
- enum class ReplaceType { REPLACE_ALL, REPLACE_FIRST };
- template <class StringType, class Matcher>
- bool DoReplaceMatchesAfterOffset(StringType* str,
- size_t initial_offset,
- Matcher matcher,
- BasicStringPiece<StringType> replace_with,
- ReplaceType replace_type) {
- using CharTraits = typename StringType::traits_type;
- const size_t find_length = matcher.MatchSize();
- if (!find_length)
- return false;
-
- size_t first_match = matcher.Find(*str, initial_offset);
- if (first_match == StringType::npos)
- return false;
-
-
- const size_t replace_length = replace_with.length();
- if (replace_type == ReplaceType::REPLACE_FIRST) {
- str->replace(first_match, find_length, replace_with.data(), replace_length);
- return true;
- }
-
-
- if (find_length == replace_length) {
- auto* buffer = &((*str)[0]);
- for (size_t offset = first_match; offset != StringType::npos;
- offset = matcher.Find(*str, offset + replace_length)) {
- CharTraits::copy(buffer + offset, replace_with.data(), replace_length);
- }
- return true;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- size_t str_length = str->length();
- size_t expansion = 0;
- if (replace_length > find_length) {
-
-
- const size_t expansion_per_match = (replace_length - find_length);
- size_t num_matches = 0;
- for (size_t match = first_match; match != StringType::npos;
- match = matcher.Find(*str, match + find_length)) {
- expansion += expansion_per_match;
- ++num_matches;
- }
- const size_t final_length = str_length + expansion;
- if (str->capacity() < final_length) {
-
-
- StringType src(str->get_allocator());
- str->swap(src);
- str->reserve(final_length);
- size_t pos = 0;
- for (size_t match = first_match;; match = matcher.Find(src, pos)) {
- str->append(src, pos, match - pos);
- str->append(replace_with.data(), replace_length);
- pos = match + find_length;
-
-
- if (!--num_matches)
- break;
- }
-
- str->append(src, pos, str_length - pos);
- return true;
- }
-
-
-
- size_t shift_src = first_match + find_length;
- size_t shift_dst = shift_src + expansion;
-
-
- if (shift_dst > str_length)
- str->resize(shift_dst);
- str->replace(shift_dst, str_length - shift_src, *str, shift_src,
- str_length - shift_src);
- str_length = final_length;
- }
-
-
-
-
-
-
-
-
-
-
- auto* buffer = &((*str)[0]);
- size_t write_offset = first_match;
- size_t read_offset = first_match + expansion;
- do {
- if (replace_length) {
- CharTraits::copy(buffer + write_offset, replace_with.data(),
- replace_length);
- write_offset += replace_length;
- }
- read_offset += find_length;
-
- size_t match = std::min(matcher.Find(*str, read_offset), str_length);
- size_t length = match - read_offset;
- if (length) {
- CharTraits::move(buffer + write_offset, buffer + read_offset, length);
- write_offset += length;
- read_offset += length;
- }
- } while (read_offset < str_length);
-
- str->resize(write_offset);
- return true;
- }
- template <class StringType>
- bool ReplaceCharsT(BasicStringPiece<StringType> input,
- BasicStringPiece<StringType> find_any_of_these,
- BasicStringPiece<StringType> replace_with,
- StringType* output) {
-
-
- if (input.data() != output->data() || input.size() != output->size())
- output->assign(input.data(), input.size());
- return DoReplaceMatchesAfterOffset(
- output, 0, CharacterMatcher<StringType>{find_any_of_these}, replace_with,
- ReplaceType::REPLACE_ALL);
- }
- template <class string_type>
- inline typename string_type::value_type* WriteIntoT(string_type* str,
- size_t length_with_null) {
- DCHECK_GE(length_with_null, 1u);
- str->reserve(length_with_null);
- str->resize(length_with_null - 1);
- return &((*str)[0]);
- }
- template <typename list_type, typename string_type>
- static string_type JoinStringT(list_type parts,
- BasicStringPiece<string_type> sep) {
- if (base::empty(parts))
- return string_type();
-
-
- size_t total_size = (parts.size() - 1) * sep.size();
- for (const auto& part : parts)
- total_size += part.size();
- string_type result;
- result.reserve(total_size);
- auto iter = parts.begin();
- DCHECK(iter != parts.end());
- result.append(iter->data(), iter->size());
- ++iter;
- for (; iter != parts.end(); ++iter) {
- result.append(sep.data(), sep.size());
- result.append(iter->data(), iter->size());
- }
-
- DCHECK_EQ(total_size, result.size());
- return result;
- }
- template <class StringType>
- StringType DoReplaceStringPlaceholders(
- BasicStringPiece<StringType> format_string,
- const std::vector<StringType>& subst,
- std::vector<size_t>* offsets) {
- size_t substitutions = subst.size();
- DCHECK_LT(substitutions, 10U);
- size_t sub_length = 0;
- for (const auto& cur : subst)
- sub_length += cur.length();
- StringType formatted;
- formatted.reserve(format_string.length() + sub_length);
- std::vector<ReplacementOffset> r_offsets;
- for (auto i = format_string.begin(); i != format_string.end(); ++i) {
- if ('$' == *i) {
- if (i + 1 != format_string.end()) {
- ++i;
- if ('$' == *i) {
- while (i != format_string.end() && '$' == *i) {
- formatted.push_back('$');
- ++i;
- }
- --i;
- } else {
- if (*i < '1' || *i > '9') {
- DLOG(ERROR) << "Invalid placeholder: $" << *i;
- continue;
- }
- uintptr_t index = *i - '1';
- if (offsets) {
- ReplacementOffset r_offset(index,
- static_cast<int>(formatted.size()));
- r_offsets.insert(
- std::upper_bound(r_offsets.begin(), r_offsets.end(), r_offset,
- &CompareParameter),
- r_offset);
- }
- if (index < substitutions)
- formatted.append(subst.at(index));
- }
- }
- } else {
- formatted.push_back(*i);
- }
- }
- if (offsets) {
- for (const auto& cur : r_offsets)
- offsets->push_back(cur.offset);
- }
- return formatted;
- }
- template <typename CHAR>
- size_t lcpyT(CHAR* dst, const CHAR* src, size_t dst_size) {
- for (size_t i = 0; i < dst_size; ++i) {
- if ((dst[i] = src[i]) == 0)
- return i;
- }
-
- if (dst_size != 0)
- dst[dst_size - 1] = 0;
-
- while (src[dst_size])
- ++dst_size;
- return dst_size;
- }
- }
- }
- #endif
|