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 Unchecked_Deallocation
;
30 with System
; use type System
.Address
;
32 package body Ada
.Containers
.Formal_Vectors
is
34 Growth_Factor
: constant := 2;
35 -- When growing a container, multiply current capacity by this. Doubling
36 -- leads to amortized linear-time copying.
38 type Int
is range System
.Min_Int
.. System
.Max_Int
;
39 type UInt
is mod System
.Max_Binary_Modulus
;
41 type Elements_Array_Ptr_Const
is access constant Elements_Array
;
44 new Unchecked_Deallocation
(Elements_Array
, Elements_Array_Ptr
);
46 function Elems
(Container
: in out Vector
) return Elements_Array_Ptr
;
48 (Container
: Vector
) return Elements_Array_Ptr_Const
;
49 -- Returns a pointer to the Elements array currently in use -- either
50 -- Container.Elements_Ptr or a pointer to Container.Elements.
54 Position
: Capacity_Range
) return Element_Type
;
60 function "=" (Left
, Right
: Vector
) return Boolean is
62 if Left
'Address = Right
'Address then
66 if Length
(Left
) /= Length
(Right
) then
70 for J
in 1 .. Length
(Left
) loop
71 if Get_Element
(Left
, J
) /= Get_Element
(Right
, J
) then
83 procedure Append
(Container
: in out Vector
; New_Item
: Vector
) is
85 for X
in First_Index
(New_Item
) .. Last_Index
(New_Item
) loop
86 Append
(Container
, Element
(New_Item
, X
));
91 (Container
: in out Vector
;
92 New_Item
: Element_Type
)
94 New_Length
: constant UInt
:= UInt
(Length
(Container
) + 1);
96 if not Bounded
and then
97 Capacity
(Container
) < Capacity_Range
(New_Length
)
101 Capacity_Range
'Max (Capacity
(Container
) * Growth_Factor
,
102 Capacity_Range
(New_Length
)));
105 if Container
.Last
= Index_Type
'Last then
106 raise Constraint_Error
with "vector is already at its maximum length";
109 -- TODO: should check whether length > max capacity (cnt_t'last) ???
111 Container
.Last
:= Container
.Last
+ 1;
112 Elems
(Container
) (Length
(Container
)) := New_Item
;
119 procedure Assign
(Target
: in out Vector
; Source
: Vector
) is
120 LS
: constant Capacity_Range
:= Length
(Source
);
123 if Target
'Address = Source
'Address then
127 if Bounded
and then Target
.Capacity
< LS
then
128 raise Constraint_Error
;
132 Append
(Target
, Source
);
139 function Capacity
(Container
: Vector
) return Capacity_Range
is
141 return Elemsc
(Container
)'Length;
148 procedure Clear
(Container
: in out Vector
) is
150 Container
.Last
:= No_Index
;
151 Free
(Container
.Elements_Ptr
);
152 -- It's OK if Container.Elements_Ptr is null
161 Item
: Element_Type
) return Boolean
164 return Find_Index
(Container
, Item
) /= No_Index
;
173 Capacity
: Capacity_Range
:= 0) return Vector
175 LS
: constant Capacity_Range
:= Length
(Source
);
181 elsif Capacity
>= LS
then
184 raise Capacity_Error
;
187 return Target
: Vector
(C
) do
188 Elems
(Target
) (1 .. LS
) := Elemsc
(Source
) (1 .. LS
);
189 Target
.Last
:= Source
.Last
;
193 ---------------------
194 -- Current_To_Last --
195 ---------------------
197 function Current_To_Last
199 Current
: Index_Type
) return Vector
202 return Result
: Vector
203 (Count_Type
(Container
.Last
- Current
+ 1))
205 for X
in Current
.. Container
.Last
loop
206 Append
(Result
, Element
(Container
, X
));
215 procedure Delete_Last
216 (Container
: in out Vector
)
218 Count
: constant Capacity_Range
:= 1;
222 Index
:= Int
'Base (Container
.Last
) - Int
'Base (Count
);
224 if Index
< Index_Type
'Pos (Index_Type
'First) then
225 Container
.Last
:= No_Index
;
227 Container
.Last
:= Index_Type
(Index
);
237 Index
: Index_Type
) return Element_Type
240 if Index
> Container
.Last
then
241 raise Constraint_Error
with "Index is out of range";
245 II
: constant Int
'Base := Int
(Index
) - Int
(No_Index
);
246 I
: constant Capacity_Range
:= Capacity_Range
(II
);
248 return Get_Element
(Container
, I
);
256 function Elems
(Container
: in out Vector
) return Elements_Array_Ptr
is
258 return (if Container
.Elements_Ptr
= null
259 then Container
.Elements
'Unrestricted_Access
260 else Container
.Elements_Ptr
);
264 (Container
: Vector
) return Elements_Array_Ptr_Const
is
266 return (if Container
.Elements_Ptr
= null
267 then Container
.Elements
'Unrestricted_Access
268 else Elements_Array_Ptr_Const
(Container
.Elements_Ptr
));
278 Index
: Index_Type
:= Index_Type
'First) return Extended_Index
281 Last
: constant Index_Type
:= Last_Index
(Container
);
284 K
:= Capacity_Range
(Int
(Index
) - Int
(No_Index
));
285 for Indx
in Index
.. Last
loop
286 if Get_Element
(Container
, K
) = Item
then
300 function First_Element
(Container
: Vector
) return Element_Type
is
302 if Is_Empty
(Container
) then
303 raise Constraint_Error
with "Container is empty";
306 return Get_Element
(Container
, 1);
313 function First_Index
(Container
: Vector
) return Index_Type
is
314 pragma Unreferenced
(Container
);
316 return Index_Type
'First;
319 -----------------------
320 -- First_To_Previous --
321 -----------------------
323 function First_To_Previous
325 Current
: Index_Type
) return Vector
328 return Result
: Vector
329 (Count_Type
(Current
- First_Index
(Container
)))
331 for X
in First_Index
(Container
) .. Current
- 1 loop
332 Append
(Result
, Element
(Container
, X
));
335 end First_To_Previous
;
337 ---------------------
338 -- Generic_Sorting --
339 ---------------------
341 package body Generic_Sorting
is
347 function Is_Sorted
(Container
: Vector
) return Boolean is
348 Last
: constant Index_Type
:= Last_Index
(Container
);
351 if Container
.Last
<= Last
then
356 L
: constant Capacity_Range
:= Length
(Container
);
358 for J
in 1 .. L
- 1 loop
359 if Get_Element
(Container
, J
+ 1) <
360 Get_Element
(Container
, J
)
374 procedure Sort
(Container
: in out Vector
)
377 new Generic_Array_Sort
378 (Index_Type
=> Capacity_Range
,
379 Element_Type
=> Element_Type
,
380 Array_Type
=> Elements_Array
,
383 Len
: constant Capacity_Range
:= Length
(Container
);
385 if Container
.Last
<= Index_Type
'First then
389 Sort
(Elems
(Container
) (1 .. Len
));
400 Position
: Capacity_Range
) return Element_Type
403 return Elemsc
(Container
) (Position
);
411 (Container
: Vector
; Position
: Extended_Index
) return Boolean is
413 return Position
in First_Index
(Container
) .. Last_Index
(Container
);
420 function Is_Empty
(Container
: Vector
) return Boolean is
422 return Last_Index
(Container
) < Index_Type
'First;
429 function Last_Element
(Container
: Vector
) return Element_Type
is
431 if Is_Empty
(Container
) then
432 raise Constraint_Error
with "Container is empty";
435 return Get_Element
(Container
, Length
(Container
));
442 function Last_Index
(Container
: Vector
) return Extended_Index
is
444 return Container
.Last
;
451 function Length
(Container
: Vector
) return Capacity_Range
is
452 L
: constant Int
:= Int
(Last_Index
(Container
));
453 F
: constant Int
:= Int
(Index_Type
'First);
454 N
: constant Int
'Base := L
- F
+ 1;
457 return Capacity_Range
(N
);
460 ---------------------
461 -- Replace_Element --
462 ---------------------
464 procedure Replace_Element
465 (Container
: in out Vector
;
467 New_Item
: Element_Type
)
470 if Index
> Container
.Last
then
471 raise Constraint_Error
with "Index is out of range";
475 II
: constant Int
'Base := Int
(Index
) - Int
(No_Index
);
476 I
: constant Capacity_Range
:= Capacity_Range
(II
);
479 Elems
(Container
) (I
) := New_Item
;
483 ----------------------
484 -- Reserve_Capacity --
485 ----------------------
487 procedure Reserve_Capacity
488 (Container
: in out Vector
;
489 Capacity
: Capacity_Range
)
493 if Capacity
> Container
.Capacity
then
494 raise Constraint_Error
with "Capacity is out of range";
497 if Capacity
> Formal_Vectors
.Capacity
(Container
) then
499 New_Elements
: constant Elements_Array_Ptr
:=
500 new Elements_Array
(1 .. Capacity
);
501 L
: constant Capacity_Range
:= Length
(Container
);
503 New_Elements
(1 .. L
) := Elemsc
(Container
) (1 .. L
);
504 Free
(Container
.Elements_Ptr
);
505 Container
.Elements_Ptr
:= New_Elements
;
509 end Reserve_Capacity
;
511 ----------------------
512 -- Reverse_Elements --
513 ----------------------
515 procedure Reverse_Elements
(Container
: in out Vector
) is
517 if Length
(Container
) <= 1 then
522 I
, J
: Capacity_Range
;
523 E
: Elements_Array
renames Elems
(Container
).all;
527 J
:= Length
(Container
);
530 EI
: constant Element_Type
:= E
(I
);
540 end Reverse_Elements
;
542 ------------------------
543 -- Reverse_Find_Index --
544 ------------------------
546 function Reverse_Find_Index
549 Index
: Index_Type
:= Index_Type
'Last) return Extended_Index
551 Last
: Index_Type
'Base;
555 if Index
> Last_Index
(Container
) then
556 Last
:= Last_Index
(Container
);
561 K
:= Capacity_Range
(Int
(Last
) - Int
(No_Index
));
562 for Indx
in reverse Index_Type
'First .. Last
loop
563 if Get_Element
(Container
, K
) = Item
then
571 end Reverse_Find_Index
;
577 procedure Swap
(Container
: in out Vector
; I
, J
: Index_Type
) is
579 if I
> Container
.Last
then
580 raise Constraint_Error
with "I index is out of range";
583 if J
> Container
.Last
then
584 raise Constraint_Error
with "J index is out of range";
592 II
: constant Int
'Base := Int
(I
) - Int
(No_Index
);
593 JJ
: constant Int
'Base := Int
(J
) - Int
(No_Index
);
595 EI
: Element_Type
renames Elems
(Container
) (Capacity_Range
(II
));
596 EJ
: Element_Type
renames Elems
(Container
) (Capacity_Range
(JJ
));
598 EI_Copy
: constant Element_Type
:= EI
;
611 (New_Item
: Element_Type
;
612 Length
: Capacity_Range
) return Vector
620 First
: constant Int
:= Int
(Index_Type
'First);
621 Last_As_Int
: constant Int
'Base := First
+ Int
(Length
) - 1;
625 if Last_As_Int
> Index_Type
'Pos (Index_Type
'Last) then
626 raise Constraint_Error
with "Length is out of range"; -- ???
629 Last
:= Index_Type
(Last_As_Int
);
631 return (Length
, (others => New_Item
), Last
=> Last
,
636 end Ada
.Containers
.Formal_Vectors
;