Skip to content

Commit 4d8affc

Browse files
mjerabekhorenmar
authored andcommitted
less copies and allocations in replaceInPlace
1 parent cde3509 commit 4d8affc

15 files changed

+318
-102
lines changed

src/catch2/internal/catch_string_manip.cpp

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// https://www.boost.org/LICENSE_1_0.txt)
66

77
// SPDX-License-Identifier: BSL-1.0
8+
#include <catch2/internal/catch_move_and_forward.hpp>
89
#include <catch2/internal/catch_string_manip.hpp>
910
#include <catch2/internal/catch_stringref.hpp>
1011

@@ -65,17 +66,29 @@ namespace Catch {
6566
}
6667

6768
bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
68-
bool replaced = false;
6969
std::size_t i = str.find( replaceThis );
70-
while( i != std::string::npos ) {
71-
replaced = true;
72-
str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() );
73-
if( i < str.size()-withThis.size() )
74-
i = str.find( replaceThis, i+withThis.size() );
70+
if (i == std::string::npos) {
71+
return false;
72+
}
73+
std::size_t copyBegin = 0;
74+
std::string origStr = CATCH_MOVE(str);
75+
str.clear();
76+
// There is at least one replacement, so reserve with the best guess
77+
// we can make without actually counting the number of occurences.
78+
str.reserve(origStr.size() - replaceThis.size() + withThis.size());
79+
do {
80+
str.append(origStr, copyBegin, i-copyBegin );
81+
str += withThis;
82+
copyBegin = i + replaceThis.size();
83+
if( copyBegin < origStr.size() )
84+
i = origStr.find( replaceThis, copyBegin );
7585
else
7686
i = std::string::npos;
87+
} while( i != std::string::npos );
88+
if ( copyBegin < origStr.size() ) {
89+
str.append(origStr, copyBegin, origStr.size() );
7790
}
78-
return replaced;
91+
return true;
7992
}
8093

