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 <algorithm>
13#include <iterator>
14#include <numeric>
15#include <random>
16#include <vector>
17
20
21 template<typename T>
23 public:
25 std::vector<Catch::Generators::GeneratorWrapper<T>>&& generators,
26 const std::vector<double>& weights
28 random_engine{std::random_device{}()},
30 {
31 assert(weights.size() == this->generators.size());
32 assert(std::reduce(weights.cbegin(), weights.cend()) == Approx(100.0));
33
34 std::transform(
35 this->generators.begin(), this->generators.end(), this->generators.begin(),
36 [](auto& generator){ return QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE::handler(std::move(generator)); }
37 );
38
39 static_cast<void>(next());
40 }
41
42 T const& get() const override { return current_value; }
43
44 bool next() override {
45 std::size_t generator_index{choice_distribution(random_engine)};
46
47 if (!generators[generator_index].next()) return false;
48 current_value = generators[generator_index].get();
49
50 return true;
51 }
52
53 private:
54 std::vector<Catch::Generators::GeneratorWrapper<T>> generators;
55
56 std::mt19937 random_engine;
57 std::discrete_distribution<std::size_t> choice_distribution;
58
59 T current_value;
60 };
61
62 } // end QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE
63
64 /*!
65 * Returns a generator whose set of elements is the union of the
66 * set of elements of the generators in \a generators.
67 *
68 * Each time the generator produces a value, a generator from \a
69 * generators is randomly chosen to produce the value.
70 *
71 * The distribution for the choice is given by \a weights.
72 * The \e {ith} element in \a weights represent the percentage
73 * probability of the \e {ith} element of \a generators to be
74 * chosen.
75 *
76 * It follows that the size of \a weights must be the same as the
77 * size of \a generators.
78 *
79 * Furthermore, the sum of elements in \a weights should be a
80 * hundred.
81 *
82 * The generator produces values until a generator that is chosen
83 * to produce a value is unable to do so.
84 * The first such generator to do so will stop the generation
85 * independently of the availability of the other generators.
86 *
87 * Similarly, values will be produced as long as the chosen
88 * generator can produce a value, independently of the other
89 * generators being exhausted already.
90 */
91 template<typename T>
92 inline Catch::Generators::GeneratorWrapper<T> oneof(
93 std::vector<Catch::Generators::GeneratorWrapper<T>>&& generators,
94 const std::vector<double>& weights
95 ) {
96 return Catch::Generators::GeneratorWrapper<T>(std::unique_ptr<Catch::Generators::IGenerator<T>>(new QDOC_CATCH_GENERATORS_PRIVATE_NAMESPACE::OneOfGenerator(std::move(generators), weights)));
97 }
98
99
100 /*!
101 * Returns a generator whose set of elements is the union of the
102 * set of elements of the generators in \a generators and in which
103 * the distribution of the generated elements is uniform over \a
104 * generators.
105 *
106 * Each time the generator produces a value, a generator from \a
107 * generators is randomly chosen to produce the value.
108 *
109 * Each generator from \a generators has the same chance of being
110 * chosen.
111 *
112 * Do note that the distribution over the set of values is not
113 * necessarily uniform.
114 *
115 * The generator produces values until a generator that is chosen
116 * to produce a value is unable to do so.
117 * The first such generator to do so will stop the generation
118 * independently of the availability of the other generators.
119 *
120 * Similarly, values will be produced as long as the chosen
121 * generator can produce a value, independently of the other
122 * generators being exhausted already.
123 */
124 template<typename T>
125 inline Catch::Generators::GeneratorWrapper<T> uniform_oneof(
126 std::vector<Catch::Generators::GeneratorWrapper<T>>&& generators
127 ) {
128 std::vector<double> weights(
129 generators.size(),
131 );
132 return oneof(std::move(generators), std::move(weights));
133 }
134
135 /*!
136 * Returns a generator whose set of elements is the union of the
137 * set of elements of the generators in \a generators and in which
138 * the distribution of the generated elements is uniform over the
139 * elements of \a generators.
140 *
141 * The generators in \a generator should have a uniform
142 * distribution and be finite.
143 * If the set of elements that the generators in \a generator is
144 * not disjoint, the distribution will be skewed towards repeated
145 * elements.
146 *
147 * Each time the generator produces a value, a generator from \a
148 * generators is randomly chosen to produce the value.
149 *
150 * Each generator from \a generators has a probability of being
151 * chosen based on the proportion of the cardinality of the subset
152 * it produces.
153 *
154 * The \e {ith} element of \a amounts should contain the
155 * cardinality of the set produced by the \e {ith} generator in \a
156 * generators.
157 *
158 * The generator produces values until a generator that is chosen
159 * to produce a value is unable to do so.
160 * The first such generator to do so will stop the generation
161 * independently of the availability of the other generators.
162 *
163 * Similarly, values will be produced as long as the chosen
164 * generator can produce a value, independently of the other
165 * generators being exhausted already.
166 */
167 template<typename T>
168 inline Catch::Generators::GeneratorWrapper<T> uniformly_valued_oneof(
169 std::vector<Catch::Generators::GeneratorWrapper<T>>&& generators,
170 const std::vector<std::size_t>& amounts
171 ) {
172 std::size_t total_amount{std::accumulate(amounts.cbegin(), amounts.cend(), std::size_t{0})};
173
174 std::vector<double> weights;
175 weights.reserve(amounts.size());
176
177 std::transform(
178 amounts.cbegin(), amounts.cend(),
179 std::back_inserter(weights),
180 [total_amount](auto element){ return QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE::percent_of(static_cast<double>(element), static_cast<double>(total_amount)); }
181 );
182
183 return oneof(std::move(generators), std::move(weights));
184 }
185
186} // 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
double uniform_probability(std::size_t cardinality)
Given the cardinality of a set, returns the percentage probability that applied to every element of t...
Definition percentages.h:30
#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