1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- G N A T . A R R A Y _ S P L I T --
9 -- Copyright (C) 2002-2009, Free Software Foundation, Inc. --
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. --
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. --
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/>. --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
30 ------------------------------------------------------------------------------
32 with Ada.Unchecked_Deallocation;
34 package body GNAT.Array_Split is
37 new Ada.Unchecked_Deallocation (Slices_Indexes, Slices_Access);
40 new Ada.Unchecked_Deallocation (Separators_Indexes, Indexes_Access);
43 new Ada.Unchecked_Deallocation (Element_Sequence, Element_Access);
46 (Source : Element_Sequence;
47 Pattern : Element_Set) return Natural;
48 -- Returns the number of occurrences of Pattern elements in Source, 0 is
49 -- returned if no occurrence is found in Source.
55 procedure Adjust (S : in out Slice_Set) is
57 S.Ref_Counter.all := S.Ref_Counter.all + 1;
66 From : Element_Sequence;
67 Separators : Element_Sequence;
68 Mode : Separator_Mode := Single)
71 Create (S, From, To_Set (Separators), Mode);
80 From : Element_Sequence;
81 Separators : Element_Set;
82 Mode : Separator_Mode := Single)
86 S.Source := new Element_Sequence'(From);
87 Set (S, Separators, Mode);
95 (Source : Element_Sequence;
96 Pattern : Element_Set) return Natural
100 for K in Source'Range loop
101 if Is_In (Source (K), Pattern) then
113 procedure Finalize (S : in out Slice_Set) is
116 new Ada.Unchecked_Deallocation (Element_Sequence, Element_Access);
119 new Ada.Unchecked_Deallocation (Natural, Counter);
122 S.Ref_Counter.all := S.Ref_Counter.all - 1;
124 if S.Ref_Counter.all = 0 then
128 Free (S.Ref_Counter);
136 procedure Initialize (S : in out Slice_Set) is
138 S.Ref_Counter := new Natural'(1);
147 Index : Slice_Number) return Slice_Separators
150 if Index > S.N_Slice then
154 or else (Index = 1 and then S.N_Slice = 1)
156 -- Whole string, or no separator used
158 return (Before => Array_End,
162 return (Before => Array_End,
163 After => S.Source (S.Slices (Index).Stop + 1));
165 elsif Index = S.N_Slice then
166 return (Before => S.Source (S.Slices (Index).Start - 1),
170 return (Before => S.Source (S.Slices (Index).Start - 1),
171 After => S.Source (S.Slices (Index).Stop + 1));
179 function Separators (S : Slice_Set) return Separators_Indexes is
181 return S.Indexes.all;
189 (S : in out Slice_Set;
190 Separators : Element_Sequence;
191 Mode : Separator_Mode := Single)
194 Set (S, To_Set (Separators), Mode);
202 (S : in out Slice_Set;
203 Separators : Element_Set;
204 Mode : Separator_Mode := Single)
206 Count_Sep : constant Natural := Count (S.Source.all, Separators);
209 -- Free old structure
213 -- Compute all separator's indexes
215 S.Indexes := new Separators_Indexes (1 .. Count_Sep);
216 J := S.Indexes'First;
218 for K in S.Source'Range loop
219 if Is_In (S.Source (K), Separators) then
225 -- Compute slice info for fast slice access
228 S_Info : Slices_Indexes (1 .. Slice_Number (Count_Sep) + 1);
230 Start, Stop : Natural;
235 Start := S.Source'First;
239 if K > Count_Sep then
241 -- No more separators, last slice ends at end of source string
243 Stop := S.Source'Last;
246 Stop := S.Indexes (K) - 1;
249 -- Add slice to the table
251 S.N_Slice := S.N_Slice + 1;
252 S_Info (S.N_Slice) := (Start, Stop);
254 exit when K > Count_Sep;
260 -- In this mode just set start to character next to the
261 -- current separator, advance the separator index.
263 Start := S.Indexes (K) + 1;
268 -- In this mode skip separators following each other
271 Start := S.Indexes (K) + 1;
273 exit when K > Count_Sep
274 or else S.Indexes (K) > S.Indexes (K - 1) + 1;
280 S.Slices := new Slices_Indexes'(S_Info (1 .. S.N_Slice));
290 Index : Slice_Number) return Element_Sequence
296 elsif Index > S.N_Slice then
300 return S.Source (S.Slices (Index).Start .. S.Slices (Index).Stop);
308 function Slice_Count (S : Slice_Set) return Slice_Number is
313 end GNAT.Array_Split;