halcheck 1.0
Loading...
Searching...
No Matches
container.hpp
1#ifndef HALCHECK_GEN_CONTAINER_HPP
2#define HALCHECK_GEN_CONTAINER_HPP
3
4#include <halcheck/gen/label.hpp>
5#include <halcheck/gen/range.hpp>
6#include <halcheck/gen/sample.hpp>
7#include <halcheck/gen/shrink.hpp>
8#include <halcheck/gen/size.hpp>
9#include <halcheck/lib/atom.hpp>
10#include <halcheck/lib/effect.hpp>
11#include <halcheck/lib/functional.hpp>
12#include <halcheck/lib/iterator.hpp>
13#include <halcheck/lib/optional.hpp>
14#include <halcheck/lib/pp.hpp>
15#include <halcheck/lib/scope.hpp>
16#include <halcheck/lib/type_traits.hpp>
17
18#include <algorithm>
19#include <cstddef>
20#include <cstdint>
21#include <iterator>
22#include <utility>
23#include <vector>
24
25namespace halcheck { namespace gen {
26
28private:
29 template<typename F>
30 struct to_label {
31 lib::invoke_result_t<const F &, lib::atom> operator()(std::uintmax_t i) const { return context.handle(func, i); }
32 lib::effect::state context;
33 F func;
34 };
35
36 struct if_noshrink {
37 bool operator()(std::uintmax_t i) const { return !skip[skip.size() - i - 1]; }
39 };
40
41 template<typename F>
42 using view = lib::transform_view<lib::filter_view<lib::iota_view<std::uintmax_t>, if_noshrink>, to_label<F>>;
43
44public:
45 template<typename F, HALCHECK_REQUIRE(lib::is_invocable<const F &, lib::atom>())>
46 view<F> operator()(lib::atom id, F gen) const {
47 using namespace lib::literals;
48
49 auto _ = gen::label(id);
50 auto context = lib::effect::save();
51
52 auto size = gen::sample("size"_s, gen::size());
53
55 {
56 auto _ = gen::label("shrink"_s);
57 for (std::uintmax_t i = 0; i < size; i++)
58 skip.push_back(gen::shrink(i).has_value());
59 }
60
61 return lib::transform(
62 lib::filter(lib::iota(size), if_noshrink{std::move(skip)}),
63 to_label<F>{std::move(context), std::move(gen)});
64 }
65} view;
66
67static const class {
68private:
69 struct to_label {
70 lib::finally_t<> operator()(std::uintmax_t i) const {
71 auto label1 = gen::label(id);
72 auto label2 = gen::label(i);
73 return std::move(label1) + std::move(label2);
74 }
75
76 lib::atom id;
77 };
78
79 struct if_noshrink {
80 bool operator()(std::uintmax_t i) const { return !skip[skip.size() - i - 1]; }
82 };
83
84 using view = lib::transform_view<lib::filter_view<lib::iota_view<std::uintmax_t>, if_noshrink>, to_label>;
85
86public:
87 view operator()(lib::atom id) const {
88 using namespace lib::literals;
89
90 auto _ = gen::label(id);
91
92 auto size = gen::sample("size"_s, gen::size());
93
95 {
96 auto _ = gen::label("shrink"_s);
97 for (std::uintmax_t i = 0; i < size; i++)
98 skip.push_back(gen::shrink(i).has_value());
99 }
100
101 return lib::transform(lib::filter(lib::iota(size), if_noshrink{std::move(skip)}), to_label{id});
102 }
103
108 template<typename F, HALCHECK_REQUIRE(lib::is_invocable<F, lib::atom>())>
109 void operator()(lib::atom id, F func) const {
110 using namespace lib::literals;
111 for (auto _ : (*this)(id))
112 lib::invoke(func, "func"_s);
113 }
114} repeat;
115
122template<
123 typename T,
124 typename F,
125 HALCHECK_REQUIRE(lib::is_insertable_range<T>()),
126 HALCHECK_REQUIRE(lib::is_invocable_r<lib::range_value_t<T>, F, lib::atom>())>
127T container(lib::atom id, F gen) {
128 using namespace lib::literals;
129 T output;
130 auto it = lib::end(output);
131 for (auto _ : gen::repeat(id))
132 it = std::next(output.insert(it, lib::invoke(gen, "gen"_s)));
133 return output;
134}
135
143template<
144 typename T,
145 typename F,
149 auto _ = gen::label(id);
150
151 T output;
152 auto it = lib::end(output);
153 while (size-- > 0)
154 it = std::next(output.insert(it, lib::invoke(gen, size)));
155 return output;
156}
157
158template<typename I, HALCHECK_REQUIRE(lib::is_forward_iterator<I>())>
159void shuffle(lib::atom id, I begin, I end) {
160 auto _ = gen::label(id);
161 for (auto it = begin; it != end; ++it)
162 std::iter_swap(it, gen::range(it - begin, it, end));
163}
164
165template<typename Range, HALCHECK_REQUIRE(lib::is_forward_range<lib::decay_t<Range>>())>
166void shuffle(lib::atom id, Range &&range) {
167 gen::shuffle(id, lib::begin(range), lib::end(range));
168}
169
170}} // namespace halcheck::gen
171
172#endif
lib::finally_t handle() &
Overrides the current set of effect handlers.
static state save()
Copies the current set of effect handlers.
Definition effect.hpp:337
static struct halcheck::gen::@9 label
Extends the unique identifiers passed to other random generation functions.
static const range_t range
Generates a random value in an closed-open interval.
Definition range.hpp:93
HALCHECK_INLINE_CONSTEXPR struct halcheck::gen::@11 sample
Obtains a random value.
std::uintmax_t size()
Gets the maximum size of value that should be generated.
Definition size.hpp:35
lib::variant< lib::symbol, lib::number > atom
An atom is either a symbol or a number.
Definition atom.hpp:194
HALCHECK_INLINE_CONSTEXPR struct halcheck::lib::@20 invoke
An implementation of std::invoke.
lib::iter_value_t< lib::iterator_t< R > > range_value_t
The type of element contained in a range.
Definition range.hpp:332
HALCHECK_INLINE_CONSTEXPR struct halcheck::lib::@31 transform
Constructs a transform_view.
#define HALCHECK_INLINE_CONSTEXPR
A backwards-compatible substitute for inline constexpr.
Definition pp.hpp:70
#define HALCHECK_REQUIRE(...)
Expands to a template argument that is only valid if the given argument evaluates to true.
Definition type_traits.hpp:24
T iter_swap(T... args)
T container(lib::atom id, F gen)
Generates a random container value.
Definition container.hpp:127
T next(T... args)
T push_back(T... args)
T size(T... args)
Determines whether a range is insertable.
Definition range.hpp:401
An implementation of std::is_invocable_r.
Definition invoke.hpp:54