Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
oneof_generator.h
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#pragma once
5
6#include "../../namespaces.h"
7#include "../../utilities/statistics/percentages.h"
8#include "../../utilities/semantics/generator_handler.h"
9
10#include <catch/catch.hpp>
11
12#include <vector>
13#include <random>
14#include <algorithm>
15#include <numeric>
16
19
20 template<typename T>
22 public:
24 std::vector<Catch::Generators::GeneratorWrapper<T>>&& generators,
25 const std::vector<double>& weights
27 random_engine{std::random_device{}()},
29 {
30 assert(weights.size() == this->generators.size());
31 assert(std::reduce(weights.cbegin(), weights.cend()) == Approx(100.0));
32
33 std::transform(
34 this->generators.begin(), this->generators.end(), this->generators.begin(),
35 [](auto& generator){ return QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE::handler(std::move(generator)); }
36 );
37
38 static_cast<void>(next());
39 }
40
41 T const& get() const override { return current_value; }
42
43 bool next() override {
44 std::size_t generator_index{choice_distribution(random_engine)};
45
46 if (!generators[generator_index].next()) return false;
47 current_value = generators[generator_index].get();
48
49 return true;
50 }
51
52 private:
53 std::vector<Catch::Generators::GeneratorWrapper<T>> generators;
54
55 std::mt19937 random_engine;
56 std::discrete_distribution<std::size_t> choice_distribution;
57
58 T current_value;
59 };
60
61 } // end QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE
62
63 /*!
64 * Returns a generator whose set of elements is the union of the
65 * set of elements of the generators in \a generators.
66 *
67 * Each time the generator produces a value, a generator from \a
68 * generators is randomly chosen to produce the value.
69 *
70 * The distribution for the choice is given by \a weights.
71 * The \e {ith} element in \a weights represent the percentage
72 * probability of the \e {ith} element of \a generators to be
73 * chosen.
74 *
75 * It follows that the size of \a weights must be the same as the
76 * size of \a generators.
77 *
78 * Furthermore, the sum of elements in \a weights should be a
79 * hundred.
80 *
81 * The generator produces values until a generator that is chosen
82 * to produce a value is unable to do so.
83 * The first such generator to do so will stop the generation
84 * independently of the availability of the other generators.
85 *
86 * Similarly, values will be produced as long as the chosen
87 * generator can produce a value, independently of the other
88 * generators being exhausted already.
89 */
90 template<typename T>
91 inline Catch::Generators::GeneratorWrapper<T> oneof(
92 std::vector<Catch::Generators::GeneratorWrapper<T>>&& generators,
93 const std::vector<double>& weights
94 ) {
95 return Catch::Generators::GeneratorWrapper<T>(std::unique_ptr<Catch::Generators::IGenerator<T>>(new QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE::OneOfGenerator(std::move(generators), weights)));
96 }
97
98
99 /*!
100 * Returns a generator whose set of elements is the union of the
101 * set of elements of the generators in \a generators and in which
102 * the distribution of the generated elements is uniform over \a
103 * generators.
104 *
105 * Each time the generator produces a value, a generator from \a
106 * generators is randomly chosen to produce the value.
107 *
108 * Each generator from \a generators has the same chance of being
109 * chosen.
110 *
111 * Do note that the distribution over the set of values is not
112 * necessarily uniform.
113 *
114 * The generator produces values until a generator that is chosen
115 * to produce a value is unable to do so.
116 * The first such generator to do so will stop the generation
117 * independently of the availability of the other generators.
118 *
119 * Similarly, values will be produced as long as the chosen
120 * generator can produce a value, independently of the other
121 * generators being exhausted already.
122 */
123 template<typename T>
124 inline Catch::Generators::GeneratorWrapper<T> uniform_oneof(
125 std::vector<Catch::Generators::GeneratorWrapper<T>>&& generators
126 ) {
127 std::vector<double> weights(
128 generators.size(),
129 QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE::uniform_probability(generators.size())
130 );
131 return oneof(std::move(generators), std::move(weights));
132 }
133
134 /*!
135 * Returns a generator whose set of elements is the union of the
136 * set of elements of the generators in \a generators and in which
137 * the distribution of the generated elements is uniform over the
138 * elements of \a generators.
139 *
140 * The generators in \a generator should have a uniform
141 * distribution and be finite.
142 * If the set of elements that the generators in \a generator is
143 * not disjoint, the distribution will be skewed towards repeated
144 * elements.
145 *
146 * Each time the generator produces a value, a generator from \a
147 * generators is randomly chosen to produce the value.
148 *
149 * Each generator from \a generators has a probability of being
150 * chosen based on the proportion of the cardinality of the subset
151 * it produces.
152 *
153 * The \e {ith} element of \a amounts should contain the
154 * cardinality of the set produced by the \e {ith} generator in \a
155 * generators.
156 *
157 * The generator produces values until a generator that is chosen
158 * to produce a value is unable to do so.
159 * The first such generator to do so will stop the generation
160 * independently of the availability of the other generators.
161 *
162 * Similarly, values will be produced as long as the chosen
163 * generator can produce a value, independently of the other
164 * generators being exhausted already.
165 */
166 template<typename T>
167 inline Catch::Generators::GeneratorWrapper<T> uniformly_valued_oneof(
168 std::vector<Catch::Generators::GeneratorWrapper<T>>&& generators,
169 const std::vector<std::size_t>& amounts
170 ) {
171 std::size_t total_amount{std::accumulate(amounts.cbegin(), amounts.cend(), std::size_t{0})};
172
173 std::vector<double> weights;
174 weights.reserve(amounts.size());
175
176 std::transform(
177 amounts.cbegin(), amounts.cend(),
178 std::back_inserter(weights),
179 [total_amount](auto element){ return QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE::percent_of(static_cast<double>(element), static_cast<double>(total_amount)); }
180 );
181
182 return oneof(std::move(generators), std::move(weights));
183 }
184
185} // end QDOC_CATCH_GENERATORS_ROOT_NAMESPACE
Approx(double value)
OneOfGenerator(std::vector< Catch::Generators::GeneratorWrapper< T > > &&generators, const std::vector< double > &weights)
Catch::Generators::GeneratorWrapper< T > oneof(std::vector< Catch::Generators::GeneratorWrapper< T > > &&generators, const std::vector< double > &weights)
Returns a generator whose set of elements is the union of the set of elements of the generators in ge...
Catch::Generators::GeneratorWrapper< T > uniform_oneof(std::vector< Catch::Generators::GeneratorWrapper< T > > &&generators)
Returns a generator whose set of elements is the union of the set of elements of the generators in ge...
Catch::Generators::GeneratorWrapper< T > uniformly_valued_oneof(std::vector< Catch::Generators::GeneratorWrapper< T > > &&generators, const std::vector< std::size_t > &amounts)
Returns a generator whose set of elements is the union of the set of elements of the generators in ge...
double percent_of(double amount, double total)
Returns the percentage of \amount over total.
Definition percentages.h:18
#define QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE
Definition namespaces.h:8
#define QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE
Definition namespaces.h:14
#define QDOC_CATCH_GENERATORS_ROOT_NAMESPACE
Definition namespaces.h:6
#define assert