| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  *  Created by Phil Nash on 15/6/2018. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Distributed under the Boost Software License, Version 1.0. (See accompanying | 
					
						
							|  |  |  |  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #ifndef TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
 | 
					
						
							|  |  |  | #define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "catch_interfaces_generatortracker.h"
 | 
					
						
							|  |  |  | #include "catch_common.h"
 | 
					
						
							| 
									
										
										
										
											2018-09-03 10:03:47 +02:00
										 |  |  | #include "catch_enforce.h"
 | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <memory>
 | 
					
						
							|  |  |  | #include <vector>
 | 
					
						
							|  |  |  | #include <cassert>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <utility>
 | 
					
						
							| 
									
										
										
										
											2019-01-27 23:50:43 +01:00
										 |  |  | #include <exception>
 | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace Catch { | 
					
						
							| 
									
										
										
										
											2019-01-27 23:50:43 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | class GeneratorException : public std::exception { | 
					
						
							|  |  |  |     const char* const m_msg = ""; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     GeneratorException(const char* msg): | 
					
						
							|  |  |  |         m_msg(msg) | 
					
						
							|  |  |  |     {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const char* what() const noexcept override final; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  | namespace Generators { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // !TBD move this into its own location?
 | 
					
						
							|  |  |  |     namespace pf{ | 
					
						
							|  |  |  |         template<typename T, typename... Args> | 
					
						
							|  |  |  |         std::unique_ptr<T> make_unique( Args&&... args ) { | 
					
						
							|  |  |  |             return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template<typename T> | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |     struct IGenerator : GeneratorUntypedBase { | 
					
						
							|  |  |  |         virtual ~IGenerator() = default; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Returns the current element of the generator
 | 
					
						
							|  |  |  |         //
 | 
					
						
							|  |  |  |         // \Precondition The generator is either freshly constructed,
 | 
					
						
							|  |  |  |         // or the last call to `next()` returned true
 | 
					
						
							|  |  |  |         virtual T const& get() const = 0; | 
					
						
							|  |  |  |         using type = T; | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template<typename T> | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |     class SingleValueGenerator final : public IGenerator<T> { | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |         T m_value; | 
					
						
							|  |  |  |     public: | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |         SingleValueGenerator(T const& value) : m_value( value ) {} | 
					
						
							|  |  |  |         SingleValueGenerator(T&& value) : m_value(std::move(value)) {} | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |         T const& get() const override { | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |             return m_value; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |         bool next() override { | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template<typename T> | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |     class FixedValuesGenerator final : public IGenerator<T> { | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |         std::vector<T> m_values; | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |         size_t m_idx = 0; | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |     public: | 
					
						
							|  |  |  |         FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |         T const& get() const override { | 
					
						
							|  |  |  |             return m_values[m_idx]; | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |         bool next() override { | 
					
						
							|  |  |  |             ++m_idx; | 
					
						
							|  |  |  |             return m_idx < m_values.size(); | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |     template <typename T> | 
					
						
							|  |  |  |     class GeneratorWrapper final { | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |         std::unique_ptr<IGenerator<T>> m_generator; | 
					
						
							|  |  |  |     public: | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |         GeneratorWrapper(std::unique_ptr<IGenerator<T>> generator): | 
					
						
							|  |  |  |             m_generator(std::move(generator)) | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |         {} | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |         T const& get() const { | 
					
						
							|  |  |  |             return m_generator->get(); | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |         bool next() { | 
					
						
							|  |  |  |             return m_generator->next(); | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |     template <typename T> | 
					
						
							|  |  |  |     GeneratorWrapper<T> value(T&& value) { | 
					
						
							|  |  |  |         return GeneratorWrapper<T>(pf::make_unique<SingleValueGenerator<T>>(std::forward<T>(value))); | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |     template <typename T> | 
					
						
							|  |  |  |     GeneratorWrapper<T> values(std::initializer_list<T> values) { | 
					
						
							|  |  |  |         return GeneratorWrapper<T>(pf::make_unique<FixedValuesGenerator<T>>(values)); | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template<typename T> | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |     class Generators : public IGenerator<T> { | 
					
						
							|  |  |  |         std::vector<GeneratorWrapper<T>> m_generators; | 
					
						
							|  |  |  |         size_t m_current = 0; | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |         void populate(GeneratorWrapper<T>&& generator) { | 
					
						
							|  |  |  |             m_generators.emplace_back(std::move(generator)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         void populate(T&& val) { | 
					
						
							|  |  |  |             m_generators.emplace_back(value(std::move(val))); | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         template<typename U> | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |         void populate(U&& val) { | 
					
						
							|  |  |  |             populate(T(std::move(val))); | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |         template<typename U, typename... Gs> | 
					
						
							|  |  |  |         void populate(U&& valueOrGenerator, Gs... moreGenerators) { | 
					
						
							|  |  |  |             populate(std::forward<U>(valueOrGenerator)); | 
					
						
							|  |  |  |             populate(std::forward<Gs>(moreGenerators)...); | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |     public: | 
					
						
							|  |  |  |         template <typename... Gs> | 
					
						
							|  |  |  |         Generators(Gs... moreGenerators) { | 
					
						
							|  |  |  |             m_generators.reserve(sizeof...(Gs)); | 
					
						
							|  |  |  |             populate(std::forward<Gs>(moreGenerators)...); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         T const& get() const override { | 
					
						
							|  |  |  |             return m_generators[m_current].get(); | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |         bool next() override { | 
					
						
							|  |  |  |             if (m_current >= m_generators.size()) { | 
					
						
							|  |  |  |                 return false; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             const bool current_status = m_generators[m_current].next(); | 
					
						
							|  |  |  |             if (!current_status) { | 
					
						
							|  |  |  |                 ++m_current; | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |             return m_current < m_generators.size(); | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     template<typename... Ts> | 
					
						
							|  |  |  |     GeneratorWrapper<std::tuple<Ts...>> table( std::initializer_list<std::tuple<typename std::decay<Ts>::type...>> tuples ) { | 
					
						
							|  |  |  |         return values<std::tuple<Ts...>>( tuples ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Tag type to signal that a generator sequence should convert arguments to a specific type
 | 
					
						
							|  |  |  |     template <typename T> | 
					
						
							|  |  |  |     struct as {}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |     template<typename T, typename... Gs> | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |     auto makeGenerators( GeneratorWrapper<T>&& generator, Gs... moreGenerators ) -> Generators<T> { | 
					
						
							|  |  |  |         return Generators<T>(std::move(generator), std::forward<Gs>(moreGenerators)...); | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     template<typename T> | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |     auto makeGenerators( GeneratorWrapper<T>&& generator ) -> Generators<T> { | 
					
						
							|  |  |  |         return Generators<T>(std::move(generator)); | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     template<typename T, typename... Gs> | 
					
						
							|  |  |  |     auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators<T> { | 
					
						
							|  |  |  |         return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     template<typename T, typename U, typename... Gs> | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |     auto makeGenerators( as<T>, U&& val, Gs... moreGenerators ) -> Generators<T> { | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |         return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-27 23:50:43 +01:00
										 |  |  |     template <typename T> | 
					
						
							|  |  |  |     class TakeGenerator : public IGenerator<T> { | 
					
						
							|  |  |  |         GeneratorWrapper<T> m_generator; | 
					
						
							|  |  |  |         size_t m_returned = 0; | 
					
						
							|  |  |  |         size_t m_target; | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |         TakeGenerator(size_t target, GeneratorWrapper<T>&& generator): | 
					
						
							|  |  |  |             m_generator(std::move(generator)), | 
					
						
							|  |  |  |             m_target(target) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             assert(target != 0 && "Empty generators are not allowed"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         T const& get() const override { | 
					
						
							|  |  |  |             return m_generator.get(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         bool next() override { | 
					
						
							|  |  |  |             ++m_returned; | 
					
						
							|  |  |  |             if (m_returned >= m_target) { | 
					
						
							|  |  |  |                 return false; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const auto success = m_generator.next(); | 
					
						
							|  |  |  |             // If the underlying generator does not contain enough values
 | 
					
						
							|  |  |  |             // then we cut short as well
 | 
					
						
							|  |  |  |             if (!success) { | 
					
						
							|  |  |  |                 m_returned = m_target; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             return success; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template <typename T> | 
					
						
							|  |  |  |     GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) { | 
					
						
							|  |  |  |         return GeneratorWrapper<T>(pf::make_unique<TakeGenerator<T>>(target, std::move(generator))); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template <typename T, typename Predicate> | 
					
						
							|  |  |  |     class FilterGenerator : public IGenerator<T> { | 
					
						
							|  |  |  |         GeneratorWrapper<T> m_generator; | 
					
						
							|  |  |  |         Predicate m_predicate; | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |         template <typename P = Predicate> | 
					
						
							|  |  |  |         FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator): | 
					
						
							|  |  |  |             m_generator(std::move(generator)), | 
					
						
							|  |  |  |             m_predicate(std::forward<P>(pred)) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (!m_predicate(m_generator.get())) { | 
					
						
							|  |  |  |                 // It might happen that there are no values that pass the
 | 
					
						
							|  |  |  |                 // filter. In that case we throw an exception.
 | 
					
						
							|  |  |  |                 auto has_initial_value = next(); | 
					
						
							|  |  |  |                 if (!has_initial_value) { | 
					
						
							|  |  |  |                     Catch::throw_exception(GeneratorException("No valid value found in filtered generator")); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         T const& get() const override { | 
					
						
							|  |  |  |             return m_generator.get(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         bool next() override { | 
					
						
							|  |  |  |             bool success = m_generator.next(); | 
					
						
							|  |  |  |             if (!success) { | 
					
						
							|  |  |  |                 return false; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true); | 
					
						
							|  |  |  |             return success; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template <typename T, typename Predicate> | 
					
						
							|  |  |  |     GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) { | 
					
						
							|  |  |  |         return GeneratorWrapper<T>(std::unique_ptr<IGenerator<T>>(pf::make_unique<FilterGenerator<T, Predicate>>(std::forward<Predicate>(pred), std::move(generator)))); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template <typename T> | 
					
						
							|  |  |  |     class RepeatGenerator : public IGenerator<T> { | 
					
						
							|  |  |  |         GeneratorWrapper<T> m_generator; | 
					
						
							|  |  |  |         mutable std::vector<T> m_returned; | 
					
						
							|  |  |  |         size_t m_target_repeats; | 
					
						
							|  |  |  |         size_t m_current_repeat = 0; | 
					
						
							|  |  |  |         size_t m_repeat_index = 0; | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |         RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator): | 
					
						
							|  |  |  |             m_generator(std::move(generator)), | 
					
						
							|  |  |  |             m_target_repeats(repeats) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             assert(m_target_repeats > 0 && "Repeat generator must repeat at least once"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         T const& get() const override { | 
					
						
							|  |  |  |             if (m_current_repeat == 0) { | 
					
						
							|  |  |  |                 m_returned.push_back(m_generator.get()); | 
					
						
							|  |  |  |                 return m_returned.back(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             return m_returned[m_repeat_index]; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         bool next() override { | 
					
						
							|  |  |  |             // There are 2 basic cases:
 | 
					
						
							|  |  |  |             // 1) We are still reading the generator
 | 
					
						
							|  |  |  |             // 2) We are reading our own cache
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // In the first case, we need to poke the underlying generator.
 | 
					
						
							|  |  |  |             // If it happily moves, we are left in that state, otherwise it is time to start reading from our cache
 | 
					
						
							|  |  |  |             if (m_current_repeat == 0) { | 
					
						
							|  |  |  |                 const auto success = m_generator.next(); | 
					
						
							|  |  |  |                 if (!success) { | 
					
						
							|  |  |  |                     ++m_current_repeat; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 return m_current_repeat < m_target_repeats; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // In the second case, we need to move indices forward and check that we haven't run up against the end
 | 
					
						
							|  |  |  |             ++m_repeat_index; | 
					
						
							|  |  |  |             if (m_repeat_index == m_returned.size()) { | 
					
						
							|  |  |  |                 m_repeat_index = 0; | 
					
						
							|  |  |  |                 ++m_current_repeat; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             return m_current_repeat < m_target_repeats; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template <typename T> | 
					
						
							|  |  |  |     GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) { | 
					
						
							|  |  |  |         return GeneratorWrapper<T>(pf::make_unique<RepeatGenerator<T>>(repeats, std::move(generator))); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template <typename T, typename U, typename Func> | 
					
						
							|  |  |  |     class MapGenerator : public IGenerator<T> { | 
					
						
							|  |  |  |         // TBD: provide static assert for mapping function, for friendly error message
 | 
					
						
							|  |  |  |         GeneratorWrapper<U> m_generator; | 
					
						
							|  |  |  |         Func m_function; | 
					
						
							|  |  |  |         // To avoid returning dangling reference, we have to save the values
 | 
					
						
							|  |  |  |         T m_cache; | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |         template <typename F2 = Func> | 
					
						
							|  |  |  |         MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) : | 
					
						
							|  |  |  |             m_generator(std::move(generator)), | 
					
						
							|  |  |  |             m_function(std::forward<F2>(function)), | 
					
						
							|  |  |  |             m_cache(m_function(m_generator.get())) | 
					
						
							|  |  |  |         {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         T const& get() const override { | 
					
						
							|  |  |  |             return m_cache; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         bool next() override { | 
					
						
							|  |  |  |             const auto success = m_generator.next(); | 
					
						
							|  |  |  |             if (success) { | 
					
						
							|  |  |  |                 m_cache = m_function(m_generator.get()); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             return success; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template <typename T, typename U, typename Func> | 
					
						
							|  |  |  |     GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) { | 
					
						
							|  |  |  |         return GeneratorWrapper<T>( | 
					
						
							|  |  |  |             pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator)) | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     template <typename T, typename Func> | 
					
						
							|  |  |  |     GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<T>&& generator) { | 
					
						
							|  |  |  |         return GeneratorWrapper<T>( | 
					
						
							|  |  |  |             pf::make_unique<MapGenerator<T, T, Func>>(std::forward<Func>(function), std::move(generator)) | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-03 16:42:24 +01:00
										 |  |  |     template <typename T> | 
					
						
							|  |  |  |     class RangeGenerator final : public IGenerator<T> { | 
					
						
							|  |  |  |         T m_current; | 
					
						
							|  |  |  |         T m_end; | 
					
						
							|  |  |  |         T m_step; | 
					
						
							|  |  |  |         bool m_positive; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |         RangeGenerator(T const& start, T const& end, T const& step): | 
					
						
							|  |  |  |             m_current(start), | 
					
						
							|  |  |  |             m_end(end), | 
					
						
							|  |  |  |             m_step(step), | 
					
						
							|  |  |  |             m_positive(m_step > T(0)) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             assert(m_current != m_end && "Range start and end cannot be equal"); | 
					
						
							|  |  |  |             assert(m_step != T(0) && "Step size cannot be zero"); | 
					
						
							|  |  |  |             assert(((m_positive && m_current <= m_end) || (!m_positive && m_current >= m_end)) && "Step moves away from end"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         RangeGenerator(T const& start, T const& end): | 
					
						
							|  |  |  |             RangeGenerator(start, end, (start < end) ? T(1) : T(-1)) | 
					
						
							|  |  |  |         {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         T const& get() const override { | 
					
						
							|  |  |  |             return m_current; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         bool next() override { | 
					
						
							|  |  |  |             m_current += m_step; | 
					
						
							|  |  |  |             return (m_positive) ? (m_current < m_end) : (m_current > m_end); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template <typename T> | 
					
						
							|  |  |  |     GeneratorWrapper<T> range(T const& start, T const& end, T const& step) { | 
					
						
							|  |  |  |         static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer"); | 
					
						
							|  |  |  |         return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end, step)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template <typename T> | 
					
						
							|  |  |  |     GeneratorWrapper<T> range(T const& start, T const& end) { | 
					
						
							|  |  |  |         static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer"); | 
					
						
							|  |  |  |         return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |     auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template<typename L> | 
					
						
							|  |  |  |     // Note: The type after -> is weird, because VS2015 cannot parse
 | 
					
						
							|  |  |  |     //       the expression used in the typedef inside, when it is in
 | 
					
						
							| 
									
										
										
										
											2019-02-18 10:33:41 +01:00
										 |  |  |     //       return type. Yeah.
 | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |     auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) { | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |         using UnderlyingType = typename decltype(generatorExpression())::type; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo ); | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |         if (!tracker.hasGenerator()) { | 
					
						
							|  |  |  |             tracker.setGenerator(pf::make_unique<Generators<UnderlyingType>>(generatorExpression())); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-27 19:46:28 +01:00
										 |  |  |         auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker.getGenerator() ); | 
					
						
							|  |  |  |         return generator.get(); | 
					
						
							| 
									
										
										
										
											2018-06-12 17:50:39 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // namespace Generators
 | 
					
						
							|  |  |  | } // namespace Catch
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define GENERATE( ... ) \
 | 
					
						
							|  |  |  |     Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, []{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif // TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
 |