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
(Capacity_Range
)
49 with Storage_Size
=> 0;
50 type Maximal_Array_Ptr_Const
is access constant
51 Elements_Array
(Capacity_Range
)
52 with Storage_Size
=> 0;
54 function Elems
(Container
: in out Vector
) return Maximal_Array_Ptr
;
56 (Container
: Vector
) return Maximal_Array_Ptr_Const
;
57 -- Returns a pointer to the Elements array currently in use -- either
58 -- Container.Elements_Ptr or a pointer to Container.Elements. We work with
59 -- pointers to a bogus array subtype that is constrained with the maximum
60 -- possible bounds. This means that the pointer is a thin pointer. This is
61 -- necessary because 'Unrestricted_Access doesn't work when it produces
62 -- access-to-unconstrained and is returned from a function.
66 Position
: Capacity_Range
) return Element_Type
;
72 function "=" (Left
, Right
: Vector
) return Boolean is
74 if Left
'Address = Right
'Address then
78 if Length
(Left
) /= Length
(Right
) then
82 for J
in 1 .. Length
(Left
) loop
83 if Get_Element
(Left
, J
) /= Get_Element
(Right
, J
) then
95 procedure Append
(Container
: in out Vector
; New_Item
: Vector
) is
97 for X
in First_Index
(New_Item
) .. Last_Index
(New_Item
) loop
98 Append
(Container
, Element
(New_Item
, X
));
103 (Container
: in out Vector
;
104 New_Item
: Element_Type
)
106 New_Length
: constant UInt
:= UInt
(Length
(Container
) + 1);
108 if not Bounded
and then
109 Capacity
(Container
) < Capacity_Range
(New_Length
)
113 Capacity_Range
'Max (Capacity
(Container
) * Growth_Factor
,
114 Capacity_Range
(New_Length
)));
117 if Container
.Last
= Index_Type
'Last then
118 raise Constraint_Error
with "vector is already at its maximum length";
121 -- TODO: should check whether length > max capacity (cnt_t'last) ???
123 Container
.Last
:= Container
.Last
+ 1;
124 Elems
(Container
) (Length
(Container
)) := New_Item
;
131 procedure Assign
(Target
: in out Vector
; Source
: Vector
) is
132 LS
: constant Capacity_Range
:= Length
(Source
);
135 if Target
'Address = Source
'Address then
139 if Bounded
and then Target
.Capacity
< LS
then
140 raise Constraint_Error
;
144 Append
(Target
, Source
);
151 function Capacity
(Container
: Vector
) return Capacity_Range
is
153 return (if Container
.Elements_Ptr
= null
154 then Container
.Elements
'Length
155 else Container
.Elements_Ptr
.all'Length);
162 procedure Clear
(Container
: in out Vector
) is
164 Container
.Last
:= No_Index
;
166 -- Free element, note that this is OK if Elements_Ptr is null
168 Free
(Container
.Elements_Ptr
);
177 Item
: Element_Type
) return Boolean
180 return Find_Index
(Container
, Item
) /= No_Index
;
189 Capacity
: Capacity_Range
:= 0) return Vector
191 LS
: constant Capacity_Range
:= Length
(Source
);
197 elsif Capacity
>= LS
then
200 raise Capacity_Error
;
203 return Target
: Vector
(C
) do
204 Elems
(Target
) (1 .. LS
) := Elemsc
(Source
) (1 .. LS
);
205 Target
.Last
:= Source
.Last
;
209 ---------------------
210 -- Current_To_Last --
211 ---------------------
213 function Current_To_Last
215 Current
: Index_Type
) return Vector
218 return Result
: Vector
(Count_Type
(Container
.Last
- Current
+ 1))
220 for X
in Current
.. Container
.Last
loop
221 Append
(Result
, Element
(Container
, X
));
230 procedure Delete_Last
231 (Container
: in out Vector
)
233 Count
: constant Capacity_Range
:= 1;
237 Index
:= Int
'Base (Container
.Last
) - Int
'Base (Count
);
239 if Index
< Index_Type
'Pos (Index_Type
'First) then
240 Container
.Last
:= No_Index
;
242 Container
.Last
:= Index_Type
(Index
);
252 Index
: Index_Type
) return Element_Type
255 if Index
> Container
.Last
then
256 raise Constraint_Error
with "Index is out of range";
260 II
: constant Int
'Base := Int
(Index
) - Int
(No_Index
);
261 I
: constant Capacity_Range
:= Capacity_Range
(II
);
263 return Get_Element
(Container
, I
);
271 function Elems
(Container
: in out Vector
) return Maximal_Array_Ptr
is
273 return (if Container
.Elements_Ptr
= null
274 then Container
.Elements
'Unrestricted_Access
275 else Container
.Elements_Ptr
.all'Unrestricted_Access);
279 (Container
: Vector
) return Maximal_Array_Ptr_Const
is
281 return (if Container
.Elements_Ptr
= null
282 then Container
.Elements
'Unrestricted_Access
283 else Container
.Elements_Ptr
.all'Unrestricted_Access);
293 Index
: Index_Type
:= Index_Type
'First) return Extended_Index
296 Last
: constant Index_Type
:= Last_Index
(Container
);
299 K
:= Capacity_Range
(Int
(Index
) - Int
(No_Index
));
300 for Indx
in Index
.. Last
loop
301 if Get_Element
(Container
, K
) = Item
then
315 function First_Element
(Container
: Vector
) return Element_Type
is
317 if Is_Empty
(Container
) then
318 raise Constraint_Error
with "Container is empty";
320 return Get_Element
(Container
, 1);
328 function First_Index
(Container
: Vector
) return Index_Type
is
329 pragma Unreferenced
(Container
);
331 return Index_Type
'First;
334 -----------------------
335 -- First_To_Previous --
336 -----------------------
338 function First_To_Previous
340 Current
: Index_Type
) return Vector
343 return Result
: Vector
344 (Count_Type
(Current
- First_Index
(Container
)))
346 for X
in First_Index
(Container
) .. Current
- 1 loop
347 Append
(Result
, Element
(Container
, X
));
350 end First_To_Previous
;
352 ---------------------
353 -- Generic_Sorting --
354 ---------------------
356 package body Generic_Sorting
is
362 function Is_Sorted
(Container
: Vector
) return Boolean is
363 L
: constant Capacity_Range
:= Length
(Container
);
365 for J
in 1 .. L
- 1 loop
366 if Get_Element
(Container
, J
+ 1) <
367 Get_Element
(Container
, J
)
380 procedure Sort
(Container
: in out Vector
)
383 new Generic_Array_Sort
384 (Index_Type
=> Capacity_Range
,
385 Element_Type
=> Element_Type
,
386 Array_Type
=> Elements_Array
,
389 Len
: constant Capacity_Range
:= Length
(Container
);
391 if Container
.Last
<= Index_Type
'First then
394 Sort
(Elems
(Container
) (1 .. Len
));
406 Position
: Capacity_Range
) return Element_Type
409 return Elemsc
(Container
) (Position
);
417 (Container
: Vector
; Position
: Extended_Index
) return Boolean is
419 return Position
in First_Index
(Container
) .. Last_Index
(Container
);
426 function Is_Empty
(Container
: Vector
) return Boolean is
428 return Last_Index
(Container
) < Index_Type
'First;
435 function Last_Element
(Container
: Vector
) return Element_Type
is
437 if Is_Empty
(Container
) then
438 raise Constraint_Error
with "Container is empty";
440 return Get_Element
(Container
, Length
(Container
));
448 function Last_Index
(Container
: Vector
) return Extended_Index
is
450 return Container
.Last
;
457 function Length
(Container
: Vector
) return Capacity_Range
is
458 L
: constant Int
:= Int
(Last_Index
(Container
));
459 F
: constant Int
:= Int
(Index_Type
'First);
460 N
: constant Int
'Base := L
- F
+ 1;
462 return Capacity_Range
(N
);
465 ---------------------
466 -- Replace_Element --
467 ---------------------
469 procedure Replace_Element
470 (Container
: in out Vector
;
472 New_Item
: Element_Type
)
475 if Index
> Container
.Last
then
476 raise Constraint_Error
with "Index is out of range";
480 II
: constant Int
'Base := Int
(Index
) - Int
(No_Index
);
481 I
: constant Capacity_Range
:= Capacity_Range
(II
);
483 Elems
(Container
) (I
) := New_Item
;
487 ----------------------
488 -- Reserve_Capacity --
489 ----------------------
491 procedure Reserve_Capacity
492 (Container
: in out Vector
;
493 Capacity
: Capacity_Range
)
497 if Capacity
> Container
.Capacity
then
498 raise Constraint_Error
with "Capacity is out of range";
501 if Capacity
> Formal_Vectors
.Capacity
(Container
) then
503 New_Elements
: constant Elements_Array_Ptr
:=
504 new Elements_Array
(1 .. Capacity
);
505 L
: constant Capacity_Range
:= Length
(Container
);
507 New_Elements
(1 .. L
) := Elemsc
(Container
) (1 .. L
);
508 Free
(Container
.Elements_Ptr
);
509 Container
.Elements_Ptr
:= New_Elements
;
513 end Reserve_Capacity
;
515 ----------------------
516 -- Reverse_Elements --
517 ----------------------
519 procedure Reverse_Elements
(Container
: in out Vector
) is
521 if Length
(Container
) <= 1 then
526 I
, J
: Capacity_Range
;
527 E
: Elements_Array
renames
528 Elems
(Container
) (1 .. Length
(Container
));
532 J
:= Length
(Container
);
535 EI
: constant Element_Type
:= E
(I
);
545 end Reverse_Elements
;
547 ------------------------
548 -- Reverse_Find_Index --
549 ------------------------
551 function Reverse_Find_Index
554 Index
: Index_Type
:= Index_Type
'Last) return Extended_Index
556 Last
: Index_Type
'Base;
560 if Index
> Last_Index
(Container
) then
561 Last
:= Last_Index
(Container
);
566 K
:= Capacity_Range
(Int
(Last
) - Int
(No_Index
));
567 for Indx
in reverse Index_Type
'First .. Last
loop
568 if Get_Element
(Container
, K
) = Item
then
576 end Reverse_Find_Index
;
582 procedure Swap
(Container
: in out Vector
; I
, J
: Index_Type
) is
584 if I
> Container
.Last
then
585 raise Constraint_Error
with "I index is out of range";
588 if J
> Container
.Last
then
589 raise Constraint_Error
with "J index is out of range";
597 II
: constant Int
'Base := Int
(I
) - Int
(No_Index
);
598 JJ
: constant Int
'Base := Int
(J
) - Int
(No_Index
);
600 EI
: Element_Type
renames Elems
(Container
) (Capacity_Range
(II
));
601 EJ
: Element_Type
renames Elems
(Container
) (Capacity_Range
(JJ
));
603 EI_Copy
: constant Element_Type
:= EI
;
616 (New_Item
: Element_Type
;
617 Length
: Capacity_Range
) return Vector
625 First
: constant Int
:= Int
(Index_Type
'First);
626 Last_As_Int
: constant Int
'Base := First
+ Int
(Length
) - 1;
630 if Last_As_Int
> Index_Type
'Pos (Index_Type
'Last) then
631 raise Constraint_Error
with "Length is out of range"; -- ???
634 Last
:= Index_Type
(Last_As_Int
);
636 return (Capacity
=> Length
,
639 Elements
=> (others => New_Item
));
643 end Ada
.Containers
.Formal_Vectors
;