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-2015, 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
37 Growth_Factor
: constant := 2;
38 -- When growing a container, multiply current capacity by this. Doubling
39 -- leads to amortized linear-time copying.
41 type Int
is range System
.Min_Int
.. System
.Max_Int
;
42 type UInt
is mod System
.Max_Binary_Modulus
;
45 new Ada
.Unchecked_Deallocation
(Elements_Array
, Elements_Array_Ptr
);
47 type Maximal_Array_Ptr
is access all Elements_Array
(Array_Index
)
48 with Storage_Size
=> 0;
49 type Maximal_Array_Ptr_Const
is access constant Elements_Array
(Array_Index
)
50 with Storage_Size
=> 0;
52 function Elems
(Container
: in out Vector
) return Maximal_Array_Ptr
;
54 (Container
: Vector
) return Maximal_Array_Ptr_Const
;
55 -- Returns a pointer to the Elements array currently in use -- either
56 -- Container.Elements_Ptr or a pointer to Container.Elements. We work with
57 -- pointers to a bogus array subtype that is constrained with the maximum
58 -- possible bounds. This means that the pointer is a thin pointer. This is
59 -- necessary because 'Unrestricted_Access doesn't work when it produces
60 -- access-to-unconstrained and is returned from a function.
62 -- Note that this is dangerous: make sure calls to this use an indexed
63 -- component or slice that is within the bounds 1 .. Length (Container).
67 Position
: Capacity_Range
) return Element_Type
;
73 function "=" (Left
, Right
: Vector
) return Boolean is
75 if Left
'Address = Right
'Address then
79 if Length
(Left
) /= Length
(Right
) then
83 for J
in 1 .. Length
(Left
) loop
84 if Get_Element
(Left
, J
) /= Get_Element
(Right
, J
) then
96 procedure Append
(Container
: in out Vector
; New_Item
: Vector
) is
98 for X
in First_Index
(New_Item
) .. Last_Index
(New_Item
) loop
99 Append
(Container
, Element
(New_Item
, X
));
104 (Container
: in out Vector
;
105 New_Item
: Element_Type
)
107 New_Length
: constant UInt
:= UInt
(Length
(Container
) + 1);
109 if not Bounded
and then
110 Capacity
(Container
) < Capacity_Range
(New_Length
)
114 Capacity_Range
'Max (Capacity
(Container
) * Growth_Factor
,
115 Capacity_Range
(New_Length
)));
118 if Container
.Last
= Index_Type
'Last then
119 raise Constraint_Error
with "vector is already at its maximum length";
122 -- TODO: should check whether length > max capacity (cnt_t'last) ???
124 Container
.Last
:= Container
.Last
+ 1;
125 Elems
(Container
) (Length
(Container
)) := New_Item
;
132 procedure Assign
(Target
: in out Vector
; Source
: Vector
) is
133 LS
: constant Capacity_Range
:= Length
(Source
);
136 if Target
'Address = Source
'Address then
140 if Bounded
and then Target
.Capacity
< LS
then
141 raise Constraint_Error
;
145 Append
(Target
, Source
);
152 function Capacity
(Container
: Vector
) return Capacity_Range
is
154 return (if Container
.Elements_Ptr
= null
155 then Container
.Elements
'Length
156 else Container
.Elements_Ptr
.all'Length);
163 procedure Clear
(Container
: in out Vector
) is
165 Container
.Last
:= No_Index
;
167 -- Free element, note that this is OK if Elements_Ptr is null
169 Free
(Container
.Elements_Ptr
);
178 Item
: Element_Type
) return Boolean
181 return Find_Index
(Container
, Item
) /= No_Index
;
190 Capacity
: Capacity_Range
:= 0) return Vector
192 LS
: constant Capacity_Range
:= Length
(Source
);
198 elsif Capacity
>= LS
then
201 raise Capacity_Error
;
204 return Target
: Vector
(C
) do
205 Elems
(Target
) (1 .. LS
) := Elemsc
(Source
) (1 .. LS
);
206 Target
.Last
:= Source
.Last
;
210 ---------------------
211 -- Current_To_Last --
212 ---------------------
214 function Current_To_Last
216 Current
: Index_Type
) return Vector
219 return Result
: Vector
(Count_Type
(Container
.Last
- Current
+ 1))
221 for X
in Current
.. Container
.Last
loop
222 Append
(Result
, Element
(Container
, X
));
231 procedure Delete_Last
232 (Container
: in out Vector
)
234 Count
: constant Capacity_Range
:= 1;
238 Index
:= Int
'Base (Container
.Last
) - Int
'Base (Count
);
240 if Index
< Index_Type
'Pos (Index_Type
'First) then
241 Container
.Last
:= No_Index
;
243 Container
.Last
:= Index_Type
(Index
);
253 Index
: Index_Type
) return Element_Type
256 if Index
> Container
.Last
then
257 raise Constraint_Error
with "Index is out of range";
261 II
: constant Int
'Base := Int
(Index
) - Int
(No_Index
);
262 I
: constant Capacity_Range
:= Capacity_Range
(II
);
264 return Get_Element
(Container
, I
);
272 function Elems
(Container
: in out Vector
) return Maximal_Array_Ptr
is
274 return (if Container
.Elements_Ptr
= null
275 then Container
.Elements
'Unrestricted_Access
276 else Container
.Elements_Ptr
.all'Unrestricted_Access);
280 (Container
: Vector
) return Maximal_Array_Ptr_Const
is
282 return (if Container
.Elements_Ptr
= null
283 then Container
.Elements
'Unrestricted_Access
284 else Container
.Elements_Ptr
.all'Unrestricted_Access);
294 Index
: Index_Type
:= Index_Type
'First) return Extended_Index
297 Last
: constant Index_Type
:= Last_Index
(Container
);
300 K
:= Capacity_Range
(Int
(Index
) - Int
(No_Index
));
301 for Indx
in Index
.. Last
loop
302 if Get_Element
(Container
, K
) = Item
then
316 function First_Element
(Container
: Vector
) return Element_Type
is
318 if Is_Empty
(Container
) then
319 raise Constraint_Error
with "Container is empty";
321 return Get_Element
(Container
, 1);
329 function First_Index
(Container
: Vector
) return Index_Type
is
330 pragma Unreferenced
(Container
);
332 return Index_Type
'First;
335 -----------------------
336 -- First_To_Previous --
337 -----------------------
339 function First_To_Previous
341 Current
: Index_Type
) return Vector
344 return Result
: Vector
345 (Count_Type
(Current
- First_Index
(Container
)))
347 for X
in First_Index
(Container
) .. Current
- 1 loop
348 Append
(Result
, Element
(Container
, X
));
351 end First_To_Previous
;
353 ---------------------
354 -- Generic_Sorting --
355 ---------------------
357 package body Generic_Sorting
with SPARK_Mode
=> Off
is
363 function Is_Sorted
(Container
: Vector
) return Boolean is
364 L
: constant Capacity_Range
:= Length
(Container
);
366 for J
in 1 .. L
- 1 loop
367 if Get_Element
(Container
, J
+ 1) <
368 Get_Element
(Container
, J
)
381 procedure Sort
(Container
: in out Vector
)
384 new Generic_Array_Sort
385 (Index_Type
=> Array_Index
,
386 Element_Type
=> Element_Type
,
387 Array_Type
=> Elements_Array
,
390 Len
: constant Capacity_Range
:= Length
(Container
);
392 if Container
.Last
<= Index_Type
'First then
395 Sort
(Elems
(Container
) (1 .. Len
));
407 Position
: Capacity_Range
) return Element_Type
410 return Elemsc
(Container
) (Position
);
418 (Container
: Vector
; Position
: Extended_Index
) return Boolean is
420 return Position
in First_Index
(Container
) .. Last_Index
(Container
);
427 function Is_Empty
(Container
: Vector
) return Boolean is
429 return Last_Index
(Container
) < Index_Type
'First;
436 function Last_Element
(Container
: Vector
) return Element_Type
is
438 if Is_Empty
(Container
) then
439 raise Constraint_Error
with "Container is empty";
441 return Get_Element
(Container
, Length
(Container
));
449 function Last_Index
(Container
: Vector
) return Extended_Index
is
451 return Container
.Last
;
458 function Length
(Container
: Vector
) return Capacity_Range
is
459 L
: constant Int
:= Int
(Last_Index
(Container
));
460 F
: constant Int
:= Int
(Index_Type
'First);
461 N
: constant Int
'Base := L
- F
+ 1;
463 return Capacity_Range
(N
);
466 ---------------------
467 -- Replace_Element --
468 ---------------------
470 procedure Replace_Element
471 (Container
: in out Vector
;
473 New_Item
: Element_Type
)
476 if Index
> Container
.Last
then
477 raise Constraint_Error
with "Index is out of range";
481 II
: constant Int
'Base := Int
(Index
) - Int
(No_Index
);
482 I
: constant Capacity_Range
:= Capacity_Range
(II
);
484 Elems
(Container
) (I
) := New_Item
;
488 ----------------------
489 -- Reserve_Capacity --
490 ----------------------
492 procedure Reserve_Capacity
493 (Container
: in out Vector
;
494 Capacity
: Capacity_Range
)
498 if Capacity
> Container
.Capacity
then
499 raise Constraint_Error
with "Capacity is out of range";
502 if Capacity
> Formal_Vectors
.Capacity
(Container
) then
504 New_Elements
: constant Elements_Array_Ptr
:=
505 new Elements_Array
(1 .. Capacity
);
506 L
: constant Capacity_Range
:= Length
(Container
);
508 New_Elements
(1 .. L
) := Elemsc
(Container
) (1 .. L
);
509 Free
(Container
.Elements_Ptr
);
510 Container
.Elements_Ptr
:= New_Elements
;
514 end Reserve_Capacity
;
516 ----------------------
517 -- Reverse_Elements --
518 ----------------------
520 procedure Reverse_Elements
(Container
: in out Vector
) is
522 if Length
(Container
) <= 1 then
527 I
, J
: Capacity_Range
;
528 E
: Elements_Array
renames
529 Elems
(Container
) (1 .. Length
(Container
));
533 J
:= Length
(Container
);
536 EI
: constant Element_Type
:= E
(I
);
546 end Reverse_Elements
;
548 ------------------------
549 -- Reverse_Find_Index --
550 ------------------------
552 function Reverse_Find_Index
555 Index
: Index_Type
:= Index_Type
'Last) return Extended_Index
557 Last
: Index_Type
'Base;
561 if Index
> Last_Index
(Container
) then
562 Last
:= Last_Index
(Container
);
567 K
:= Capacity_Range
(Int
(Last
) - Int
(No_Index
));
568 for Indx
in reverse Index_Type
'First .. Last
loop
569 if Get_Element
(Container
, K
) = Item
then
577 end Reverse_Find_Index
;
583 procedure Swap
(Container
: in out Vector
; I
, J
: Index_Type
) is
585 if I
> Container
.Last
then
586 raise Constraint_Error
with "I index is out of range";
589 if J
> Container
.Last
then
590 raise Constraint_Error
with "J index is out of range";
598 II
: constant Int
'Base := Int
(I
) - Int
(No_Index
);
599 JJ
: constant Int
'Base := Int
(J
) - Int
(No_Index
);
601 EI
: Element_Type
renames Elems
(Container
) (Capacity_Range
(II
));
602 EJ
: Element_Type
renames Elems
(Container
) (Capacity_Range
(JJ
));
604 EI_Copy
: constant Element_Type
:= EI
;
617 (New_Item
: Element_Type
;
618 Length
: Capacity_Range
) return Vector
626 First
: constant Int
:= Int
(Index_Type
'First);
627 Last_As_Int
: constant Int
'Base := First
+ Int
(Length
) - 1;
631 if Last_As_Int
> Index_Type
'Pos (Index_Type
'Last) then
632 raise Constraint_Error
with "Length is out of range"; -- ???
635 Last
:= Index_Type
(Last_As_Int
);
637 return (Capacity
=> Length
,
640 Elements
=> (others => New_Item
));
644 end Ada
.Containers
.Formal_Vectors
;