1------------------------------------------------------------------------------ 2-- -- 3-- GNAT LIBRARY COMPONENTS -- 4-- -- 5-- ADA.CONTAINERS.RED_BLACK_TREES.GENERIC_BOUNDED_SET_OPERATIONS -- 6-- -- 7-- B o d y -- 8-- -- 9-- Copyright (C) 2004-2019, Free Software Foundation, Inc. -- 10-- -- 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. -- 17-- -- 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. -- 21-- -- 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-- -- 27-- This unit was originally developed by Matthew J Heaney. -- 28------------------------------------------------------------------------------ 29 30with System; use type System.Address; 31 32package body Ada.Containers.Red_Black_Trees.Generic_Bounded_Set_Operations is 33 34 pragma Warnings (Off, "variable ""Busy*"" is not referenced"); 35 pragma Warnings (Off, "variable ""Lock*"" is not referenced"); 36 -- See comment in Ada.Containers.Helpers 37 38 ----------------------- 39 -- Local Subprograms -- 40 ----------------------- 41 42 function Copy (Source : Set_Type) return Set_Type; 43 44 ---------- 45 -- Copy -- 46 ---------- 47 48 function Copy (Source : Set_Type) return Set_Type is 49 begin 50 return Target : Set_Type (Source.Length) do 51 Assign (Target => Target, Source => Source); 52 end return; 53 end Copy; 54 55 -------------------- 56 -- Set_Difference -- 57 -------------------- 58 59 procedure Set_Difference (Target : in out Set_Type; Source : Set_Type) is 60 Tgt, Src : Count_Type; 61 62 TN : Nodes_Type renames Target.Nodes; 63 SN : Nodes_Type renames Source.Nodes; 64 65 Compare : Integer; 66 67 begin 68 if Target'Address = Source'Address then 69 TC_Check (Target.TC); 70 71 Tree_Operations.Clear_Tree (Target); 72 return; 73 end if; 74 75 if Source.Length = 0 then 76 return; 77 end if; 78 79 TC_Check (Target.TC); 80 81 Tgt := Target.First; 82 Src := Source.First; 83 loop 84 if Tgt = 0 then 85 exit; 86 end if; 87 88 if Src = 0 then 89 exit; 90 end if; 91 92 -- Per AI05-0022, the container implementation is required to detect 93 -- element tampering by a generic actual subprogram. 94 95 declare 96 Lock_Target : With_Lock (Target.TC'Unrestricted_Access); 97 Lock_Source : With_Lock (Source.TC'Unrestricted_Access); 98 begin 99 if Is_Less (TN (Tgt), SN (Src)) then 100 Compare := -1; 101 elsif Is_Less (SN (Src), TN (Tgt)) then 102 Compare := 1; 103 else 104 Compare := 0; 105 end if; 106 end; 107 108 if Compare < 0 then 109 Tgt := Tree_Operations.Next (Target, Tgt); 110 111 elsif Compare > 0 then 112 Src := Tree_Operations.Next (Source, Src); 113 114 else 115 declare 116 X : constant Count_Type := Tgt; 117 begin 118 Tgt := Tree_Operations.Next (Target, Tgt); 119 120 Tree_Operations.Delete_Node_Sans_Free (Target, X); 121 Tree_Operations.Free (Target, X); 122 end; 123 124 Src := Tree_Operations.Next (Source, Src); 125 end if; 126 end loop; 127 end Set_Difference; 128 129 function Set_Difference (Left, Right : Set_Type) return Set_Type is 130 begin 131 if Left'Address = Right'Address then 132 return S : Set_Type (0); -- Empty set 133 end if; 134 135 if Left.Length = 0 then 136 return S : Set_Type (0); -- Empty set 137 end if; 138 139 if Right.Length = 0 then 140 return Copy (Left); 141 end if; 142 143 return Result : Set_Type (Left.Length) do 144 -- Per AI05-0022, the container implementation is required to detect 145 -- element tampering by a generic actual subprogram. 146 147 declare 148 Lock_Left : With_Lock (Left.TC'Unrestricted_Access); 149 Lock_Right : With_Lock (Right.TC'Unrestricted_Access); 150 151 L_Node : Count_Type; 152 R_Node : Count_Type; 153 154 Dst_Node : Count_Type; 155 pragma Warnings (Off, Dst_Node); 156 157 begin 158 L_Node := Left.First; 159 R_Node := Right.First; 160 loop 161 if L_Node = 0 then 162 exit; 163 end if; 164 165 if R_Node = 0 then 166 while L_Node /= 0 loop 167 Insert_With_Hint 168 (Dst_Set => Result, 169 Dst_Hint => 0, 170 Src_Node => Left.Nodes (L_Node), 171 Dst_Node => Dst_Node); 172 173 L_Node := Tree_Operations.Next (Left, L_Node); 174 end loop; 175 176 exit; 177 end if; 178 179 if Is_Less (Left.Nodes (L_Node), Right.Nodes (R_Node)) then 180 Insert_With_Hint 181 (Dst_Set => Result, 182 Dst_Hint => 0, 183 Src_Node => Left.Nodes (L_Node), 184 Dst_Node => Dst_Node); 185 186 L_Node := Tree_Operations.Next (Left, L_Node); 187 188 elsif Is_Less (Right.Nodes (R_Node), Left.Nodes (L_Node)) then 189 R_Node := Tree_Operations.Next (Right, R_Node); 190 191 else 192 L_Node := Tree_Operations.Next (Left, L_Node); 193 R_Node := Tree_Operations.Next (Right, R_Node); 194 end if; 195 end loop; 196 end; 197 end return; 198 end Set_Difference; 199 200 ---------------------- 201 -- Set_Intersection -- 202 ---------------------- 203 204 procedure Set_Intersection 205 (Target : in out Set_Type; 206 Source : Set_Type) 207 is 208 Tgt : Count_Type; 209 Src : Count_Type; 210 211 Compare : Integer; 212 213 begin 214 if Target'Address = Source'Address then 215 return; 216 end if; 217 218 TC_Check (Target.TC); 219 220 if Source.Length = 0 then 221 Tree_Operations.Clear_Tree (Target); 222 return; 223 end if; 224 225 Tgt := Target.First; 226 Src := Source.First; 227 while Tgt /= 0 228 and then Src /= 0 229 loop 230 -- Per AI05-0022, the container implementation is required to detect 231 -- element tampering by a generic actual subprogram. 232 233 declare 234 Lock_Target : With_Lock (Target.TC'Unrestricted_Access); 235 Lock_Source : With_Lock (Source.TC'Unrestricted_Access); 236 begin 237 if Is_Less (Target.Nodes (Tgt), Source.Nodes (Src)) then 238 Compare := -1; 239 elsif Is_Less (Source.Nodes (Src), Target.Nodes (Tgt)) then 240 Compare := 1; 241 else 242 Compare := 0; 243 end if; 244 end; 245 246 if Compare < 0 then 247 declare 248 X : constant Count_Type := Tgt; 249 begin 250 Tgt := Tree_Operations.Next (Target, Tgt); 251 252 Tree_Operations.Delete_Node_Sans_Free (Target, X); 253 Tree_Operations.Free (Target, X); 254 end; 255 256 elsif Compare > 0 then 257 Src := Tree_Operations.Next (Source, Src); 258 259 else 260 Tgt := Tree_Operations.Next (Target, Tgt); 261 Src := Tree_Operations.Next (Source, Src); 262 end if; 263 end loop; 264 265 while Tgt /= 0 loop 266 declare 267 X : constant Count_Type := Tgt; 268 begin 269 Tgt := Tree_Operations.Next (Target, Tgt); 270 271 Tree_Operations.Delete_Node_Sans_Free (Target, X); 272 Tree_Operations.Free (Target, X); 273 end; 274 end loop; 275 end Set_Intersection; 276 277 function Set_Intersection (Left, Right : Set_Type) return Set_Type is 278 begin 279 if Left'Address = Right'Address then 280 return Copy (Left); 281 end if; 282 283 return Result : Set_Type (Count_Type'Min (Left.Length, Right.Length)) do 284 285 -- Per AI05-0022, the container implementation is required to detect 286 -- element tampering by a generic actual subprogram. 287 288 declare 289 Lock_Left : With_Lock (Left.TC'Unrestricted_Access); 290 Lock_Right : With_Lock (Right.TC'Unrestricted_Access); 291 292 L_Node : Count_Type; 293 R_Node : Count_Type; 294 295 Dst_Node : Count_Type; 296 pragma Warnings (Off, Dst_Node); 297 298 begin 299 L_Node := Left.First; 300 R_Node := Right.First; 301 loop 302 if L_Node = 0 then 303 exit; 304 end if; 305 306 if R_Node = 0 then 307 exit; 308 end if; 309 310 if Is_Less (Left.Nodes (L_Node), Right.Nodes (R_Node)) then 311 L_Node := Tree_Operations.Next (Left, L_Node); 312 313 elsif Is_Less (Right.Nodes (R_Node), Left.Nodes (L_Node)) then 314 R_Node := Tree_Operations.Next (Right, R_Node); 315 316 else 317 Insert_With_Hint 318 (Dst_Set => Result, 319 Dst_Hint => 0, 320 Src_Node => Left.Nodes (L_Node), 321 Dst_Node => Dst_Node); 322 323 L_Node := Tree_Operations.Next (Left, L_Node); 324 R_Node := Tree_Operations.Next (Right, R_Node); 325 end if; 326 end loop; 327 end; 328 end return; 329 end Set_Intersection; 330 331 ---------------- 332 -- Set_Subset -- 333 ---------------- 334 335 function Set_Subset 336 (Subset : Set_Type; 337 Of_Set : Set_Type) return Boolean 338 is 339 begin 340 if Subset'Address = Of_Set'Address then 341 return True; 342 end if; 343 344 if Subset.Length > Of_Set.Length then 345 return False; 346 end if; 347 348 -- Per AI05-0022, the container implementation is required to detect 349 -- element tampering by a generic actual subprogram. 350 351 declare 352 Lock_Subset : With_Lock (Subset.TC'Unrestricted_Access); 353 Lock_Of_Set : With_Lock (Of_Set.TC'Unrestricted_Access); 354 355 Subset_Node : Count_Type; 356 Set_Node : Count_Type; 357 begin 358 Subset_Node := Subset.First; 359 Set_Node := Of_Set.First; 360 loop 361 if Set_Node = 0 then 362 return Subset_Node = 0; 363 end if; 364 365 if Subset_Node = 0 then 366 return True; 367 end if; 368 369 if Is_Less (Subset.Nodes (Subset_Node), 370 Of_Set.Nodes (Set_Node)) 371 then 372 return False; 373 end if; 374 375 if Is_Less (Of_Set.Nodes (Set_Node), 376 Subset.Nodes (Subset_Node)) 377 then 378 Set_Node := Tree_Operations.Next (Of_Set, Set_Node); 379 else 380 Set_Node := Tree_Operations.Next (Of_Set, Set_Node); 381 Subset_Node := Tree_Operations.Next (Subset, Subset_Node); 382 end if; 383 end loop; 384 end; 385 end Set_Subset; 386 387 ----------------- 388 -- Set_Overlap -- 389 ----------------- 390 391 function Set_Overlap (Left, Right : Set_Type) return Boolean is 392 begin 393 if Left'Address = Right'Address then 394 return Left.Length /= 0; 395 end if; 396 397 -- Per AI05-0022, the container implementation is required to detect 398 -- element tampering by a generic actual subprogram. 399 400 declare 401 Lock_Left : With_Lock (Left.TC'Unrestricted_Access); 402 Lock_Right : With_Lock (Right.TC'Unrestricted_Access); 403 404 L_Node : Count_Type; 405 R_Node : Count_Type; 406 begin 407 L_Node := Left.First; 408 R_Node := Right.First; 409 loop 410 if L_Node = 0 411 or else R_Node = 0 412 then 413 return False; 414 end if; 415 416 if Is_Less (Left.Nodes (L_Node), Right.Nodes (R_Node)) then 417 L_Node := Tree_Operations.Next (Left, L_Node); 418 elsif Is_Less (Right.Nodes (R_Node), Left.Nodes (L_Node)) then 419 R_Node := Tree_Operations.Next (Right, R_Node); 420 else 421 return True; 422 end if; 423 end loop; 424 end; 425 end Set_Overlap; 426 427 ------------------------------ 428 -- Set_Symmetric_Difference -- 429 ------------------------------ 430 431 procedure Set_Symmetric_Difference 432 (Target : in out Set_Type; 433 Source : Set_Type) 434 is 435 Tgt : Count_Type; 436 Src : Count_Type; 437 438 New_Tgt_Node : Count_Type; 439 pragma Warnings (Off, New_Tgt_Node); 440 441 Compare : Integer; 442 443 begin 444 if Target'Address = Source'Address then 445 Tree_Operations.Clear_Tree (Target); 446 return; 447 end if; 448 449 Tgt := Target.First; 450 Src := Source.First; 451 loop 452 if Tgt = 0 then 453 while Src /= 0 loop 454 Insert_With_Hint 455 (Dst_Set => Target, 456 Dst_Hint => 0, 457 Src_Node => Source.Nodes (Src), 458 Dst_Node => New_Tgt_Node); 459 460 Src := Tree_Operations.Next (Source, Src); 461 end loop; 462 463 return; 464 end if; 465 466 if Src = 0 then 467 return; 468 end if; 469 470 -- Per AI05-0022, the container implementation is required to detect 471 -- element tampering by a generic actual subprogram. 472 473 declare 474 Lock_Target : With_Lock (Target.TC'Unrestricted_Access); 475 Lock_Source : With_Lock (Source.TC'Unrestricted_Access); 476 begin 477 if Is_Less (Target.Nodes (Tgt), Source.Nodes (Src)) then 478 Compare := -1; 479 elsif Is_Less (Source.Nodes (Src), Target.Nodes (Tgt)) then 480 Compare := 1; 481 else 482 Compare := 0; 483 end if; 484 end; 485 486 if Compare < 0 then 487 Tgt := Tree_Operations.Next (Target, Tgt); 488 489 elsif Compare > 0 then 490 Insert_With_Hint 491 (Dst_Set => Target, 492 Dst_Hint => Tgt, 493 Src_Node => Source.Nodes (Src), 494 Dst_Node => New_Tgt_Node); 495 496 Src := Tree_Operations.Next (Source, Src); 497 498 else 499 declare 500 X : constant Count_Type := Tgt; 501 begin 502 Tgt := Tree_Operations.Next (Target, Tgt); 503 504 Tree_Operations.Delete_Node_Sans_Free (Target, X); 505 Tree_Operations.Free (Target, X); 506 end; 507 508 Src := Tree_Operations.Next (Source, Src); 509 end if; 510 end loop; 511 end Set_Symmetric_Difference; 512 513 function Set_Symmetric_Difference 514 (Left, Right : Set_Type) return Set_Type 515 is 516 begin 517 if Left'Address = Right'Address then 518 return S : Set_Type (0); -- Empty set 519 end if; 520 521 if Right.Length = 0 then 522 return Copy (Left); 523 end if; 524 525 if Left.Length = 0 then 526 return Copy (Right); 527 end if; 528 529 return Result : Set_Type (Left.Length + Right.Length) do 530 531 -- Per AI05-0022, the container implementation is required to detect 532 -- element tampering by a generic actual subprogram. 533 534 declare 535 Lock_Left : With_Lock (Left.TC'Unrestricted_Access); 536 Lock_Right : With_Lock (Right.TC'Unrestricted_Access); 537 538 L_Node : Count_Type; 539 R_Node : Count_Type; 540 541 Dst_Node : Count_Type; 542 pragma Warnings (Off, Dst_Node); 543 544 begin 545 L_Node := Left.First; 546 R_Node := Right.First; 547 loop 548 if L_Node = 0 then 549 while R_Node /= 0 loop 550 Insert_With_Hint 551 (Dst_Set => Result, 552 Dst_Hint => 0, 553 Src_Node => Right.Nodes (R_Node), 554 Dst_Node => Dst_Node); 555 556 R_Node := Tree_Operations.Next (Right, R_Node); 557 end loop; 558 559 exit; 560 end if; 561 562 if R_Node = 0 then 563 while L_Node /= 0 loop 564 Insert_With_Hint 565 (Dst_Set => Result, 566 Dst_Hint => 0, 567 Src_Node => Left.Nodes (L_Node), 568 Dst_Node => Dst_Node); 569 570 L_Node := Tree_Operations.Next (Left, L_Node); 571 end loop; 572 573 exit; 574 end if; 575 576 if Is_Less (Left.Nodes (L_Node), Right.Nodes (R_Node)) then 577 Insert_With_Hint 578 (Dst_Set => Result, 579 Dst_Hint => 0, 580 Src_Node => Left.Nodes (L_Node), 581 Dst_Node => Dst_Node); 582 583 L_Node := Tree_Operations.Next (Left, L_Node); 584 585 elsif Is_Less (Right.Nodes (R_Node), Left.Nodes (L_Node)) then 586 Insert_With_Hint 587 (Dst_Set => Result, 588 Dst_Hint => 0, 589 Src_Node => Right.Nodes (R_Node), 590 Dst_Node => Dst_Node); 591 592 R_Node := Tree_Operations.Next (Right, R_Node); 593 594 else 595 L_Node := Tree_Operations.Next (Left, L_Node); 596 R_Node := Tree_Operations.Next (Right, R_Node); 597 end if; 598 end loop; 599 end; 600 end return; 601 end Set_Symmetric_Difference; 602 603 --------------- 604 -- Set_Union -- 605 --------------- 606 607 procedure Set_Union (Target : in out Set_Type; Source : Set_Type) is 608 Hint : Count_Type := 0; 609 610 procedure Process (Node : Count_Type); 611 pragma Inline (Process); 612 613 procedure Iterate is new Tree_Operations.Generic_Iteration (Process); 614 615 ------------- 616 -- Process -- 617 ------------- 618 619 procedure Process (Node : Count_Type) is 620 begin 621 Insert_With_Hint 622 (Dst_Set => Target, 623 Dst_Hint => Hint, 624 Src_Node => Source.Nodes (Node), 625 Dst_Node => Hint); 626 end Process; 627 628 -- Start of processing for Union 629 630 begin 631 if Target'Address = Source'Address then 632 return; 633 end if; 634 635 -- Per AI05-0022, the container implementation is required to detect 636 -- element tampering by a generic actual subprogram. 637 638 declare 639 Lock_Source : With_Lock (Source.TC'Unrestricted_Access); 640 begin 641 -- Note that there's no way to decide a priori whether the target has 642 -- enough capacity for the union with source. We cannot simply 643 -- compare the sum of the existing lengths to the capacity of the 644 -- target, because equivalent items from source are not included in 645 -- the union. 646 647 Iterate (Source); 648 end; 649 end Set_Union; 650 651 function Set_Union (Left, Right : Set_Type) return Set_Type is 652 begin 653 if Left'Address = Right'Address then 654 return Copy (Left); 655 end if; 656 657 if Left.Length = 0 then 658 return Copy (Right); 659 end if; 660 661 if Right.Length = 0 then 662 return Copy (Left); 663 end if; 664 665 return Result : Set_Type (Left.Length + Right.Length) do 666 declare 667 Lock_Left : With_Lock (Left.TC'Unrestricted_Access); 668 Lock_Right : With_Lock (Right.TC'Unrestricted_Access); 669 begin 670 Assign (Target => Result, Source => Left); 671 672 Insert_Right : declare 673 Hint : Count_Type := 0; 674 675 procedure Process (Node : Count_Type); 676 pragma Inline (Process); 677 678 procedure Iterate is 679 new Tree_Operations.Generic_Iteration (Process); 680 681 ------------- 682 -- Process -- 683 ------------- 684 685 procedure Process (Node : Count_Type) is 686 begin 687 Insert_With_Hint 688 (Dst_Set => Result, 689 Dst_Hint => Hint, 690 Src_Node => Right.Nodes (Node), 691 Dst_Node => Hint); 692 end Process; 693 694 -- Start of processing for Insert_Right 695 696 begin 697 Iterate (Right); 698 end Insert_Right; 699 end; 700 end return; 701 end Set_Union; 702 703end Ada.Containers.Red_Black_Trees.Generic_Bounded_Set_Operations; 704