8194
std::vector<StringRef> splitStringRef( StringRef str, char delimiter ) {

tests/SelfTest/Baselines/compact.sw.approved.txt

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1733,13 +1733,13 @@ Tag.tests.cpp:<line number>: passed: testCase.tags, VectorContains( Tag( "tag wi
17331733
Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for: 1 == 1
17341734
Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for: 1 == 1
17351735
Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for: 1.0 == 1
1736-
Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 1 > 0
1737-
Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 4 > 0
1738-
Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 1 > 0
1739-
Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 4 > 0
1740-
Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 4 > 0
1741-
Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 1 > 0
1742-
Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 4 > 0
1736+
Misc.tests.cpp:<line number>: passed: std::is_default_constructible<TestType>::value for: true
1737+
Misc.tests.cpp:<line number>: passed: std::is_default_constructible<TestType>::value for: true
1738+
Misc.tests.cpp:<line number>: passed: std::is_trivially_copyable<TestType>::value for: true
1739+
Misc.tests.cpp:<line number>: passed: std::is_trivially_copyable<TestType>::value for: true
1740+
Misc.tests.cpp:<line number>: passed: std::is_arithmetic<TestType>::value for: true
1741+
Misc.tests.cpp:<line number>: passed: std::is_arithmetic<TestType>::value for: true
1742+
Misc.tests.cpp:<line number>: passed: std::is_arithmetic<TestType>::value for: true
17431743
Misc.tests.cpp:<line number>: passed: v.size() == 5 for: 5 == 5
17441744
Misc.tests.cpp:<line number>: passed: v.capacity() >= 5 for: 5 >= 5
17451745
Misc.tests.cpp:<line number>: passed: v.size() == 10 for: 10 == 10
@@ -2479,6 +2479,10 @@ StringManip.tests.cpp:<line number>: passed: Catch::replaceInPlace(letters, lett
24792479
StringManip.tests.cpp:<line number>: passed: letters == "replaced" for: "replaced" == "replaced"
24802480
StringManip.tests.cpp:<line number>: passed: !(Catch::replaceInPlace(letters, "x", "z")) for: !false
24812481
StringManip.tests.cpp:<line number>: passed: letters == letters for: "abcdefcg" == "abcdefcg"
2482+
StringManip.tests.cpp:<line number>: passed: Catch::replaceInPlace(letters, "c", "cc") for: true
2483+
StringManip.tests.cpp:<line number>: passed: letters == "abccdefccg" for: "abccdefccg" == "abccdefccg"
2484+
StringManip.tests.cpp:<line number>: passed: Catch::replaceInPlace(s, "--", "-") for: true
2485+
StringManip.tests.cpp:<line number>: passed: s == "--" for: "--" == "--"
24822486
StringManip.tests.cpp:<line number>: passed: Catch::replaceInPlace(s, "'", "|'") for: true
24832487
StringManip.tests.cpp:<line number>: passed: s == "didn|'t" for: "didn|'t" == "didn|'t"
24842488
Stream.tests.cpp:<line number>: passed: Catch::makeStream( "%somestream" )
@@ -2686,6 +2690,6 @@ InternalBenchmark.tests.cpp:<line number>: passed: q3 == 23. for: 23.0 == 23.0
26862690
Misc.tests.cpp:<line number>: passed:
26872691
Misc.tests.cpp:<line number>: passed:
26882692
test cases: 417 | 312 passed | 85 failed | 6 skipped | 14 failed as expected
2689-
assertions: 2256 | 2075 passed | 146 failed | 35 failed as expected
2693+
assertions: 2260 | 2079 passed | 146 failed | 35 failed as expected
26902694

26912695

tests/SelfTest/Baselines/compact.sw.multi.approved.txt

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1726,13 +1726,13 @@ Tag.tests.cpp:<line number>: passed: testCase.tags, VectorContains( Tag( "tag wi
17261726
Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for: 1 == 1
17271727
Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for: 1 == 1
17281728
Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for: 1.0 == 1
1729-
Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 1 > 0
1730-
Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 4 > 0
1731-
Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 1 > 0
1732-
Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 4 > 0
1733-
Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 4 > 0
1734-
Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 1 > 0
1735-
Misc.tests.cpp:<line number>: passed: sizeof(TestType) > 0 for: 4 > 0
1729+
Misc.tests.cpp:<line number>: passed: std::is_default_constructible<TestType>::value for: true
1730+
Misc.tests.cpp:<line number>: passed: std::is_default_constructible<TestType>::value for: true
1731+
Misc.tests.cpp:<line number>: passed: std::is_trivially_copyable<TestType>::value for: true
1732+
Misc.tests.cpp:<line number>: passed: std::is_trivially_copyable<TestType>::value for: true
1733+
Misc.tests.cpp:<line number>: passed: std::is_arithmetic<TestType>::value for: true
1734+
Misc.tests.cpp:<line number>: passed: std::is_arithmetic<TestType>::value for: true
1735+
Misc.tests.cpp:<line number>: passed: std::is_arithmetic<TestType>::value for: true
17361736
Misc.tests.cpp:<line number>: passed: v.size() == 5 for: 5 == 5
17371737
Misc.tests.cpp:<line number>: passed: v.capacity() >= 5 for: 5 >= 5
17381738
Misc.tests.cpp:<line number>: passed: v.size() == 10 for: 10 == 10
@@ -2468,6 +2468,10 @@ StringManip.tests.cpp:<line number>: passed: Catch::replaceInPlace(letters, lett
24682468
StringManip.tests.cpp:<line number>: passed: letters == "replaced" for: "replaced" == "replaced"
24692469
StringManip.tests.cpp:<line number>: passed: !(Catch::replaceInPlace(letters, "x", "z")) for: !false
24702470
StringManip.tests.cpp:<line number>: passed: letters == letters for: "abcdefcg" == "abcdefcg"
2471+
StringManip.tests.cpp:<line number>: passed: Catch::replaceInPlace(letters, "c", "cc") for: true
2472+
StringManip.tests.cpp:<line number>: passed: letters == "abccdefccg" for: "abccdefccg" == "abccdefccg"
2473+
StringManip.tests.cpp:<line number>: passed: Catch::replaceInPlace(s, "--", "-") for: true
2474+
StringManip.tests.cpp:<line number>: passed: s == "--" for: "--" == "--"
24712475
StringManip.tests.cpp:<line number>: passed: Catch::replaceInPlace(s, "'", "|'") for: true
24722476
StringManip.tests.cpp:<line number>: passed: s == "didn|'t" for: "didn|'t" == "didn|'t"
24732477
Stream.tests.cpp:<line number>: passed: Catch::makeStream( "%somestream" )
@@ -2675,6 +2679,6 @@ InternalBenchmark.tests.cpp:<line number>: passed: q3 == 23. for: 23.0 == 23.0
26752679
Misc.tests.cpp:<line number>: passed:
26762680
Misc.tests.cpp:<line number>: passed:
26772681
test cases: 417 | 312 passed | 85 failed | 6 skipped | 14 failed as expected
2678-
assertions: 2256 | 2075 passed | 146 failed | 35 failed as expected
2682+
assertions: 2260 | 2079 passed | 146 failed | 35 failed as expected
26792683

26802684

tests/SelfTest/Baselines/console.std.approved.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1589,5 +1589,5 @@ due to unexpected exception with message:
15891589

15901590
===============================================================================
15911591
test cases: 417 | 326 passed | 70 failed | 7 skipped | 14 failed as expected
1592-
assertions: 2239 | 2075 passed | 129 failed | 35 failed as expected
1592+
assertions: 2243 | 2079 passed | 129 failed | 35 failed as expected
15931593

tests/SelfTest/Baselines/console.sw.approved.txt

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11655,9 +11655,9 @@ Misc.tests.cpp:<line number>
1165511655
...............................................................................
1165611656

1165711657
Misc.tests.cpp:<line number>: PASSED:
11658-
REQUIRE( sizeof(TestType) > 0 )
11658+
REQUIRE( std::is_default_constructible<TestType>::value )
1165911659
with expansion:
11660-
1 > 0
11660+
true
1166111661

1166211662
-------------------------------------------------------------------------------
1166311663
Template test case with test types specified inside non-copyable and non-
@@ -11667,9 +11667,9 @@ Misc.tests.cpp:<line number>
1166711667
...............................................................................
1166811668

1166911669
Misc.tests.cpp:<line number>: PASSED:
11670-
REQUIRE( sizeof(TestType) > 0 )
11670+
REQUIRE( std::is_default_constructible<TestType>::value )
1167111671
with expansion:
11672-
4 > 0
11672+
true
1167311673

1167411674
-------------------------------------------------------------------------------
1167511675
Template test case with test types specified inside non-default-constructible
@@ -11679,9 +11679,9 @@ Misc.tests.cpp:<line number>
1167911679
...............................................................................
1168011680

1168111681
Misc.tests.cpp:<line number>: PASSED:
11682-
REQUIRE( sizeof(TestType) > 0 )
11682+
REQUIRE( std::is_trivially_copyable<TestType>::value )
1168311683
with expansion:
11684-
1 > 0
11684+
true
1168511685

1168611686
-------------------------------------------------------------------------------
1168711687
Template test case with test types specified inside non-default-constructible
@@ -11691,9 +11691,9 @@ Misc.tests.cpp:<line number>
1169111691
...............................................................................
1169211692

1169311693
Misc.tests.cpp:<line number>: PASSED:
11694-
REQUIRE( sizeof(TestType) > 0 )
11694+
REQUIRE( std::is_trivially_copyable<TestType>::value )
1169511695
with expansion:
11696-
4 > 0
11696+
true
1169711697

1169811698
-------------------------------------------------------------------------------
1169911699
Template test case with test types specified inside std::tuple - MyTypes - 0
@@ -11702,9 +11702,9 @@ Misc.tests.cpp:<line number>
1170211702
...............................................................................
1170311703

1170411704
Misc.tests.cpp:<line number>: PASSED:
11705-
REQUIRE( sizeof(TestType) > 0 )
11705+
REQUIRE( std::is_arithmetic<TestType>::value )
1170611706
with expansion:
11707-
4 > 0
11707+
true
1170811708

1170911709
-------------------------------------------------------------------------------
1171011710
Template test case with test types specified inside std::tuple - MyTypes - 1
@@ -11713,9 +11713,9 @@ Misc.tests.cpp:<line number>
1171311713
...............................................................................
1171411714

1171511715
Misc.tests.cpp:<line number>: PASSED:
11716-
REQUIRE( sizeof(TestType) > 0 )
11716+
REQUIRE( std::is_arithmetic<TestType>::value )
1171711717
with expansion:
11718-
1 > 0
11718+
true
1171911719

1172011720
-------------------------------------------------------------------------------
1172111721
Template test case with test types specified inside std::tuple - MyTypes - 2
@@ -11724,9 +11724,9 @@ Misc.tests.cpp:<line number>
1172411724
...............................................................................
1172511725

1172611726
Misc.tests.cpp:<line number>: PASSED:
11727-
REQUIRE( sizeof(TestType) > 0 )
11727+
REQUIRE( std::is_arithmetic<TestType>::value )
1172811728
with expansion:
11729-
4 > 0
11729+
true
1173011730

1173111731
-------------------------------------------------------------------------------
1173211732
TemplateTest: vectors can be sized and resized - float
@@ -17289,6 +17289,42 @@ StringManip.tests.cpp:<line number>: PASSED:
1728917289
with expansion:
1729017290
"abcdefcg" == "abcdefcg"
1729117291

17292+
-------------------------------------------------------------------------------
17293+
replaceInPlace
17294+
no replace in already-replaced string
17295+
lengthening
17296+
-------------------------------------------------------------------------------
17297+
StringManip.tests.cpp:<line number>
17298+
...............................................................................
17299+
17300+
StringManip.tests.cpp:<line number>: PASSED:
17301+
CHECK( Catch::replaceInPlace(letters, "c", "cc") )
17302+
with expansion:
17303+
true
17304+
17305+
StringManip.tests.cpp:<line number>: PASSED:
17306+
CHECK( letters == "abccdefccg" )
17307+
with expansion:
17308+
"abccdefccg" == "abccdefccg"
17309+
17310+
-------------------------------------------------------------------------------
17311+
replaceInPlace
17312+
no replace in already-replaced string
17313+
shortening
17314+
-------------------------------------------------------------------------------
17315+
StringManip.tests.cpp:<line number>
17316+
...............................................................................
17317+
17318+
StringManip.tests.cpp:<line number>: PASSED:
17319+
CHECK( Catch::replaceInPlace(s, "--", "-") )
17320+
with expansion:
17321+
true
17322+
17323+
StringManip.tests.cpp:<line number>: PASSED:
17324+
CHECK( s == "--" )
17325+
with expansion:
17326+
"--" == "--"
17327+
1729217328
-------------------------------------------------------------------------------
1729317329
replaceInPlace
1729417330
escape '
@@ -18732,5 +18768,5 @@ Misc.tests.cpp:<line number>: PASSED:
1873218768

1873318769
===============================================================================
1873418770
test cases: 417 | 312 passed | 85 failed | 6 skipped | 14 failed as expected
18735-
assertions: 2256 | 2075 passed | 146 failed | 35 failed as expected
18771+
assertions: 2260 | 2079 passed | 146 failed | 35 failed as expected
1873618772

tests/SelfTest/Baselines/console.sw.multi.approved.txt

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11648,9 +11648,9 @@ Misc.tests.cpp:<line number>
1164811648
...............................................................................
1164911649

1165011650
Misc.tests.cpp:<line number>: PASSED:
11651-
REQUIRE( sizeof(TestType) > 0 )
11651+
REQUIRE( std::is_default_constructible<TestType>::value )
1165211652
with expansion:
11653-
1 > 0
11653+
true
1165411654

1165511655
-------------------------------------------------------------------------------
1165611656
Template test case with test types specified inside non-copyable and non-
@@ -11660,9 +11660,9 @@ Misc.tests.cpp:<line number>
1166011660
...............................................................................
1166111661

1166211662
Misc.tests.cpp:<line number>: PASSED:
11663-
REQUIRE( sizeof(TestType) > 0 )
11663+
REQUIRE( std::is_default_constructible<TestType>::value )
1166411664
with expansion:
11665-
4 > 0
11665+
true
1166611666

1166711667
-------------------------------------------------------------------------------
1166811668
Template test case with test types specified inside non-default-constructible
@@ -11672,9 +11672,9 @@ Misc.tests.cpp:<line number>
1167211672
...............................................................................
1167311673

1167411674
Misc.tests.cpp:<line number>: PASSED:
11675-
REQUIRE( sizeof(TestType) > 0 )
11675+
REQUIRE( std::is_trivially_copyable<TestType>::value )
1167611676
with expansion:
11677-
1 > 0
11677+
true
1167811678

1167911679
-------------------------------------------------------------------------------
1168011680
Template test case with test types specified inside non-default-constructible
@@ -11684,9 +11684,9 @@ Misc.tests.cpp:<line number>
1168411684
...............................................................................
1168511685

1168611686
Misc.tests.cpp:<line number>: PASSED:
11687-
REQUIRE( sizeof(TestType) > 0 )
11687+
REQUIRE( std::is_trivially_copyable<TestType>::value )
1168811688
with expansion:
11689-
4 > 0
11689+
true
1169011690

1169111691
-------------------------------------------------------------------------------
1169211692
Template test case with test types specified inside std::tuple - MyTypes - 0
@@ -11695,9 +11695,9 @@ Misc.tests.cpp:<line number>
1169511695
...............................................................................
1169611696

1169711697
Misc.tests.cpp:<line number>: PASSED:
11698-
REQUIRE( sizeof(TestType) > 0 )
11698+
REQUIRE( std::is_arithmetic<TestType>::value )
1169911699
with expansion:
11700-
4 > 0
11700+
true
1170111701

1170211702
-------------------------------------------------------------------------------
1170311703
Template test case with test types specified inside std::tuple - MyTypes - 1
@@ -11706,9 +11706,9 @@ Misc.tests.cpp:<line number>
1170611706
...............................................................................
1170711707

1170811708
Misc.tests.cpp:<line number>: PASSED:
11709-
REQUIRE( sizeof(TestType) > 0 )
11709+
REQUIRE( std::is_arithmetic<TestType>::value )
1171011710
with expansion:
11711-
1 > 0
11711+
true
1171211712

1171311713
-------------------------------------------------------------------------------
1171411714
Template test case with test types specified inside std::tuple - MyTypes - 2
@@ -11717,9 +11717,9 @@ Misc.tests.cpp:<line number>
1171711717
...............................................................................
1171811718

1171911719
Misc.tests.cpp:<line number>: PASSED:
11720-
REQUIRE( sizeof(TestType) > 0 )
11720+
REQUIRE( std::is_arithmetic<TestType>::value )
1172111721
with expansion:
11722-
4 > 0
11722+
true
1172311723

1172411724
-------------------------------------------------------------------------------
1172511725
TemplateTest: vectors can be sized and resized - float
@@ -17278,6 +17278,42 @@ StringManip.tests.cpp:<line number>: PASSED:
1727817278
with expansion:
1727917279
"abcdefcg" == "abcdefcg"
1728017280

17281+
-------------------------------------------------------------------------------
17282+
replaceInPlace
17283+
no replace in already-replaced string
17284+
lengthening
17285+
-------------------------------------------------------------------------------
17286+
StringManip.tests.cpp:<line number>
17287+
...............................................................................
17288+
17289+
StringManip.tests.cpp:<line number>: PASSED:
17290+
CHECK( Catch::replaceInPlace(letters, "c", "cc") )
17291+
with expansion:
17292+
true
17293+
17294+
StringManip.tests.cpp:<line number>: PASSED:
17295+
CHECK( letters == "abccdefccg" )
17296+
with expansion:
17297+
"abccdefccg" == "abccdefccg"
17298+
17299+
-------------------------------------------------------------------------------
17300+
replaceInPlace
17301+
no replace in already-replaced string
17302+
shortening
17303+
-------------------------------------------------------------------------------
17304+
StringManip.tests.cpp:<line number>
17305+
...............................................................................
17306+
17307+
StringManip.tests.cpp:<line number>: PASSED:
17308+
CHECK( Catch::replaceInPlace(s, "--", "-") )
17309+
with expansion:
17310+
true
17311+
17312+
StringManip.tests.cpp:<line number>: PASSED:
17313+
CHECK( s == "--" )
17314+
with expansion:
17315+
"--" == "--"
17316+
1728117317
-------------------------------------------------------------------------------
1728217318
replaceInPlace
1728317319
escape '
@@ -18721,5 +18757,5 @@ Misc.tests.cpp:<line number>: PASSED:
1872118757

1872218758
===============================================================================
1872318759
test cases: 417 | 312 passed | 85 failed | 6 skipped | 14 failed as expected
18724-
assertions: 2256 | 2075 passed | 146 failed | 35 failed as expected
18760+
assertions: 2260 | 2079 passed | 146 failed | 35 failed as expected
1872518761

0 commit comments

Comments
 (0)