1 /*
2 Copyright (C) 2020 Julian Rüth
3
4 This file is part of e-antic
5
6 e-antic is free software: you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License (LGPL) as published
8 by the Free Software Foundation; either version 3.0 of the License, or
9 (at your option) any later version. See <http://www.gnu.org/licenses/>.
10 */
11
12 #ifndef E_ANTIC_TEST_RENF_ELEM_GENERATOR_HPP
13 #define E_ANTIC_TEST_RENF_ELEM_GENERATOR_HPP
14
15 #include "../e-antic/renf_elem.h"
16
17 #include "renf_generator.hpp"
18
19 #include "external/catch2/single_include/catch2/catch.hpp"
20
21 namespace {
22
23 /*
24 * A generator of random renf_elem_t in a given number field renf_t.
25 */
26 struct RenfElemGenerator : public Catch::Generators::IGenerator<renf_elem_t&>
27 {
28 flint_rand_t& state;
29 renf_t& nf;
30 ulong minbits, maxbits;
31
32 mutable renf_t _nf;
33 mutable renf_elem_t a;
34 mutable bool has_value_for_iteration = false;
35 mutable bool initial = true;
36
RenfElemGenerator__anon992918230111::RenfElemGenerator37 RenfElemGenerator(flint_rand_t& state, renf_t& nf, ulong minbits, ulong maxbits) : state(state), nf(nf), minbits(minbits), maxbits(maxbits)
38 {
39 assert(maxbits > minbits);
40 }
41
clear__anon992918230111::RenfElemGenerator42 void clear()
43 {
44 if (has_value_for_iteration) {
45 renf_elem_clear(a, _nf);
46 renf_clear(_nf);
47 }
48 has_value_for_iteration = false;
49 }
50
next__anon992918230111::RenfElemGenerator51 bool next() override
52 {
53 clear();
54 return true;
55 }
56
get__anon992918230111::RenfElemGenerator57 renf_elem_t& get() const override
58 {
59 if (!has_value_for_iteration)
60 {
61 renf_init_set(_nf, nf);
62 renf_elem_init(a, _nf);
63
64 if (initial)
65 {
66 initial = false;
67 renf_elem_zero(a, nf);
68 }
69 else
70 {
71 ulong bits = minbits + n_randint(state, maxbits - minbits);
72
73 renf_elem_randtest(a, state, bits, _nf);
74 }
75
76 has_value_for_iteration = true;
77 }
78 return a;
79 }
80
~RenfElemGenerator__anon992918230111::RenfElemGenerator81 ~RenfElemGenerator() override
82 {
83 clear();
84 }
85 };
86
87 /*
88 * Wrap RenfElemGenerator for use as GENERATE_REF(take(64, renf_elems(...))).
89 */
renf_elems(flint_rand_t & state,renf_t & nf,ulong minbits=10,ulong maxbits=40)90 [[maybe_unused]] Catch::Generators::GeneratorWrapper<renf_elem_t&> renf_elems(flint_rand_t& state, renf_t& nf, ulong minbits = 10, ulong maxbits = 40)
91 {
92 return Catch::Generators::GeneratorWrapper<renf_elem_t&>(std::unique_ptr<Catch::Generators::IGenerator<renf_elem_t&>>(new RenfElemGenerator(state, nf, minbits, maxbits)));
93 }
94
95 }
96
97 namespace Catch {
98
99 /*
100 * Make printing of `renf_elem_t` work in Catch, i.e., show meaingful debug
101 * output for `CAPTURE(a)` where `a` is a `renf_elem_t`.
102 * Note that it's a bit of a hack how we handle the containing renf_t here.
103 * Namely, we store the current `renf_t` in a static variable so we can
104 * correctly print the following `renf_elem_t`. This allows us to write:
105 * ```
106 * CAPTURE(nf);
107 * CAPTURE(a);
108 * ```
109 * An alternative would have been to create a printer for something like
110 * `tuple<renf_t, renf_elem_t>` and then call:
111 * ```
112 * CAPTURE(std::tuple(nf, a));
113 * ```
114 * But we want to make C programmers feel mostly at home in our
115 * test code so that's probably too confusing.
116 */
117 template <>
118 struct StringMaker<renf_elem_t>
119 {
convertCatch::StringMaker120 static std::string convert(const renf_elem_t& a)
121 {
122 assert(StringMaker<renf_t>::latest != nullptr && "you must always CAPTURE(nf) before capturing a contained renf_elem_t");
123
124 char * alg = renf_elem_get_str_pretty(const_cast<renf_elem_struct*>(a), "x", StringMaker<renf_t>::latest, 10, EANTIC_STR_ALG);
125 char * emb = arb_get_str(a->emb, 10, ARB_STR_MORE);
126
127 std::stringstream str;
128 str << alg << " ~ " << emb;
129
130 flint_free(alg);
131 flint_free(emb);
132
133 return str.str();
134 }
135 };
136
137 }
138
139
140 #endif
141