]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/gmp-utils.h
Add methods and operators to gdb_mpz
[thirdparty/binutils-gdb.git] / gdb / gmp-utils.h
1 /* Miscellaneous routines making it easier to use GMP within GDB's framework.
2
3 Copyright (C) 2019-2023 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20 #ifndef GMP_UTILS_H
21 #define GMP_UTILS_H
22
23 /* Include <stdio.h> and <stdarg.h> ahead of <gmp.h>, so as to get
24 access to GMP's various formatting functions. */
25 #include <stdio.h>
26 #include <stdarg.h>
27 #include <gmp.h>
28 #include "gdbsupport/traits.h"
29
30 /* Same as gmp_asprintf, but returning an std::string. */
31
32 std::string gmp_string_printf (const char *fmt, ...);
33
34 /* A class to make it easier to use GMP's mpz_t values within GDB. */
35
36 struct gdb_mpz
37 {
38 mpz_t val;
39
40 /* Constructors. */
41 gdb_mpz () { mpz_init (val); }
42
43 explicit gdb_mpz (const mpz_t &from_val)
44 {
45 mpz_init (val);
46 mpz_set (val, from_val);
47 }
48
49 gdb_mpz (const gdb_mpz &from)
50 {
51 mpz_init (val);
52 mpz_set (val, from.val);
53 }
54
55 /* Initialize using the given integral value.
56
57 The main advantage of this method is that it handles both signed
58 and unsigned types, with no size restriction. */
59 template<typename T, typename = gdb::Requires<std::is_integral<T>>>
60 explicit gdb_mpz (T src)
61 {
62 mpz_init (val);
63 set (src);
64 }
65
66 explicit gdb_mpz (gdb_mpz &&from)
67 {
68 mpz_init (val);
69 mpz_swap (val, from.val);
70 }
71
72
73 gdb_mpz &operator= (const gdb_mpz &from)
74 {
75 mpz_set (val, from.val);
76 return *this;
77 }
78
79 gdb_mpz &operator= (gdb_mpz &&other)
80 {
81 mpz_swap (val, other.val);
82 return *this;
83 }
84
85 template<typename T, typename = gdb::Requires<std::is_integral<T>>>
86 gdb_mpz &operator= (T src)
87 {
88 set (src);
89 return *this;
90 }
91
92 /* Initialize this value from a string and a base. Returns true if
93 the string was parsed successfully, false otherwise. */
94 bool set (const char *str, int base)
95 {
96 return mpz_set_str (val, str, base) != -1;
97 }
98
99 /* Return a new value that is BASE**EXP. */
100 static gdb_mpz pow (unsigned long base, unsigned long exp)
101 {
102 gdb_mpz result;
103 mpz_ui_pow_ui (result.val, base, exp);
104 return result;
105 }
106
107 /* Convert VAL to an integer of the given type.
108
109 The return type can signed or unsigned, with no size restriction. */
110 template<typename T> T as_integer () const;
111
112 /* Set VAL by importing the number stored in the byte array (BUF),
113 using the given BYTE_ORDER. The size of the data to read is
114 the byte array's size.
115
116 UNSIGNED_P indicates whether the number has an unsigned type. */
117 void read (gdb::array_view<const gdb_byte> buf, enum bfd_endian byte_order,
118 bool unsigned_p);
119
120 /* Write VAL into BUF as a number whose byte size is the size of BUF,
121 using the given BYTE_ORDER.
122
123 UNSIGNED_P indicates whether the number has an unsigned type. */
124 void write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
125 bool unsigned_p) const;
126
127 /* Return a string containing VAL. */
128 std::string str () const { return gmp_string_printf ("%Zd", val); }
129
130 /* The destructor. */
131 ~gdb_mpz () { mpz_clear (val); }
132
133 /* Negate this value in place. */
134 void negate ()
135 {
136 mpz_neg (val, val);
137 }
138
139 gdb_mpz &operator*= (long other)
140 {
141 mpz_mul_si (val, val, other);
142 return *this;
143 }
144
145 gdb_mpz &operator+= (unsigned long other)
146 {
147 mpz_add_ui (val, val, other);
148 return *this;
149 }
150
151 gdb_mpz &operator-= (unsigned long other)
152 {
153 mpz_sub_ui (val, val, other);
154 return *this;
155 }
156
157 gdb_mpz &operator<<= (unsigned long nbits)
158 {
159 mpz_mul_2exp (val, val, nbits);
160 return *this;
161 }
162
163 bool operator> (const gdb_mpz &other) const
164 {
165 return mpz_cmp (val, other.val) > 0;
166 }
167
168 bool operator< (int other) const
169 {
170 return mpz_cmp_si (val, other) < 0;
171 }
172
173 bool operator== (int other) const
174 {
175 return mpz_cmp_si (val, other) == 0;
176 }
177
178 bool operator== (const gdb_mpz &other) const
179 {
180 return mpz_cmp (val, other.val) == 0;
181 }
182
183 private:
184
185 /* Helper template for constructor and operator=. */
186 template<typename T> void set (T src);
187
188 /* Low-level function to export VAL into BUF as a number whose byte size
189 is the size of BUF.
190
191 If UNSIGNED_P is true, then export VAL into BUF as an unsigned value.
192 Otherwise, export it as a signed value.
193
194 The API is inspired from GMP's mpz_export, hence the naming and types
195 of the following parameter:
196 - ENDIAN should be:
197 . 1 for most significant byte first; or
198 . -1 for least significant byte first; or
199 . 0 for native endianness.
200
201 An error is raised if BUF is not large enough to contain the value
202 being exported. */
203 void safe_export (gdb::array_view<gdb_byte> buf,
204 int endian, bool unsigned_p) const;
205 };
206
207 /* A class to make it easier to use GMP's mpq_t values within GDB. */
208
209 struct gdb_mpq
210 {
211 mpq_t val;
212
213 /* Constructors. */
214 gdb_mpq () { mpq_init (val); }
215
216 explicit gdb_mpq (const mpq_t &from_val)
217 {
218 mpq_init (val);
219 mpq_set (val, from_val);
220 }
221
222 gdb_mpq (const gdb_mpq &from)
223 {
224 mpq_init (val);
225 mpq_set (val, from.val);
226 }
227
228 explicit gdb_mpq (gdb_mpq &&from)
229 {
230 mpq_init (val);
231 mpq_swap (val, from.val);
232 }
233
234 gdb_mpq (const gdb_mpz &num, const gdb_mpz &denom)
235 {
236 mpq_init (val);
237 mpz_set (mpq_numref (val), num.val);
238 mpz_set (mpq_denref (val), denom.val);
239 mpq_canonicalize (val);
240 }
241
242 /* Copy assignment operator. */
243 gdb_mpq &operator= (const gdb_mpq &from)
244 {
245 mpq_set (val, from.val);
246 return *this;
247 }
248
249 gdb_mpq &operator= (gdb_mpq &&from)
250 {
251 mpq_swap (val, from.val);
252 return *this;
253 }
254
255 gdb_mpq &operator= (const gdb_mpz &from)
256 {
257 mpq_set_z (val, from.val);
258 return *this;
259 }
260
261 /* Return a string representing VAL as "<numerator> / <denominator>". */
262 std::string str () const { return gmp_string_printf ("%Qd", val); }
263
264 /* Return VAL rounded to the nearest integer. */
265 gdb_mpz get_rounded () const;
266
267 /* Return this value as an integer, rounded toward zero. */
268 gdb_mpz as_integer () const
269 {
270 gdb_mpz result;
271 mpz_tdiv_q (result.val, mpq_numref (val), mpq_denref (val));
272 return result;
273 }
274
275 /* Set VAL from the contents of the given byte array (BUF), which
276 contains the unscaled value of a fixed point type object.
277 The byte size of the data is the size of BUF.
278
279 BYTE_ORDER provides the byte_order to use when reading the data.
280
281 UNSIGNED_P indicates whether the number has an unsigned type.
282 SCALING_FACTOR is the scaling factor to apply after having
283 read the unscaled value from our buffer. */
284 void read_fixed_point (gdb::array_view<const gdb_byte> buf,
285 enum bfd_endian byte_order, bool unsigned_p,
286 const gdb_mpq &scaling_factor);
287
288 /* Write VAL into BUF as fixed point value following the given BYTE_ORDER.
289 The size of BUF is used as the length to write the value into.
290
291 UNSIGNED_P indicates whether the number has an unsigned type.
292 SCALING_FACTOR is the scaling factor to apply before writing
293 the unscaled value to our buffer. */
294 void write_fixed_point (gdb::array_view<gdb_byte> buf,
295 enum bfd_endian byte_order, bool unsigned_p,
296 const gdb_mpq &scaling_factor) const;
297
298 /* The destructor. */
299 ~gdb_mpq () { mpq_clear (val); }
300 };
301
302 /* A class to make it easier to use GMP's mpf_t values within GDB.
303
304 Should MPFR become a required dependency, we should probably
305 drop this class in favor of using MPFR. */
306
307 struct gdb_mpf
308 {
309 mpf_t val;
310
311 /* Constructors. */
312 gdb_mpf () { mpf_init (val); }
313
314 DISABLE_COPY_AND_ASSIGN (gdb_mpf);
315
316 /* Set VAL from the contents of the given buffer (BUF), which
317 contains the unscaled value of a fixed point type object
318 with the given size (LEN) and byte order (BYTE_ORDER).
319
320 UNSIGNED_P indicates whether the number has an unsigned type.
321 SCALING_FACTOR is the scaling factor to apply after having
322 read the unscaled value from our buffer. */
323 void read_fixed_point (gdb::array_view<const gdb_byte> buf,
324 enum bfd_endian byte_order, bool unsigned_p,
325 const gdb_mpq &scaling_factor)
326 {
327 gdb_mpq tmp_q;
328
329 tmp_q.read_fixed_point (buf, byte_order, unsigned_p, scaling_factor);
330 mpf_set_q (val, tmp_q.val);
331 }
332
333 /* The destructor. */
334 ~gdb_mpf () { mpf_clear (val); }
335 };
336
337 /* See declaration above. */
338
339 template<typename T>
340 void
341 gdb_mpz::set (T src)
342 {
343 mpz_import (val, 1 /* count */, -1 /* order */,
344 sizeof (T) /* size */, 0 /* endian (0 = native) */,
345 0 /* nails */, &src /* op */);
346 if (std::is_signed<T>::value && src < 0)
347 {
348 /* mpz_import does not handle the sign, so our value was imported
349 as an unsigned. Adjust that imported value so as to make it
350 the correct negative value. */
351 gdb_mpz neg_offset;
352
353 mpz_ui_pow_ui (neg_offset.val, 2, sizeof (T) * HOST_CHAR_BIT);
354 mpz_sub (val, val, neg_offset.val);
355 }
356 }
357
358 /* See declaration above. */
359
360 template<typename T>
361 T
362 gdb_mpz::as_integer () const
363 {
364 T result;
365
366 this->safe_export ({(gdb_byte *) &result, sizeof (result)},
367 0 /* endian (0 = native) */,
368 !std::is_signed<T>::value /* unsigned_p */);
369
370 return result;
371 }
372
373 #endif