Skip to content

Commit 024aec9

Browse files
committed
Add efficient skip forward to Values, Map and Take generators
1 parent 9eca713 commit 024aec9

20 files changed

Lines changed: 944 additions & 18 deletions

src/catch2/generators/catch_generators.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,15 @@ namespace Detail {
9393
"specialization, use SingleValue Generator instead.");
9494
std::vector<T> m_values;
9595
size_t m_idx = 0;
96+
97+
void skipToNthElementImpl( std::size_t n ) override {
98+
if ( n >= m_values.size() ) {
99+
Detail::throw_generator_exception(
100+
"Coud not jump to Nth element: not enough elements" );
101+
}
102+
m_idx = n;
103+
}
104+
96105
public:
97106
FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}
98107

src/catch2/generators/catch_generators_adapters.hpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,22 @@ namespace Generators {
2222
GeneratorWrapper<T> m_generator;
2323
size_t m_returned = 0;
2424
size_t m_target;
25+
26+
void skipToNthElementImpl( std::size_t n ) override {
27+
if ( n >= m_target ) {
28+
Detail::throw_generator_exception(
29+
"Coud not jump to Nth element: not enough elements" );
30+
}
31+
32+
for (; m_returned < n; ++m_returned) {
33+
const auto success = m_generator.next();
34+
if ( !success ) {
35+
Detail::throw_generator_exception(
36+
"Coud not jump to Nth element: not enough elements" );
37+
}
38+
}
39+
}
40+
2541
public:
2642
TakeGenerator(size_t target, GeneratorWrapper<T>&& generator):
2743
m_generator(CATCH_MOVE(generator)),
@@ -158,6 +174,21 @@ namespace Generators {
158174
Func m_function;
159175
// To avoid returning dangling reference, we have to save the values
160176
T m_cache;
177+
178+
void skipToNthElementImpl( std::size_t n ) override {
179+
for ( size_t curr = GeneratorUntypedBase::currentElementIndex();
180+
curr < n;
181+
++curr ) {
182+
const auto success = m_generator.next();
183+
if (!success) {
184+
Detail::throw_generator_exception(
185+
"Coud not jump to Nth element: not enough elements" );
186+
}
187+
}
188+
189+
m_cache = m_function( m_generator.get() );
190+
}
191+
161192
public:
162193
template <typename F2 = Func>
163194
MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ Nor would this
165165
:test-result: FAIL FAIL_CHECK does not abort the test
166166
:test-result: PASS Factorials are computed
167167
:test-result: PASS Filter generator throws exception for empty generator
168+
:test-result: PASS FixedValuesGenerator can be skipped forward
168169
:test-result: PASS Floating point matchers: double
169170
:test-result: PASS Floating point matchers: float
170171
:test-result: PASS GENERATE can combine literals and generators
@@ -190,6 +191,7 @@ Nor would this
190191
:test-result: PASS Lambdas in assertions
191192
:test-result: PASS Less-than inequalities with different epsilons
192193
:test-result: PASS ManuallyRegistered
194+
:test-result: PASS MapGenerator can be skipped forward efficiently
193195
:test-result: PASS Matchers can be (AllOf) composed with the && operator
194196
:test-result: PASS Matchers can be (AnyOf) composed with the || operator
195197
:test-result: PASS Matchers can be composed with both && and ||
@@ -262,6 +264,7 @@ Message from section two
262264
:test-result: FAIL Tabs and newlines show in output
263265
:test-result: PASS Tag alias can be registered against tag patterns
264266
:test-result: PASS Tags with spaces and non-alphanumerical characters are accepted
267+
:test-result: PASS TakeGenerator can be skipped forward
265268
:test-result: PASS Template test case method with test types specified inside std::tuple - MyTypes - 0
266269
:test-result: PASS Template test case method with test types specified inside std::tuple - MyTypes - 1
267270
:test-result: PASS Template test case method with test types specified inside std::tuple - MyTypes - 2

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@
163163
:test-result: FAIL FAIL_CHECK does not abort the test
164164
:test-result: PASS Factorials are computed
165165
:test-result: PASS Filter generator throws exception for empty generator
166+
:test-result: PASS FixedValuesGenerator can be skipped forward
166167
:test-result: PASS Floating point matchers: double
167168
:test-result: PASS Floating point matchers: float
168169
:test-result: PASS GENERATE can combine literals and generators
@@ -188,6 +189,7 @@
188189
:test-result: PASS Lambdas in assertions
189190
:test-result: PASS Less-than inequalities with different epsilons
190191
:test-result: PASS ManuallyRegistered
192+
:test-result: PASS MapGenerator can be skipped forward efficiently
191193
:test-result: PASS Matchers can be (AllOf) composed with the && operator
192194
:test-result: PASS Matchers can be (AnyOf) composed with the || operator
193195
:test-result: PASS Matchers can be composed with both && and ||
@@ -255,6 +257,7 @@
255257
:test-result: FAIL Tabs and newlines show in output
256258
:test-result: PASS Tag alias can be registered against tag patterns
257259
:test-result: PASS Tags with spaces and non-alphanumerical characters are accepted
260+
:test-result: PASS TakeGenerator can be skipped forward
258261
:test-result: PASS Template test case method with test types specified inside std::tuple - MyTypes - 0
259262
:test-result: PASS Template test case method with test types specified inside std::tuple - MyTypes - 1
260263
:test-result: PASS Template test case method with test types specified inside std::tuple - MyTypes - 2

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

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,12 @@ Misc.tests.cpp:<line number>: passed: Factorial(2) == 2 for: 2 == 2
678678
Misc.tests.cpp:<line number>: passed: Factorial(3) == 6 for: 6 == 6
679679
Misc.tests.cpp:<line number>: passed: Factorial(10) == 3628800 for: 3628800 (0x<hex digits>) == 3628800 (0x<hex digits>)
680680
GeneratorsImpl.tests.cpp:<line number>: passed: filter( []( int ) { return false; }, value( 3 ) ), Catch::GeneratorException
681+
GeneratorsImpl.tests.cpp:<line number>: passed: values.currentElementIndex() == 0 for: 0 == 0
682+
GeneratorsImpl.tests.cpp:<line number>: passed: values.currentElementIndex() == 3 for: 3 == 3
683+
GeneratorsImpl.tests.cpp:<line number>: passed: values.get() == 3 for: 3 == 3
684+
GeneratorsImpl.tests.cpp:<line number>: passed: values.currentElementIndex() == 4 for: 4 == 4
685+
GeneratorsImpl.tests.cpp:<line number>: passed: values.get() == 4 for: 4 == 4
686+
GeneratorsImpl.tests.cpp:<line number>: passed: values.skipToNthElement( 5 )
681687
Matchers.tests.cpp:<line number>: passed: 10., WithinRel( 11.1, 0.1 ) for: 10.0 and 11.09999999999999964 are within 10% of each other
682688
Matchers.tests.cpp:<line number>: passed: 10., !WithinRel( 11.2, 0.1 ) for: 10.0 not and 11.19999999999999929 are within 10% of each other
683689
Matchers.tests.cpp:<line number>: passed: 1., !WithinRel( 0., 0.99 ) for: 1.0 not and 0.0 are within 99% of each other
@@ -1243,6 +1249,14 @@ Approx.tests.cpp:<line number>: passed: d <= Approx( 1.22 ).epsilon(0.1) for: 1.
12431249
<=
12441250
Approx( 1.21999999999999997 )
12451251
Misc.tests.cpp:<line number>: passed: with 1 message: 'was called'
1252+
GeneratorsImpl.tests.cpp:<line number>: passed: map_generator.get() == 4 for: 4 == 4
1253+
GeneratorsImpl.tests.cpp:<line number>: passed: map_calls == map_calls_1 + 1 for: 2 == 2
1254+
GeneratorsImpl.tests.cpp:<line number>: passed: map_generator.get() == 4 for: 4 == 4
1255+
GeneratorsImpl.tests.cpp:<line number>: passed: map_calls == map_calls_1 + 1 for: 2 == 2
1256+
GeneratorsImpl.tests.cpp:<line number>: passed: map_generator.get() == 6 for: 6 == 6
1257+
GeneratorsImpl.tests.cpp:<line number>: passed: map_calls == map_calls_2 + 1 for: 3 == 3
1258+
GeneratorsImpl.tests.cpp:<line number>: passed: map_generator.skipToNthElement( 7 )
1259+
GeneratorsImpl.tests.cpp:<line number>: passed: map_calls == map_calls_2 + 1 for: 3 == 3
12461260
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), ContainsSubstring( "string" ) && ContainsSubstring( "abc" ) && ContainsSubstring( "substring" ) && ContainsSubstring( "contains" ) for: "this string contains 'abc' as a substring" ( contains: "string" and contains: "abc" and contains: "substring" and contains: "contains" )
12471261
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), ContainsSubstring( "string" ) || ContainsSubstring( "different" ) || ContainsSubstring( "random" ) for: "this string contains 'abc' as a substring" ( contains: "string" or contains: "different" or contains: "random" )
12481262
Matchers.tests.cpp:<line number>: passed: testStringForMatching2(), ContainsSubstring( "string" ) || ContainsSubstring( "different" ) || ContainsSubstring( "random" ) for: "some completely different text that contains one common word" ( contains: "string" or contains: "different" or contains: "random" )
@@ -1930,6 +1944,14 @@ Tag.tests.cpp:<line number>: passed: registry.add( "@no square bracket at start]
19301944
Tag.tests.cpp:<line number>: passed: registry.add( "[@no square bracket at end", "", Catch::SourceLineInfo( "file", 3 ) )
19311945
Tag.tests.cpp:<line number>: passed: testCase.tags.size() == 2 for: 2 == 2
19321946
Tag.tests.cpp:<line number>: passed: testCase.tags, VectorContains( Tag( "tag with spaces" ) ) && VectorContains( Tag( "I said \"good day\" sir!"_catch_sr ) ) for: { {?}, {?} } ( Contains: {?} and Contains: {?} )
1947+
GeneratorsImpl.tests.cpp:<line number>: passed: take.get() == 0 for: 0 == 0
1948+
GeneratorsImpl.tests.cpp:<line number>: passed: take.get() == 2 for: 2 == 2
1949+
GeneratorsImpl.tests.cpp:<line number>: passed: take.get() == 5 for: 5 == 5
1950+
GeneratorsImpl.tests.cpp:<line number>: passed: take.skipToNthElement( 6 )
1951+
GeneratorsImpl.tests.cpp:<line number>: passed: take.get() == 0 for: 0 == 0
1952+
GeneratorsImpl.tests.cpp:<line number>: passed: take.get() == 2 for: 2 == 2
1953+
GeneratorsImpl.tests.cpp:<line number>: passed: take.get() == 5 for: 5 == 5
1954+
GeneratorsImpl.tests.cpp:<line number>: passed: take.skipToNthElement( 6 )
19331955
Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for: 1 == 1
19341956
Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for: 1 == 1
19351957
Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for: 1.0 == 1
@@ -2924,7 +2946,7 @@ InternalBenchmark.tests.cpp:<line number>: passed: med == 18. for: 18.0 == 18.0
29242946
InternalBenchmark.tests.cpp:<line number>: passed: q3 == 23. for: 23.0 == 23.0
29252947
Misc.tests.cpp:<line number>: passed:
29262948
Misc.tests.cpp:<line number>: passed:
2927-
test cases: 440 | 320 passed | 96 failed | 6 skipped | 18 failed as expected
2928-
assertions: 2340 | 2139 passed | 158 failed | 43 failed as expected
2949+
test cases: 443 | 323 passed | 96 failed | 6 skipped | 18 failed as expected
2950+
assertions: 2362 | 2161 passed | 158 failed | 43 failed as expected
29292951

29302952

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

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,12 @@ Misc.tests.cpp:<line number>: passed: Factorial(2) == 2 for: 2 == 2
676676
Misc.tests.cpp:<line number>: passed: Factorial(3) == 6 for: 6 == 6
677677
Misc.tests.cpp:<line number>: passed: Factorial(10) == 3628800 for: 3628800 (0x<hex digits>) == 3628800 (0x<hex digits>)
678678
GeneratorsImpl.tests.cpp:<line number>: passed: filter( []( int ) { return false; }, value( 3 ) ), Catch::GeneratorException
679+
GeneratorsImpl.tests.cpp:<line number>: passed: values.currentElementIndex() == 0 for: 0 == 0
680+
GeneratorsImpl.tests.cpp:<line number>: passed: values.currentElementIndex() == 3 for: 3 == 3
681+
GeneratorsImpl.tests.cpp:<line number>: passed: values.get() == 3 for: 3 == 3
682+
GeneratorsImpl.tests.cpp:<line number>: passed: values.currentElementIndex() == 4 for: 4 == 4
683+
GeneratorsImpl.tests.cpp:<line number>: passed: values.get() == 4 for: 4 == 4
684+
GeneratorsImpl.tests.cpp:<line number>: passed: values.skipToNthElement( 5 )
679685
Matchers.tests.cpp:<line number>: passed: 10., WithinRel( 11.1, 0.1 ) for: 10.0 and 11.09999999999999964 are within 10% of each other
680686
Matchers.tests.cpp:<line number>: passed: 10., !WithinRel( 11.2, 0.1 ) for: 10.0 not and 11.19999999999999929 are within 10% of each other
681687
Matchers.tests.cpp:<line number>: passed: 1., !WithinRel( 0., 0.99 ) for: 1.0 not and 0.0 are within 99% of each other
@@ -1241,6 +1247,14 @@ Approx.tests.cpp:<line number>: passed: d <= Approx( 1.22 ).epsilon(0.1) for: 1.
12411247
<=
12421248
Approx( 1.21999999999999997 )
12431249
Misc.tests.cpp:<line number>: passed: with 1 message: 'was called'
1250+
GeneratorsImpl.tests.cpp:<line number>: passed: map_generator.get() == 4 for: 4 == 4
1251+
GeneratorsImpl.tests.cpp:<line number>: passed: map_calls == map_calls_1 + 1 for: 2 == 2
1252+
GeneratorsImpl.tests.cpp:<line number>: passed: map_generator.get() == 4 for: 4 == 4
1253+
GeneratorsImpl.tests.cpp:<line number>: passed: map_calls == map_calls_1 + 1 for: 2 == 2
1254+
GeneratorsImpl.tests.cpp:<line number>: passed: map_generator.get() == 6 for: 6 == 6
1255+
GeneratorsImpl.tests.cpp:<line number>: passed: map_calls == map_calls_2 + 1 for: 3 == 3
1256+
GeneratorsImpl.tests.cpp:<line number>: passed: map_generator.skipToNthElement( 7 )
1257+
GeneratorsImpl.tests.cpp:<line number>: passed: map_calls == map_calls_2 + 1 for: 3 == 3
12441258
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), ContainsSubstring( "string" ) && ContainsSubstring( "abc" ) && ContainsSubstring( "substring" ) && ContainsSubstring( "contains" ) for: "this string contains 'abc' as a substring" ( contains: "string" and contains: "abc" and contains: "substring" and contains: "contains" )
12451259
Matchers.tests.cpp:<line number>: passed: testStringForMatching(), ContainsSubstring( "string" ) || ContainsSubstring( "different" ) || ContainsSubstring( "random" ) for: "this string contains 'abc' as a substring" ( contains: "string" or contains: "different" or contains: "random" )
12461260
Matchers.tests.cpp:<line number>: passed: testStringForMatching2(), ContainsSubstring( "string" ) || ContainsSubstring( "different" ) || ContainsSubstring( "random" ) for: "some completely different text that contains one common word" ( contains: "string" or contains: "different" or contains: "random" )
@@ -1923,6 +1937,14 @@ Tag.tests.cpp:<line number>: passed: registry.add( "@no square bracket at start]
19231937
Tag.tests.cpp:<line number>: passed: registry.add( "[@no square bracket at end", "", Catch::SourceLineInfo( "file", 3 ) )
19241938
Tag.tests.cpp:<line number>: passed: testCase.tags.size() == 2 for: 2 == 2
19251939
Tag.tests.cpp:<line number>: passed: testCase.tags, VectorContains( Tag( "tag with spaces" ) ) && VectorContains( Tag( "I said \"good day\" sir!"_catch_sr ) ) for: { {?}, {?} } ( Contains: {?} and Contains: {?} )
1940+
GeneratorsImpl.tests.cpp:<line number>: passed: take.get() == 0 for: 0 == 0
1941+
GeneratorsImpl.tests.cpp:<line number>: passed: take.get() == 2 for: 2 == 2
1942+
GeneratorsImpl.tests.cpp:<line number>: passed: take.get() == 5 for: 5 == 5
1943+
GeneratorsImpl.tests.cpp:<line number>: passed: take.skipToNthElement( 6 )
1944+
GeneratorsImpl.tests.cpp:<line number>: passed: take.get() == 0 for: 0 == 0
1945+
GeneratorsImpl.tests.cpp:<line number>: passed: take.get() == 2 for: 2 == 2
1946+
GeneratorsImpl.tests.cpp:<line number>: passed: take.get() == 5 for: 5 == 5
1947+
GeneratorsImpl.tests.cpp:<line number>: passed: take.skipToNthElement( 6 )
19261948
Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for: 1 == 1
19271949
Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for: 1 == 1
19281950
Class.tests.cpp:<line number>: passed: Template_Fixture<TestType>::m_a == 1 for: 1.0 == 1
@@ -2913,7 +2935,7 @@ InternalBenchmark.tests.cpp:<line number>: passed: med == 18. for: 18.0 == 18.0
29132935
InternalBenchmark.tests.cpp:<line number>: passed: q3 == 23. for: 23.0 == 23.0
29142936
Misc.tests.cpp:<line number>: passed:
29152937
Misc.tests.cpp:<line number>: passed:
2916-
test cases: 440 | 320 passed | 96 failed | 6 skipped | 18 failed as expected
2917-
assertions: 2340 | 2139 passed | 158 failed | 43 failed as expected
2938+
test cases: 443 | 323 passed | 96 failed | 6 skipped | 18 failed as expected
2939+
assertions: 2362 | 2161 passed | 158 failed | 43 failed as expected
29182940

29192941

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1743,6 +1743,6 @@ due to unexpected exception with message:
17431743
Why would you throw a std::string?
17441744

17451745
===============================================================================
1746-
test cases: 440 | 338 passed | 76 failed | 7 skipped | 19 failed as expected
1747-
assertions: 2318 | 2139 passed | 136 failed | 43 failed as expected
1746+
test cases: 443 | 341 passed | 76 failed | 7 skipped | 19 failed as expected
1747+
assertions: 2340 | 2161 passed | 136 failed | 43 failed as expected
17481748

0 commit comments

Comments
 (0)