huangcm
2025-02-28 b45e871a67cd1272e3da9ba5bd383f832b0f1824
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
 *  Created by Martin 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_SPECIFIC_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_GENERATORS_SPECIFIC_HPP_INCLUDED
 
#include "catch_context.h"
#include "catch_generators.hpp"
#include "catch_interfaces_config.h"
 
#include <random>
 
namespace Catch {
namespace Generators {
 
template <typename Float>
class RandomFloatingGenerator final : public IGenerator<Float> {
    // FIXME: What is the right seed?
    std::minstd_rand m_rand;
    std::uniform_real_distribution<Float> m_dist;
    Float m_current_number;
public:
 
    RandomFloatingGenerator(Float a, Float b):
        m_rand(getCurrentContext().getConfig()->rngSeed()),
        m_dist(a, b) {
        static_cast<void>(next());
    }
 
    Float const& get() const override {
        return m_current_number;
    }
    bool next() override {
        m_current_number = m_dist(m_rand);
        return true;
    }
};
 
template <typename Integer>
class RandomIntegerGenerator final : public IGenerator<Integer> {
    std::minstd_rand m_rand;
    std::uniform_int_distribution<Integer> m_dist;
    Integer m_current_number;
public:
 
    RandomIntegerGenerator(Integer a, Integer b):
        m_rand(getCurrentContext().getConfig()->rngSeed()),
        m_dist(a, b) {
        static_cast<void>(next());
    }
 
    Integer const& get() const override {
        return m_current_number;
    }
    bool next() override {
        m_current_number = m_dist(m_rand);
        return true;
    }
};
 
// TODO: Ideally this would be also constrained against the various char types,
//       but I don't expect users to run into that in practice.
template <typename T>
typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value,
GeneratorWrapper<T>>::type
random(T a, T b) {
    return GeneratorWrapper<T>(
        pf::make_unique<RandomIntegerGenerator<T>>(a, b)
    );
}
 
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value,
GeneratorWrapper<T>>::type
random(T a, T b) {
    return GeneratorWrapper<T>(
        pf::make_unique<RandomFloatingGenerator<T>>(a, b)
    );
}
 
 
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));
}
 
 
} // namespace Generators
} // namespace Catch
 
 
#endif // TWOBLUECUBES_CATCH_GENERATORS_SPECIFIC_HPP_INCLUDED