1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . F O R M A L _ V E C T O R S --
9 -- Copyright (C) 2010-2014, 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/>. --
26 ------------------------------------------------------------------------------
28 with Ada
.Containers
.Generic_Array_Sort
;
29 with Ada
.Unchecked_Deallocation
;
31 with System
; use type System
.Address
;
33 package body Ada
.Containers
.Formal_Vectors
with
36 pragma Annotate
(CodePeer
, Skip_Analysis
);
38 Growth_Factor
: constant := 2;
39 -- When growing a container, multiply current capacity by this. Doubling
40 -- leads to amortized linear-time copying.
42 type Int
is range System
.Min_Int
.. System
.Max_Int
;
43 type UInt
is mod System
.Max_Binary_Modulus
;
46 new Ada
.Unchecked_Deallocation
(Elements_Array
, Elements_Array_Ptr
);
48 type Maximal_Array_Ptr
is access all Elements_Array
(Array_Index
)
49 with Storage_Size
=> 0;
50 type Maximal_Array_Ptr_Const
is access constant Elements_Array
(Array_Index
)
51 with Storage_Size
=> 0;
53 function Elems
(Container
: in out Vector
) return Maximal_Array_Ptr
;
55 (Container
: Vector
) return Maximal_Array_Ptr_Const
;
56 -- Returns a pointer to the Elements array currently in use -- either
57 -- Container.Elements_Ptr or a pointer to Container.Elements. We work with
58 -- pointers to a bogus array subtype that is constrained with the maximum
59 -- possible bounds. This means that the pointer is a thin pointer. This is
60 -- necessary because 'Unrestricted_Access doesn't work when it produces
61 -- access-to-unconstrained and is returned from a function.
63 -- Note that this is dangerous: make sure calls to this use an indexed
64 -- component or slice that is within the bounds 1 .. Length (Container).
68 Position
: Capacity_Range
) return Element_Type
;
74 function "=" (Left
, Right
: Vector
) return Boolean is
76 if Left
'Address = Right
'Address then
80 if Length
(Left
) /= Length
(Right
) then
84 for J
in 1 .. Length
(Left
) loop
85 if Get_Element
(Left
, J
) /= Get_Element
(Right
, J
) then
97 procedure Append
(Container
: in out Vector
; New_Item
: Vector
) is
99 for X
in First_Index
(New_Item
) .. Last_Index
(New_Item
) loop
100 Append
(Container
, Element
(New_Item
, X
));
105 (Container
: in out Vector
;
106 New_Item
: Element_Type
)
108 New_Length
: constant UInt
:= UInt
(Length
(Container
) + 1);
110 if not Bounded
and then
111 Capacity
(Container
) < Capacity_Range
(New_Length
)
115 Capacity_Range
'Max (Capacity
(Container
) * Growth_Factor
,
116 Capacity_Range
(New_Length
)));
119 if Container
.Last
= Index_Type
'Last then
120 raise Constraint_Error
with "vector is already at its maximum length";
123 -- TODO: should check whether length > max capacity (cnt_t'last) ???
125 Container
.Last
:= Container
.Last
+ 1;
126 Elems
(Container
) (Length
(Container
)) := New_Item
;
133 procedure Assign
(Target
: in out Vector
; Source
: Vector
) is
134 LS
: constant Capacity_Range
:= Length
(Source
);
137 if Target
'Address = Source
'Address then
141 if Bounded
and then Target
.Capacity
< LS
then
142 raise Constraint_Error
;
146 Append
(Target
, Source
);
153 function Capacity
(Container
: Vector
) return Capacity_Range
is
155 return (if Container
.Elements_Ptr
= null
156 then Container
.Elements
'Length
157 else Container
.Elements_Ptr
.all'Length);
164 procedure Clear
(Container
: in out Vector
) is
166 Container
.Last
:= No_Index
;
168 -- Free element, note that this is OK if Elements_Ptr is null
170 Free
(Container
.Elements_Ptr
);
179 Item
: Element_Type
) return Boolean
182 return Find_Index
(Container
, Item
) /= No_Index
;
191 Capacity
: Capacity_Range
:= 0) return Vector
193 LS
: constant Capacity_Range
:= Length
(Source
);
199 elsif Capacity
>= LS
then
202 raise Capacity_Error
;
205 return Target
: Vector
(C
) do
206 Elems
(Target
) (1 .. LS
) := Elemsc
(Source
) (1 .. LS
);
207 Target
.Last
:= Source
.Last
;
211 ---------------------
212 -- Current_To_Last --
213 ---------------------
215 function Current_To_Last
217 Current
: Index_Type
) return Vector
220 return Result
: Vector
(Count_Type
(Container
.Last
- Current
+ 1))
222 for X
in Current
.. Container
.Last
loop
223 Append
(Result
, Element
(Container
, X
));
232 procedure Delete_Last
233 (Container
: in out Vector
)
235 Count
: constant Capacity_Range
:= 1;
239 Index
:= Int
'Base (Container
.Last
) - Int
'Base (Count
);
241 if Index
< Index_Type
'Pos (Index_Type
'First) then
242 Container
.Last
:= No_Index
;
244 Container
.Last
:= Index_Type
(Index
);
254 Index
: Index_Type
) return Element_Type
257 if Index
> Container
.Last
then
258 raise Constraint_Error
with "Index is out of range";
262 II
: constant Int
'Base := Int
(Index
) - Int
(No_Index
);
263 I
: constant Capacity_Range
:= Capacity_Range
(II
);
265 return Get_Element
(Container
, I
);
273 function Elems
(Container
: in out Vector
) return Maximal_Array_Ptr
is
275 return (if Container
.Elements_Ptr
= null
276 then Container
.Elements
'Unrestricted_Access
277 else Container
.Elements_Ptr
.all'Unrestricted_Access);
281 (Container
: Vector
) return Maximal_Array_Ptr_Const
is
283 return (if Container
.Elements_Ptr
= null
284 then Container
.Elements
'Unrestricted_Access
285 else Container
.Elements_Ptr
.all'Unrestricted_Access);
295 Index
: Index_Type
:= Index_Type
'First) return Extended_Index
298 Last
: constant Index_Type
:= Last_Index
(Container
);
301 K
:= Capacity_Range
(Int
(Index
) - Int
(No_Index
));
302 for Indx
in Index
.. Last
loop
303 if Get_Element
(Container
, K
) = Item
then
317 function First_Element
(Container
: Vector
) return Element_Type
is
319 if Is_Empty
(Container
) then
320 raise Constraint_Error
with "Container is empty";
322 return Get_Element
(Container
, 1);
330 function First_Index
(Container
: Vector
) return Index_Type
is
331 pragma Unreferenced
(Container
);
333 return Index_Type
'First;
336 -----------------------
337 -- First_To_Previous --
338 -----------------------
340 function First_To_Previous
342 Current
: Index_Type
) return Vector
345 return Result
: Vector
346 (Count_Type
(Current
- First_Index
(Container
)))
348 for X
in First_Index
(Container
) .. Current
- 1 loop
349 Append
(Result
, Element
(Container
, X
));
352 end First_To_Previous
;
354 ---------------------
355 -- Generic_Sorting --
356 ---------------------
358 package body Generic_Sorting
is
364 function Is_Sorted
(Container
: Vector
) return Boolean is
365 L
: constant Capacity_Range
:= Length
(Container
);
367 for J
in 1 .. L
- 1 loop
368 if Get_Element
(Container
, J
+ 1) <
369 Get_Element
(Container
, J
)
382 procedure Sort
(Container
: in out Vector
)
385 new Generic_Array_Sort
386 (Index_Type
=> Array_Index
,
387 Element_Type
=> Element_Type
,
388 Array_Type
=> Elements_Array
,
391 Len
: constant Capacity_Range
:= Length
(Container
);
393 if Container
.Last
<= Index_Type
'First then
396 Sort
(Elems
(Container
) (1 .. Len
));
408 Position
: Capacity_Range
) return Element_Type
411 return Elemsc
(Container
) (Position
);
419 (Container
: Vector
; Position
: Extended_Index
) return Boolean is
421 return Position
in First_Index
(Container
) .. Last_Index
(Container
);
428 function Is_Empty
(Container
: Vector
) return Boolean is
430 return Last_Index
(Container
) < Index_Type
'First;
437 function Last_Element
(Container
: Vector
) return Element_Type
is
439 if Is_Empty
(Container
) then
440 raise Constraint_Error
with "Container is empty";
442 return Get_Element
(Container
, Length
(Container
));
450 function Last_Index
(Container
: Vector
) return Extended_Index
is
452 return Container
.Last
;
459 function Length
(Container
: Vector
) return Capacity_Range
is
460 L
: constant Int
:= Int
(Last_Index
(Container
));
461 F
: constant Int
:= Int
(Index_Type
'First);
462 N
: constant Int
'Base := L
- F
+ 1;
464 return Capacity_Range
(N
);
467 ---------------------
468 -- Replace_Element --
469 ---------------------
471 procedure Replace_Element
472 (Container
: in out Vector
;
474 New_Item
: Element_Type
)
477 if Index
> Container
.Last
then
478 raise Constraint_Error
with "Index is out of range";
482 II
: constant Int
'Base := Int
(Index
) - Int
(No_Index
);
483 I
: constant Capacity_Range
:= Capacity_Range
(II
);
485 Elems
(Container
) (I
) := New_Item
;
489 ----------------------
490 -- Reserve_Capacity --
491 ----------------------
493 procedure Reserve_Capacity
494 (Container
: in out Vector
;
495 Capacity
: Capacity_Range
)
499 if Capacity
> Container
.Capacity
then
500 raise Constraint_Error
with "Capacity is out of range";
503 if Capacity
> Formal_Vectors
.Capacity
(Container
) then
505 New_Elements
: constant Elements_Array_Ptr
:=
506 new Elements_Array
(1 .. Capacity
);
507 L
: constant Capacity_Range
:= Length
(Container
);
509 New_Elements
(1 .. L
) := Elemsc
(Container
) (1 .. L
);
510 Free
(Container
.Elements_Ptr
);
511 Container
.Elements_Ptr
:= New_Elements
;
515 end Reserve_Capacity
;
517 ----------------------
518 -- Reverse_Elements --
519 ----------------------
521 procedure Reverse_Elements
(Container
: in out Vector
) is
523 if Length
(Container
) <= 1 then
528 I
, J
: Capacity_Range
;
529 E
: Elements_Array
renames
530 Elems
(Container
) (1 .. Length
(Container
));
534 J
:= Length
(Container
);
537 EI
: constant Element_Type
:= E
(I
);
547 end Reverse_Elements
;
549 ------------------------
550 -- Reverse_Find_Index --
551 ------------------------
553 function Reverse_Find_Index
556 Index
: Index_Type
:= Index_Type
'Last) return Extended_Index
558 Last
: Index_Type
'Base;
562 if Index
> Last_Index
(Container
) then
563 Last
:= Last_Index
(Container
);
568 K
:= Capacity_Range
(Int
(Last
) - Int
(No_Index
));
569 for Indx
in reverse Index_Type
'First .. Last
loop
570 if Get_Element
(Container
, K
) = Item
then
578 end Reverse_Find_Index
;
584 procedure Swap
(Container
: in out Vector
; I
, J
: Index_Type
) is
586 if I
> Container
.Last
then
587 raise Constraint_Error
with "I index is out of range";
590 if J
> Container
.Last
then
591 raise Constraint_Error
with "J index is out of range";
599 II
: constant Int
'Base := Int
(I
) - Int
(No_Index
);
600 JJ
: constant Int
'Base := Int
(J
) - Int
(No_Index
);
602 EI
: Element_Type
renames Elems
(Container
) (Capacity_Range
(II
));
603 EJ
: Element_Type
renames Elems
(Container
) (Capacity_Range
(JJ
));
605 EI_Copy
: constant Element_Type
:= EI
;
618 (New_Item
: Element_Type
;
619 Length
: Capacity_Range
) return Vector
627 First
: constant Int
:= Int
(Index_Type
'First);
628 Last_As_Int
: constant Int
'Base := First
+ Int
(Length
) - 1;
632 if Last_As_Int
> Index_Type
'Pos (Index_Type
'Last) then
633 raise Constraint_Error
with "Length is out of range"; -- ???
636 Last
:= Index_Type
(Last_As_Int
);
638 return (Capacity
=> Length
,
641 Elements
=> (others => New_Item
));
645 end Ada
.Containers
.Formal_Vectors
;