gmp-utils: New API to simply use of GMP's integer/rational/float objects
[deliverable/binutils-gdb.git] / gdb / gmp-utils.h
CommitLineData
b34c74ab
JB
1/* Miscellaneous routines making it easier to use GMP within GDB's framework.
2
3 Copyright (C) 2019-2020 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 "defs.h"
24
25/* Include <stdio.h> and <stdarg.h> ahead of <gmp.h>, so as to get
26 access to GMP's various formatting functions. */
27#include <stdio.h>
28#include <stdarg.h>
29#include <gmp.h>
30#include "gdbsupport/traits.h"
31
32/* Same as gmp_asprintf, but returning a convenient wrapper type. */
33
34gdb::unique_xmalloc_ptr<char> gmp_string_asprintf (const char *fmt, ...);
35
36/* A class to make it easier to use GMP's mpz_t values within GDB. */
37
38struct gdb_mpz
39{
40 mpz_t val;
41
42 /* Constructors. */
43 gdb_mpz () { mpz_init (val); }
44
45 explicit gdb_mpz (const mpz_t &from_val)
46 {
47 mpz_init (val);
48 mpz_set (val, from_val);
49 }
50
51 gdb_mpz (const gdb_mpz &from)
52 {
53 mpz_init (val);
54 mpz_set (val, from.val);
55 }
56
57 /* Initialize using the given integral value.
58
59 The main advantage of this method is that it handles both signed
60 and unsigned types, with no size restriction. */
61 template<typename T, typename = gdb::Requires<std::is_integral<T>>>
62 explicit gdb_mpz (T src)
63 {
64 mpz_init (val);
65 set (src);
66 }
67
68 explicit gdb_mpz (gdb_mpz &&from)
69 {
70 mpz_init (val);
71 mpz_swap (val, from.val);
72 }
73
74
75 gdb_mpz &operator= (const gdb_mpz &from)
76 {
77 mpz_set (val, from.val);
78 return *this;
79 }
80
81 gdb_mpz &operator= (gdb_mpz &&other)
82 {
83 mpz_swap (val, other.val);
84 return *this;
85 }
86
87 template<typename T, typename = gdb::Requires<std::is_integral<T>>>
88 gdb_mpz &operator= (T src)
89 {
90 set (src);
91 return *this;
92 }
93
94 /* Convert VAL to an integer of the given type.
95
96 The return type can signed or unsigned, with no size restriction. */
97 template<typename T> T as_integer () const;
98
99 /* Set VAL by importing the number stored in the byte buffer (BUF),
100 given its size (LEN) and BYTE_ORDER.
101
102 UNSIGNED_P indicates whether the number has an unsigned type. */
103 void read (const gdb_byte *buf, int len, enum bfd_endian byte_order,
104 bool unsigned_p);
105
106 /* Write VAL into BUF as a LEN-bytes number with the given BYTE_ORDER.
107
108 UNSIGNED_P indicates whether the number has an unsigned type. */
109 void write (gdb_byte *buf, int len, enum bfd_endian byte_order,
110 bool unsigned_p) const;
111
112 /* Return a string containing VAL. */
113 gdb::unique_xmalloc_ptr<char> str () const
114 { return gmp_string_asprintf ("%Zd", val); }
115
116 /* The destructor. */
117 ~gdb_mpz () { mpz_clear (val); }
118
119private:
120
121 /* Helper template for constructor and operator=. */
122 template<typename T> void set (T src);
123};
124
125/* A class to make it easier to use GMP's mpq_t values within GDB. */
126
127struct gdb_mpq
128{
129 mpq_t val;
130
131 /* Constructors. */
132 gdb_mpq () { mpq_init (val); }
133
134 explicit gdb_mpq (const mpq_t &from_val)
135 {
136 mpq_init (val);
137 mpq_set (val, from_val);
138 }
139
140 gdb_mpq (const gdb_mpq &from)
141 {
142 mpq_init (val);
143 mpq_set (val, from.val);
144 }
145
146 explicit gdb_mpq (gdb_mpq &&from)
147 {
148 mpq_init (val);
149 mpq_swap (val, from.val);
150 }
151
152 /* Copy assignment operator. */
153 gdb_mpq &operator= (const gdb_mpq &from)
154 {
155 mpq_set (val, from.val);
156 return *this;
157 }
158
159 gdb_mpq &operator= (gdb_mpq &&from)
160 {
161 mpq_swap (val, from.val);
162 return *this;
163 }
164
165 /* Return a string representing VAL as "<numerator> / <denominator>". */
166 gdb::unique_xmalloc_ptr<char> str () const
167 { return gmp_string_asprintf ("%Qd", val); }
168
169 /* Return VAL rounded to the nearest integer. */
170 gdb_mpz get_rounded () const;
171
172 /* Set VAL from the contents of the given buffer (BUF), which
173 contains the unscaled value of a fixed point type object
174 with the given size (LEN) and byte order (BYTE_ORDER).
175
176 UNSIGNED_P indicates whether the number has an unsigned type.
177 SCALING_FACTOR is the scaling factor to apply after having
178 read the unscaled value from our buffer. */
179 void read_fixed_point (const gdb_byte *buf, int len,
180 enum bfd_endian byte_order, bool unsigned_p,
181 const gdb_mpq &scaling_factor);
182
183 /* Write VAL into BUF as a LEN-bytes fixed point value following
184 the given BYTE_ORDER.
185
186 UNSIGNED_P indicates whether the number has an unsigned type.
187 SCALING_FACTOR is the scaling factor to apply before writing
188 the unscaled value to our buffer. */
189 void write_fixed_point (gdb_byte *buf, int len,
190 enum bfd_endian byte_order, bool unsigned_p,
191 const gdb_mpq &scaling_factor) const;
192
193 /* The destructor. */
194 ~gdb_mpq () { mpq_clear (val); }
195};
196
197/* A class to make it easier to use GMP's mpf_t values within GDB.
198
199 Should MPFR become a required dependency, we should probably
200 drop this class in favor of using MPFR. */
201
202struct gdb_mpf
203{
204 mpf_t val;
205
206 /* Constructors. */
207 gdb_mpf () { mpf_init (val); }
208
209 DISABLE_COPY_AND_ASSIGN (gdb_mpf);
210
211 /* Set VAL from the contents of the given buffer (BUF), which
212 contains the unscaled value of a fixed point type object
213 with the given size (LEN) and byte order (BYTE_ORDER).
214
215 UNSIGNED_P indicates whether the number has an unsigned type.
216 SCALING_FACTOR is the scaling factor to apply after having
217 read the unscaled value from our buffer. */
218 void read_fixed_point (const gdb_byte *buf, int len,
219 enum bfd_endian byte_order, bool unsigned_p,
220 const gdb_mpq &scaling_factor)
221 {
222 gdb_mpq tmp_q;
223
224 tmp_q.read_fixed_point (buf, len, byte_order, unsigned_p, scaling_factor);
225 mpf_set_q (val, tmp_q.val);
226 }
227
228 /* The destructor. */
229 ~gdb_mpf () { mpf_clear (val); }
230};
231
232/* See declaration above. */
233
234template<typename T>
235void
236gdb_mpz::set (T src)
237{
238 mpz_import (val, 1 /* count */, -1 /* order */,
239 sizeof (T) /* size */, 0 /* endian (0 = native) */,
240 0 /* nails */, &src /* op */);
241 if (std::is_signed<T>::value && src < 0)
242 {
243 /* mpz_import does not handle the sign, so our value was imported
244 as an unsigned. Adjust that imported value so as to make it
245 the correct negative value. */
246 gdb_mpz neg_offset;
247
248 mpz_ui_pow_ui (neg_offset.val, 2, sizeof (T) * HOST_CHAR_BIT);
249 mpz_sub (val, val, neg_offset.val);
250 }
251}
252
253/* See declaration above. */
254
255template<typename T>
256T
257gdb_mpz::as_integer () const
258{
259 /* Initialize RESULT, because mpz_export only write the minimum
260 number of bytes, including none if our value is zero! */
261 T result = 0;
262
263 gdb_mpz exported_val (val);
264 if (std::is_signed<T>::value && mpz_cmp_ui (val, 0) < 0)
265 {
266 /* We want to use mpz_export to set the return value, but
267 this function does not handle the sign. So give exported_val
268 a value which is at the same time positive, and has the same
269 bit representation as our negative value. */
270 gdb_mpz neg_offset;
271
272 mpz_ui_pow_ui (neg_offset.val, 2, sizeof (T) * HOST_CHAR_BIT);
273 mpz_add (exported_val.val, exported_val.val, neg_offset.val);
274 }
275
276 mpz_export (&result, NULL /* count */, -1 /* order */,
277 sizeof (T) /* size */, 0 /* endian (0 = native) */,
278 0 /* nails */, exported_val.val);
279 return result;
280}
281
282#endif
This page took 0.032257 seconds and 4 git commands to generate.