MCPcopy Create free account
hub / github.com/ashvardanian/StringZilla / try_replace_all_

Method try_replace_all_

include/stringzilla/stringzilla.hpp:4371–4462  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

4369template <typename char_type_, typename allocator_>
4370template <typename pattern_type>
4371bool basic_string<char_type_, allocator_>::try_replace_all_(pattern_type pattern, string_view replacement) noexcept {
4372 // Depending on the size of the pattern and the replacement, we may need to allocate more space.
4373 // There are 3 cases to consider:
4374 // 1. The pattern and the replacement are of the same length. Piece of cake!
4375 // 2. The pattern is longer than the replacement. We need to compact the strings.
4376 // 3. The pattern is shorter than the replacement. We may have to allocate more memory.
4377 using matcher_type = typename std::conditional<is_same_type<pattern_type, byteset>::value,
4378 matcher_find_first_of<string_view, pattern_type>,
4379 matcher_find<string_view, exclude_overlaps_type>>::type;
4380 matcher_type matcher({pattern});
4381 string_view this_view = view();
4382
4383 // 1. The pattern and the replacement are of the same length.
4384 if (matcher.needle_length() == replacement.length()) {
4385 using matches_type = range_matches<string_view, matcher_type>;
4386 // Instead of iterating with `begin()` and `end()`, we could use the cheaper sentinel-based approach.
4387 // for (string_view match : matches) { ... }
4388 matches_type matches = matches_type(this_view, {pattern});
4389 for (auto matches_iterator = matches.begin(); matches_iterator != end_sentinel_type {}; ++matches_iterator) {
4390 replacement.copy(const_cast<pointer>((*matches_iterator).data()));
4391 }
4392 return true;
4393 }
4394
4395 // 2. The pattern is longer than the replacement. We need to compact the strings.
4396 else if (matcher.needle_length() > replacement.length()) {
4397 // Dealing with shorter replacements, we will avoid memory allocations, but we can also minimize the number
4398 // of `memmove`-s, by keeping one more iterator, pointing to the end of the last compacted area.
4399 // Having the split-ranges, however, we reuse their logic.
4400 using splits_type = range_splits<string_view, matcher_type>;
4401 splits_type splits = splits_type(this_view, {pattern});
4402 auto matches_iterator = splits.begin();
4403 auto compacted_end = (*matches_iterator).end();
4404 if (compacted_end == end()) return true; // No matches.
4405
4406 ++matches_iterator; // Skip the first match.
4407 do {
4408 string_view match_view = *matches_iterator;
4409 replacement.copy(const_cast<pointer>(compacted_end));
4410 compacted_end += replacement.length();
4411 sz_move((sz_ptr_t)compacted_end, match_view.begin(), match_view.length());
4412 compacted_end += match_view.length();
4413 ++matches_iterator;
4414 } while (matches_iterator != end_sentinel_type {});
4415
4416 // Can't fail, so let's just return true :)
4417 try_resize(compacted_end - begin());
4418 return true;
4419 }
4420
4421 // 3. The pattern is shorter than the replacement. We may have to allocate more memory.
4422 else {
4423 using rmatcher_type = typename std::conditional<is_same_type<pattern_type, byteset>::value,
4424 matcher_find_last_of<string_view, pattern_type>,
4425 matcher_rfind<string_view, exclude_overlaps_type>>::type;
4426 using rmatches_type = range_rmatches<string_view, rmatcher_type>;
4427 rmatches_type rmatches = rmatches_type(this_view, {pattern});
4428

Callers

nothing calls this directly

Calls 10

sz_moveFunction · 0.70
needle_lengthMethod · 0.45
lengthMethod · 0.45
beginMethod · 0.45
copyMethod · 0.45
dataMethod · 0.45
endMethod · 0.45
sizeMethod · 0.45
frontMethod · 0.45
is_lastMethod · 0.45

Tested by

no test coverage detected