1 #pragma once
2 
3 #include "rapidcheck/shrinkable/Transform.h"
4 #include "rapidcheck/gen/Arbitrary.h"
5 #include "rapidcheck/gen/Tuple.h"
6 #include "rapidcheck/GenerationFailure.h"
7 #include "rapidcheck/Random.h"
8 
9 namespace rc {
10 namespace gen {
11 namespace detail {
12 
13 template <typename T, typename Mapper>
14 class MapGen {
15 public:
16   using U = Decay<typename std::result_of<Mapper(T)>::type>;
17 
18   template <typename MapperArg>
MapGen(Gen<T> gen,MapperArg && mapper)19   MapGen(Gen<T> gen, MapperArg &&mapper)
20       : m_mapper(std::forward<MapperArg>(mapper))
21       , m_gen(std::move(gen)) {}
22 
operator ()(const Random & random,int size) const23   Shrinkable<U> operator()(const Random &random, int size) const {
24     return shrinkable::map(m_gen(random, size), m_mapper);
25   }
26 
27 private:
28   Mapper m_mapper;
29   Gen<T> m_gen;
30 };
31 
32 template <typename T, typename Mapper>
33 class MapcatGen {
34 public:
35   using U = typename std::result_of<Mapper(T)>::type::ValueType;
36 
37   template <typename MapperArg>
MapcatGen(Gen<T> gen,MapperArg && mapper)38   explicit MapcatGen(Gen<T> gen, MapperArg &&mapper)
39       : m_gen(std::move(gen))
40       , m_mapper(std::forward<MapperArg>(mapper)) {}
41 
operator ()(const Random & random,int size) const42   Shrinkable<U> operator()(const Random &random, int size) const {
43     auto r1 = random;
44     auto r2 = r1.split();
45     const auto mapper = m_mapper;
46     return shrinkable::mapcat(
47         m_gen(r1, size), [=](T &&x) { return mapper(std::move(x))(r2, size); });
48   }
49 
50 private:
51   Gen<T> m_gen;
52   Mapper m_mapper;
53 };
54 
55 template <typename T>
56 class JoinGen {
57 public:
JoinGen(Gen<Gen<T>> gen)58   explicit JoinGen(Gen<Gen<T>> gen)
59       : m_gen(std::move(gen)) {}
60 
operator ()(const Random & random,int size) const61   Shrinkable<T> operator()(const Random &random, int size) const {
62     auto r1 = random;
63     auto r2 = r1.split();
64     return shrinkable::mapcat(
65         m_gen(r1, size),
66         [=](const Gen<T> &innerGen) { return innerGen(r2, size); });
67   }
68 
69 private:
70   Gen<Gen<T>> m_gen;
71 };
72 
73 } // namespace detail
74 
75 template <typename T, typename Mapper>
map(Gen<T> gen,Mapper && mapper)76 Gen<Decay<typename std::result_of<Mapper(T)>::type>> map(Gen<T> gen,
77                                                          Mapper &&mapper) {
78   return detail::MapGen<T, Decay<Mapper>>(std::move(gen),
79                                           std::forward<Mapper>(mapper));
80 }
81 
82 template <typename T, typename Mapper>
map(Mapper && mapper)83 Gen<Decay<typename std::result_of<Mapper(T)>::type>> map(Mapper &&mapper) {
84   return gen::map(gen::arbitrary<T>(), std::forward<Mapper>(mapper));
85 }
86 
87 template <typename T, typename Mapper>
88 Gen<typename std::result_of<Mapper(T)>::type::ValueType>
mapcat(Gen<T> gen,Mapper && mapper)89 mapcat(Gen<T> gen, Mapper &&mapper) {
90   return detail::MapcatGen<T, Decay<Mapper>>(std::move(gen),
91                                              std::forward<Mapper>(mapper));
92 }
93 
94 template <typename T>
join(Gen<Gen<T>> gen)95 Gen<T> join(Gen<Gen<T>> gen) {
96   return detail::JoinGen<T>(std::move(gen));
97 }
98 
99 template <typename Callable, typename... Ts>
apply(Callable && callable,Gen<Ts>...gens)100 Gen<typename std::result_of<Callable(Ts...)>::type> apply(Callable &&callable,
101                                                           Gen<Ts>... gens) {
102   return gen::map(gen::tuple(std::move(gens)...),
103                   [=](std::tuple<Ts...> &&tuple) {
104                     return rc::detail::applyTuple(std::move(tuple), callable);
105                   });
106 }
107 
108 template <typename T, typename U>
cast(Gen<U> gen)109 Gen<T> cast(Gen<U> gen) {
110   return gen::map(std::move(gen),
111                   [](U &&x) { return static_cast<T>(std::move(x)); });
112 }
113 
114 template <typename T>
resize(int size,Gen<T> gen)115 Gen<T> resize(int size, Gen<T> gen) {
116   return [=](const Random &random, int) { return gen(random, size); };
117 }
118 
119 template <typename T>
scale(double scale,Gen<T> gen)120 Gen<T> scale(double scale, Gen<T> gen) {
121   return [=](const Random &random, int size) {
122     return gen(random, static_cast<int>(size * scale));
123   };
124 }
125 
126 template <typename Callable>
127 Gen<typename std::result_of<Callable(int)>::type::ValueType>
withSize(Callable && callable)128 withSize(Callable &&callable) {
129   return [=](const Random &random, int size) {
130     return callable(size)(random, size);
131   };
132 }
133 
134 template <typename T>
noShrink(Gen<T> gen)135 Gen<T> noShrink(Gen<T> gen) {
136   return [=](const Random &random, int size) {
137     return shrinkable::mapShrinks(gen(random, size),
138                                   fn::constant(Seq<Shrinkable<T>>()));
139   };
140 }
141 
142 template <typename T, typename Shrink>
shrink(Gen<T> gen,Shrink && shrink)143 Gen<T> shrink(Gen<T> gen, Shrink &&shrink) {
144   return [=](const Random &random, int size) {
145     return shrinkable::postShrink(gen(random, size), shrink);
146   };
147 }
148 
149 } // namespace gen
150 } // namespace rc
151