gcc:
[official-gcc.git] / gcc / ada / g-arrspl.adb
blob571388ac294209e63c83b944db03bfa9c5706970
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 ------------------------------------------------------------------------------
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) return Natural;
47 -- Returns the number of occurences of Pattern elements in Source, 0 is
48 -- returned if no occurence is found in Source.
50 ------------
51 -- Adjust --
52 ------------
54 procedure Adjust (S : in out Slice_Set) is
55 begin
56 S.Ref_Counter.all := S.Ref_Counter.all + 1;
57 end Adjust;
59 ------------
60 -- Create --
61 ------------
63 procedure Create
64 (S : out Slice_Set;
65 From : Element_Sequence;
66 Separators : Element_Sequence;
67 Mode : Separator_Mode := Single)
69 begin
70 Create (S, From, To_Set (Separators), Mode);
71 end Create;
73 ------------
74 -- Create --
75 ------------
77 procedure Create
78 (S : out Slice_Set;
79 From : Element_Sequence;
80 Separators : Element_Set;
81 Mode : Separator_Mode := Single)
83 begin
84 S.Source := new Element_Sequence'(From);
85 Set (S, Separators, Mode);
86 end Create;
88 -----------
89 -- Count --
90 -----------
92 function Count
93 (Source : Element_Sequence;
94 Pattern : Element_Set) return Natural
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;
104 return C;
105 end Count;
107 --------------
108 -- Finalize --
109 --------------
111 procedure Finalize (S : in out Slice_Set) is
113 procedure Free is
114 new Ada.Unchecked_Deallocation (Element_Sequence, Element_Access);
116 procedure Free is
117 new Ada.Unchecked_Deallocation (Natural, Counter);
119 begin
120 S.Ref_Counter.all := S.Ref_Counter.all - 1;
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;
130 ----------------
131 -- Initialize --
132 ----------------
134 procedure Initialize (S : in out Slice_Set) is
135 begin
136 S.Ref_Counter := new Natural'(1);
137 end Initialize;
139 ----------------
140 -- Separators --
141 ----------------
143 function Separators
144 (S : Slice_Set;
145 Index : Slice_Number) return Slice_Separators
147 begin
148 if Index > S.N_Slice then
149 raise Index_Error;
151 elsif Index = 0
152 or else (Index = 1 and then S.N_Slice = 1)
153 then
154 -- Whole string, or no separator used
156 return (Before => Array_End,
157 After => Array_End);
159 elsif Index = 1 then
160 return (Before => Array_End,
161 After => S.Source (S.Slices (Index).Stop + 1));
163 elsif Index = S.N_Slice then
164 return (Before => S.Source (S.Slices (Index).Start - 1),
165 After => Array_End);
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;
173 ----------------
174 -- Separators --
175 ----------------
177 function Separators (S : Slice_Set) return Separators_Indexes is
178 begin
179 return S.Indexes.all;
180 end Separators;
182 ---------
183 -- Set --
184 ---------
186 procedure Set
187 (S : in out Slice_Set;
188 Separators : Element_Sequence;
189 Mode : Separator_Mode := Single)
191 begin
192 Set (S, To_Set (Separators), Mode);
193 end Set;
195 ---------
196 -- Set --
197 ---------
199 procedure Set
200 (S : in out Slice_Set;
201 Separators : Element_Set;
202 Mode : Separator_Mode := Single)
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);
211 -- Compute all separator's indexes
213 S.Indexes := new Separators_Indexes (1 .. Count_Sep);
214 J := S.Indexes'First;
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;
223 -- Compute slice info for fast slice access
225 declare
226 S_Info : Slices_Indexes (1 .. Slice_Number (Count_Sep) + 1);
227 K : Natural := 1;
228 Start, Stop : Natural;
230 begin
231 S.N_Slice := 0;
233 Start := S.Source'First;
234 Stop := 0;
236 loop
237 if K > Count_Sep then
239 -- No more separators, last slice ends at the end of the source
240 -- string.
242 Stop := S.Source'Last;
243 else
244 Stop := S.Indexes (K) - 1;
245 end if;
247 -- Add slice to the table
249 S.N_Slice := S.N_Slice + 1;
250 S_Info (S.N_Slice) := (Start, Stop);
252 exit when K > Count_Sep;
254 case Mode is
256 when Single =>
258 -- In this mode just set start to character next to the
259 -- current separator, advance the separator index.
261 Start := S.Indexes (K) + 1;
262 K := K + 1;
264 when Multiple =>
266 -- In this mode skip separators following each other
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;
275 end case;
276 end loop;
278 S.Slices := new Slices_Indexes'(S_Info (1 .. S.N_Slice));
279 end;
280 end Set;
282 -----------
283 -- Slice --
284 -----------
286 function Slice
287 (S : Slice_Set;
288 Index : Slice_Number) return Element_Sequence
290 begin
291 if Index = 0 then
292 return S.Source.all;
294 elsif Index > S.N_Slice then
295 raise Index_Error;
297 else
298 return S.Source (S.Slices (Index).Start .. S.Slices (Index).Stop);
299 end if;
300 end Slice;
302 -----------------
303 -- Slice_Count --
304 -----------------
306 function Slice_Count (S : Slice_Set) return Slice_Number is
307 begin
308 return S.N_Slice;
309 end Slice_Count;
311 end GNAT.Array_Split;