halcheck 1.0
Loading...
Searching...
No Matches
shrink.hpp
1#ifndef HALCHECK_GEN_SHRINK_HPP
2#define HALCHECK_GEN_SHRINK_HPP
3#include <halcheck/gen/label.hpp>
4#include <halcheck/lib/atom.hpp>
5#include <halcheck/lib/effect.hpp>
6#include <halcheck/lib/functional.hpp>
7#include <halcheck/lib/iterator.hpp>
8#include <halcheck/lib/numeric.hpp>
9#include <halcheck/lib/optional.hpp>
10#include <halcheck/lib/pp.hpp>
11#include <halcheck/lib/scope.hpp>
12#include <halcheck/lib/type_traits.hpp>
13
14#include <climits>
15#include <cmath>
16#include <cstddef>
17#include <cstdint>
18#include <initializer_list>
19#include <utility>
20#include <vector>
21
22namespace halcheck { namespace gen {
23
24struct shrink_effect {
25 std::uintmax_t size;
26 lib::optional<std::uintmax_t> fallback() const { return lib::nullopt; }
27};
28
30 lib::optional<std::uintmax_t> operator()(lib::atom id, std::uintmax_t size = 1) const {
31 auto _ = gen::label(id);
33 }
34
35 template<
36 typename T,
37 typename I,
38 HALCHECK_REQUIRE(lib::is_forward_iterator<I>()),
40 T &operator()(lib::atom id, T &root, I begin, I end) const {
41 if (auto index = (*this)(id, std::distance(begin, end)))
42 return *std::next(begin, index);
43 else
44 return root;
45 }
46
47 template<
48 typename T,
49 typename R,
50 HALCHECK_REQUIRE(lib::is_range<R>()),
52 T &operator()(lib::atom id, T &root, const R &range) const {
53 return (*this)(id, root, lib::begin(range), lib::end(range));
54 }
55
56 template<typename T>
57 T &operator()(lib::atom id, T &root, const std::initializer_list<T> &range) const {
58 return (*this)(id, root, lib::begin(range), lib::end(range));
59 }
60
67 template<
68 typename T,
69 typename F,
70 HALCHECK_REQUIRE(lib::is_invocable<F, T>()),
73 T operator()(lib::atom id, T root, F func) const {
74 auto _ = gen::label(id);
75 for (std::uintmax_t i = 0;; i++) {
76 auto children = lib::invoke(func, root);
77 auto begin = lib::begin(children);
78 auto end = lib::end(children);
79 if (auto j = (*this)(i, std::distance(begin, end)))
80 root = std::move(*std::next(begin, *j));
81 else
82 break;
83 }
84
85 return root;
86 }
87} shrink;
88
95 template<typename T, HALCHECK_REQUIRE(std::is_integral<T>())>
96 T operator()(lib::atom id, T dst, T src) const {
97 return gen::shrink(
98 id,
99 std::make_pair(dst, src),
100 [](std::pair<T, T> pair) {
102 while (pair.first != pair.second) {
103 auto mid = lib::midpoint(pair.first, pair.second);
104 output.push_back({pair.first, mid});
105 pair.first = pair.first < pair.second ? mid + 1 : mid - 1;
106 }
107 return output;
108 })
109 .second;
110 }
111
117 template<typename T, HALCHECK_REQUIRE(std::is_floating_point<T>())>
118 T operator()(lib::atom id, T dst, T src) const {
119 return gen::shrink(
120 id,
121 std::make_pair(dst, src),
122 [](std::pair<T, T> pair) {
124 for (std::size_t i = 0; pair.first != pair.second && i < sizeof(T) * CHAR_BIT; i++) {
125 auto mid = lib::midpoint(pair.first, pair.second);
126 output.push_back({pair.first, mid});
127 pair.first = std::nextafter(mid, pair.second);
128 }
129 return output;
130 })
131 .second;
132 }
133
139 template<typename T, typename U, HALCHECK_REQUIRE(!std::is_same<T, U>())>
140 lib::common_type_t<T, U> operator()(lib::atom id, T dst, U src) const {
141 return this->operator()<lib::common_type_t<T, U>>(id, dst, src);
142 }
143} shrink_to;
144
146 struct handler : lib::effect::handler<handler, gen::shrink_effect> {
147 lib::optional<std::uintmax_t> operator()(gen::shrink_effect) final { return lib::nullopt; }
148 };
149
150 handler::owning_scope operator()() const { return handler().handle(); }
151
152 template<typename F, typename... Args, HALCHECK_REQUIRE(lib::is_invocable<F, Args...>())>
153 lib::invoke_result_t<F, Args...> operator()(F func, Args &&...args) const {
154 return handler().handle(std::move(func), std::forward<Args>(args)...);
155 }
156} noshrink;
157
158}} // namespace halcheck::gen
159
160#endif
static lib::effect_result_t< T > invoke(T args)
Invokes an effect.
Definition effect.hpp:118
T distance(T... args)
T forward(T... args)
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
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.
decltype(lib::invoke(std::declval< F >(), std::declval< Args >()...)) invoke_result_t
An implementation of std::invoke_result_t.
Definition invoke.hpp:42
lib::iter_value_t< lib::iterator_t< R > > range_value_t
The type of element contained in a range.
Definition range.hpp:332
typename std::iterator_traits< I >::reference iter_reference_t
The return type of operator* for an iterator.
Definition base.hpp:24
lib::iter_reference_t< lib::iterator_t< R > > range_reference_t
The type returned by operator* for a range type's iterators.
Definition range.hpp:340
HALCHECK_INLINE_CONSTEXPR struct halcheck::lib::end_cpo::@28 end
Gets an iterator to past the end of a range.
HALCHECK_INLINE_CONSTEXPR struct halcheck::lib::begin_cpo::@27 begin
Gets an iterator to the first element of a range.
constexpr T midpoint(T min, T max) noexcept
An implementation of std::midpoint.
Definition numeric.hpp:24
static constexpr nullopt_t nullopt
An implementation of std::nullopt.
Definition optional.hpp:41
#define HALCHECK_INLINE_CONSTEXPR
A backwards-compatible substitute for inline constexpr.
Definition pp.hpp:70
typename std::common_type< Args... >::type common_type_t
An implementation of std::common_type_t.
Definition type_traits.hpp:133
#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 make_pair(T... args)
lib::variant< std::integral_constant< std::size_t, Ints >... > index(lib::atom id, lib::index_sequence< Ints... >={})
Generates a random std::integral_constant from the given set of indices.
Definition variant.hpp:39
T next(T... args)
T nextafter(T... args)
T push_back(T... args)