OSDN Git Service

* pa.h (LEGITIMATE_CONSTANT_P): Simplify.
[pf3gnuchains/gcc-fork.git] / gcc / ada / g-arrspl.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
5 --                     G N A T . A R R A Y _ S P L I T                      --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 2002-2005, 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 2,  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.  See the GNU General Public License --
17 -- for  more details.  You should have  received  a copy of the GNU General --
18 -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
19 -- to  the  Free Software Foundation,  51  Franklin  Street,  Fifth  Floor, --
20 -- Boston, MA 02110-1301, USA.                                              --
21 --                                                                          --
22 -- As a special exception,  if other files  instantiate  generics from this --
23 -- unit, or you link  this unit with other files  to produce an executable, --
24 -- this  unit  does not  by itself cause  the resulting  executable  to  be --
25 -- covered  by the  GNU  General  Public  License.  This exception does not --
26 -- however invalidate  any other reasons why  the executable file  might be --
27 -- covered by the  GNU Public License.                                      --
28 --                                                                          --
29 -- GNAT was originally developed  by the GNAT team at  New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
31 --                                                                          --
32 ------------------------------------------------------------------------------
33
34 with Ada.Unchecked_Deallocation;
35
36 package body GNAT.Array_Split is
37
38    procedure Free is
39       new Ada.Unchecked_Deallocation (Slices_Indexes, Slices_Access);
40
41    procedure Free is
42       new Ada.Unchecked_Deallocation (Separators_Indexes, Indexes_Access);
43
44    function Count
45      (Source  : Element_Sequence;
46       Pattern : Element_Set) return Natural;
47    --  Returns the number of occurences of Pattern elements in Source, 0 is
48    --  returned if no occurence is found in Source.
49
50    ------------
51    -- Adjust --
52    ------------
53
54    procedure Adjust (S : in out Slice_Set) is
55    begin
56       S.Ref_Counter.all := S.Ref_Counter.all + 1;
57    end Adjust;
58
59    ------------
60    -- Create --
61    ------------
62
63    procedure Create
64      (S          : out Slice_Set;
65       From       : Element_Sequence;
66       Separators : Element_Sequence;
67       Mode       : Separator_Mode := Single)
68    is
69    begin
70       Create (S, From, To_Set (Separators), Mode);
71    end Create;
72
73    ------------
74    -- Create --
75    ------------
76
77    procedure Create
78      (S          : out Slice_Set;
79       From       : Element_Sequence;
80       Separators : Element_Set;
81       Mode       : Separator_Mode := Single)
82    is
83    begin
84       S.Source := new Element_Sequence'(From);
85       Set (S, Separators, Mode);
86    end Create;
87
88    -----------
89    -- Count --
90    -----------
91
92    function Count
93      (Source  : Element_Sequence;
94       Pattern : Element_Set) return Natural
95    is
96       C : Natural := 0;
97    begin
98       for K in Source'Range loop
99          if Is_In (Source (K), Pattern) then
100             C := C + 1;
101          end if;
102       end loop;
103
104       return C;
105    end Count;
106
107    --------------
108    -- Finalize --
109    --------------
110
111    procedure Finalize (S : in out Slice_Set) is
112
113       procedure Free is
114          new Ada.Unchecked_Deallocation (Element_Sequence, Element_Access);
115
116       procedure Free is
117          new Ada.Unchecked_Deallocation (Natural, Counter);
118
119    begin
120       S.Ref_Counter.all := S.Ref_Counter.all - 1;
121
122       if S.Ref_Counter.all = 0 then
123          Free (S.Source);
124          Free (S.Indexes);
125          Free (S.Slices);
126          Free (S.Ref_Counter);
127       end if;
128    end Finalize;
129
130    ----------------
131    -- Initialize --
132    ----------------
133
134    procedure Initialize (S : in out Slice_Set) is
135    begin
136       S.Ref_Counter := new Natural'(1);
137    end Initialize;
138
139    ----------------
140    -- Separators --
141    ----------------
142
143    function Separators
144      (S     : Slice_Set;
145       Index : Slice_Number) return Slice_Separators
146    is
147    begin
148       if Index > S.N_Slice then
149          raise Index_Error;
150
151       elsif Index = 0
152         or else (Index = 1 and then S.N_Slice = 1)
153       then
154          --  Whole string, or no separator used
155
156          return (Before => Array_End,
157                  After  => Array_End);
158
159       elsif Index = 1 then
160          return (Before => Array_End,
161                  After  => S.Source (S.Slices (Index).Stop + 1));
162
163       elsif Index = S.N_Slice then
164          return (Before => S.Source (S.Slices (Index).Start - 1),
165                  After  => Array_End);
166
167       else
168          return (Before => S.Source (S.Slices (Index).Start - 1),
169                  After  => S.Source (S.Slices (Index).Stop + 1));
170       end if;
171    end Separators;
172
173    ----------------
174    -- Separators --
175    ----------------
176
177    function Separators (S : Slice_Set) return Separators_Indexes is
178    begin
179       return S.Indexes.all;
180    end Separators;
181
182    ---------
183    -- Set --
184    ---------
185
186    procedure Set
187      (S          : in out Slice_Set;
188       Separators : Element_Sequence;
189       Mode       : Separator_Mode := Single)
190    is
191    begin
192       Set (S, To_Set (Separators), Mode);
193    end Set;
194
195    ---------
196    -- Set --
197    ---------
198
199    procedure Set
200      (S          : in out Slice_Set;
201       Separators : Element_Set;
202       Mode       : Separator_Mode := Single)
203    is
204       Count_Sep : constant Natural := Count (S.Source.all, Separators);
205       J : Positive;
206    begin
207       --  Free old structure
208       Free (S.Indexes);
209       Free (S.Slices);
210
211       --  Compute all separator's indexes
212
213       S.Indexes := new Separators_Indexes (1 .. Count_Sep);
214       J := S.Indexes'First;
215
216       for K in S.Source'Range loop
217          if Is_In (S.Source (K), Separators) then
218             S.Indexes (J) := K;
219             J := J + 1;
220          end if;
221       end loop;
222
223       --  Compute slice info for fast slice access
224
225       declare
226          S_Info      : Slices_Indexes (1 .. Slice_Number (Count_Sep) + 1);
227          K           : Natural := 1;
228          Start, Stop : Natural;
229
230       begin
231          S.N_Slice := 0;
232
233          Start := S.Source'First;
234          Stop  := 0;
235
236          loop
237             if K > Count_Sep then
238
239                --  No more separators, last slice ends at the end of the source
240                --  string.
241
242                Stop := S.Source'Last;
243             else
244                Stop := S.Indexes (K) - 1;
245             end if;
246
247             --  Add slice to the table
248
249             S.N_Slice := S.N_Slice + 1;
250             S_Info (S.N_Slice) := (Start, Stop);
251
252             exit when K > Count_Sep;
253
254             case Mode is
255
256                when Single =>
257
258                   --  In this mode just set start to character next to the
259                   --  current separator, advance the separator index.
260
261                   Start := S.Indexes (K) + 1;
262                   K := K + 1;
263
264                when Multiple =>
265
266                   --  In this mode skip separators following each other
267
268                   loop
269                      Start := S.Indexes (K) + 1;
270                      K := K + 1;
271                      exit when K > Count_Sep
272                        or else S.Indexes (K) > S.Indexes (K - 1) + 1;
273                   end loop;
274
275             end case;
276          end loop;
277
278          S.Slices := new Slices_Indexes'(S_Info (1 .. S.N_Slice));
279       end;
280    end Set;
281
282    -----------
283    -- Slice --
284    -----------
285
286    function Slice
287      (S     : Slice_Set;
288       Index : Slice_Number) return Element_Sequence
289    is
290    begin
291       if Index = 0 then
292          return S.Source.all;
293
294       elsif Index > S.N_Slice then
295          raise Index_Error;
296
297       else
298          return S.Source (S.Slices (Index).Start .. S.Slices (Index).Stop);
299       end if;
300    end Slice;
301
302    -----------------
303    -- Slice_Count --
304    -----------------
305
306    function Slice_Count (S : Slice_Set) return Slice_Number is
307    begin
308       return S.N_Slice;
309    end Slice_Count;
310
311 end GNAT.Array_Split;