------------------------------------------------------------------------------ -- -- -- GNAT LIBRARY COMPONENTS -- -- -- -- ADA.CONTAINERS.RED_BLACK_TREES.GENERIC_BOUNDED_SET_OPERATIONS -- -- -- -- B o d y -- -- -- -- Copyright (C) 2004-2013, 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_Bounded_Set_Operations is ----------------------- -- Local Subprograms -- ----------------------- function Copy (Source : Set_Type) return Set_Type; ---------- -- Copy -- ---------- function Copy (Source : Set_Type) return Set_Type is begin return Target : Set_Type (Source.Length) do Assign (Target => Target, Source => Source); end return; end Copy; ---------------- -- Difference -- ---------------- procedure Set_Difference (Target : in out Set_Type; Source : Set_Type) is BT : Natural renames Target.Busy; LT : Natural renames Target.Lock; BS : Natural renames Source'Unrestricted_Access.Busy; LS : Natural renames Source'Unrestricted_Access.Lock; Tgt, Src : Count_Type; TN : Nodes_Type renames Target.Nodes; SN : Nodes_Type renames Source.Nodes; Compare : Integer; begin if Target'Address = Source'Address then if Target.Busy > 0 then raise Program_Error with "attempt to tamper with cursors (container is busy)"; end if; Tree_Operations.Clear_Tree (Target); return; end if; if Source.Length = 0 then return; end if; if Target.Busy > 0 then raise Program_Error with "attempt to tamper with cursors (container is busy)"; end if; Tgt := Target.First; Src := Source.First; loop if Tgt = 0 then exit; end if; if Src = 0 then exit; end if; -- Per AI05-0022, the container implementation is required to detect -- element tampering by a generic actual subprogram. begin BT := BT + 1; LT := LT + 1; BS := BS + 1; LS := LS + 1; if Is_Less (TN (Tgt), SN (Src)) then Compare := -1; elsif Is_Less (SN (Src), TN (Tgt)) then Compare := 1; else Compare := 0; end if; BT := BT - 1; LT := LT - 1; BS := BS - 1; LS := LS - 1; exception when others => BT := BT - 1; LT := LT - 1; BS := BS - 1; LS := LS - 1; raise; end; if Compare < 0 then Tgt := Tree_Operations.Next (Target, Tgt); elsif Compare > 0 then Src := Tree_Operations.Next (Source, Src); else declare X : constant Count_Type := Tgt; begin Tgt := Tree_Operations.Next (Target, Tgt); Tree_Operations.Delete_Node_Sans_Free (Target, X); Tree_Operations.Free (Target, X); end; Src := Tree_Operations.Next (Source, Src); end if; end loop; end Set_Difference; function Set_Difference (Left, Right : Set_Type) return Set_Type is begin if Left'Address = Right'Address then return S : Set_Type (0); -- Empty set end if; if Left.Length = 0 then return S : Set_Type (0); -- Empty set end if; if Right.Length = 0 then return Copy (Left); end if; return Result : Set_Type (Left.Length) do -- Per AI05-0022, the container implementation is required to detect -- element tampering by a generic actual subprogram. declare BL : Natural renames Left'Unrestricted_Access.Busy; LL : Natural renames Left'Unrestricted_Access.Lock; BR : Natural renames Right'Unrestricted_Access.Busy; LR : Natural renames Right'Unrestricted_Access.Lock; L_Node : Count_Type; R_Node : Count_Type; Dst_Node : Count_Type; pragma Warnings (Off, Dst_Node); begin BL := BL + 1; LL := LL + 1; BR := BR + 1; LR := LR + 1; L_Node := Left.First; R_Node := Right.First; loop if L_Node = 0 then exit; end if; if R_Node = 0 then while L_Node /= 0 loop Insert_With_Hint (Dst_Set => Result, Dst_Hint => 0, Src_Node => Left.Nodes (L_Node), Dst_Node => Dst_Node); L_Node := Tree_Operations.Next (Left, L_Node); end loop; exit; end if; if Is_Less (Left.Nodes (L_Node), Right.Nodes (R_Node)) then Insert_With_Hint (Dst_Set => Result, Dst_Hint => 0, Src_Node => Left.Nodes (L_Node), Dst_Node => Dst_Node); L_Node := Tree_Operations.Next (Left, L_Node); elsif Is_Less (Right.Nodes (R_Node), Left.Nodes (L_Node)) then R_Node := Tree_Operations.Next (Right, R_Node); else L_Node := Tree_Operations.Next (Left, L_Node); R_Node := Tree_Operations.Next (Right, R_Node); end if; end loop; BL := BL - 1; LL := LL - 1; BR := BR - 1; LR := LR - 1; exception when others => BL := BL - 1; LL := LL - 1; BR := BR - 1; LR := LR - 1; raise; end; end return; end Set_Difference; ------------------ -- Intersection -- ------------------ procedure Set_Intersection (Target : in out Set_Type; Source : Set_Type) is BT : Natural renames Target.Busy; LT : Natural renames Target.Lock; BS : Natural renames Source'Unrestricted_Access.Busy; LS : Natural renames Source'Unrestricted_Access.Lock; Tgt : Count_Type; Src : Count_Type; Compare : Integer; begin if Target'Address = Source'Address then return; end if; if Target.Busy > 0 then raise Program_Error with "attempt to tamper with cursors (container is busy)"; end if; if Source.Length = 0 then Tree_Operations.Clear_Tree (Target); return; end if; Tgt := Target.First; Src := Source.First; while Tgt /= 0 and then Src /= 0 loop -- Per AI05-0022, the container implementation is required to detect -- element tampering by a generic actual subprogram. begin BT := BT + 1; LT := LT + 1; BS := BS + 1; LS := LS + 1; if Is_Less (Target.Nodes (Tgt), Source.Nodes (Src)) then Compare := -1; elsif Is_Less (Source.Nodes (Src), Target.Nodes (Tgt)) then Compare := 1; else Compare := 0; end if; BT := BT - 1; LT := LT - 1; BS := BS - 1; LS := LS - 1; exception when others => BT := BT - 1; LT := LT - 1; BS := BS - 1; LS := LS - 1; raise; end; if Compare < 0 then declare X : constant Count_Type := Tgt; begin Tgt := Tree_Operations.Next (Target, Tgt); Tree_Operations.Delete_Node_Sans_Free (Target, X); Tree_Operations.Free (Target, X); end; elsif Compare > 0 then Src := Tree_Operations.Next (Source, Src); else Tgt := Tree_Operations.Next (Target, Tgt); Src := Tree_Operations.Next (Source, Src); end if; end loop; while Tgt /= 0 loop declare X : constant Count_Type := Tgt; begin Tgt := Tree_Operations.Next (Target, Tgt); Tree_Operations.Delete_Node_Sans_Free (Target, X); Tree_Operations.Free (Target, X); end; end loop; end Set_Intersection; function Set_Intersection (Left, Right : Set_Type) return Set_Type is begin if Left'Address = Right'Address then return Copy (Left); end if; return Result : Set_Type (Count_Type'Min (Left.Length, Right.Length)) do -- Per AI05-0022, the container implementation is required to detect -- element tampering by a generic actual subprogram. declare BL : Natural renames Left'Unrestricted_Access.Busy; LL : Natural renames Left'Unrestricted_Access.Lock; BR : Natural renames Right'Unrestricted_Access.Busy; LR : Natural renames Right'Unrestricted_Access.Lock; L_Node : Count_Type; R_Node : Count_Type; Dst_Node : Count_Type; pragma Warnings (Off, Dst_Node); begin BL := BL + 1; LL := LL + 1; BR := BR + 1; LR := LR + 1; L_Node := Left.First; R_Node := Right.First; loop if L_Node = 0 then exit; end if; if R_Node = 0 then exit; end if; if Is_Less (Left.Nodes (L_Node), Right.Nodes (R_Node)) then L_Node := Tree_Operations.Next (Left, L_Node); elsif Is_Less (Right.Nodes (R_Node), Left.Nodes (L_Node)) then R_Node := Tree_Operations.Next (Right, R_Node); else Insert_With_Hint (Dst_Set => Result, Dst_Hint => 0, Src_Node => Left.Nodes (L_Node), Dst_Node => Dst_Node); L_Node := Tree_Operations.Next (Left, L_Node); R_Node := Tree_Operations.Next (Right, R_Node); end if; end loop; BL := BL - 1; LL := LL - 1; BR := BR - 1; LR := LR - 1; exception when others => BL := BL - 1; LL := LL - 1; BR := BR - 1; LR := LR - 1; raise; end; end return; end Set_Intersection; --------------- -- Is_Subset -- --------------- function Set_Subset (Subset : Set_Type; Of_Set : Set_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 BL : Natural renames Subset'Unrestricted_Access.Busy; LL : Natural renames Subset'Unrestricted_Access.Lock; BR : Natural renames Of_Set'Unrestricted_Access.Busy; LR : Natural renames Of_Set'Unrestricted_Access.Lock; Subset_Node : Count_Type; Set_Node : Count_Type; Result : Boolean; begin BL := BL + 1; LL := LL + 1; BR := BR + 1; LR := LR + 1; Subset_Node := Subset.First; Set_Node := Of_Set.First; loop if Set_Node = 0 then Result := Subset_Node = 0; exit; end if; if Subset_Node = 0 then Result := True; exit; end if; if Is_Less (Subset.Nodes (Subset_Node), Of_Set.Nodes (Set_Node)) then Result := False; exit; end if; if Is_Less (Of_Set.Nodes (Set_Node), Subset.Nodes (Subset_Node)) then Set_Node := Tree_Operations.Next (Of_Set, Set_Node); else Set_Node := Tree_Operations.Next (Of_Set, Set_Node); Subset_Node := Tree_Operations.Next (Subset, Subset_Node); end if; end loop; BL := BL - 1; LL := LL - 1; BR := BR - 1; LR := LR - 1; return Result; exception when others => BL := BL - 1; LL := LL - 1; BR := BR - 1; LR := LR - 1; raise; end; end Set_Subset; ------------- -- Overlap -- ------------- function Set_Overlap (Left, Right : Set_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 BL : Natural renames Left'Unrestricted_Access.Busy; LL : Natural renames Left'Unrestricted_Access.Lock; BR : Natural renames Right'Unrestricted_Access.Busy; LR : Natural renames Right'Unrestricted_Access.Lock; L_Node : Count_Type; R_Node : Count_Type; Result : Boolean; begin BL := BL + 1; LL := LL + 1; BR := BR + 1; LR := LR + 1; L_Node := Left.First; R_Node := Right.First; loop if L_Node = 0 or else R_Node = 0 then Result := False; exit; end if; if Is_Less (Left.Nodes (L_Node), Right.Nodes (R_Node)) then L_Node := Tree_Operations.Next (Left, L_Node); elsif Is_Less (Right.Nodes (R_Node), Left.Nodes (L_Node)) then R_Node := Tree_Operations.Next (Right, R_Node); else Result := True; exit; end if; end loop; BL := BL - 1; LL := LL - 1; BR := BR - 1; LR := LR - 1; return Result; exception when others => BL := BL - 1; LL := LL - 1; BR := BR - 1; LR := LR - 1; raise; end; end Set_Overlap; -------------------------- -- Symmetric_Difference -- -------------------------- procedure Set_Symmetric_Difference (Target : in out Set_Type; Source : Set_Type) is BT : Natural renames Target.Busy; LT : Natural renames Target.Lock; BS : Natural renames Source'Unrestricted_Access.Busy; LS : Natural renames Source'Unrestricted_Access.Lock; Tgt : Count_Type; Src : Count_Type; New_Tgt_Node : Count_Type; pragma Warnings (Off, New_Tgt_Node); Compare : Integer; begin if Target'Address = Source'Address then Tree_Operations.Clear_Tree (Target); return; end if; Tgt := Target.First; Src := Source.First; loop if Tgt = 0 then while Src /= 0 loop Insert_With_Hint (Dst_Set => Target, Dst_Hint => 0, Src_Node => Source.Nodes (Src), Dst_Node => New_Tgt_Node); Src := Tree_Operations.Next (Source, Src); end loop; return; end if; if Src = 0 then return; end if; -- Per AI05-0022, the container implementation is required to detect -- element tampering by a generic actual subprogram. begin BT := BT + 1; LT := LT + 1; BS := BS + 1; LS := LS + 1; if Is_Less (Target.Nodes (Tgt), Source.Nodes (Src)) then Compare := -1; elsif Is_Less (Source.Nodes (Src), Target.Nodes (Tgt)) then Compare := 1; else Compare := 0; end if; BT := BT - 1; LT := LT - 1; BS := BS - 1; LS := LS - 1; exception when others => BT := BT - 1; LT := LT - 1; BS := BS - 1; LS := LS - 1; raise; end; if Compare < 0 then Tgt := Tree_Operations.Next (Target, Tgt); elsif Compare > 0 then Insert_With_Hint (Dst_Set => Target, Dst_Hint => Tgt, Src_Node => Source.Nodes (Src), Dst_Node => New_Tgt_Node); Src := Tree_Operations.Next (Source, Src); else declare X : constant Count_Type := Tgt; begin Tgt := Tree_Operations.Next (Target, Tgt); Tree_Operations.Delete_Node_Sans_Free (Target, X); Tree_Operations.Free (Target, X); end; Src := Tree_Operations.Next (Source, Src); end if; end loop; end Set_Symmetric_Difference; function Set_Symmetric_Difference (Left, Right : Set_Type) return Set_Type is begin if Left'Address = Right'Address then return S : Set_Type (0); -- Empty set end if; if Right.Length = 0 then return Copy (Left); end if; if Left.Length = 0 then return Copy (Right); end if; return Result : Set_Type (Left.Length + Right.Length) do -- Per AI05-0022, the container implementation is required to detect -- element tampering by a generic actual subprogram. declare BL : Natural renames Left'Unrestricted_Access.Busy; LL : Natural renames Left'Unrestricted_Access.Lock; BR : Natural renames Right'Unrestricted_Access.Busy; LR : Natural renames Right'Unrestricted_Access.Lock; L_Node : Count_Type; R_Node : Count_Type; Dst_Node : Count_Type; pragma Warnings (Off, Dst_Node); begin BL := BL + 1; LL := LL + 1; BR := BR + 1; LR := LR + 1; L_Node := Left.First; R_Node := Right.First; loop if L_Node = 0 then while R_Node /= 0 loop Insert_With_Hint (Dst_Set => Result, Dst_Hint => 0, Src_Node => Right.Nodes (R_Node), Dst_Node => Dst_Node); R_Node := Tree_Operations.Next (Right, R_Node); end loop; exit; end if; if R_Node = 0 then while L_Node /= 0 loop Insert_With_Hint (Dst_Set => Result, Dst_Hint => 0, Src_Node => Left.Nodes (L_Node), Dst_Node => Dst_Node); L_Node := Tree_Operations.Next (Left, L_Node); end loop; exit; end if; if Is_Less (Left.Nodes (L_Node), Right.Nodes (R_Node)) then Insert_With_Hint (Dst_Set => Result, Dst_Hint => 0, Src_Node => Left.Nodes (L_Node), Dst_Node => Dst_Node); L_Node := Tree_Operations.Next (Left, L_Node); elsif Is_Less (Right.Nodes (R_Node), Left.Nodes (L_Node)) then Insert_With_Hint (Dst_Set => Result, Dst_Hint => 0, Src_Node => Right.Nodes (R_Node), Dst_Node => Dst_Node); R_Node := Tree_Operations.Next (Right, R_Node); else L_Node := Tree_Operations.Next (Left, L_Node); R_Node := Tree_Operations.Next (Right, R_Node); end if; end loop; BL := BL - 1; LL := LL - 1; BR := BR - 1; LR := LR - 1; exception when others => BL := BL - 1; LL := LL - 1; BR := BR - 1; LR := LR - 1; raise; end; end return; end Set_Symmetric_Difference; ----------- -- Union -- ----------- procedure Set_Union (Target : in out Set_Type; Source : Set_Type) is Hint : Count_Type := 0; procedure Process (Node : Count_Type); pragma Inline (Process); procedure Iterate is new Tree_Operations.Generic_Iteration (Process); ------------- -- Process -- ------------- procedure Process (Node : Count_Type) is begin Insert_With_Hint (Dst_Set => Target, Dst_Hint => Hint, Src_Node => Source.Nodes (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 BS : Natural renames Source'Unrestricted_Access.Busy; LS : Natural renames Source'Unrestricted_Access.Lock; begin BS := BS + 1; LS := LS + 1; -- Note that there's no way to decide a priori whether the target has -- enough capacity for the union with source. We cannot simply -- compare the sum of the existing lengths to the capacity of the -- target, because equivalent items from source are not included in -- the union. Iterate (Source); BS := BS - 1; LS := LS - 1; exception when others => BS := BS - 1; LS := LS - 1; raise; end; end Set_Union; function Set_Union (Left, Right : Set_Type) return Set_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; return Result : Set_Type (Left.Length + Right.Length) do declare BL : Natural renames Left'Unrestricted_Access.Busy; LL : Natural renames Left'Unrestricted_Access.Lock; BR : Natural renames Right'Unrestricted_Access.Busy; LR : Natural renames Right'Unrestricted_Access.Lock; begin BL := BL + 1; LL := LL + 1; BR := BR + 1; LR := LR + 1; Assign (Target => Result, Source => Left); Insert_Right : declare Hint : Count_Type := 0; procedure Process (Node : Count_Type); pragma Inline (Process); procedure Iterate is new Tree_Operations.Generic_Iteration (Process); ------------- -- Process -- ------------- procedure Process (Node : Count_Type) is begin Insert_With_Hint (Dst_Set => Result, Dst_Hint => Hint, Src_Node => Right.Nodes (Node), Dst_Node => Hint); end Process; -- Start of processing for Insert_Right begin Iterate (Right); end Insert_Right; BL := BL - 1; LL := LL - 1; BR := BR - 1; LR := LR - 1; exception when others => BL := BL - 1; LL := LL - 1; BR := BR - 1; LR := LR - 1; raise; end; end return; end Set_Union; end Ada.Containers.Red_Black_Trees.Generic_Bounded_Set_Operations;