Daily bump.
[official-gcc.git] / gcc / ada / libgnat / g-pehage.adb
blob4212653b335aaeafd9413f60e4820ebd852c999f
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- G N A T . P E R F E C T _ H A S H _ G E N E R A T O R S --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2002-2024, AdaCore --
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 Ada.IO_Exceptions; use Ada.IO_Exceptions;
33 with Ada.Characters.Handling; use Ada.Characters.Handling;
35 with GNAT.OS_Lib; use GNAT.OS_Lib;
37 package body GNAT.Perfect_Hash_Generators is
39 use SPHG;
41 function Image (Int : Integer; W : Natural := 0) return String;
42 function Image (Str : String; W : Natural := 0) return String;
43 -- Return a string which includes string Str or integer Int preceded by
44 -- leading spaces if required by width W.
46 EOL : constant Character := ASCII.LF;
48 Max : constant := 78;
49 Last : Natural := 0;
50 Line : String (1 .. Max);
51 -- Use this line to provide buffered IO
53 NK : Natural := 0;
54 -- NK : Number of Keys
56 Opt : Optimization;
57 -- Optimization mode (memory vs CPU)
59 procedure Add (C : Character);
60 procedure Add (S : String);
61 -- Add a character or a string in Line and update Last
63 procedure Put
64 (F : File_Descriptor;
65 S : String;
66 F1 : Natural;
67 L1 : Natural;
68 C1 : Natural;
69 F2 : Natural;
70 L2 : Natural;
71 C2 : Natural);
72 -- Write string S into file F as a element of an array of one or two
73 -- dimensions. Fk (resp. Lk and Ck) indicates the first (resp last and
74 -- current) index in the k-th dimension. If F1 = L1 the array is considered
75 -- as a one dimension array. This dimension is described by F2 and L2. This
76 -- routine takes care of all the parenthesis, spaces and commas needed to
77 -- format correctly the array. Moreover, the array is well indented and is
78 -- wrapped to fit in a 80 col line. When the line is full, the routine
79 -- writes it into file F. When the array is completed, the routine adds
80 -- semi-colon and writes the line into file F.
82 procedure New_Line (File : File_Descriptor);
83 -- Simulate Ada.Text_IO.New_Line with GNAT.OS_Lib
85 procedure Put (File : File_Descriptor; Str : String);
86 -- Simulate Ada.Text_IO.Put with GNAT.OS_Lib
88 procedure Put_Int_Matrix
89 (File : File_Descriptor;
90 Title : String;
91 Table : Table_Name;
92 Len_1 : Natural;
93 Len_2 : Natural);
94 -- Output a title and a matrix. When the matrix has only one non-empty
95 -- dimension (Len_2 = 0), output a vector.
97 function Ada_File_Base_Name (Pkg_Name : String) return String;
98 -- Return the base file name (i.e. without .ads/.adb extension) for an
99 -- Ada source file containing the named package, using the standard GNAT
100 -- file-naming convention. For example, if Pkg_Name is "Parent.Child", we
101 -- return "parent-child".
103 ------------------------
104 -- Ada_File_Base_Name --
105 ------------------------
107 function Ada_File_Base_Name (Pkg_Name : String) return String is
108 begin
109 -- Convert to lower case, then replace '.' with '-'
111 return Result : String := To_Lower (Pkg_Name) do
112 for J in Result'Range loop
113 if Result (J) = '.' then
114 Result (J) := '-';
115 end if;
116 end loop;
117 end return;
118 end Ada_File_Base_Name;
120 ---------
121 -- Add --
122 ---------
124 procedure Add (C : Character) is
125 pragma Assert (C /= ASCII.NUL);
126 begin
127 Line (Last + 1) := C;
128 Last := Last + 1;
129 end Add;
131 ---------
132 -- Add --
133 ---------
135 procedure Add (S : String) is
136 Len : constant Natural := S'Length;
137 begin
138 for J in S'Range loop
139 pragma Assert (S (J) /= ASCII.NUL);
140 null;
141 end loop;
143 Line (Last + 1 .. Last + Len) := S;
144 Last := Last + Len;
145 end Add;
147 -------------
148 -- Compute --
149 -------------
151 procedure Compute (Position : String := Default_Position) is
152 begin
153 SPHG.Compute (Position);
154 end Compute;
156 --------------
157 -- Finalize --
158 --------------
160 procedure Finalize is
161 begin
162 NK := 0;
163 SPHG.Finalize;
164 end Finalize;
166 -----------
167 -- Image --
168 -----------
170 function Image (Int : Integer; W : Natural := 0) return String is
171 B : String (1 .. 32);
172 L : Natural := 0;
174 procedure Img (V : Natural);
175 -- Compute image of V into B, starting at B (L), incrementing L
177 ---------
178 -- Img --
179 ---------
181 procedure Img (V : Natural) is
182 begin
183 if V > 9 then
184 Img (V / 10);
185 end if;
187 L := L + 1;
188 B (L) := Character'Val ((V mod 10) + Character'Pos ('0'));
189 end Img;
191 -- Start of processing for Image
193 begin
194 if Int < 0 then
195 L := L + 1;
196 B (L) := '-';
197 Img (-Int);
198 else
199 Img (Int);
200 end if;
202 return Image (B (1 .. L), W);
203 end Image;
205 -----------
206 -- Image --
207 -----------
209 function Image (Str : String; W : Natural := 0) return String is
210 Len : constant Natural := Str'Length;
211 Max : Natural := Len;
213 begin
214 if Max < W then
215 Max := W;
216 end if;
218 declare
219 Buf : String (1 .. Max) := (1 .. Max => ' ');
221 begin
222 for J in 0 .. Len - 1 loop
223 Buf (Max - Len + 1 + J) := Str (Str'First + J);
224 end loop;
226 return Buf;
227 end;
228 end Image;
230 ----------------
231 -- Initialize --
232 ----------------
234 procedure Initialize
235 (Seed : Natural;
236 K_To_V : Float := Default_K_To_V;
237 Optim : Optimization := Memory_Space;
238 Tries : Positive := Default_Tries)
240 V : constant Positive := Positive (Float (NK) * K_To_V);
242 begin
243 Opt := Optim;
244 SPHG.Initialize (Seed, V, SPHG.Optimization (Optim), Tries);
245 end Initialize;
247 ------------
248 -- Insert --
249 ------------
251 procedure Insert (Value : String) is
252 begin
253 NK := NK + 1;
254 SPHG.Insert (Value);
255 end Insert;
257 --------------
258 -- New_Line --
259 --------------
261 procedure New_Line (File : File_Descriptor) is
262 begin
263 if Write (File, EOL'Address, 1) /= 1 then
264 raise Program_Error;
265 end if;
266 end New_Line;
268 -------------
269 -- Produce --
270 -------------
272 procedure Produce
273 (Pkg_Name : String := Default_Pkg_Name;
274 Use_Stdout : Boolean := False)
276 File : File_Descriptor := Standout;
278 Siz, L1, L2 : Natural;
279 -- For calls to Define
281 Status : Boolean;
282 -- For call to Close
284 function Array_Img (N, T, R1 : String; R2 : String := "") return String;
285 -- Return string "N : constant array (R1[, R2]) of T;"
287 function Range_Img (F, L : Natural; T : String := "") return String;
288 -- Return string "[T range ]F .. L"
290 function Type_Img (Siz : Positive) return String;
291 -- Return the name of the unsigned type of size S
293 ---------------
294 -- Array_Img --
295 ---------------
297 function Array_Img
298 (N, T, R1 : String;
299 R2 : String := "") return String
301 begin
302 Last := 0;
303 Add (" ");
304 Add (N);
305 Add (" : constant array (");
306 Add (R1);
308 if R2 /= "" then
309 Add (", ");
310 Add (R2);
311 end if;
313 Add (") of ");
314 Add (T);
315 Add (" :=");
316 return Line (1 .. Last);
317 end Array_Img;
319 ---------------
320 -- Range_Img --
321 ---------------
323 function Range_Img (F, L : Natural; T : String := "") return String is
324 FI : constant String := Image (F);
325 FL : constant Natural := FI'Length;
326 LI : constant String := Image (L);
327 LL : constant Natural := LI'Length;
328 TL : constant Natural := T'Length;
329 RI : String (1 .. TL + 7 + FL + 4 + LL);
330 Len : Natural := 0;
332 begin
333 if TL /= 0 then
334 RI (Len + 1 .. Len + TL) := T;
335 Len := Len + TL;
336 RI (Len + 1 .. Len + 7) := " range ";
337 Len := Len + 7;
338 end if;
340 RI (Len + 1 .. Len + FL) := FI;
341 Len := Len + FL;
342 RI (Len + 1 .. Len + 4) := " .. ";
343 Len := Len + 4;
344 RI (Len + 1 .. Len + LL) := LI;
345 Len := Len + LL;
346 return RI (1 .. Len);
347 end Range_Img;
349 --------------
350 -- Type_Img --
351 --------------
353 function Type_Img (Siz : Positive) return String is
354 S : constant String := Image (Siz);
355 U : String := "Unsigned_ ";
356 N : Natural := 9;
358 begin
359 for J in S'Range loop
360 N := N + 1;
361 U (N) := S (J);
362 end loop;
364 return U (1 .. N);
365 end Type_Img;
367 P : Natural;
369 FName : String := Ada_File_Base_Name (Pkg_Name) & ".ads";
370 -- Initially, the name of the spec file, then modified to be the name of
371 -- the body file. Not used if Use_Stdout is True.
373 -- Start of processing for Produce
375 begin
376 if not Use_Stdout then
377 File := Create_File (FName, Binary);
379 if File = Invalid_FD then
380 raise Program_Error with "cannot create: " & FName;
381 end if;
382 end if;
384 Put (File, "package ");
385 Put (File, Pkg_Name);
386 Put (File, " is");
387 New_Line (File);
388 Put (File, " function Hash (S : String) return Natural;");
389 New_Line (File);
390 Put (File, "end ");
391 Put (File, Pkg_Name);
392 Put (File, ";");
393 New_Line (File);
395 if not Use_Stdout then
396 Close (File, Status);
398 if not Status then
399 raise Device_Error;
400 end if;
401 end if;
403 if not Use_Stdout then
405 -- Set to body file name
407 FName (FName'Last) := 'b';
409 File := Create_File (FName, Binary);
411 if File = Invalid_FD then
412 raise Program_Error with "cannot create: " & FName;
413 end if;
414 end if;
416 Put (File, "with Interfaces; use Interfaces;");
417 New_Line (File);
418 New_Line (File);
419 Put (File, "package body ");
420 Put (File, Pkg_Name);
421 Put (File, " is");
422 New_Line (File);
423 New_Line (File);
425 if Opt = CPU_Time then
426 -- The format of this table is fixed
428 Define (Used_Character_Set, Siz, L1, L2);
429 pragma Assert (L1 = 256 and then L2 = 0);
431 Put (File, Array_Img ("C", Type_Img (Siz), "Character"));
432 New_Line (File);
434 for J in 0 .. 255 loop
435 P := Value (Used_Character_Set, J);
436 Put (File, Image (P), 1, 0, 1, 0, 255, J);
437 end loop;
439 New_Line (File);
440 end if;
442 Define (Character_Position, Siz, L1, L2);
443 pragma Assert (Siz = 31 and then L2 = 0);
445 Put (File, Array_Img ("P", "Natural", Range_Img (0, L1 - 1)));
446 New_Line (File);
448 for J in 0 .. L1 - 1 loop
449 P := Value (Character_Position, J);
450 Put (File, Image (P), 1, 0, 1, 0, L1 - 1, J);
451 end loop;
453 New_Line (File);
455 Define (Function_Table_1, Siz, L1, L2);
457 case Opt is
458 when CPU_Time =>
459 Put_Int_Matrix
460 (File,
461 Array_Img ("T1", Type_Img (Siz),
462 Range_Img (0, L1 - 1),
463 Range_Img (0, L2 - 1, Type_Img (8))),
464 Function_Table_1, L1, L2);
466 when Memory_Space =>
467 Put_Int_Matrix
468 (File,
469 Array_Img ("T1", Type_Img (Siz),
470 Range_Img (0, L1 - 1)),
471 Function_Table_1, L1, 0);
472 end case;
474 New_Line (File);
476 Define (Function_Table_2, Siz, L1, L2);
478 case Opt is
479 when CPU_Time =>
480 Put_Int_Matrix
481 (File,
482 Array_Img ("T2", Type_Img (Siz),
483 Range_Img (0, L1 - 1),
484 Range_Img (0, L2 - 1, Type_Img (8))),
485 Function_Table_2, L1, L2);
487 when Memory_Space =>
488 Put_Int_Matrix
489 (File,
490 Array_Img ("T2", Type_Img (Siz),
491 Range_Img (0, L1 - 1)),
492 Function_Table_2, L1, 0);
493 end case;
495 New_Line (File);
497 Define (Graph_Table, Siz, L1, L2);
498 pragma Assert (L2 = 0);
500 Put (File, Array_Img ("G", Type_Img (Siz),
501 Range_Img (0, L1 - 1)));
502 New_Line (File);
504 for J in 0 .. L1 - 1 loop
505 P := Value (Graph_Table, J);
506 Put (File, Image (P), 1, 0, 1, 0, L1 - 1, J);
507 end loop;
509 New_Line (File);
511 Put (File, " function Hash (S : String) return Natural is");
512 New_Line (File);
513 Put (File, " F : constant Natural := S'First - 1;");
514 New_Line (File);
515 Put (File, " L : constant Natural := S'Length;");
516 New_Line (File);
517 Put (File, " F1, F2 : Natural := 0;");
518 New_Line (File);
520 Put (File, " J : ");
522 case Opt is
523 when CPU_Time =>
524 Put (File, Type_Img (8));
526 when Memory_Space =>
527 Put (File, "Natural");
528 end case;
530 Put (File, ";");
531 New_Line (File);
533 Put (File, " begin");
534 New_Line (File);
535 Put (File, " for K in P'Range loop");
536 New_Line (File);
537 Put (File, " exit when L < P (K);");
538 New_Line (File);
539 Put (File, " J := ");
541 case Opt is
542 when CPU_Time =>
543 Put (File, "C");
545 when Memory_Space =>
546 Put (File, "Character'Pos");
547 end case;
549 Put (File, " (S (P (K) + F));");
550 New_Line (File);
552 Put (File, " F1 := (F1 + Natural (T1 (K");
554 if Opt = CPU_Time then
555 Put (File, ", J");
556 end if;
558 Put (File, "))");
560 if Opt = Memory_Space then
561 Put (File, " * J");
562 end if;
564 Put (File, ") mod ");
565 Put (File, Image (L1));
566 Put (File, ";");
567 New_Line (File);
569 Put (File, " F2 := (F2 + Natural (T2 (K");
571 if Opt = CPU_Time then
572 Put (File, ", J");
573 end if;
575 Put (File, "))");
577 if Opt = Memory_Space then
578 Put (File, " * J");
579 end if;
581 Put (File, ") mod ");
582 Put (File, Image (L1));
583 Put (File, ";");
584 New_Line (File);
586 Put (File, " end loop;");
587 New_Line (File);
589 Put (File,
590 " return (Natural (G (F1)) + Natural (G (F2))) mod ");
592 Put (File, Image (NK));
593 Put (File, ";");
594 New_Line (File);
595 Put (File, " end Hash;");
596 New_Line (File);
597 New_Line (File);
598 Put (File, "end ");
599 Put (File, Pkg_Name);
600 Put (File, ";");
601 New_Line (File);
603 if not Use_Stdout then
604 Close (File, Status);
606 if not Status then
607 raise Device_Error;
608 end if;
609 end if;
610 end Produce;
612 ---------
613 -- Put --
614 ---------
616 procedure Put (File : File_Descriptor; Str : String) is
617 Len : constant Natural := Str'Length;
618 begin
619 for J in Str'Range loop
620 pragma Assert (Str (J) /= ASCII.NUL);
621 null;
622 end loop;
624 if Write (File, Str'Address, Len) /= Len then
625 raise Program_Error;
626 end if;
627 end Put;
629 ---------
630 -- Put --
631 ---------
633 procedure Put
634 (F : File_Descriptor;
635 S : String;
636 F1 : Natural;
637 L1 : Natural;
638 C1 : Natural;
639 F2 : Natural;
640 L2 : Natural;
641 C2 : Natural)
643 Len : constant Natural := S'Length;
645 procedure Flush;
646 -- Write current line, followed by LF
648 -----------
649 -- Flush --
650 -----------
652 procedure Flush is
653 begin
654 Put (F, Line (1 .. Last));
655 New_Line (F);
656 Last := 0;
657 end Flush;
659 -- Start of processing for Put
661 begin
662 if C1 = F1 and then C2 = F2 then
663 Last := 0;
664 end if;
666 if Last + Len + 3 >= Max then
667 Flush;
668 end if;
670 if Last = 0 then
671 Add (" ");
673 if F1 <= L1 then
674 if C1 = F1 and then C2 = F2 then
675 Add ('(');
677 if F1 = L1 then
678 Add ("0 .. 0 => ");
679 end if;
681 else
682 Add (' ');
683 end if;
684 end if;
685 end if;
687 if C2 = F2 then
688 Add ('(');
690 if F2 = L2 then
691 Add ("0 .. 0 => ");
692 end if;
694 else
695 Add (' ');
696 end if;
698 Add (S);
700 if C2 = L2 then
701 Add (')');
703 if F1 > L1 then
704 Add (';');
705 Flush;
707 elsif C1 /= L1 then
708 Add (',');
709 Flush;
711 else
712 Add (')');
713 Add (';');
714 Flush;
715 end if;
717 else
718 Add (',');
719 end if;
720 end Put;
722 --------------------
723 -- Put_Int_Matrix --
724 --------------------
726 procedure Put_Int_Matrix
727 (File : File_Descriptor;
728 Title : String;
729 Table : Table_Name;
730 Len_1 : Natural;
731 Len_2 : Natural)
733 F1 : constant Integer := 0;
734 L1 : constant Integer := Len_1 - 1;
735 F2 : constant Integer := 0;
736 L2 : constant Integer := Len_2 - 1;
737 Ix : Natural;
739 begin
740 Put (File, Title);
741 New_Line (File);
743 if Len_2 = 0 then
744 for J in F1 .. L1 loop
745 Ix := Value (Table, J, 0);
746 Put (File, Image (Ix), 1, 0, 1, F1, L1, J);
747 end loop;
749 else
750 for J in F1 .. L1 loop
751 for K in F2 .. L2 loop
752 Ix := Value (Table, J, K);
753 Put (File, Image (Ix), F1, L1, J, F2, L2, K);
754 end loop;
755 end loop;
756 end if;
757 end Put_Int_Matrix;
759 end GNAT.Perfect_Hash_Generators;