1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- G N A T . D Y N A M I C _ T A B L E S --
9 -- Copyright (C) 2000-2016, AdaCore --
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 pragma Compiler_Unit_Warning
;
34 with GNAT
.Heap_Sort_G
;
36 with Ada
.Unchecked_Deallocation
;
38 package body GNAT
.Dynamic_Tables
is
40 Empty
: constant Table_Ptr
:=
41 Empty_Table_Array_Ptr_To_Table_Ptr
(Empty_Table_Array
'Access);
43 -----------------------
44 -- Local Subprograms --
45 -----------------------
47 procedure Grow
(T
: in out Instance
; New_Last
: Table_Count_Type
);
48 -- This is called when we are about to set the value of Last to a value
49 -- that is larger than Last_Allocated. This reallocates the table to the
50 -- larger size, as indicated by New_Last. At the time this is called,
51 -- T.P.Last is still the old value.
57 procedure Allocate
(T
: in out Instance
; Num
: Integer := 1) is
59 -- Note that Num can be negative
61 Set_Last
(T
, T
.P
.Last
+ Table_Index_Type
'Base (Num
));
68 procedure Append
(T
: in out Instance
; New_Val
: Table_Component_Type
) is
70 Set_Item
(T
, T
.P
.Last
+ 1, New_Val
);
77 procedure Append_All
(T
: in out Instance
; New_Vals
: Table_Type
) is
79 for J
in New_Vals
'Range loop
80 Append
(T
, New_Vals
(J
));
88 procedure Decrement_Last
(T
: in out Instance
) is
97 function First
return Table_Index_Type
is
99 return Table_Low_Bound
;
106 procedure For_Each
(Table
: Instance
) is
107 Quit
: Boolean := False;
109 for Index
in Table_Low_Bound
.. Table
.P
.Last
loop
110 Action
(Index
, Table
.Table
(Index
), Quit
);
119 procedure Free
(T
: in out Instance
) is
120 subtype Alloc_Type
is Table_Type
(First
.. T
.P
.Last_Allocated
);
121 type Alloc_Ptr
is access all Alloc_Type
;
123 procedure Free
is new Ada
.Unchecked_Deallocation
(Alloc_Type
, Alloc_Ptr
);
124 function To_Alloc_Ptr
is
125 new Ada
.Unchecked_Conversion
(Table_Ptr
, Alloc_Ptr
);
127 Temp
: Alloc_Ptr
:= To_Alloc_Ptr
(T
.Table
);
130 if T
.Table
= Empty
then
131 pragma Assert
(T
.P
.Last_Allocated
= First
- 1);
132 pragma Assert
(T
.P
.Last
= First
- 1);
137 T
.P
.Last_Allocated
:= First
- 1;
138 T
.P
.Last
:= First
- 1;
146 procedure Grow
(T
: in out Instance
; New_Last
: Table_Count_Type
) is
148 -- Note: Type Alloc_Ptr below needs to be declared locally so we know
149 -- the bounds. That means that the collection is local, so is finalized
150 -- when leaving Grow. That's why this package doesn't support controlled
151 -- types; the table elements would be finalized prematurely. An Ada
152 -- implementation would also be within its rights to reclaim the
153 -- storage. Fortunately, GNAT doesn't do that.
155 pragma Assert
(not T
.Locked
);
156 pragma Assert
(New_Last
> T
.P
.Last_Allocated
);
158 subtype Table_Length_Type
is Table_Index_Type
'Base
159 range 0 .. Table_Index_Type
'Base'Last;
161 Old_Last_Allocated : constant Table_Count_Type := T.P.Last_Allocated;
162 Old_Allocated_Length : constant Table_Length_Type :=
163 Old_Last_Allocated - First + 1;
165 New_Length : constant Table_Length_Type := New_Last - First + 1;
166 New_Allocated_Length : Table_Length_Type;
169 if T.Table = Empty then
170 New_Allocated_Length := Table_Length_Type (Table_Initial);
172 New_Allocated_Length :=
174 (Long_Long_Integer (Old_Allocated_Length) *
175 (100 + Long_Long_Integer (Table_Increment)) / 100);
178 -- Make sure it really did grow
180 if New_Allocated_Length <= Old_Allocated_Length then
181 New_Allocated_Length := Old_Allocated_Length + 10;
184 if New_Allocated_Length <= New_Length then
185 New_Allocated_Length := New_Length + 10;
188 pragma Assert (New_Allocated_Length > Old_Allocated_Length);
189 pragma Assert (New_Allocated_Length > New_Length);
191 T.P.Last_Allocated := First + New_Allocated_Length - 1;
194 subtype Old_Alloc_Type is Table_Type (First .. Old_Last_Allocated);
195 type Old_Alloc_Ptr is access all Old_Alloc_Type;
198 new Ada.Unchecked_Deallocation (Old_Alloc_Type, Old_Alloc_Ptr);
199 function To_Old_Alloc_Ptr is
200 new Ada.Unchecked_Conversion (Table_Ptr, Old_Alloc_Ptr);
202 subtype Alloc_Type is
203 Table_Type (First .. First + New_Allocated_Length - 1);
204 type Alloc_Ptr is access all Alloc_Type;
206 function To_Table_Ptr is
207 new Ada.Unchecked_Conversion (Alloc_Ptr, Table_Ptr);
209 Old_Table : Old_Alloc_Ptr := To_Old_Alloc_Ptr (T.Table);
210 New_Table : constant Alloc_Ptr := new Alloc_Type;
213 if T.Table /= Empty then
214 New_Table (First .. T.P.Last) := Old_Table (First .. T.P.Last);
218 T.Table := To_Table_Ptr (New_Table);
221 pragma Assert (New_Last <= T.P.Last_Allocated);
222 pragma Assert (T.Table /= null);
223 pragma Assert (T.Table /= Empty);
230 procedure Increment_Last (T : in out Instance) is
239 procedure Init (T : in out Instance) is
248 function Last (T : Instance) return Table_Count_Type is
257 procedure Release (T : in out Instance) is
258 pragma Assert (not T.Locked);
259 Old_Last_Allocated : constant Table_Count_Type := T.P.Last_Allocated;
261 if T.P.Last /= T.P.Last_Allocated then
262 pragma Assert (T.P.Last < T.P.Last_Allocated);
263 pragma Assert (T.Table /= Empty);
266 subtype Old_Alloc_Type is Table_Type (First .. Old_Last_Allocated);
267 type Old_Alloc_Ptr is access all Old_Alloc_Type;
270 new Ada.Unchecked_Deallocation (Old_Alloc_Type, Old_Alloc_Ptr);
271 function To_Old_Alloc_Ptr is
272 new Ada.Unchecked_Conversion (Table_Ptr, Old_Alloc_Ptr);
274 subtype Alloc_Type is
275 Table_Type (First .. First + T.P.Last - 1);
276 type Alloc_Ptr is access all Alloc_Type;
278 function To_Table_Ptr is
279 new Ada.Unchecked_Conversion (Alloc_Ptr, Table_Ptr);
281 Old_Table : Old_Alloc_Ptr := To_Old_Alloc_Ptr (T.Table);
282 New_Table : constant Alloc_Ptr := new Alloc_Type'(Old_Table
.all);
284 T
.P
.Last_Allocated
:= T
.P
.Last
;
286 T
.Table
:= To_Table_Ptr
(New_Table
);
290 pragma Assert
(T
.P
.Last
= T
.P
.Last_Allocated
);
298 (T
: in out Instance
;
299 Index
: Valid_Table_Index_Type
;
300 Item
: Table_Component_Type
)
302 Item_Copy
: constant Table_Component_Type
:= Item
;
304 -- If Set_Last is going to reallocate the table, we make a copy of Item,
305 -- in case the call was "Set_Item (T, X, T.Table (Y));", and Item is
306 -- passed by reference. Without the copy, we would deallocate the array
307 -- containing Item, leaving a dangling pointer.
309 if Index
> T
.P
.Last_Allocated
then
311 Item_Copy
: constant Table_Component_Type
:= Item
;
314 T
.Table
(Index
) := Item_Copy
;
320 if Index
> T
.P
.Last
then
324 T
.Table
(Index
) := Item_Copy
;
331 procedure Set_Last
(T
: in out Instance
; New_Val
: Table_Count_Type
) is
332 pragma Assert
(not T
.Locked
);
334 if New_Val
> T
.P
.Last_Allocated
then
345 procedure Sort_Table
(Table
: in out Instance
) is
346 Temp
: Table_Component_Type
;
347 -- A temporary position to simulate index 0
351 function Index_Of
(Idx
: Natural) return Table_Index_Type
'Base;
352 -- Return index of Idx'th element of table
354 function Lower_Than
(Op1
, Op2
: Natural) return Boolean;
355 -- Compare two components
357 procedure Move
(From
: Natural; To
: Natural);
358 -- Move one component
360 package Heap_Sort
is new GNAT
.Heap_Sort_G
(Move
, Lower_Than
);
366 function Index_Of
(Idx
: Natural) return Table_Index_Type
'Base is
367 J
: constant Integer'Base :=
368 Table_Index_Type
'Base'Pos (First) + Idx - 1;
370 return Table_Index_Type'Base'Val
(J
);
377 procedure Move
(From
: Natural; To
: Natural) is
380 Table
.Table
(Index_Of
(To
)) := Temp
;
383 Temp
:= Table
.Table
(Index_Of
(From
));
386 Table
.Table
(Index_Of
(To
)) :=
387 Table
.Table
(Index_Of
(From
));
395 function Lower_Than
(Op1
, Op2
: Natural) return Boolean is
398 return Lt
(Temp
, Table
.Table
(Index_Of
(Op2
)));
401 return Lt
(Table
.Table
(Index_Of
(Op1
)), Temp
);
405 Lt
(Table
.Table
(Index_Of
(Op1
)), Table
.Table
(Index_Of
(Op2
)));
409 -- Start of processing for Sort_Table
412 Heap_Sort
.Sort
(Natural (Last
(Table
) - First
) + 1);
415 end GNAT
.Dynamic_Tables
;