File indexing completed on 2025-01-18 09:54:04
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef CATCH_GENERATORS_ADAPTERS_HPP_INCLUDED
0009 #define CATCH_GENERATORS_ADAPTERS_HPP_INCLUDED
0010
0011 #include <catch2/generators/catch_generators.hpp>
0012 #include <catch2/internal/catch_meta.hpp>
0013 #include <catch2/internal/catch_move_and_forward.hpp>
0014
0015 #include <cassert>
0016
0017 namespace Catch {
0018 namespace Generators {
0019
0020 template <typename T>
0021 class TakeGenerator final : public IGenerator<T> {
0022 GeneratorWrapper<T> m_generator;
0023 size_t m_returned = 0;
0024 size_t m_target;
0025 public:
0026 TakeGenerator(size_t target, GeneratorWrapper<T>&& generator):
0027 m_generator(CATCH_MOVE(generator)),
0028 m_target(target)
0029 {
0030 assert(target != 0 && "Empty generators are not allowed");
0031 }
0032 T const& get() const override {
0033 return m_generator.get();
0034 }
0035 bool next() override {
0036 ++m_returned;
0037 if (m_returned >= m_target) {
0038 return false;
0039 }
0040
0041 const auto success = m_generator.next();
0042
0043
0044 if (!success) {
0045 m_returned = m_target;
0046 }
0047 return success;
0048 }
0049 };
0050
0051 template <typename T>
0052 GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) {
0053 return GeneratorWrapper<T>(Catch::Detail::make_unique<TakeGenerator<T>>(target, CATCH_MOVE(generator)));
0054 }
0055
0056
0057 template <typename T, typename Predicate>
0058 class FilterGenerator final : public IGenerator<T> {
0059 GeneratorWrapper<T> m_generator;
0060 Predicate m_predicate;
0061 public:
0062 template <typename P = Predicate>
0063 FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator):
0064 m_generator(CATCH_MOVE(generator)),
0065 m_predicate(CATCH_FORWARD(pred))
0066 {
0067 if (!m_predicate(m_generator.get())) {
0068
0069
0070 auto has_initial_value = next();
0071 if (!has_initial_value) {
0072 Detail::throw_generator_exception("No valid value found in filtered generator");
0073 }
0074 }
0075 }
0076
0077 T const& get() const override {
0078 return m_generator.get();
0079 }
0080
0081 bool next() override {
0082 bool success = m_generator.next();
0083 if (!success) {
0084 return false;
0085 }
0086 while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true);
0087 return success;
0088 }
0089 };
0090
0091
0092 template <typename T, typename Predicate>
0093 GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) {
0094 return GeneratorWrapper<T>(Catch::Detail::make_unique<FilterGenerator<T, Predicate>>(CATCH_FORWARD(pred), CATCH_MOVE(generator)));
0095 }
0096
0097 template <typename T>
0098 class RepeatGenerator final : public IGenerator<T> {
0099 static_assert(!std::is_same<T, bool>::value,
0100 "RepeatGenerator currently does not support bools"
0101 "because of std::vector<bool> specialization");
0102 GeneratorWrapper<T> m_generator;
0103 mutable std::vector<T> m_returned;
0104 size_t m_target_repeats;
0105 size_t m_current_repeat = 0;
0106 size_t m_repeat_index = 0;
0107 public:
0108 RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator):
0109 m_generator(CATCH_MOVE(generator)),
0110 m_target_repeats(repeats)
0111 {
0112 assert(m_target_repeats > 0 && "Repeat generator must repeat at least once");
0113 }
0114
0115 T const& get() const override {
0116 if (m_current_repeat == 0) {
0117 m_returned.push_back(m_generator.get());
0118 return m_returned.back();
0119 }
0120 return m_returned[m_repeat_index];
0121 }
0122
0123 bool next() override {
0124
0125
0126
0127
0128
0129
0130 if (m_current_repeat == 0) {
0131 const auto success = m_generator.next();
0132 if (!success) {
0133 ++m_current_repeat;
0134 }
0135 return m_current_repeat < m_target_repeats;
0136 }
0137
0138
0139 ++m_repeat_index;
0140 if (m_repeat_index == m_returned.size()) {
0141 m_repeat_index = 0;
0142 ++m_current_repeat;
0143 }
0144 return m_current_repeat < m_target_repeats;
0145 }
0146 };
0147
0148 template <typename T>
0149 GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) {
0150 return GeneratorWrapper<T>(Catch::Detail::make_unique<RepeatGenerator<T>>(repeats, CATCH_MOVE(generator)));
0151 }
0152
0153 template <typename T, typename U, typename Func>
0154 class MapGenerator final : public IGenerator<T> {
0155
0156 GeneratorWrapper<U> m_generator;
0157 Func m_function;
0158
0159 T m_cache;
0160 public:
0161 template <typename F2 = Func>
0162 MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :
0163 m_generator(CATCH_MOVE(generator)),
0164 m_function(CATCH_FORWARD(function)),
0165 m_cache(m_function(m_generator.get()))
0166 {}
0167
0168 T const& get() const override {
0169 return m_cache;
0170 }
0171 bool next() override {
0172 const auto success = m_generator.next();
0173 if (success) {
0174 m_cache = m_function(m_generator.get());
0175 }
0176 return success;
0177 }
0178 };
0179
0180 template <typename Func, typename U, typename T = FunctionReturnType<Func, U>>
0181 GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
0182 return GeneratorWrapper<T>(
0183 Catch::Detail::make_unique<MapGenerator<T, U, Func>>(CATCH_FORWARD(function), CATCH_MOVE(generator))
0184 );
0185 }
0186
0187 template <typename T, typename U, typename Func>
0188 GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
0189 return GeneratorWrapper<T>(
0190 Catch::Detail::make_unique<MapGenerator<T, U, Func>>(CATCH_FORWARD(function), CATCH_MOVE(generator))
0191 );
0192 }
0193
0194 template <typename T>
0195 class ChunkGenerator final : public IGenerator<std::vector<T>> {
0196 std::vector<T> m_chunk;
0197 size_t m_chunk_size;
0198 GeneratorWrapper<T> m_generator;
0199 bool m_used_up = false;
0200 public:
0201 ChunkGenerator(size_t size, GeneratorWrapper<T> generator) :
0202 m_chunk_size(size), m_generator(CATCH_MOVE(generator))
0203 {
0204 m_chunk.reserve(m_chunk_size);
0205 if (m_chunk_size != 0) {
0206 m_chunk.push_back(m_generator.get());
0207 for (size_t i = 1; i < m_chunk_size; ++i) {
0208 if (!m_generator.next()) {
0209 Detail::throw_generator_exception("Not enough values to initialize the first chunk");
0210 }
0211 m_chunk.push_back(m_generator.get());
0212 }
0213 }
0214 }
0215 std::vector<T> const& get() const override {
0216 return m_chunk;
0217 }
0218 bool next() override {
0219 m_chunk.clear();
0220 for (size_t idx = 0; idx < m_chunk_size; ++idx) {
0221 if (!m_generator.next()) {
0222 return false;
0223 }
0224 m_chunk.push_back(m_generator.get());
0225 }
0226 return true;
0227 }
0228 };
0229
0230 template <typename T>
0231 GeneratorWrapper<std::vector<T>> chunk(size_t size, GeneratorWrapper<T>&& generator) {
0232 return GeneratorWrapper<std::vector<T>>(
0233 Catch::Detail::make_unique<ChunkGenerator<T>>(size, CATCH_MOVE(generator))
0234 );
0235 }
0236
0237 }
0238 }
0239
0240
0241 #endif