PR target/16201
[official-gcc.git] / gcc / ada / g-arrspl.adb
blob78fa8c4608173cd25ae99b523b2015a550e84bf9
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- G N A T . A R R A Y _ S P I T --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2002-2003 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, 59 Temple Place - Suite 330, Boston, --
20 -- MA 02111-1307, 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 ------------------------------------------------------------------------------
34 with Ada.Unchecked_Deallocation;
36 package body GNAT.Array_Split is
38 procedure Free is
39 new Ada.Unchecked_Deallocation (Slices_Indexes, Slices_Access);
41 procedure Free is
42 new Ada.Unchecked_Deallocation (Separators_Indexes, Indexes_Access);
44 function Count
45 (Source : Element_Sequence;
46 Pattern : Element_Set)
47 return Natural;
48 -- Returns the number of occurences of Pattern elements in Source, 0 is
49 -- returned if no occurence is found in Source.
51 ------------
52 -- Adjust --
53 ------------
55 procedure Adjust (S : in out Slice_Set) is
56 begin
57 S.Ref_Counter.all := S.Ref_Counter.all + 1;
58 end Adjust;
60 ------------
61 -- Create --
62 ------------
64 procedure Create
65 (S : out Slice_Set;
66 From : Element_Sequence;
67 Separators : Element_Sequence;
68 Mode : Separator_Mode := Single)
70 begin
71 Create (S, From, To_Set (Separators), Mode);
72 end Create;
74 ------------
75 -- Create --
76 ------------
78 procedure Create
79 (S : out Slice_Set;
80 From : Element_Sequence;
81 Separators : Element_Set;
82 Mode : Separator_Mode := Single)
84 begin
85 S.Source := new Element_Sequence'(From);
86 Set (S, Separators, Mode);
87 end Create;
89 -----------
90 -- Count --
91 -----------
93 function Count
94 (Source : Element_Sequence;
95 Pattern : Element_Set)
96 return Natural
98 C : Natural := 0;
99 begin
100 for K in Source'Range loop
101 if Is_In (Source (K), Pattern) then
102 C := C + 1;
103 end if;
104 end loop;
106 return C;
107 end Count;
109 --------------
110 -- Finalize --
111 --------------
113 procedure Finalize (S : in out Slice_Set) is
115 procedure Free is
116 new Ada.Unchecked_Deallocation (Element_Sequence, Element_Access);
118 procedure Free is
119 new Ada.Unchecked_Deallocation (Natural, Counter);
121 begin
122 S.Ref_Counter.all := S.Ref_Counter.all - 1;
124 if S.Ref_Counter.all = 0 then
125 Free (S.Source);
126 Free (S.Indexes);
127 Free (S.Slices);
128 Free (S.Ref_Counter);
129 end if;
130 end Finalize;
132 ----------------
133 -- Initialize --
134 ----------------
136 procedure Initialize (S : in out Slice_Set) is
137 begin
138 S.Ref_Counter := new Natural'(1);
139 end Initialize;
141 ----------------
142 -- Separators --
143 ----------------
145 function Separators
146 (S : Slice_Set;
147 Index : Slice_Number)
148 return Slice_Separators
150 begin
151 if Index > S.N_Slice then
152 raise Index_Error;
154 elsif Index = 0
155 or else (Index = 1 and then S.N_Slice = 1)
156 then
157 -- Whole string, or no separator used.
159 return (Before => Array_End,
160 After => Array_End);
162 elsif Index = 1 then
163 return (Before => Array_End,
164 After => S.Source (S.Slices (Index).Stop + 1));
166 elsif Index = S.N_Slice then
167 return (Before => S.Source (S.Slices (Index).Start - 1),
168 After => Array_End);
170 else
171 return (Before => S.Source (S.Slices (Index).Start - 1),
172 After => S.Source (S.Slices (Index).Stop + 1));
173 end if;
174 end Separators;
176 ----------------
177 -- Separators --
178 ----------------
180 function Separators (S : Slice_Set) return Separators_Indexes is
181 begin
182 return S.Indexes.all;
183 end Separators;
185 ---------
186 -- Set --
187 ---------
189 procedure Set
190 (S : in out Slice_Set;
191 Separators : Element_Sequence;
192 Mode : Separator_Mode := Single)
194 begin
195 Set (S, To_Set (Separators), Mode);
196 end Set;
198 ---------
199 -- Set --
200 ---------
202 procedure Set
203 (S : in out Slice_Set;
204 Separators : Element_Set;
205 Mode : Separator_Mode := Single)
207 Count_Sep : constant Natural := Count (S.Source.all, Separators);
208 J : Positive;
209 begin
210 -- Free old structure
211 Free (S.Indexes);
212 Free (S.Slices);
214 -- Compute all separator's indexes
216 S.Indexes := new Separators_Indexes (1 .. Count_Sep);
217 J := S.Indexes'First;
219 for K in S.Source'Range loop
220 if Is_In (S.Source (K), Separators) then
221 S.Indexes (J) := K;
222 J := J + 1;
223 end if;
224 end loop;
226 -- Compute slice info for fast slice access
228 declare
229 S_Info : Slices_Indexes (1 .. Slice_Number (Count_Sep) + 1);
230 K : Natural := 1;
231 Start, Stop : Natural;
233 begin
234 S.N_Slice := 0;
236 Start := S.Source'First;
237 Stop := 0;
239 loop
240 if K > Count_Sep then
241 -- No more separator, last slice end at the end of the source
242 -- string.
243 Stop := S.Source'Last;
244 else
245 Stop := S.Indexes (K) - 1;
246 end if;
248 -- Add slice to the table
250 S.N_Slice := S.N_Slice + 1;
251 S_Info (S.N_Slice) := (Start, Stop);
253 exit when K > Count_Sep;
255 case Mode is
257 when Single =>
258 -- In this mode just set start to character next to the
259 -- current separator, advance the separator index.
260 Start := S.Indexes (K) + 1;
261 K := K + 1;
263 when Multiple =>
264 -- In this mode skip separators following each others
265 loop
266 Start := S.Indexes (K) + 1;
267 K := K + 1;
268 exit when K > Count_Sep
269 or else S.Indexes (K) > S.Indexes (K - 1) + 1;
270 end loop;
272 end case;
273 end loop;
275 S.Slices := new Slices_Indexes'(S_Info (1 .. S.N_Slice));
276 end;
277 end Set;
279 -----------
280 -- Slice --
281 -----------
283 function Slice
284 (S : Slice_Set;
285 Index : Slice_Number)
286 return Element_Sequence
288 begin
289 if Index = 0 then
290 return S.Source.all;
292 elsif Index > S.N_Slice then
293 raise Index_Error;
295 else
296 return S.Source (S.Slices (Index).Start .. S.Slices (Index).Stop);
297 end if;
298 end Slice;
300 -----------------
301 -- Slice_Count --
302 -----------------
304 function Slice_Count (S : Slice_Set) return Slice_Number is
305 begin
306 return S.N_Slice;
307 end Slice_Count;
309 end GNAT.Array_Split;