Skip to content

Commit fecf606

Browse files
committed
Add option to skip forward to the generator interface
1 parent 363ca5a commit fecf606

22 files changed

Lines changed: 353 additions & 19 deletions

docs/generators.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,9 +252,23 @@ struct IGenerator : GeneratorUntypedBase {
252252
// Returns user-friendly string showing the current generator element
253253
// Does not have to be overridden, IGenerator provides default implementation
254254
virtual std::string stringifyImpl() const;
255+
256+
/**
257+
* Customization point for `skipToNthElement`
258+
*
259+
* Does not have to be overridden, there is a default implementation.
260+
* Can be overridden for better performance.
261+
*
262+
* If there are not enough elements, shall throw an error.
263+
*
264+
* Going backwards is not supported.
265+
*/
266+
virtual void skipToNthElementImpl( std::size_t n );
255267
};
256268
```
257269

270+
> `skipToNthElementImpl` was added in Catch2 vX.Y.Z
271+
258272
However, to be able to use your custom generator inside `GENERATE`, it
259273
will need to be wrapped inside a `GeneratorWrapper<T>`.
260274
`GeneratorWrapper<T>` is a value wrapper around a

examples/300-Gen-OwnGenerator.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,22 @@ class RandomIntGenerator final : public Catch::Generators::IGenerator<int> {
3939
current_number = m_dist(m_rand);
4040
return true;
4141
}
42+
43+
// Note: this improves the performance only a bit, but it is here
44+
// to show how you can override the skip functionality.
45+
void skipToNthElementImpl( std::size_t n ) override {
46+
auto current_index = currentElementIndex();
47+
assert(current_index <= n);
48+
// We cannot jump forward the underlying generator directly,
49+
// because we do not know how many bits each distributed number
50+
// would consume to be generated.
51+
for (; current_index < n; ++current_index) {
52+
(void)m_dist(m_rand);
53+
}
54+
55+
// We do not have to touch the current element index; it is handled
56+
// by the base class.
57+
}
4258
};
4359

4460
// Avoids -Wweak-vtables

src/catch2/interfaces/catch_interfaces_generatortracker.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
// SPDX-License-Identifier: BSL-1.0
88

99
#include <catch2/interfaces/catch_interfaces_generatortracker.hpp>
10+
#include <catch2/generators/catch_generators.hpp>
11+
1012
#include <string>
1113

1214
namespace Catch {
@@ -21,6 +23,30 @@ namespace Catch {
2123
return ret;
2224
}
2325

26+
void GeneratorUntypedBase::skipToNthElementImpl( std::size_t n ) {
27+
for ( size_t i = m_currentElementIndex; i < n; ++i ) {
28+
bool isValid = next();
29+
if ( !isValid ) {
30+
Detail::throw_generator_exception(
31+
"Coud not jump to Nth element: not enough elements" );
32+
}
33+
}
34+
}
35+
36+
void GeneratorUntypedBase::skipToNthElement( std::size_t n ) {
37+
if ( n < m_currentElementIndex ) {
38+
Detail::throw_generator_exception(
39+
"Tried to jump generator backwards" );
40+
}
41+
skipToNthElementImpl(n);
42+
43+
// Fixup tracking after moving the generator forward
44+
// * Ensure that the correct element index is set after skipping
45+
// * Invalidate cache
46+
m_currentElementIndex = n;
47+
m_stringReprCache.clear();
48+
}
49+
2450
StringRef GeneratorUntypedBase::currentElementAsString() const {
2551
if ( m_stringReprCache.empty() ) {
2652
m_stringReprCache = stringifyImpl();

src/catch2/interfaces/catch_interfaces_generatortracker.hpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ namespace Catch {
3535
//! Customization point for `currentElementAsString`
3636
virtual std::string stringifyImpl() const = 0;
3737

38+
/**
39+
* Customization point for skipping to the n-th element
40+
*
41+
* Defaults to successively calling `countedNext`. If there
42+
* are not enough elements to reach the nth one, will throw
43+
* an error.
44+
*/
45+
virtual void skipToNthElementImpl( std::size_t n );
46+
3847
public:
3948
GeneratorUntypedBase() = default;
4049
// Generation of copy ops is deprecated (and Clang will complain)
@@ -58,6 +67,13 @@ namespace Catch {
5867

5968
std::size_t currentElementIndex() const { return m_currentElementIndex; }
6069

70+
/**
71+
* Moves the generator forward **to** the n-th element
72+
*
73+
* Cannot move backwards.
74+
*/
75+
void skipToNthElement( std::size_t n );
76+
6177
/**
6278
* Returns generator's current element as user-friendly string.
6379
*

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ Nor would this
168168
:test-result: PASS GENERATE can combine literals and generators
169169
:test-result: PASS Generators -- adapters
170170
:test-result: PASS Generators -- simple
171+
:test-result: PASS Generators can be skipped forward
171172
:test-result: PASS Generators internals
172173
:test-result: PASS Greater-than inequalities with different epsilons
173174
:test-result: PASS Hashers with different seed produce different hash with same test case

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@
166166
:test-result: PASS GENERATE can combine literals and generators
167167
:test-result: PASS Generators -- adapters
168168
:test-result: PASS Generators -- simple
169+
:test-result: PASS Generators can be skipped forward
169170
:test-result: PASS Generators internals
170171
:test-result: PASS Greater-than inequalities with different epsilons
171172
:test-result: PASS Hashers with different seed produce different hash with same test case

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,13 @@ Generators.tests.cpp:<line number>: passed: j < i for: -1 < 3
787787
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 12 > 1
788788
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 12 > 2
789789
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 12 > 3
790+
GeneratorsImpl.tests.cpp:<line number>: passed: generator.currentElementIndex() == 0 for: 0 == 0
791+
GeneratorsImpl.tests.cpp:<line number>: passed: generator.currentElementIndex() == 3 for: 3 == 3
792+
GeneratorsImpl.tests.cpp:<line number>: passed: generator.get() == 3 for: 3 == 3
793+
GeneratorsImpl.tests.cpp:<line number>: passed: generator.currentElementIndex() == 5 for: 5 == 5
794+
GeneratorsImpl.tests.cpp:<line number>: passed: generator.get() == 5 for: 5 == 5
795+
GeneratorsImpl.tests.cpp:<line number>: passed: generator.skipToNthElement( 3 )
796+
GeneratorsImpl.tests.cpp:<line number>: passed: generator.skipToNthElement( 6 )
790797
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 123 for: 123 == 123
791798
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
792799
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 1 for: 1 == 1
@@ -2888,7 +2895,7 @@ InternalBenchmark.tests.cpp:<line number>: passed: med == 18. for: 18.0 == 18.0
28882895
InternalBenchmark.tests.cpp:<line number>: passed: q3 == 23. for: 23.0 == 23.0
28892896
Misc.tests.cpp:<line number>: passed:
28902897
Misc.tests.cpp:<line number>: passed:
2891-
test cases: 435 | 317 passed | 95 failed | 6 skipped | 17 failed as expected
2892-
assertions: 2303 | 2105 passed | 157 failed | 41 failed as expected
2898+
test cases: 436 | 318 passed | 95 failed | 6 skipped | 17 failed as expected
2899+
assertions: 2310 | 2112 passed | 157 failed | 41 failed as expected
28932900

28942901

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,13 @@ Generators.tests.cpp:<line number>: passed: j < i for: -1 < 3
785785
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 12 > 1
786786
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 12 > 2
787787
Generators.tests.cpp:<line number>: passed: 4u * i > str.size() for: 12 > 3
788+
GeneratorsImpl.tests.cpp:<line number>: passed: generator.currentElementIndex() == 0 for: 0 == 0
789+
GeneratorsImpl.tests.cpp:<line number>: passed: generator.currentElementIndex() == 3 for: 3 == 3
790+
GeneratorsImpl.tests.cpp:<line number>: passed: generator.get() == 3 for: 3 == 3
791+
GeneratorsImpl.tests.cpp:<line number>: passed: generator.currentElementIndex() == 5 for: 5 == 5
792+
GeneratorsImpl.tests.cpp:<line number>: passed: generator.get() == 5 for: 5 == 5
793+
GeneratorsImpl.tests.cpp:<line number>: passed: generator.skipToNthElement( 3 )
794+
GeneratorsImpl.tests.cpp:<line number>: passed: generator.skipToNthElement( 6 )
788795
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 123 for: 123 == 123
789796
GeneratorsImpl.tests.cpp:<line number>: passed: !(gen.next()) for: !false
790797
GeneratorsImpl.tests.cpp:<line number>: passed: gen.get() == 1 for: 1 == 1
@@ -2877,7 +2884,7 @@ InternalBenchmark.tests.cpp:<line number>: passed: med == 18. for: 18.0 == 18.0
28772884
InternalBenchmark.tests.cpp:<line number>: passed: q3 == 23. for: 23.0 == 23.0
28782885
Misc.tests.cpp:<line number>: passed:
28792886
Misc.tests.cpp:<line number>: passed:
2880-
test cases: 435 | 317 passed | 95 failed | 6 skipped | 17 failed as expected
2881-
assertions: 2303 | 2105 passed | 157 failed | 41 failed as expected
2887+
test cases: 436 | 318 passed | 95 failed | 6 skipped | 17 failed as expected
2888+
assertions: 2310 | 2112 passed | 157 failed | 41 failed as expected
28822889

28832890

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

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

17211721
===============================================================================
1722-
test cases: 435 | 335 passed | 76 failed | 7 skipped | 17 failed as expected
1723-
assertions: 2282 | 2105 passed | 136 failed | 41 failed as expected
1722+
test cases: 436 | 336 passed | 76 failed | 7 skipped | 17 failed as expected
1723+
assertions: 2289 | 2112 passed | 136 failed | 41 failed as expected
17241724

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

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5831,6 +5831,43 @@ Generators.tests.cpp:<line number>: PASSED:
58315831
with expansion:
58325832
12 > 3
58335833

5834+
-------------------------------------------------------------------------------
5835+
Generators can be skipped forward
5836+
-------------------------------------------------------------------------------
5837+
GeneratorsImpl.tests.cpp:<line number>
5838+
...............................................................................
5839+
5840+
GeneratorsImpl.tests.cpp:<line number>: PASSED:
5841+
REQUIRE( generator.currentElementIndex() == 0 )
5842+
with expansion:
5843+
0 == 0
5844+
5845+
GeneratorsImpl.tests.cpp:<line number>: PASSED:
5846+
REQUIRE( generator.currentElementIndex() == 3 )
5847+
with expansion:
5848+
3 == 3
5849+
5850+
GeneratorsImpl.tests.cpp:<line number>: PASSED:
5851+
REQUIRE( generator.get() == 3 )
5852+
with expansion:
5853+
3 == 3
5854+
5855+
GeneratorsImpl.tests.cpp:<line number>: PASSED:
5856+
REQUIRE( generator.currentElementIndex() == 5 )
5857+
with expansion:
5858+
5 == 5
5859+
5860+
GeneratorsImpl.tests.cpp:<line number>: PASSED:
5861+
REQUIRE( generator.get() == 5 )
5862+
with expansion:
5863+
5 == 5
5864+
5865+
GeneratorsImpl.tests.cpp:<line number>: PASSED:
5866+
REQUIRE_THROWS( generator.skipToNthElement( 3 ) )
5867+
5868+
GeneratorsImpl.tests.cpp:<line number>: PASSED:
5869+
REQUIRE_THROWS( generator.skipToNthElement( 6 ) )
5870+
58345871
-------------------------------------------------------------------------------
58355872
Generators internals
58365873
Single value
@@ -19295,6 +19332,6 @@ Misc.tests.cpp:<line number>
1929519332
Misc.tests.cpp:<line number>: PASSED:
1929619333

1929719334
===============================================================================
19298-
test cases: 435 | 317 passed | 95 failed | 6 skipped | 17 failed as expected
19299-
assertions: 2303 | 2105 passed | 157 failed | 41 failed as expected
19335+
test cases: 436 | 318 passed | 95 failed | 6 skipped | 17 failed as expected
19336+
assertions: 2310 | 2112 passed | 157 failed | 41 failed as expected
1930019337

0 commit comments

Comments
 (0)