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
generator_handler.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
8#include <catch/catch.hpp>
9
10#include <optional>
11#include <cassert>
12
14
15 template<typename T>
17 public:
18
19 GeneratorHandler(Catch::Generators::GeneratorWrapper<T>&& generator)
20 : generator{std::move(generator)},
21 first_call{true}
22 {}
23
24 T const& get() const override {
25 assert(!first_call);
26 return generator.get();
27 }
28
29 bool next() override {
30 if (first_call) {
31 first_call = false;
32 return true;
33 }
34
35 return generator.next();
36 }
37
38 private:
39 Catch::Generators::GeneratorWrapper<T> generator;
40 bool first_call;
41 };
42
43
44 /*!
45 * Returns a generator wrapping \a generator that ensures that
46 * changes its semantics so that the first call to get should be
47 * preceded by a call to next.
48 *
49 * Catch generators require that is valid to call get and obtain a
50 * valid value on a generator that was just created.
51 * That is, generators should be non-empty and their first value
52 * should be initialized on construction.
53 *
54 * Normally, this is not a problem, and the next implementation of
55 * the generator can be simply called in the constructor.
56 * But when a generator depends on other generators, doing so will
57 * generally skip the first value that the generator
58 * produces, as the wrapping generator will need to advance the
59 * underlying generator, losing the value in the process.
60 * This is in particular, a problem, on generators that are finite
61 * or infinite and ordered.
62 *
63 * To solve the issue, the original value can be saved before
64 * advancing the generator or some code can be duplicated or
65 * abstracted so that what a new element can be generated without
66 * advancing the underlying generator.
67 *
68 * While this is acceptable, it can be error prone on more complex
69 * generators, generators that randomly access a collection of
70 * generators and so on.
71 *
72 * To simplify this process, this generator changes the semantics
73 * of the wrapped generator such that the first value of the
74 * generator is produced after the first call to next and the
75 * generator is considered in an invalid state before the first
76 * advancement.
77 *
78 * In this way, by wrapping all generators that a generator
79 * depends on, the implementation required for the first value is
80 * the same as the one required for all following values, with
81 * regards to the sequencing of next and get operations,
82 * simplifying the implementation of dependent generators.
83 *
84 * Do note that, while the generator returned by this function
85 * implments the generator interface that Catch2 requires, it
86 * cannot be normally used as a generator as it fails to comply
87 * with the first value semantics that a generator requires.
88 * Indeed, it should only be used as an intermediate wrapper for
89 * the implementation of generators that depends on other
90 * generators.
91 */
92 template<typename T>
93 inline Catch::Generators::GeneratorWrapper<T> handler(Catch::Generators::GeneratorWrapper<T>&& generator) {
94 return Catch::Generators::GeneratorWrapper<T>(std::unique_ptr<Catch::Generators::IGenerator<T>>(new GeneratorHandler(std::move(generator))));
95 }
96
97} // end QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE
GeneratorHandler(Catch::Generators::GeneratorWrapper< T > &&generator)
Catch::Generators::GeneratorWrapper< T > handler(Catch::Generators::GeneratorWrapper< T > &&generator)
Returns a generator wrapping generator that ensures that changes its semantics so that the first call...
#define QDOC_CATCH_GENERATORS_UTILITIES_ABSOLUTE_NAMESPACE
Definition namespaces.h:14
#define assert