Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:54:04

0001 
0002 //              Copyright Catch2 Authors
0003 // Distributed under the Boost Software License, Version 1.0.
0004 //   (See accompanying file LICENSE.txt or copy at
0005 //        https://www.boost.org/LICENSE_1_0.txt)
0006 
0007 // SPDX-License-Identifier: BSL-1.0
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             // If the underlying generator does not contain enough values
0043             // then we cut short as well
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                 // It might happen that there are no values that pass the
0069                 // filter. In that case we throw an exception.
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             // There are 2 basic cases:
0125             // 1) We are still reading the generator
0126             // 2) We are reading our own cache
0127 
0128             // In the first case, we need to poke the underlying generator.
0129             // If it happily moves, we are left in that state, otherwise it is time to start reading from our cache
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             // In the second case, we need to move indices forward and check that we haven't run up against the end
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         // TBD: provide static assert for mapping function, for friendly error message
0156         GeneratorWrapper<U> m_generator;
0157         Func m_function;
0158         // To avoid returning dangling reference, we have to save the values
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 } // namespace Generators
0238 } // namespace Catch
0239 
0240 
0241 #endif // CATCH_GENERATORS_ADAPTERS_HPP_INCLUDED