------------------------------------------------------------------------------ -- -- -- GNAT LIBRARY COMPONENTS -- -- -- -- ADA.CONTAINERS.RED_BLACK_TREES.GENERIC_SET_OPERATIONS -- -- -- -- B o d y -- -- -- -- Copyright (C) 2004-2024, Free Software Foundation, Inc. -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 3, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- -- This unit was originally developed by Matthew J Heaney. -- ------------------------------------------------------------------------------ with System; use type System.Address; package body Ada.Containers.Red_Black_Trees.Generic_Set_Operations is pragma Warnings (Off, "variable ""Busy*"" is not referenced"); pragma Warnings (Off, "variable ""Lock*"" is not referenced"); -- See comment in Ada.Containers.Helpers ----------------------- -- Local Subprograms -- ----------------------- procedure Clear (Tree : in out Tree_Type); function Copy (Source : Tree_Type) return Tree_Type; ----------- -- Clear -- ----------- procedure Clear (Tree : in out Tree_Type) is use type Helpers.Tamper_Counts; pragma Assert (Tree.TC = (Busy => 0, Lock => 0)); Root : Node_Access := Tree.Root; pragma Warnings (Off, Root); begin Tree.Root := null; Tree.First := null; Tree.Last := null; Tree.Length := 0; Delete_Tree (Root); end Clear; ---------- -- Copy -- ---------- function Copy (Source : Tree_Type) return Tree_Type is Target : Tree_Type; begin if Source.Length = 0 then return Target; end if; Target.Root := Copy_Tree (Source.Root); Target.First := Tree_Operations.Min (Target.Root); Target.Last := Tree_Operations.Max (Target.Root); Target.Length := Source.Length; return Target; end Copy; ---------------- -- Difference -- ---------------- procedure Difference (Target : in out Tree_Type; Source : Tree_Type) is Tgt : Node_Access; Src : Node_Access; Compare : Integer; begin TC_Check (Target.TC); if Target'Address = Source'Address then Clear (Target); return; end if; if Source.Length = 0 then return; end if; Tgt := Target.First; Src := Source.First; loop if Tgt = null then exit; end if; if Src = null then exit; end if; -- Per AI05-0022, the container implementation is required to detect -- element tampering by a generic actual subprogram. declare Lock_Target : With_Lock (Target.TC'Unrestricted_Access); Lock_Source : With_Lock (Source.TC'Unrestricted_Access); begin if Is_Less (Tgt, Src) then Compare := -1; elsif Is_Less (Src, Tgt) then Compare := 1; else Compare := 0; end if; end; if Compare < 0 then Tgt := Tree_Operations.Next (Tgt); elsif Compare > 0 then Src := Tree_Operations.Next (Src); else declare X : Node_Access := Tgt; begin Tgt := Tree_Operations.Next (Tgt); Tree_Operations.Delete_Node_Sans_Free (Target, X); Free (X); end; Src := Tree_Operations.Next (Src); end if; end loop; end Difference; function Difference (Left, Right : Tree_Type) return Tree_Type is begin if Left'Address = Right'Address then return Tree_Type'(others => <>); -- Empty set end if; if Left.Length = 0 then return Tree_Type'(others => <>); -- Empty set end if; if Right.Length = 0 then return Copy (Left); end if; -- Per AI05-0022, the container implementation is required to detect -- element tampering by a generic actual subprogram. declare Lock_Left : With_Lock (Left.TC'Unrestricted_Access); Lock_Right : With_Lock (Right.TC'Unrestricted_Access); Tree : Tree_Type; L_Node : Node_Access; R_Node : Node_Access; Dst_Node : Node_Access; pragma Warnings (Off, Dst_Node); begin L_Node := Left.First; R_Node := Right.First; loop if L_Node = null then exit; end if; if R_Node = null then while L_Node /= null loop Insert_With_Hint (Dst_Tree => Tree, Dst_Hint => null, Src_Node => L_Node, Dst_Node => Dst_Node); L_Node := Tree_Operations.Next (L_Node); end loop; exit; end if; if Is_Less (L_Node, R_Node) then Insert_With_Hint (Dst_Tree => Tree, Dst_Hint => null, Src_Node => L_Node, Dst_Node => Dst_Node); L_Node := Tree_Operations.Next (L_Node); elsif Is_Less (R_Node, L_Node) then R_Node := Tree_Operations.Next (R_Node); else L_Node := Tree_Operations.Next (L_Node); R_Node := Tree_Operations.Next (R_Node); end if; end loop; return Tree; exception when others => Delete_Tree (Tree.Root); raise; end; end Difference; ------------------ -- Intersection -- ------------------ procedure Intersection (Target : in out Tree_Type; Source : Tree_Type) is Tgt : Node_Access; Src : Node_Access; Compare : Integer; begin if Target'Address = Source'Address then return; end if; TC_Check (Target.TC); if Source.Length = 0 then Clear (Target); return; end if; Tgt := Target.First; Src := Source.First; while Tgt /= null and then Src /= null loop -- Per AI05-0022, the container implementation is required to detect -- element tampering by a generic actual subprogram. declare Lock_Target : With_Lock (Target.TC'Unrestricted_Access); Lock_Source : With_Lock (Source.TC'Unrestricted_Access); begin if Is_Less (Tgt, Src) then Compare := -1; elsif Is_Less (Src, Tgt) then Compare := 1; else Compare := 0; end if; end; if Compare < 0 then declare X : Node_Access := Tgt; begin Tgt := Tree_Operations.Next (Tgt); Tree_Operations.Delete_Node_Sans_Free (Target, X); Free (X); end; elsif Compare > 0 then Src := Tree_Operations.Next (Src); else Tgt := Tree_Operations.Next (Tgt); Src := Tree_Operations.Next (Src); end if; end loop; while Tgt /= null loop declare X : Node_Access := Tgt; begin Tgt := Tree_Operations.Next (Tgt); Tree_Operations.Delete_Node_Sans_Free (Target, X); Free (X); end; end loop; end Intersection; function Intersection (Left, Right : Tree_Type) return Tree_Type is begin if Left'Address = Right'Address then return Copy (Left); end if; -- Per AI05-0022, the container implementation is required to detect -- element tampering by a generic actual subprogram. declare Lock_Left : With_Lock (Left.TC'Unrestricted_Access); Lock_Right : With_Lock (Right.TC'Unrestricted_Access); Tree : Tree_Type; L_Node : Node_Access; R_Node : Node_Access; Dst_Node : Node_Access; pragma Warnings (Off, Dst_Node); begin L_Node := Left.First; R_Node := Right.First; loop if L_Node = null then exit; end if; if R_Node = null then exit; end if; if Is_Less (L_Node, R_Node) then L_Node := Tree_Operations.Next (L_Node); elsif Is_Less (R_Node, L_Node) then R_Node := Tree_Operations.Next (R_Node); else Insert_With_Hint (Dst_Tree => Tree, Dst_Hint => null, Src_Node => L_Node, Dst_Node => Dst_Node); L_Node := Tree_Operations.Next (L_Node); R_Node := Tree_Operations.Next (R_Node); end if; end loop; return Tree; exception when others => Delete_Tree (Tree.Root); raise; end; end Intersection; --------------- -- Is_Subset -- --------------- function Is_Subset (Subset : Tree_Type; Of_Set : Tree_Type) return Boolean is begin if Subset'Address = Of_Set'Address then return True; end if; if Subset.Length > Of_Set.Length then return False; end if; -- Per AI05-0022, the container implementation is required to detect -- element tampering by a generic actual subprogram. declare Lock_Subset : With_Lock (Subset.TC'Unrestricted_Access); Lock_Of_Set : With_Lock (Of_Set.TC'Unrestricted_Access); Subset_Node : Node_Access; Set_Node : Node_Access; begin Subset_Node := Subset.First; Set_Node := Of_Set.First; loop if Set_Node = null then return Subset_Node = null; end if; if Subset_Node = null then return True; end if; if Is_Less (Subset_Node, Set_Node) then return False; end if; if Is_Less (Set_Node, Subset_Node) then Set_Node := Tree_Operations.Next (Set_Node); else Set_Node := Tree_Operations.Next (Set_Node); Subset_Node := Tree_Operations.Next (Subset_Node); end if; end loop; end; end Is_Subset; ------------- -- Overlap -- ------------- function Overlap (Left, Right : Tree_Type) return Boolean is begin if Left'Address = Right'Address then return Left.Length /= 0; end if; -- Per AI05-0022, the container implementation is required to detect -- element tampering by a generic actual subprogram. declare Lock_Left : With_Lock (Left.TC'Unrestricted_Access); Lock_Right : With_Lock (Right.TC'Unrestricted_Access); L_Node : Node_Access; R_Node : Node_Access; begin L_Node := Left.First; R_Node := Right.First; loop if L_Node = null or else R_Node = null then return False; end if; if Is_Less (L_Node, R_Node) then L_Node := Tree_Operations.Next (L_Node); elsif Is_Less (R_Node, L_Node) then R_Node := Tree_Operations.Next (R_Node); else return True; end if; end loop; end; end Overlap; -------------------------- -- Symmetric_Difference -- -------------------------- procedure Symmetric_Difference (Target : in out Tree_Type; Source : Tree_Type) is Tgt : Node_Access; Src : Node_Access; New_Tgt_Node : Node_Access; pragma Warnings (Off, New_Tgt_Node); Compare : Integer; begin if Target'Address = Source'Address then Clear (Target); return; end if; Tgt := Target.First; Src := Source.First; loop if Tgt = null then while Src /= null loop Insert_With_Hint (Dst_Tree => Target, Dst_Hint => null, Src_Node => Src, Dst_Node => New_Tgt_Node); Src := Tree_Operations.Next (Src); end loop; return; end if; if Src = null then return; end if; -- Per AI05-0022, the container implementation is required to detect -- element tampering by a generic actual subprogram. declare Lock_Target : With_Lock (Target.TC'Unrestricted_Access); Lock_Source : With_Lock (Source.TC'Unrestricted_Access); begin if Is_Less (Tgt, Src) then Compare := -1; elsif Is_Less (Src, Tgt) then Compare := 1; else Compare := 0; end if; end; if Compare < 0 then Tgt := Tree_Operations.Next (Tgt); elsif Compare > 0 then Insert_With_Hint (Dst_Tree => Target, Dst_Hint => Tgt, Src_Node => Src, Dst_Node => New_Tgt_Node); Src := Tree_Operations.Next (Src); else declare X : Node_Access := Tgt; begin Tgt := Tree_Operations.Next (Tgt); Tree_Operations.Delete_Node_Sans_Free (Target, X); Free (X); end; Src := Tree_Operations.Next (Src); end if; end loop; end Symmetric_Difference; function Symmetric_Difference (Left, Right : Tree_Type) return Tree_Type is begin if Left'Address = Right'Address then return Tree_Type'(others => <>); -- Empty set end if; if Right.Length = 0 then return Copy (Left); end if; if Left.Length = 0 then return Copy (Right); end if; -- Per AI05-0022, the container implementation is required to detect -- element tampering by a generic actual subprogram. declare Lock_Left : With_Lock (Left.TC'Unrestricted_Access); Lock_Right : With_Lock (Right.TC'Unrestricted_Access); Tree : Tree_Type; L_Node : Node_Access; R_Node : Node_Access; Dst_Node : Node_Access; pragma Warnings (Off, Dst_Node); begin L_Node := Left.First; R_Node := Right.First; loop if L_Node = null then while R_Node /= null loop Insert_With_Hint (Dst_Tree => Tree, Dst_Hint => null, Src_Node => R_Node, Dst_Node => Dst_Node); R_Node := Tree_Operations.Next (R_Node); end loop; exit; end if; if R_Node = null then while L_Node /= null loop Insert_With_Hint (Dst_Tree => Tree, Dst_Hint => null, Src_Node => L_Node, Dst_Node => Dst_Node); L_Node := Tree_Operations.Next (L_Node); end loop; exit; end if; if Is_Less (L_Node, R_Node) then Insert_With_Hint (Dst_Tree => Tree, Dst_Hint => null, Src_Node => L_Node, Dst_Node => Dst_Node); L_Node := Tree_Operations.Next (L_Node); elsif Is_Less (R_Node, L_Node) then Insert_With_Hint (Dst_Tree => Tree, Dst_Hint => null, Src_Node => R_Node, Dst_Node => Dst_Node); R_Node := Tree_Operations.Next (R_Node); else L_Node := Tree_Operations.Next (L_Node); R_Node := Tree_Operations.Next (R_Node); end if; end loop; return Tree; exception when others => Delete_Tree (Tree.Root); raise; end; end Symmetric_Difference; ----------- -- Union -- ----------- procedure Union (Target : in out Tree_Type; Source : Tree_Type) is Hint : Node_Access; procedure Process (Node : Node_Access); pragma Inline (Process); procedure Iterate is new Tree_Operations.Generic_Iteration (Process); ------------- -- Process -- ------------- procedure Process (Node : Node_Access) is begin Insert_With_Hint (Dst_Tree => Target, Dst_Hint => Hint, -- use node most recently inserted as hint Src_Node => Node, Dst_Node => Hint); end Process; -- Start of processing for Union begin if Target'Address = Source'Address then return; end if; -- Per AI05-0022, the container implementation is required to detect -- element tampering by a generic actual subprogram. declare Lock_Source : With_Lock (Source.TC'Unrestricted_Access); begin Iterate (Source); end; end Union; function Union (Left, Right : Tree_Type) return Tree_Type is begin if Left'Address = Right'Address then return Copy (Left); end if; if Left.Length = 0 then return Copy (Right); end if; if Right.Length = 0 then return Copy (Left); end if; declare Lock_Left : With_Lock (Left.TC'Unrestricted_Access); Lock_Right : With_Lock (Right.TC'Unrestricted_Access); Tree : Tree_Type := Copy (Left); Hint : Node_Access; procedure Process (Node : Node_Access); pragma Inline (Process); procedure Iterate is new Tree_Operations.Generic_Iteration (Process); ------------- -- Process -- ------------- procedure Process (Node : Node_Access) is begin Insert_With_Hint (Dst_Tree => Tree, Dst_Hint => Hint, -- use node most recently inserted as hint Src_Node => Node, Dst_Node => Hint); end Process; -- Start of processing for Union begin Iterate (Right); return Tree; exception when others => Delete_Tree (Tree.Root); raise; end; end Union; end Ada.Containers.Red_Black_Trees.Generic_Set_Operations;