MapGenerator only calls mapping function if the result is used

Previously the mapping was eager on construction and calls to
`next()`. This was fine when generators were always exhausted fully,
but with the new generator filtering, we might not want to call
the map function eagerly; rather we want to call it only once,
after the generator is moved to the target element.
This commit is contained in:
Martin Hořeňovský committed 2026-02-15 20:44:21 +01:00
1 parent 3a0cf7e75f
commit 056e4fe88d
13 files changed
+117 -86

No files matched your search

@@ -11,6 +11,7 @@
#include <catch2/generators/catch_generators.hpp>
#include <catch2/internal/catch_meta.hpp>
#include <catch2/internal/catch_move_and_forward.hpp>
#include <catch2/internal/catch_optional.hpp>
#include <cassert>
@@ -182,7 +183,7 @@ namespace Generators {
GeneratorWrapper<U> m_generator;
Func m_function;
// To avoid returning dangling reference, we have to save the values
T m_cache;
mutable Optional<T> m_cache;
void skipToNthElementImpl( std::size_t n ) override {
for ( size_t curr = GeneratorUntypedBase::currentElementIndex();
@@ -202,19 +203,16 @@ namespace Generators {
template <typename F2 = Func>
MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :
m_generator(CATCH_MOVE(generator)),
m_function(CATCH_FORWARD(function)),
m_cache(m_function(m_generator.get()))
m_function(CATCH_FORWARD(function))
{}
T const& get() const override {
return m_cache;
if ( !m_cache ) { m_cache = m_function( m_generator.get() ); }
return *m_cache;
}
bool next() override {
const auto success = m_generator.next();
if (success) {
m_cache = m_function(m_generator.get());
}
return success;
m_cache.reset();
return m_generator.next();
}
bool isFinite() const override { return m_generator.isFinite(); }