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 _ H A S H E D _ S E T S --
9 -- Copyright (C) 2004-2017, Free Software Foundation, Inc. --
11 -- This specification is derived from the Ada Reference Manual for use with --
12 -- GNAT. The copyright notice above, and the license provisions that follow --
13 -- apply solely to the contents of the part following the private keyword. --
15 -- GNAT is free software; you can redistribute it and/or modify it under --
16 -- terms of the GNU General Public License as published by the Free Soft- --
17 -- ware Foundation; either version 3, or (at your option) any later ver- --
18 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
19 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
20 -- or FITNESS FOR A PARTICULAR PURPOSE. --
22 -- As a special exception under Section 7 of GPL version 3, you are granted --
23 -- additional permissions described in the GCC Runtime Library Exception, --
24 -- version 3.1, as published by the Free Software Foundation. --
26 -- You should have received a copy of the GNU General Public License and --
27 -- a copy of the GCC Runtime Library Exception along with this program; --
28 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
29 -- <http://www.gnu.org/licenses/>. --
30 ------------------------------------------------------------------------------
32 -- This spec is derived from package Ada.Containers.Bounded_Hashed_Sets in the
33 -- Ada 2012 RM. The modifications are meant to facilitate formal proofs by
34 -- making it easier to express properties, and by making the specification of
35 -- this unit compatible with SPARK 2014. Note that the API of this unit may be
36 -- subject to incompatible changes as SPARK 2014 evolves.
38 -- The modifications are:
40 -- A parameter for the container is added to every function reading the
41 -- content of a container: Element, Next, Query_Element, Has_Element, Key,
42 -- Iterate, Equivalent_Elements. This change is motivated by the need to
43 -- have cursors which are valid on different containers (typically a
44 -- container C and its previous version C'Old) for expressing properties,
45 -- which is not possible if cursors encapsulate an access to the underlying
48 with Ada
.Containers
.Functional_Maps
;
49 with Ada
.Containers
.Functional_Sets
;
50 with Ada
.Containers
.Functional_Vectors
;
51 private with Ada
.Containers
.Hash_Tables
;
54 type Element_Type
is private;
56 with function Hash
(Element
: Element_Type
) return Hash_Type
;
58 with function Equivalent_Elements
60 Right
: Element_Type
) return Boolean is "=";
62 package Ada
.Containers
.Formal_Hashed_Sets
with
65 pragma Annotate
(CodePeer
, Skip_Analysis
);
67 type Set
(Capacity
: Count_Type
; Modulus
: Hash_Type
) is private with
68 Iterable
=> (First
=> First
,
70 Has_Element
=> Has_Element
,
72 Default_Initial_Condition
=> Is_Empty
(Set
);
73 pragma Preelaborable_Initialization
(Set
);
79 No_Element
: constant Cursor
:= (Node
=> 0);
81 function Length
(Container
: Set
) return Count_Type
with
83 Post
=> Length
'Result <= Container
.Capacity
;
85 pragma Unevaluated_Use_Of_Old
(Allow
);
87 package Formal_Model
with Ghost
is
88 subtype Positive_Count_Type
is Count_Type
range 1 .. Count_Type
'Last;
90 package M
is new Ada
.Containers
.Functional_Sets
91 (Element_Type
=> Element_Type
,
92 Equivalent_Elements
=> Equivalent_Elements
);
96 Right
: M
.Set
) return Boolean renames M
."=";
100 Right
: M
.Set
) return Boolean renames M
."<=";
102 package E
is new Ada
.Containers
.Functional_Vectors
103 (Element_Type
=> Element_Type
,
104 Index_Type
=> Positive_Count_Type
);
108 Right
: E
.Sequence
) return Boolean renames E
."=";
112 Right
: E
.Sequence
) return Boolean renames E
."<";
116 Right
: E
.Sequence
) return Boolean renames E
."<=";
119 (Container
: E
.Sequence
;
120 Item
: Element_Type
) return Count_Type
121 -- Search for Item in Container
126 (if Find
'Result > 0 then
127 Find
'Result <= E
.Length
(Container
)
128 and Equivalent_Elements
129 (Item
, E
.Get
(Container
, Find
'Result)));
131 function E_Elements_Included
133 Right
: E
.Sequence
) return Boolean
134 -- The elements of Left are contained in Right
139 E_Elements_Included
'Result =
140 (for all I
in 1 .. E
.Length
(Left
) =>
141 Find
(Right
, E
.Get
(Left
, I
)) > 0
142 and then E
.Get
(Right
, Find
(Right
, E
.Get
(Left
, I
))) =
144 pragma Annotate
(GNATprove
, Inline_For_Proof
, E_Elements_Included
);
146 function E_Elements_Included
149 Right
: E
.Sequence
) return Boolean
150 -- The elements of Container contained in Model are in Right
155 E_Elements_Included
'Result =
156 (for all I
in 1 .. E
.Length
(Left
) =>
157 (if M
.Contains
(Model
, E
.Get
(Left
, I
)) then
158 Find
(Right
, E
.Get
(Left
, I
)) > 0
159 and then E
.Get
(Right
, Find
(Right
, E
.Get
(Left
, I
))) =
161 pragma Annotate
(GNATprove
, Inline_For_Proof
, E_Elements_Included
);
163 function E_Elements_Included
164 (Container
: E
.Sequence
;
167 Right
: E
.Sequence
) return Boolean
168 -- The elements of Container contained in Model are in Left and others
174 E_Elements_Included
'Result =
175 (for all I
in 1 .. E
.Length
(Container
) =>
176 (if M
.Contains
(Model
, E
.Get
(Container
, I
)) then
177 Find
(Left
, E
.Get
(Container
, I
)) > 0
178 and then E
.Get
(Left
, Find
(Left
, E
.Get
(Container
, I
))) =
181 Find
(Right
, E
.Get
(Container
, I
)) > 0
183 (Right
, Find
(Right
, E
.Get
(Container
, I
))) =
184 E
.Get
(Container
, I
)));
185 pragma Annotate
(GNATprove
, Inline_For_Proof
, E_Elements_Included
);
187 package P
is new Ada
.Containers
.Functional_Maps
189 Element_Type
=> Positive_Count_Type
,
190 Equivalent_Keys
=> "=",
191 Enable_Handling_Of_Equivalence
=> False);
195 Right
: P
.Map
) return Boolean renames P
."=";
199 Right
: P
.Map
) return Boolean renames P
."<=";
201 function Mapping_Preserved
202 (E_Left
: E
.Sequence
;
203 E_Right
: E
.Sequence
;
205 P_Right
: P
.Map
) return Boolean
210 (if Mapping_Preserved
'Result then
212 -- Right contains all the cursors of Left
214 P
.Keys_Included
(P_Left
, P_Right
)
216 -- Right contains all the elements of Left
218 and E_Elements_Included
(E_Left
, E_Right
)
220 -- Mappings from cursors to elements induced by E_Left, P_Left
221 -- and E_Right, P_Right are the same.
223 and (for all C
of P_Left
=>
224 E
.Get
(E_Left
, P
.Get
(P_Left
, C
)) =
225 E
.Get
(E_Right
, P
.Get
(P_Right
, C
))));
227 function Mapping_Preserved_Except
228 (E_Left
: E
.Sequence
;
229 E_Right
: E
.Sequence
;
232 Position
: Cursor
) return Boolean
237 (if Mapping_Preserved_Except
'Result then
239 -- Right contains all the cursors of Left
241 P
.Keys_Included
(P_Left
, P_Right
)
243 -- Mappings from cursors to elements induced by E_Left, P_Left
244 -- and E_Right, P_Right are the same except for Position.
246 and (for all C
of P_Left
=>
247 (if C
/= Position
then
248 E
.Get
(E_Left
, P
.Get
(P_Left
, C
)) =
249 E
.Get
(E_Right
, P
.Get
(P_Right
, C
)))));
251 function Model
(Container
: Set
) return M
.Set
with
252 -- The high-level model of a set is a set of elements. Neither cursors
253 -- nor order of elements are represented in this model. Elements are
254 -- modeled up to equivalence.
258 Post
=> M
.Length
(Model
'Result) = Length
(Container
);
260 function Elements
(Container
: Set
) return E
.Sequence
with
261 -- The Elements sequence represents the underlying list structure of
262 -- sets that is used for iteration. It stores the actual values of
263 -- elements in the set. It does not model cursors.
268 E
.Length
(Elements
'Result) = Length
(Container
)
270 -- It only contains keys contained in Model
272 and (for all Item
of Elements
'Result =>
273 M
.Contains
(Model
(Container
), Item
))
275 -- It contains all the elements contained in Model
277 and (for all Item
of Model
(Container
) =>
278 (Find
(Elements
'Result, Item
) > 0
279 and then Equivalent_Elements
280 (E
.Get
(Elements
'Result,
281 Find
(Elements
'Result, Item
)),
284 -- It has no duplicate
286 and (for all I
in 1 .. Length
(Container
) =>
287 Find
(Elements
'Result, E
.Get
(Elements
'Result, I
)) = I
)
289 and (for all I
in 1 .. Length
(Container
) =>
290 (for all J
in 1 .. Length
(Container
) =>
291 (if Equivalent_Elements
292 (E
.Get
(Elements
'Result, I
),
293 E
.Get
(Elements
'Result, J
))
295 pragma Annotate
(GNATprove
, Iterable_For_Proof
, "Model", Elements
);
297 function Positions
(Container
: Set
) return P
.Map
with
298 -- The Positions map is used to model cursors. It only contains valid
299 -- cursors and maps them to their position in the container.
304 not P
.Has_Key
(Positions
'Result, No_Element
)
306 -- Positions of cursors are smaller than the container's length
309 (for all I
of Positions
'Result =>
310 P
.Get
(Positions
'Result, I
) in 1 .. Length
(Container
)
312 -- No two cursors have the same position. Note that we do not
313 -- state that there is a cursor in the map for each position, as
314 -- it is rarely needed.
317 (for all J
of Positions
'Result =>
318 (if P
.Get
(Positions
'Result, I
) = P
.Get
(Positions
'Result, J
)
321 procedure Lift_Abstraction_Level
(Container
: Set
) with
322 -- Lift_Abstraction_Level is a ghost procedure that does nothing but
323 -- assume that we can access the same elements by iterating over
324 -- positions or cursors.
325 -- This information is not generally useful except when switching from
326 -- a low-level, cursor-aware view of a container, to a high-level,
327 -- position-based view.
332 (for all Item
of Elements
(Container
) =>
333 (for some I
of Positions
(Container
) =>
334 E
.Get
(Elements
(Container
), P
.Get
(Positions
(Container
), I
)) =
339 K
: Element_Type
) return Boolean renames M
.Contains
;
340 -- To improve readability of contracts, we rename the function used to
341 -- search for an element in the model to Contains.
346 Empty_Set
: constant Set
;
348 function "=" (Left
, Right
: Set
) return Boolean with
352 (Length (Left) = Length (Right)
353 and E_Elements_Included (Elements (Left), Elements (Right)))
356 (E_Elements_Included
(Elements
(Left
), Elements
(Right
))
357 and E_Elements_Included
(Elements
(Right
), Elements
(Left
)));
359 function Equivalent_Sets
(Left
, Right
: Set
) return Boolean with
361 Post
=> Equivalent_Sets
'Result = (Model
(Left
) = Model
(Right
));
363 function To_Set
(New_Item
: Element_Type
) return Set
with
366 M
.Is_Singleton
(Model
(To_Set
'Result), New_Item
)
367 and Length
(To_Set
'Result) = 1
368 and E
.Get
(Elements
(To_Set
'Result), 1) = New_Item
;
370 function Capacity
(Container
: Set
) return Count_Type
with
372 Post
=> Capacity
'Result = Container
.Capacity
;
374 procedure Reserve_Capacity
375 (Container
: in out Set
;
376 Capacity
: Count_Type
)
379 Pre
=> Capacity
<= Container
.Capacity
,
381 Model
(Container
) = Model
(Container
)'Old
382 and Length
(Container
)'Old = Length
(Container
)
384 -- Actual elements are preserved
386 and E_Elements_Included
387 (Elements
(Container
), Elements
(Container
)'Old)
388 and E_Elements_Included
389 (Elements
(Container
)'Old, Elements
(Container
));
391 function Is_Empty
(Container
: Set
) return Boolean with
393 Post
=> Is_Empty
'Result = (Length
(Container
) = 0);
395 procedure Clear
(Container
: in out Set
) with
397 Post
=> Length
(Container
) = 0 and M
.Is_Empty
(Model
(Container
));
399 procedure Assign
(Target
: in out Set
; Source
: Set
) with
401 Pre
=> Target
.Capacity
>= Length
(Source
),
403 Model
(Target
) = Model
(Source
)
404 and Length
(Target
) = Length
(Source
)
406 -- Actual elements are preserved
408 and E_Elements_Included
(Elements
(Target
), Elements
(Source
))
409 and E_Elements_Included
(Elements
(Source
), Elements
(Target
));
413 Capacity
: Count_Type
:= 0) return Set
416 Pre
=> Capacity
= 0 or else Capacity
>= Source
.Capacity
,
418 Model
(Copy
'Result) = Model
(Source
)
419 and Elements
(Copy
'Result) = Elements
(Source
)
420 and Positions
(Copy
'Result) = Positions
(Source
)
421 and (if Capacity
= 0 then
422 Copy
'Result.Capacity
= Source
.Capacity
424 Copy
'Result.Capacity
= Capacity
);
428 Position
: Cursor
) return Element_Type
431 Pre
=> Has_Element
(Container
, Position
),
434 E
.Get
(Elements
(Container
), P
.Get
(Positions
(Container
), Position
));
435 pragma Annotate
(GNATprove
, Inline_For_Proof
, Element
);
437 procedure Replace_Element
438 (Container
: in out Set
;
440 New_Item
: Element_Type
)
443 Pre
=> Has_Element
(Container
, Position
),
445 Length
(Container
) = Length
(Container
)'Old
447 -- Position now maps to New_Item
449 and Element
(Container
, Position
) = New_Item
451 -- New_Item is contained in Container
453 and Contains
(Model
(Container
), New_Item
)
455 -- Other elements are preserved
457 and M
.Included_Except
458 (Model
(Container
)'Old,
460 Element
(Container
, Position
)'Old)
461 and M
.Included_Except
463 Model
(Container
)'Old,
466 -- Mapping from cursors to elements is preserved
468 and Mapping_Preserved_Except
469 (E_Left
=> Elements
(Container
)'Old,
470 E_Right
=> Elements
(Container
),
471 P_Left
=> Positions
(Container
)'Old,
472 P_Right
=> Positions
(Container
),
473 Position
=> Position
)
474 and Positions
(Container
) = Positions
(Container
)'Old;
476 procedure Move
(Target
: in out Set
; Source
: in out Set
) with
478 Pre
=> Target
.Capacity
>= Length
(Source
),
481 and Model
(Target
) = Model
(Source
)'Old
482 and Length
(Target
) = Length
(Source
)'Old
484 -- Actual elements are preserved
486 and E_Elements_Included
(Elements
(Target
), Elements
(Source
)'Old)
487 and E_Elements_Included
(Elements
(Source
)'Old, Elements
(Target
));
490 (Container
: in out Set
;
491 New_Item
: Element_Type
;
492 Position
: out Cursor
;
493 Inserted
: out Boolean)
497 Length
(Container
) < Container
.Capacity
498 or Contains
(Container
, New_Item
),
500 Contains
(Container
, New_Item
)
501 and Has_Element
(Container
, Position
)
502 and Equivalent_Elements
(Element
(Container
, Position
), New_Item
),
505 -- If New_Item is already in Container, it is not modified and Inserted
508 (Contains
(Container
, New_Item
) =>
510 and Model
(Container
) = Model
(Container
)'Old
511 and Elements
(Container
) = Elements
(Container
)'Old
512 and Positions
(Container
) = Positions
(Container
)'Old,
514 -- Otherwise, New_Item is inserted in Container and Inserted is set to
519 and Length
(Container
) = Length
(Container
)'Old + 1
521 -- Position now maps to New_Item
523 and Element
(Container
, Position
) = New_Item
525 -- Other elements are preserved
527 and Model
(Container
)'Old <= Model
(Container
)
528 and M
.Included_Except
530 Model
(Container
)'Old,
533 -- Mapping from cursors to elements is preserved
535 and Mapping_Preserved
536 (E_Left
=> Elements
(Container
)'Old,
537 E_Right
=> Elements
(Container
),
538 P_Left
=> Positions
(Container
)'Old,
539 P_Right
=> Positions
(Container
))
540 and P
.Keys_Included_Except
541 (Positions
(Container
),
542 Positions
(Container
)'Old,
545 procedure Insert
(Container
: in out Set
; New_Item
: Element_Type
) with
547 Pre
=> Length
(Container
) < Container
.Capacity
548 and then (not Contains
(Container
, New_Item
)),
550 Length
(Container
) = Length
(Container
)'Old + 1
551 and Contains
(Container
, New_Item
)
552 and Element
(Container
, Find
(Container
, New_Item
)) = New_Item
554 -- Other elements are preserved
556 and Model
(Container
)'Old <= Model
(Container
)
557 and M
.Included_Except
559 Model
(Container
)'Old,
562 -- Mapping from cursors to elements is preserved
564 and Mapping_Preserved
565 (E_Left
=> Elements
(Container
)'Old,
566 E_Right
=> Elements
(Container
),
567 P_Left
=> Positions
(Container
)'Old,
568 P_Right
=> Positions
(Container
))
569 and P
.Keys_Included_Except
570 (Positions
(Container
),
571 Positions
(Container
)'Old,
572 Find
(Container
, New_Item
));
574 procedure Include
(Container
: in out Set
; New_Item
: Element_Type
) with
577 Length
(Container
) < Container
.Capacity
578 or Contains
(Container
, New_Item
),
580 Contains
(Container
, New_Item
)
581 and Element
(Container
, Find
(Container
, New_Item
)) = New_Item
,
584 -- If an element equivalent to New_Item is already in Container, it is
585 -- replaced by New_Item.
587 (Contains
(Container
, New_Item
) =>
589 -- Elements are preserved modulo equivalence
591 Model
(Container
) = Model
(Container
)'Old
593 -- Cursors are preserved
595 and Positions
(Container
) = Positions
(Container
)'Old
597 -- The actual value of other elements is preserved
600 (Elements
(Container
)'Old,
601 Elements
(Container
),
602 P
.Get
(Positions
(Container
), Find
(Container
, New_Item
))),
604 -- Otherwise, New_Item is inserted in Container
607 Length
(Container
) = Length
(Container
)'Old + 1
609 -- Other elements are preserved
611 and Model
(Container
)'Old <= Model
(Container
)
612 and M
.Included_Except
614 Model
(Container
)'Old,
617 -- Mapping from cursors to elements is preserved
619 and Mapping_Preserved
620 (E_Left
=> Elements
(Container
)'Old,
621 E_Right
=> Elements
(Container
),
622 P_Left
=> Positions
(Container
)'Old,
623 P_Right
=> Positions
(Container
))
624 and P
.Keys_Included_Except
625 (Positions
(Container
),
626 Positions
(Container
)'Old,
627 Find
(Container
, New_Item
)));
629 procedure Replace
(Container
: in out Set
; New_Item
: Element_Type
) with
631 Pre
=> Contains
(Container
, New_Item
),
634 -- Elements are preserved modulo equivalence
636 Model
(Container
) = Model
(Container
)'Old
637 and Contains
(Container
, New_Item
)
639 -- Cursors are preserved
641 and Positions
(Container
) = Positions
(Container
)'Old
643 -- The element equivalent to New_Item in Container is replaced by
646 and Element
(Container
, Find
(Container
, New_Item
)) = New_Item
648 (Elements
(Container
)'Old,
649 Elements
(Container
),
650 P
.Get
(Positions
(Container
), Find
(Container
, New_Item
)));
652 procedure Exclude
(Container
: in out Set
; Item
: Element_Type
) with
654 Post
=> not Contains
(Container
, Item
),
657 -- If Item is not in Container, nothing is changed
659 (not Contains
(Container
, Item
) =>
660 Model
(Container
) = Model
(Container
)'Old
661 and Elements
(Container
) = Elements
(Container
)'Old
662 and Positions
(Container
) = Positions
(Container
)'Old,
664 -- Otherwise, Item is removed from Container
667 Length
(Container
) = Length
(Container
)'Old - 1
669 -- Other elements are preserved
671 and Model
(Container
) <= Model
(Container
)'Old
672 and M
.Included_Except
673 (Model
(Container
)'Old,
677 -- Mapping from cursors to elements is preserved
679 and Mapping_Preserved
680 (E_Left
=> Elements
(Container
),
681 E_Right
=> Elements
(Container
)'Old,
682 P_Left
=> Positions
(Container
),
683 P_Right
=> Positions
(Container
)'Old)
684 and P
.Keys_Included_Except
685 (Positions
(Container
)'Old,
686 Positions
(Container
),
687 Find
(Container
, Item
)'Old));
689 procedure Delete
(Container
: in out Set
; Item
: Element_Type
) with
691 Pre
=> Contains
(Container
, Item
),
693 Length
(Container
) = Length
(Container
)'Old - 1
695 -- Item is no longer in Container
697 and not Contains
(Container
, Item
)
699 -- Other elements are preserved
701 and Model
(Container
) <= Model
(Container
)'Old
702 and M
.Included_Except
703 (Model
(Container
)'Old,
707 -- Mapping from cursors to elements is preserved
709 and Mapping_Preserved
710 (E_Left
=> Elements
(Container
),
711 E_Right
=> Elements
(Container
)'Old,
712 P_Left
=> Positions
(Container
),
713 P_Right
=> Positions
(Container
)'Old)
714 and P
.Keys_Included_Except
715 (Positions
(Container
)'Old,
716 Positions
(Container
),
717 Find
(Container
, Item
)'Old);
719 procedure Delete
(Container
: in out Set
; Position
: in out Cursor
) with
721 Pre
=> Has_Element
(Container
, Position
),
723 Position
= No_Element
724 and Length
(Container
) = Length
(Container
)'Old - 1
726 -- The element at position Position is no longer in Container
728 and not Contains
(Container
, Element
(Container
, Position
)'Old)
729 and not P
.Has_Key
(Positions
(Container
), Position
'Old)
731 -- Other elements are preserved
733 and Model
(Container
) <= Model
(Container
)'Old
734 and M
.Included_Except
735 (Model
(Container
)'Old,
737 Element
(Container
, Position
)'Old)
739 -- Mapping from cursors to elements is preserved
741 and Mapping_Preserved
742 (E_Left
=> Elements
(Container
),
743 E_Right
=> Elements
(Container
)'Old,
744 P_Left
=> Positions
(Container
),
745 P_Right
=> Positions
(Container
)'Old)
746 and P
.Keys_Included_Except
747 (Positions
(Container
)'Old,
748 Positions
(Container
),
751 procedure Union
(Target
: in out Set
; Source
: Set
) with
754 Length
(Source
) - Length
(Target
and Source
) <=
755 Target
.Capacity
- Length
(Target
),
757 Length
(Target
) = Length
(Target
)'Old
758 - M
.Num_Overlaps
(Model
(Target
)'Old, Model
(Source
))
761 -- Elements already in Target are still in Target
763 and Model
(Target
)'Old <= Model
(Target
)
765 -- Elements of Source are included in Target
767 and Model
(Source
) <= Model
(Target
)
769 -- Elements of Target come from either Source or Target
771 and M
.Included_In_Union
772 (Model
(Target
), Model
(Source
), Model
(Target
)'Old)
774 -- Actual value of elements come from either Left or Right
776 and E_Elements_Included
779 Elements
(Target
)'Old,
782 and E_Elements_Included
783 (Elements
(Target
)'Old, Model
(Target
)'Old, Elements
(Target
))
785 and E_Elements_Included
791 -- Mapping from cursors of Target to elements is preserved
793 and Mapping_Preserved
794 (E_Left
=> Elements
(Target
)'Old,
795 E_Right
=> Elements
(Target
),
796 P_Left
=> Positions
(Target
)'Old,
797 P_Right
=> Positions
(Target
));
799 function Union
(Left
, Right
: Set
) return Set
with
801 Pre
=> Length
(Left
) <= Count_Type
'Last - Length
(Right
),
803 Length
(Union
'Result) = Length
(Left
)
804 - M
.Num_Overlaps
(Model
(Left
), Model
(Right
))
807 -- Elements of Left and Right are in the result of Union
809 and Model
(Left
) <= Model
(Union
'Result)
810 and Model
(Right
) <= Model
(Union
'Result)
812 -- Elements of the result of union come from either Left or Right
816 (Model
(Union
'Result), Model
(Left
), Model
(Right
))
818 -- Actual value of elements come from either Left or Right
820 and E_Elements_Included
821 (Elements
(Union
'Result),
826 and E_Elements_Included
827 (Elements
(Left
), Model
(Left
), Elements
(Union
'Result))
829 and E_Elements_Included
833 Elements
(Union
'Result));
835 function "or" (Left
, Right
: Set
) return Set
renames Union
;
837 procedure Intersection
(Target
: in out Set
; Source
: Set
) with
841 M
.Num_Overlaps
(Model
(Target
)'Old, Model
(Source
))
843 -- Elements of Target were already in Target
845 and Model
(Target
) <= Model
(Target
)'Old
847 -- Elements of Target are in Source
849 and Model
(Target
) <= Model
(Source
)
851 -- Elements both in Source and Target are in the intersection
853 and M
.Includes_Intersection
854 (Model
(Target
), Model
(Source
), Model
(Target
)'Old)
856 -- Actual value of elements of Target is preserved
858 and E_Elements_Included
(Elements
(Target
), Elements
(Target
)'Old)
859 and E_Elements_Included
860 (Elements
(Target
)'Old, Model
(Source
), Elements
(Target
))
862 -- Mapping from cursors of Target to elements is preserved
864 and Mapping_Preserved
865 (E_Left
=> Elements
(Target
),
866 E_Right
=> Elements
(Target
)'Old,
867 P_Left
=> Positions
(Target
),
868 P_Right
=> Positions
(Target
)'Old);
870 function Intersection
(Left
, Right
: Set
) return Set
with
873 Length
(Intersection
'Result) =
874 M
.Num_Overlaps
(Model
(Left
), Model
(Right
))
876 -- Elements in the result of Intersection are in Left and Right
878 and Model
(Intersection
'Result) <= Model
(Left
)
879 and Model
(Intersection
'Result) <= Model
(Right
)
881 -- Elements both in Left and Right are in the result of Intersection
883 and M
.Includes_Intersection
884 (Model
(Intersection
'Result), Model
(Left
), Model
(Right
))
886 -- Actual value of elements come from Left
888 and E_Elements_Included
889 (Elements
(Intersection
'Result), Elements
(Left
))
891 and E_Elements_Included
892 (Elements
(Left
), Model
(Right
),
893 Elements
(Intersection
'Result));
895 function "and" (Left
, Right
: Set
) return Set
renames Intersection
;
897 procedure Difference
(Target
: in out Set
; Source
: Set
) with
900 Length
(Target
) = Length
(Target
)'Old -
901 M
.Num_Overlaps
(Model
(Target
)'Old, Model
(Source
))
903 -- Elements of Target were already in Target
905 and Model
(Target
) <= Model
(Target
)'Old
907 -- Elements of Target are not in Source
909 and M
.No_Overlap
(Model
(Target
), Model
(Source
))
911 -- Elements in Target but not in Source are in the difference
913 and M
.Included_In_Union
914 (Model
(Target
)'Old, Model
(Target
), Model
(Source
))
916 -- Actual value of elements of Target is preserved
918 and E_Elements_Included
(Elements
(Target
), Elements
(Target
)'Old)
919 and E_Elements_Included
920 (Elements
(Target
)'Old, Model
(Target
), Elements
(Target
))
922 -- Mapping from cursors of Target to elements is preserved
924 and Mapping_Preserved
925 (E_Left
=> Elements
(Target
),
926 E_Right
=> Elements
(Target
)'Old,
927 P_Left
=> Positions
(Target
),
928 P_Right
=> Positions
(Target
)'Old);
930 function Difference
(Left
, Right
: Set
) return Set
with
933 Length
(Difference
'Result) = Length
(Left
) -
934 M
.Num_Overlaps
(Model
(Left
), Model
(Right
))
936 -- Elements of the result of Difference are in Left
938 and Model
(Difference
'Result) <= Model
(Left
)
940 -- Elements of the result of Difference are in Right
942 and M
.No_Overlap
(Model
(Difference
'Result), Model
(Right
))
944 -- Elements in Left but not in Right are in the difference
946 and M
.Included_In_Union
947 (Model
(Left
), Model
(Difference
'Result), Model
(Right
))
949 -- Actual value of elements come from Left
951 and E_Elements_Included
952 (Elements
(Difference
'Result), Elements
(Left
))
954 and E_Elements_Included
956 Model
(Difference
'Result),
957 Elements
(Difference
'Result));
959 function "-" (Left
, Right
: Set
) return Set
renames Difference
;
961 procedure Symmetric_Difference
(Target
: in out Set
; Source
: Set
) with
964 Length
(Source
) - Length
(Target
and Source
) <=
965 Target
.Capacity
- Length
(Target
) + Length
(Target
and Source
),
967 Length
(Target
) = Length
(Target
)'Old -
968 2 * M
.Num_Overlaps
(Model
(Target
)'Old, Model
(Source
)) +
971 -- Elements of the difference were not both in Source and in Target
973 and M
.Not_In_Both
(Model
(Target
), Model
(Target
)'Old, Model
(Source
))
975 -- Elements in Target but not in Source are in the difference
977 and M
.Included_In_Union
978 (Model
(Target
)'Old, Model
(Target
), Model
(Source
))
980 -- Elements in Source but not in Target are in the difference
982 and M
.Included_In_Union
983 (Model
(Source
), Model
(Target
), Model
(Target
)'Old)
985 -- Actual value of elements come from either Left or Right
987 and E_Elements_Included
990 Elements
(Target
)'Old,
993 and E_Elements_Included
994 (Elements
(Target
)'Old, Model
(Target
), Elements
(Target
))
996 and E_Elements_Included
997 (Elements
(Source
), Model
(Target
), Elements
(Target
));
999 function Symmetric_Difference
(Left
, Right
: Set
) return Set
with
1001 Pre
=> Length
(Left
) <= Count_Type
'Last - Length
(Right
),
1003 Length
(Symmetric_Difference
'Result) = Length
(Left
) -
1004 2 * M
.Num_Overlaps
(Model
(Left
), Model
(Right
)) +
1007 -- Elements of the difference were not both in Left and Right
1010 (Model
(Symmetric_Difference
'Result),
1014 -- Elements in Left but not in Right are in the difference
1016 and M
.Included_In_Union
1018 Model
(Symmetric_Difference
'Result),
1021 -- Elements in Right but not in Left are in the difference
1023 and M
.Included_In_Union
1025 Model
(Symmetric_Difference
'Result),
1028 -- Actual value of elements come from either Left or Right
1030 and E_Elements_Included
1031 (Elements
(Symmetric_Difference
'Result),
1036 and E_Elements_Included
1038 Model
(Symmetric_Difference
'Result),
1039 Elements
(Symmetric_Difference
'Result))
1041 and E_Elements_Included
1043 Model
(Symmetric_Difference
'Result),
1044 Elements
(Symmetric_Difference
'Result));
1046 function "xor" (Left
, Right
: Set
) return Set
1047 renames Symmetric_Difference
;
1049 function Overlap
(Left
, Right
: Set
) return Boolean with
1052 Overlap
'Result = not (M
.No_Overlap
(Model
(Left
), Model
(Right
)));
1054 function Is_Subset
(Subset
: Set
; Of_Set
: Set
) return Boolean with
1056 Post
=> Is_Subset
'Result = (Model
(Subset
) <= Model
(Of_Set
));
1058 function First
(Container
: Set
) return Cursor
with
1061 (Length
(Container
) = 0 =>
1062 First
'Result = No_Element
,
1065 Has_Element
(Container
, First
'Result)
1066 and P
.Get
(Positions
(Container
), First
'Result) = 1);
1068 function Next
(Container
: Set
; Position
: Cursor
) return Cursor
with
1071 Has_Element
(Container
, Position
) or else Position
= No_Element
,
1073 (Position
= No_Element
1074 or else P
.Get
(Positions
(Container
), Position
) = Length
(Container
)
1076 Next
'Result = No_Element
,
1079 Has_Element
(Container
, Next
'Result)
1080 and then P
.Get
(Positions
(Container
), Next
'Result) =
1081 P
.Get
(Positions
(Container
), Position
) + 1);
1083 procedure Next
(Container
: Set
; Position
: in out Cursor
) with
1086 Has_Element
(Container
, Position
) or else Position
= No_Element
,
1088 (Position
= No_Element
1089 or else P
.Get
(Positions
(Container
), Position
) = Length
(Container
)
1091 Position
= No_Element
,
1094 Has_Element
(Container
, Position
)
1095 and then P
.Get
(Positions
(Container
), Position
) =
1096 P
.Get
(Positions
(Container
), Position
'Old) + 1);
1100 Item
: Element_Type
) return Cursor
1105 -- If Item is not contained in Container, Find returns No_Element
1107 (not Contains
(Model
(Container
), Item
) =>
1108 Find
'Result = No_Element
,
1110 -- Otherwise, Find returns a valid cursor in Container
1113 P
.Has_Key
(Positions
(Container
), Find
'Result)
1114 and P
.Get
(Positions
(Container
), Find
'Result) =
1115 Find
(Elements
(Container
), Item
)
1117 -- The element designated by the result of Find is Item
1119 and Equivalent_Elements
1120 (Element
(Container
, Find
'Result), Item
));
1122 function Contains
(Container
: Set
; Item
: Element_Type
) return Boolean with
1124 Post
=> Contains
'Result = Contains
(Model
(Container
), Item
);
1125 pragma Annotate
(GNATprove
, Inline_For_Proof
, Contains
);
1127 function Has_Element
(Container
: Set
; Position
: Cursor
) return Boolean
1131 Has_Element
'Result = P
.Has_Key
(Positions
(Container
), Position
);
1132 pragma Annotate
(GNATprove
, Inline_For_Proof
, Has_Element
);
1134 function Default_Modulus
(Capacity
: Count_Type
) return Hash_Type
with
1138 type Key_Type
(<>) is private;
1140 with function Key
(Element
: Element_Type
) return Key_Type
;
1142 with function Hash
(Key
: Key_Type
) return Hash_Type
;
1144 with function Equivalent_Keys
(Left
, Right
: Key_Type
) return Boolean;
1146 package Generic_Keys
with SPARK_Mode
is
1148 package Formal_Model
with Ghost
is
1150 function M_Included_Except
1153 Key
: Key_Type
) return Boolean
1157 M_Included_Except
'Result =
1158 (for all E
of Left
=>
1160 or Equivalent_Keys
(Generic_Keys
.Key
(E
), Key
));
1165 function Key
(Container
: Set
; Position
: Cursor
) return Key_Type
with
1167 Post
=> Key
'Result = Key
(Element
(Container
, Position
));
1168 pragma Annotate
(GNATprove
, Inline_For_Proof
, Key
);
1170 function Element
(Container
: Set
; Key
: Key_Type
) return Element_Type
1173 Pre
=> Contains
(Container
, Key
),
1175 Element
'Result = Element
(Container
, Find
(Container
, Key
));
1176 pragma Annotate
(GNATprove
, Inline_For_Proof
, Element
);
1179 (Container
: in out Set
;
1181 New_Item
: Element_Type
)
1184 Pre
=> Contains
(Container
, Key
),
1186 Length
(Container
) = Length
(Container
)'Old
1188 -- Key now maps to New_Item
1190 and Element
(Container
, Key
) = New_Item
1192 -- New_Item is contained in Container
1194 and Contains
(Model
(Container
), New_Item
)
1196 -- Other elements are preserved
1198 and M_Included_Except
1199 (Model
(Container
)'Old,
1202 and M
.Included_Except
1204 Model
(Container
)'Old,
1207 -- Mapping from cursors to elements is preserved
1209 and Mapping_Preserved_Except
1210 (E_Left
=> Elements
(Container
)'Old,
1211 E_Right
=> Elements
(Container
),
1212 P_Left
=> Positions
(Container
)'Old,
1213 P_Right
=> Positions
(Container
),
1214 Position
=> Find
(Container
, Key
))
1215 and Positions
(Container
) = Positions
(Container
)'Old;
1217 procedure Exclude
(Container
: in out Set
; Key
: Key_Type
) with
1219 Post
=> not Contains
(Container
, Key
),
1222 -- If Key is not in Container, nothing is changed
1224 (not Contains
(Container
, Key
) =>
1225 Model
(Container
) = Model
(Container
)'Old
1226 and Elements
(Container
) = Elements
(Container
)'Old
1227 and Positions
(Container
) = Positions
(Container
)'Old,
1229 -- Otherwise, Key is removed from Container
1232 Length
(Container
) = Length
(Container
)'Old - 1
1234 -- Other elements are preserved
1236 and Model
(Container
) <= Model
(Container
)'Old
1237 and M_Included_Except
1238 (Model
(Container
)'Old,
1242 -- Mapping from cursors to elements is preserved
1244 and Mapping_Preserved
1245 (E_Left
=> Elements
(Container
),
1246 E_Right
=> Elements
(Container
)'Old,
1247 P_Left
=> Positions
(Container
),
1248 P_Right
=> Positions
(Container
)'Old)
1249 and P
.Keys_Included_Except
1250 (Positions
(Container
)'Old,
1251 Positions
(Container
),
1252 Find
(Container
, Key
)'Old));
1254 procedure Delete
(Container
: in out Set
; Key
: Key_Type
) with
1256 Pre
=> Contains
(Container
, Key
),
1258 Length
(Container
) = Length
(Container
)'Old - 1
1260 -- Key is no longer in Container
1262 and not Contains
(Container
, Key
)
1264 -- Other elements are preserved
1266 and Model
(Container
) <= Model
(Container
)'Old
1267 and M_Included_Except
1268 (Model
(Container
)'Old,
1272 -- Mapping from cursors to elements is preserved
1274 and Mapping_Preserved
1275 (E_Left
=> Elements
(Container
),
1276 E_Right
=> Elements
(Container
)'Old,
1277 P_Left
=> Positions
(Container
),
1278 P_Right
=> Positions
(Container
)'Old)
1279 and P
.Keys_Included_Except
1280 (Positions
(Container
)'Old,
1281 Positions
(Container
),
1282 Find
(Container
, Key
)'Old);
1284 function Find
(Container
: Set
; Key
: Key_Type
) return Cursor
with
1288 -- If Key is not contained in Container, Find returns No_Element
1290 ((for all E
of Model
(Container
) =>
1291 not Equivalent_Keys
(Key
, Generic_Keys
.Key
(E
))) =>
1292 Find
'Result = No_Element
,
1294 -- Otherwise, Find returns a valid cursor in Container
1297 P
.Has_Key
(Positions
(Container
), Find
'Result)
1299 -- The key designated by the result of Find is Key
1302 (Generic_Keys
.Key
(Container
, Find
'Result), Key
));
1304 function Contains
(Container
: Set
; Key
: Key_Type
) return Boolean with
1308 (for some E
of Model
(Container
) =>
1309 Equivalent_Keys
(Key
, Generic_Keys
.Key
(E
)));
1314 pragma SPARK_Mode
(Off
);
1316 pragma Inline
(Next
);
1320 Element
: Element_Type
;
1322 Has_Element
: Boolean := False;
1325 package HT_Types
is new
1326 Ada
.Containers
.Hash_Tables
.Generic_Bounded_Hash_Table_Types
(Node_Type
);
1328 type Set
(Capacity
: Count_Type
; Modulus
: Hash_Type
) is
1329 new HT_Types
.Hash_Table_Type
(Capacity
, Modulus
) with null record;
1333 Empty_Set
: constant Set
:= (Capacity
=> 0, Modulus
=> 0, others => <>);
1335 end Ada
.Containers
.Formal_Hashed_Sets
;