Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
catch_generators_generic.hpp
Go to the documentation of this file.
1/*
2 * Created by Martin on 23/2/2019.
3 *
4 * Distributed under the Boost Software License, Version 1.0. (See accompanying
5 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 */
7#ifndef TWOBLUECUBES_CATCH_GENERATORS_GENERIC_HPP_INCLUDED
8#define TWOBLUECUBES_CATCH_GENERATORS_GENERIC_HPP_INCLUDED
9
10#include "catch_generators.hpp"
11
12namespace Catch {
13namespace Generators {
14
15 template <typename T>
16 class TakeGenerator : public IGenerator<T> {
17 GeneratorWrapper<T> m_generator;
18 size_t m_returned = 0;
19 size_t m_target;
20 public:
21 TakeGenerator(size_t target, GeneratorWrapper<T>&& generator):
22 m_generator(std::move(generator)),
23 m_target(target)
24 {
25 assert(target != 0 && "Empty generators are not allowed");
26 }
27 T const& get() const override {
28 return m_generator.get();
29 }
30 bool next() override {
31 ++m_returned;
32 if (m_returned >= m_target) {
33 return false;
34 }
35
36 const auto success = m_generator.next();
37 // If the underlying generator does not contain enough values
38 // then we cut short as well
39 if (!success) {
40 m_returned = m_target;
41 }
42 return success;
43 }
44 };
45
46 template <typename T>
47 GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) {
48 return GeneratorWrapper<T>(pf::make_unique<TakeGenerator<T>>(target, std::move(generator)));
49 }
50
51
52 template <typename T, typename Predicate>
53 class FilterGenerator : public IGenerator<T> {
54 GeneratorWrapper<T> m_generator;
55 Predicate m_predicate;
56 public:
57 template <typename P = Predicate>
59 m_generator(std::move(generator)),
60 m_predicate(std::forward<P>(pred))
61 {
62 if (!m_predicate(m_generator.get())) {
63 // It might happen that there are no values that pass the
64 // filter. In that case we throw an exception.
65 auto has_initial_value = next();
66 if (!has_initial_value) {
67 Catch::throw_exception(GeneratorException("No valid value found in filtered generator"));
68 }
69 }
70 }
71
72 T const& get() const override {
73 return m_generator.get();
74 }
75
76 bool next() override {
77 bool success = m_generator.next();
78 if (!success) {
79 return false;
80 }
81 while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true);
82 return success;
83 }
84 };
85
86
87 template <typename T, typename Predicate>
89 return GeneratorWrapper<T>(std::unique_ptr<IGenerator<T>>(pf::make_unique<FilterGenerator<T, Predicate>>(std::forward<Predicate>(pred), std::move(generator))));
90 }
91
92 template <typename T>
93 class RepeatGenerator : public IGenerator<T> {
94 GeneratorWrapper<T> m_generator;
95 mutable std::vector<T> m_returned;
96 size_t m_target_repeats;
97 size_t m_current_repeat = 0;
98 size_t m_repeat_index = 0;
99 public:
100 RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator):
101 m_generator(std::move(generator)),
102 m_target_repeats(repeats)
103 {
104 assert(m_target_repeats > 0 && "Repeat generator must repeat at least once");
105 }
106
107 T const& get() const override {
108 if (m_current_repeat == 0) {
109 m_returned.push_back(m_generator.get());
110 return m_returned.back();
111 }
112 return m_returned[m_repeat_index];
113 }
114
115 bool next() override {
116 // There are 2 basic cases:
117 // 1) We are still reading the generator
118 // 2) We are reading our own cache
119
120 // In the first case, we need to poke the underlying generator.
121 // If it happily moves, we are left in that state, otherwise it is time to start reading from our cache
122 if (m_current_repeat == 0) {
123 const auto success = m_generator.next();
124 if (!success) {
125 ++m_current_repeat;
126 }
127 return m_current_repeat < m_target_repeats;
128 }
129
130 // In the second case, we need to move indices forward and check that we haven't run up against the end
131 ++m_repeat_index;
132 if (m_repeat_index == m_returned.size()) {
133 m_repeat_index = 0;
134 ++m_current_repeat;
135 }
136 return m_current_repeat < m_target_repeats;
137 }
138 };
139
140 template <typename T>
141 GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) {
142 return GeneratorWrapper<T>(pf::make_unique<RepeatGenerator<T>>(repeats, std::move(generator)));
143 }
144
145 template <typename T, typename U, typename Func>
146 class MapGenerator : public IGenerator<T> {
147 // TBD: provide static assert for mapping function, for friendly error message
148 GeneratorWrapper<U> m_generator;
149 Func m_function;
150 // To avoid returning dangling reference, we have to save the values
151 T m_cache;
152 public:
153 template <typename F2 = Func>
154 MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :
155 m_generator(std::move(generator)),
156 m_function(std::forward<F2>(function)),
157 m_cache(m_function(m_generator.get()))
158 {}
159
160 T const& get() const override {
161 return m_cache;
162 }
163 bool next() override {
164 const auto success = m_generator.next();
165 if (success) {
166 m_cache = m_function(m_generator.get());
167 }
168 return success;
169 }
170 };
171
172#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703
173 // std::result_of is deprecated in C++17 and removed in C++20. Hence, it is
174 // replaced with std::invoke_result here. Also *_t format is preferred over
175 // typename *::type format.
176 template <typename Func, typename U>
177 using MapFunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U>>>;
178#else
179 template <typename Func, typename U>
180 using MapFunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U)>::type>::type>::type;
181#endif
182
183 template <typename Func, typename U, typename T = MapFunctionReturnType<Func, U>>
184 GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
185 return GeneratorWrapper<T>(
186 pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))
187 );
188 }
189
190 template <typename T, typename U, typename Func>
191 GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
192 return GeneratorWrapper<T>(
193 pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))
194 );
195 }
196
197 template <typename T>
198 class ChunkGenerator final : public IGenerator<std::vector<T>> {
199 std::vector<T> m_chunk;
200 size_t m_chunk_size;
201 GeneratorWrapper<T> m_generator;
202 bool m_used_up = false;
203 public:
204 ChunkGenerator(size_t size, GeneratorWrapper<T> generator) :
205 m_chunk_size(size), m_generator(std::move(generator))
206 {
207 m_chunk.reserve(m_chunk_size);
208 m_chunk.push_back(m_generator.get());
209 for (size_t i = 1; i < m_chunk_size; ++i) {
210 if (!m_generator.next()) {
211 Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk"));
212 }
213 m_chunk.push_back(m_generator.get());
214 }
215 }
216 std::vector<T> const& get() const override {
217 return m_chunk;
218 }
219 bool next() override {
220 m_chunk.clear();
221 for (size_t idx = 0; idx < m_chunk_size; ++idx) {
222 if (!m_generator.next()) {
223 return false;
224 }
225 m_chunk.push_back(m_generator.get());
226 }
227 return true;
228 }
229 };
230
231 template <typename T>
234 pf::make_unique<ChunkGenerator<T>>(size, std::move(generator))
235 );
236 }
237
238} // namespace Generators
239} // namespace Catch
240
241
242#endif // TWOBLUECUBES_CATCH_GENERATORS_GENERIC_HPP_INCLUDED
ChunkGenerator(size_t size, GeneratorWrapper< T > generator)
std::vector< T > const & get() const override
FilterGenerator(P &&pred, GeneratorWrapper< T > &&generator)
MapGenerator(F2 &&function, GeneratorWrapper< U > &&generator)
RepeatGenerator(size_t repeats, GeneratorWrapper< T > &&generator)
TakeGenerator(size_t target, GeneratorWrapper< T > &&generator)
#define P
Definition dtoa.c:437
std::unique_ptr< T > make_unique(Args &&... args)
typename std::remove_reference< typename std::remove_cv< typename std::result_of< Func(U)>::type >::type >::type MapFunctionReturnType
GeneratorWrapper< std::vector< T > > chunk(size_t size, GeneratorWrapper< T > &&generator)
GeneratorWrapper< T > take(size_t target, GeneratorWrapper< T > &&generator)
Generic::PredicateMatcher< T > Predicate(std::function< bool(T const &)> const &predicate, std::string const &description="")
void throw_exception(std::exception const &e)
Definition name.hpp:106
#define T(meth, val, expected)
Definition dtoa.c:306
yh_object_type type
Definition yubihsm.h:672