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