Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(154)

Side by Side Diff: base/strings/string_util.cc

Issue 935333002: Update from https://crrev.com/316786 (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/process/process_info_win.cc ('k') | base/system_monitor/system_monitor.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/strings/string_util.h" 5 #include "base/strings/string_util.h"
6 6
7 #include <ctype.h> 7 #include <ctype.h>
8 #include <errno.h> 8 #include <errno.h>
9 #include <math.h> 9 #include <math.h>
10 #include <stdarg.h> 10 #include <stdarg.h>
(...skipping 436 matching lines...) Expand 10 before | Expand all | Expand 10 after
447 const char* b) { 447 const char* b) {
448 return DoLowerCaseEqualsASCII(a_begin, a_end, b); 448 return DoLowerCaseEqualsASCII(a_begin, a_end, b);
449 } 449 }
450 450
451 bool LowerCaseEqualsASCII(string16::const_iterator a_begin, 451 bool LowerCaseEqualsASCII(string16::const_iterator a_begin,
452 string16::const_iterator a_end, 452 string16::const_iterator a_end,
453 const char* b) { 453 const char* b) {
454 return DoLowerCaseEqualsASCII(a_begin, a_end, b); 454 return DoLowerCaseEqualsASCII(a_begin, a_end, b);
455 } 455 }
456 456
457 // TODO(jdduke): Remove guards after complete adoption of libc++ on Android. 457 // TODO(port): Resolve wchar_t/iterator issues that require OS_ANDROID here.
458 #if !defined(OS_ANDROID) || !defined(USE_STLPORT) 458 #if !defined(OS_ANDROID)
459 bool LowerCaseEqualsASCII(const char* a_begin, 459 bool LowerCaseEqualsASCII(const char* a_begin,
460 const char* a_end, 460 const char* a_end,
461 const char* b) { 461 const char* b) {
462 return DoLowerCaseEqualsASCII(a_begin, a_end, b); 462 return DoLowerCaseEqualsASCII(a_begin, a_end, b);
463 } 463 }
464 464
465 bool LowerCaseEqualsASCII(const char16* a_begin, 465 bool LowerCaseEqualsASCII(const char16* a_begin,
466 const char16* a_end, 466 const char16* a_end,
467 const char* b) { 467 const char* b) {
468 return DoLowerCaseEqualsASCII(a_begin, a_end, b); 468 return DoLowerCaseEqualsASCII(a_begin, a_end, b);
469 } 469 }
470 #endif // !defined(OS_ANDROID) || !defined(USE_STLPORT) 470
471 #endif // !defined(OS_ANDROID)
471 472
472 bool EqualsASCII(const string16& a, const base::StringPiece& b) { 473 bool EqualsASCII(const string16& a, const base::StringPiece& b) {
473 if (a.length() != b.length()) 474 if (a.length() != b.length())
474 return false; 475 return false;
475 return std::equal(b.begin(), b.end(), a.begin()); 476 return std::equal(b.begin(), b.end(), a.begin());
476 } 477 }
477 478
478 bool StartsWithASCII(const std::string& str, 479 bool StartsWithASCII(const std::string& str,
479 const std::string& search, 480 const std::string& search,
480 bool case_sensitive) { 481 bool case_sensitive) {
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
548 base::snprintf(buf, arraysize(buf), "%.1lf%s", unit_amount, 549 base::snprintf(buf, arraysize(buf), "%.1lf%s", unit_amount,
549 kByteStringsUnlocalized[dimension]); 550 kByteStringsUnlocalized[dimension]);
550 } else { 551 } else {
551 base::snprintf(buf, arraysize(buf), "%.0lf%s", unit_amount, 552 base::snprintf(buf, arraysize(buf), "%.0lf%s", unit_amount,
552 kByteStringsUnlocalized[dimension]); 553 kByteStringsUnlocalized[dimension]);
553 } 554 }
554 555
555 return base::ASCIIToUTF16(buf); 556 return base::ASCIIToUTF16(buf);
556 } 557 }
557 558
559 // Runs in O(n) time in the length of |str|.
558 template<class StringType> 560 template<class StringType>
559 void DoReplaceSubstringsAfterOffset(StringType* str, 561 void DoReplaceSubstringsAfterOffset(StringType* str,
560 size_t start_offset, 562 size_t offset,
561 const StringType& find_this, 563 const StringType& find_this,
562 const StringType& replace_with, 564 const StringType& replace_with,
563 bool replace_all) { 565 bool replace_all) {
564 if ((start_offset == StringType::npos) || (start_offset >= str->length())) 566 DCHECK(!find_this.empty());
567
568 // If the find string doesn't appear, there's nothing to do.
569 offset = str->find(find_this, offset);
570 if (offset == StringType::npos)
565 return; 571 return;
566 572
567 DCHECK(!find_this.empty()); 573 // If we're only replacing one instance, there's no need to do anything
568 for (size_t offs(str->find(find_this, start_offset)); 574 // complicated.
569 offs != StringType::npos; offs = str->find(find_this, offs)) { 575 size_t find_length = find_this.length();
570 str->replace(offs, find_this.length(), replace_with); 576 if (!replace_all) {
571 offs += replace_with.length(); 577 str->replace(offset, find_length, replace_with);
578 return;
579 }
572 580
573 if (!replace_all) 581 // If the find and replace strings are the same length, we can simply use
574 break; 582 // replace() on each instance, and finish the entire operation in O(n) time.
583 size_t replace_length = replace_with.length();
584 if (find_length == replace_length) {
585 do {
586 str->replace(offset, find_length, replace_with);
587 offset = str->find(find_this, offset + replace_length);
588 } while (offset != StringType::npos);
589 return;
590 }
591
592 // Since the find and replace strings aren't the same length, a loop like the
593 // one above would be O(n^2) in the worst case, as replace() will shift the
594 // entire remaining string each time. We need to be more clever to keep
595 // things O(n).
596 //
597 // If we're shortening the string, we can alternate replacements with shifting
598 // forward the intervening characters using memmove().
599 size_t str_length = str->length();
600 if (find_length > replace_length) {
601 size_t write_offset = offset;
602 do {
603 if (replace_length) {
604 str->replace(write_offset, replace_length, replace_with);
605 write_offset += replace_length;
606 }
607 size_t read_offset = offset + find_length;
608 offset = std::min(str->find(find_this, read_offset), str_length);
609 size_t length = offset - read_offset;
610 if (length) {
611 memmove(&(*str)[write_offset], &(*str)[read_offset],
612 length * sizeof(typename StringType::value_type));
613 write_offset += length;
614 }
615 } while (offset < str_length);
616 str->resize(write_offset);
617 return;
618 }
619
620 // We're lengthening the string. We can use alternating replacements and
621 // memmove() calls like above, but we need to precalculate the final string
622 // length and then expand from back-to-front to avoid overwriting the string
623 // as we're reading it, needing to shift, or having to copy to a second string
624 // temporarily.
625 size_t first_match = offset;
626
627 // First, calculate the final length and resize the string.
628 size_t final_length = str_length;
629 size_t expansion = replace_length - find_length;
630 size_t current_match;
631 do {
632 final_length += expansion;
633 // Minor optimization: save this offset into |current_match|, so that on
634 // exit from the loop, |current_match| will point at the last instance of
635 // the find string, and we won't need to find() it again immediately.
636 current_match = offset;
637 offset = str->find(find_this, offset + find_length);
638 } while (offset != StringType::npos);
639 str->resize(final_length);
640
641 // Now do the replacement loop, working backwards through the string.
642 for (size_t prev_match = str_length, write_offset = final_length; ;
643 current_match = str->rfind(find_this, current_match - 1)) {
644 size_t read_offset = current_match + find_length;
645 size_t length = prev_match - read_offset;
646 if (length) {
647 write_offset -= length;
648 memmove(&(*str)[write_offset], &(*str)[read_offset],
649 length * sizeof(typename StringType::value_type));
650 }
651 write_offset -= replace_length;
652 str->replace(write_offset, replace_length, replace_with);
653 if (current_match == first_match)
654 return;
655 prev_match = current_match;
575 } 656 }
576 } 657 }
577 658
578 void ReplaceFirstSubstringAfterOffset(string16* str, 659 void ReplaceFirstSubstringAfterOffset(string16* str,
579 size_t start_offset, 660 size_t start_offset,
580 const string16& find_this, 661 const string16& find_this,
581 const string16& replace_with) { 662 const string16& replace_with) {
582 DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with, 663 DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
583 false); // replace first instance 664 false); // replace first instance
584 } 665 }
(...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after
948 } 1029 }
949 1030
950 } // namespace 1031 } // namespace
951 1032
952 size_t base::strlcpy(char* dst, const char* src, size_t dst_size) { 1033 size_t base::strlcpy(char* dst, const char* src, size_t dst_size) {
953 return lcpyT<char>(dst, src, dst_size); 1034 return lcpyT<char>(dst, src, dst_size);
954 } 1035 }
955 size_t base::wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) { 1036 size_t base::wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) {
956 return lcpyT<wchar_t>(dst, src, dst_size); 1037 return lcpyT<wchar_t>(dst, src, dst_size);
957 } 1038 }
OLDNEW
« no previous file with comments | « base/process/process_info_win.cc ('k') | base/system_monitor/system_monitor.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698