openmp: Fix signed/unsigned warning
[official-gcc.git] / gcc / ada / libgnat / s-imguti.adb
blobc6d39b54ce8b4664f636834d5c3e6d6881ee4b1f
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUN-TIME COMPONENTS --
4 -- --
5 -- S Y S T E M . I M G _ U T I L --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2020-2024, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
17 -- --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 -- --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
29 -- --
30 ------------------------------------------------------------------------------
32 with System.Img_Uns; use System.Img_Uns;
34 package body System.Img_Util is
36 ------------------------
37 -- Set_Decimal_Digits --
38 ------------------------
40 pragma Annotate (Gnatcheck, Exempt_On, "Unassigned_OUT_Parameters",
41 "the OUT parameter is assigned by component");
42 procedure Set_Decimal_Digits
43 (Digs : in out String;
44 NDigs : Natural;
45 S : out String;
46 P : in out Natural;
47 Scale : Integer;
48 Fore : Natural;
49 Aft : Natural;
50 Exp : Natural)
52 pragma Annotate (Gnatcheck, Exempt_Off, "Unassigned_OUT_Parameters");
54 pragma Assert (NDigs >= 1);
55 pragma Assert (Digs'First = 1);
56 pragma Assert (Digs'First < Digs'Last);
58 Minus : constant Boolean := (Digs (Digs'First) = '-');
59 -- Set True if input is negative
61 Zero : Boolean := (Digs (Digs'First + 1) = '0');
62 -- Set True if input is exactly zero (only case when a leading zero
63 -- is permitted in the input string given to this procedure). This
64 -- flag can get set later if rounding causes the value to become zero.
66 FD : Natural := 2;
67 -- First digit position of digits remaining to be processed
69 LD : Natural := NDigs;
70 -- Last digit position of digits remaining to be processed
72 ND : Natural := NDigs - 1;
73 -- Number of digits remaining to be processed (LD - FD + 1)
75 Digits_Before_Point : Integer := ND - Scale;
76 -- Number of digits before decimal point in the input value. This
77 -- value can be negative if the input value is less than 0.1, so
78 -- it is an indication of the current exponent. Digits_Before_Point
79 -- is adjusted if the rounding step generates an extra digit.
81 Digits_After_Point : constant Natural := Integer'Max (1, Aft);
82 -- Digit positions after decimal point in result string
84 Expon : Integer;
85 -- Integer value of exponent
87 procedure Round (N : Integer);
88 -- Round the number in Digs. N is the position of the last digit to be
89 -- retained in the rounded position (rounding is based on Digs (N + 1)
90 -- FD, LD, ND are reset as necessary if required. Note that if the
91 -- result value rounds up (e.g. 9.99 => 10.0), an extra digit can be
92 -- placed in the sign position as a result of the rounding, this is
93 -- the case in which FD is adjusted. The call to Round has no effect
94 -- if N is outside the range FD .. LD.
96 procedure Set (C : Character);
97 pragma Inline (Set);
98 -- Sets character C in output buffer
100 procedure Set_Blanks_And_Sign (N : Integer);
101 -- Sets leading blanks and minus sign if needed. N is the number of
102 -- positions to be filled (a minus sign is output even if N is zero
103 -- or negative, but for a positive value, if N is non-positive, then
104 -- the call has no effect).
106 procedure Set_Digits (S, E : Natural);
107 pragma Inline (Set_Digits);
108 -- Set digits S through E from Digs, no effect if S > E
110 procedure Set_Zeroes (N : Integer);
111 pragma Inline (Set_Zeroes);
112 -- Set N zeroes, no effect if N is negative
114 -----------
115 -- Round --
116 -----------
118 procedure Round (N : Integer) is
119 D : Character;
121 pragma Assert (NDigs >= 1);
122 pragma Assert (Digs'First = 1);
123 pragma Assert (Digs'First < Digs'Last);
125 begin
126 pragma Annotate (Gnatcheck, Exempt_On, "Improper_Returns",
127 "early returns for performance");
129 -- Nothing to do if rounding past the last digit we have
131 if N >= LD then
132 return;
134 -- Cases of rounding before the initial digit
136 elsif N < FD then
138 -- The result is zero, unless we are rounding just before
139 -- the first digit, and the first digit is five or more.
141 if N = 1 and then Digs (Digs'First + 1) >= '5' then
142 Digs (Digs'First) := '1';
143 else
144 Digs (Digs'First) := '0';
145 Zero := True;
146 end if;
148 Digits_Before_Point := Digits_Before_Point + 1;
149 FD := 1;
150 LD := 1;
151 ND := 1;
153 -- Normal case of rounding an existing digit
155 else
156 LD := N;
157 pragma Assert (LD >= 1);
158 -- In this case, we have N < LD and N >= FD. FD is a Natural,
159 -- So we can conclude, LD >= 1
160 ND := LD - 1;
161 pragma Assert (N + 1 <= Digs'Last);
163 if Digs (N + 1) >= '5' then
164 for J in reverse Digs'First + 1 .. Digs'First + N - 1 loop
165 pragma Assert (Digs (J) in '0' .. '9' | ' ' | '-');
166 -- Because it is a decimal image, we can assume that
167 -- it can only contain these characters.
168 D := Character'Succ (Digs (J));
170 if D <= '9' then
171 Digs (J) := D;
172 return;
173 else
174 Digs (J) := '0';
175 end if;
176 end loop;
178 -- Here the rounding overflows into the sign position. That's
179 -- OK, because we already captured the value of the sign and
180 -- we are in any case destroying the value in the Digs buffer
182 Digs (Digs'First) := '1';
183 FD := 1;
184 ND := ND + 1;
185 Digits_Before_Point := Digits_Before_Point + 1;
186 end if;
187 end if;
189 pragma Annotate (Gnatcheck, Exempt_Off, "Improper_Returns");
190 end Round;
192 ---------
193 -- Set --
194 ---------
196 procedure Set (C : Character) is
197 begin
198 pragma Assert (P >= (S'First - 1) and P < S'Last and
199 P < Natural'Last);
200 -- No check is done as documented in the header : updating P to
201 -- point to the last character stored, the caller promises that the
202 -- buffer is large enough and no check is made for this.
203 -- Constraint_Error will not necessarily be raised if this
204 -- requirement is violated, since it is perfectly valid to compile
205 -- this unit with checks off.
206 P := P + 1;
207 S (P) := C;
208 end Set;
210 -------------------------
211 -- Set_Blanks_And_Sign --
212 -------------------------
214 procedure Set_Blanks_And_Sign (N : Integer) is
215 begin
216 if Minus then
217 for J in 1 .. N - 1 loop
218 Set (' ');
219 end loop;
221 Set ('-');
223 else
224 for J in 1 .. N loop
225 Set (' ');
226 end loop;
227 end if;
228 end Set_Blanks_And_Sign;
230 ----------------
231 -- Set_Digits --
232 ----------------
234 procedure Set_Digits (S, E : Natural) is
235 begin
236 pragma Assert (S >= Digs'First and E <= Digs'Last);
237 -- S and E should be in the Digs array range
238 for J in S .. E loop
239 Set (Digs (J));
240 end loop;
241 end Set_Digits;
243 ----------------
244 -- Set_Zeroes --
245 ----------------
247 procedure Set_Zeroes (N : Integer) is
248 begin
249 for J in 1 .. N loop
250 Set ('0');
251 end loop;
252 end Set_Zeroes;
254 -- Start of processing for Set_Decimal_Digits
256 begin
257 pragma Annotate (Gnatcheck, Exempt_On, "Improper_Returns",
258 "early returns for performance");
260 -- Case of exponent given
262 if Exp > 0 then
263 Set_Blanks_And_Sign (Fore - 1);
264 Round (Digits_After_Point + 2);
266 Set (Digs (FD));
267 FD := FD + 1;
268 pragma Assert (ND >= 1);
269 ND := ND - 1;
270 Set ('.');
272 if ND >= Digits_After_Point then
273 Set_Digits (FD, FD + Digits_After_Point - 1);
274 else
275 Set_Digits (FD, LD);
276 Set_Zeroes (Digits_After_Point - ND);
277 end if;
279 -- Calculate exponent. The number of digits before the decimal point
280 -- in the input is Digits_Before_Point, and the number of digits
281 -- before the decimal point in the output is 1, so we can get the
282 -- exponent as the difference between these two values. The one
283 -- exception is for the value zero, which by convention has an
284 -- exponent of +0.
286 Expon := (if Zero then 0 else Digits_Before_Point - 1);
288 Set ('E');
289 ND := 0;
291 if Expon >= 0 then
292 Set ('+');
293 Set_Image_Unsigned (Unsigned (Expon), Digs, ND);
294 else
295 Set ('-');
296 Set_Image_Unsigned (Unsigned (-Expon), Digs, ND);
297 end if;
299 Set_Zeroes (Exp - ND - 1);
300 Set_Digits (1, ND);
301 return;
303 -- Case of no exponent given. To make these cases clear, we use
304 -- examples. For all the examples, we assume Fore = 2, Aft = 3.
305 -- A P in the example input string is an implied zero position,
306 -- not included in the input string.
308 else
309 -- Round at correct position
310 -- Input: 4PP => unchanged
311 -- Input: 400.03 => unchanged
312 -- Input 3.4567 => 3.457
313 -- Input: 9.9999 => 10.000
314 -- Input: 0.PPP5 => 0.001
315 -- Input: 0.PPP4 => 0
316 -- Input: 0.00003 => 0
318 Round (LD - (Scale - Digits_After_Point));
320 -- No digits before point in input
321 -- Input: .123 Output: 0.123
322 -- Input: .PP3 Output: 0.003
324 if Digits_Before_Point <= 0 then
325 Set_Blanks_And_Sign (Fore - 1);
326 Set ('0');
327 Set ('.');
329 declare
330 DA : Natural := Digits_After_Point;
331 -- Digits remaining to output after point
333 LZ : constant Integer := Integer'Min (DA, -Digits_Before_Point);
334 -- Number of leading zeroes after point. Note: there used to be
335 -- a Max of this result with zero, but that's redundant, since
336 -- we know DA is positive, and because of the test above, we
337 -- know that -Digits_Before_Point >= 0.
339 begin
340 Set_Zeroes (LZ);
341 DA := DA - LZ;
343 if DA < ND then
345 -- Note: it is definitely possible for the above condition
346 -- to be True, for example:
348 -- V => 1234, Scale => 5, Fore => 0, After => 1, Exp => 0
350 -- but in this case DA = 0, ND = 1, FD = 1, FD + DA-1 = 0
351 -- so the arguments in the call are (1, 0) meaning that no
352 -- digits are output.
354 -- No obvious example exists where the following call to
355 -- Set_Digits actually outputs some digits, but we lack a
356 -- proof that no such example exists.
358 -- So it is safer to retain this call, even though as a
359 -- result it is hard (or perhaps impossible) to create a
360 -- coverage test for the inlined code of the call.
362 Set_Digits (FD, FD + DA - 1);
364 else
365 Set_Digits (FD, LD);
366 Set_Zeroes (DA - ND);
367 end if;
368 end;
370 -- At least one digit before point in input
372 else
373 -- Less digits in input than are needed before point
374 -- Input: 1PP Output: 100.000
376 if ND < Digits_Before_Point then
378 -- Special case, if the input is the single digit 0, then we
379 -- do not want 000.000, but instead 0.000.
381 if ND = 1 and then Digs (FD) = '0' then
382 Set_Blanks_And_Sign (Fore - 1);
383 Set ('0');
385 -- Normal case where we need to output scaling zeroes
387 else
388 Set_Blanks_And_Sign (Fore - Digits_Before_Point);
389 Set_Digits (FD, LD);
390 Set_Zeroes (Digits_Before_Point - ND);
391 end if;
393 -- Set period and zeroes after the period
395 Set ('.');
396 Set_Zeroes (Digits_After_Point);
398 -- Input has full amount of digits before decimal point
400 else
401 Set_Blanks_And_Sign (Fore - Digits_Before_Point);
402 pragma Assert (FD + Digits_Before_Point - 1 >= 0);
403 -- In this branch, we have Digits_Before_Point > 0. It is the
404 -- else of test (Digits_Before_Point <= 0)
405 Set_Digits (FD, FD + Digits_Before_Point - 1);
406 Set ('.');
407 Set_Digits (FD + Digits_Before_Point, LD);
408 Set_Zeroes (Digits_After_Point - (ND - Digits_Before_Point));
409 end if;
410 end if;
411 end if;
413 pragma Annotate (Gnatcheck, Exempt_Off, "Improper_Returns");
414 end Set_Decimal_Digits;
416 --------------------------------
417 -- Set_Floating_Invalid_Value --
418 --------------------------------
420 pragma Annotate (Gnatcheck, Exempt_On, "Unassigned_OUT_Parameters",
421 "the OUT parameter is assigned by component");
422 procedure Set_Floating_Invalid_Value
423 (V : Floating_Invalid_Value;
424 S : out String;
425 P : in out Natural;
426 Fore : Natural;
427 Aft : Natural;
428 Exp : Natural)
430 pragma Annotate (Gnatcheck, Exempt_Off, "Unassigned_OUT_Parameters");
432 procedure Set (C : Character);
433 -- Sets character C in output buffer
435 procedure Set_Special_Fill (N : Natural);
436 -- After outputting +Inf, -Inf or NaN, this routine fills out the
437 -- rest of the field with * characters. The argument is the number
438 -- of characters output so far (either 3 or 4)
440 ---------
441 -- Set --
442 ---------
444 procedure Set (C : Character) is
445 begin
446 pragma Assert (P in S'First - 1 .. S'Last - 1);
447 -- No check is done as documented in the header: updating P to point
448 -- to the last character stored, the caller promises that the buffer
449 -- is large enough and no check is made for this. Constraint_Error
450 -- will not necessarily be raised if this requirement is violated,
451 -- since it is perfectly valid to compile this unit with checks off.
453 P := P + 1;
454 S (P) := C;
455 end Set;
457 ----------------------
458 -- Set_Special_Fill --
459 ----------------------
461 procedure Set_Special_Fill (N : Natural) is
462 begin
463 if Exp /= 0 then
464 for J in N + 1 .. Fore + 1 + Aft + 1 + Exp loop
465 Set ('*');
466 end loop;
468 else
469 for J in N + 1 .. Fore + 1 + Aft loop
470 Set ('*');
471 end loop;
472 end if;
473 end Set_Special_Fill;
475 -- Start of processing for Set_Floating_Invalid_Value
477 begin
478 case V is
479 when Minus_Infinity =>
480 Set ('-');
481 Set ('I');
482 Set ('n');
483 Set ('f');
484 Set_Special_Fill (4);
486 when Infinity =>
487 Set ('+');
488 Set ('I');
489 Set ('n');
490 Set ('f');
491 Set_Special_Fill (4);
493 when Not_A_Number =>
494 Set ('N');
495 Set ('a');
496 Set ('N');
497 Set_Special_Fill (3);
498 end case;
499 end Set_Floating_Invalid_Value;
501 end System.Img_Util;