File : a-stzunb-shared.adb


   1 ------------------------------------------------------------------------------
   2 --                                                                          --
   3 --                         GNAT RUN-TIME COMPONENTS                         --
   4 --                                                                          --
   5 --      A D A . S T R I N G S . W I D E _ W I D E _ U N B O U N D E D       --
   6 --                                                                          --
   7 --                                 B o d y                                  --
   8 --                                                                          --
   9 --          Copyright (C) 1992-2014, 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 --                                                                          --
  19 --                                                                          --
  20 --                                                                          --
  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 -- GNAT was originally developed  by the GNAT team at  New York University. --
  28 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
  29 --                                                                          --
  30 ------------------------------------------------------------------------------
  31 
  32 with Ada.Strings.Wide_Wide_Search;
  33 with Ada.Unchecked_Deallocation;
  34 
  35 package body Ada.Strings.Wide_Wide_Unbounded is
  36 
  37    use Ada.Strings.Wide_Wide_Maps;
  38 
  39    Growth_Factor : constant := 32;
  40    --  The growth factor controls how much extra space is allocated when
  41    --  we have to increase the size of an allocated unbounded string. By
  42    --  allocating extra space, we avoid the need to reallocate on every
  43    --  append, particularly important when a string is built up by repeated
  44    --  append operations of small pieces. This is expressed as a factor so
  45    --  32 means add 1/32 of the length of the string as growth space.
  46 
  47    Min_Mul_Alloc : constant := Standard'Maximum_Alignment;
  48    --  Allocation will be done by a multiple of Min_Mul_Alloc. This causes
  49    --  no memory loss as most (all?) malloc implementations are obliged to
  50    --  align the returned memory on the maximum alignment as malloc does not
  51    --  know the target alignment.
  52 
  53    function Aligned_Max_Length (Max_Length : Natural) return Natural;
  54    --  Returns recommended length of the shared string which is greater or
  55    --  equal to specified length. Calculation take in sense alignment of
  56    --  the allocated memory segments to use memory effectively by
  57    --  Append/Insert/etc operations.
  58 
  59    ---------
  60    -- "&" --
  61    ---------
  62 
  63    function "&"
  64      (Left  : Unbounded_Wide_Wide_String;
  65       Right : Unbounded_Wide_Wide_String) return Unbounded_Wide_Wide_String
  66    is
  67       LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
  68       RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
  69       DL : constant Natural := LR.Last + RR.Last;
  70       DR : Shared_Wide_Wide_String_Access;
  71 
  72    begin
  73       --  Result is an empty string, reuse shared empty string
  74 
  75       if DL = 0 then
  76          Reference (Empty_Shared_Wide_Wide_String'Access);
  77          DR := Empty_Shared_Wide_Wide_String'Access;
  78 
  79       --  Left string is empty, return Rigth string
  80 
  81       elsif LR.Last = 0 then
  82          Reference (RR);
  83          DR := RR;
  84 
  85       --  Right string is empty, return Left string
  86 
  87       elsif RR.Last = 0 then
  88          Reference (LR);
  89          DR := LR;
  90 
  91       --  Overwise, allocate new shared string and fill data
  92 
  93       else
  94          DR := Allocate (DL);
  95          DR.Data (1 .. LR.Last) := LR.Data (1 .. LR.Last);
  96          DR.Data (LR.Last + 1 .. DL) := RR.Data (1 .. RR.Last);
  97          DR.Last := DL;
  98       end if;
  99 
 100       return (AF.Controlled with Reference => DR);
 101    end "&";
 102 
 103    function "&"
 104      (Left  : Unbounded_Wide_Wide_String;
 105       Right : Wide_Wide_String) return Unbounded_Wide_Wide_String
 106    is
 107       LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
 108       DL : constant Natural := LR.Last + Right'Length;
 109       DR : Shared_Wide_Wide_String_Access;
 110 
 111    begin
 112       --  Result is an empty string, reuse shared empty string
 113 
 114       if DL = 0 then
 115          Reference (Empty_Shared_Wide_Wide_String'Access);
 116          DR := Empty_Shared_Wide_Wide_String'Access;
 117 
 118       --  Right is an empty string, return Left string
 119 
 120       elsif Right'Length = 0 then
 121          Reference (LR);
 122          DR := LR;
 123 
 124       --  Otherwise, allocate new shared string and fill it
 125 
 126       else
 127          DR := Allocate (DL);
 128          DR.Data (1 .. LR.Last) := LR.Data (1 .. LR.Last);
 129          DR.Data (LR.Last + 1 .. DL) := Right;
 130          DR.Last := DL;
 131       end if;
 132 
 133       return (AF.Controlled with Reference => DR);
 134    end "&";
 135 
 136    function "&"
 137      (Left  : Wide_Wide_String;
 138       Right : Unbounded_Wide_Wide_String) return Unbounded_Wide_Wide_String
 139    is
 140       RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
 141       DL : constant Natural := Left'Length + RR.Last;
 142       DR : Shared_Wide_Wide_String_Access;
 143 
 144    begin
 145       --  Result is an empty string, reuse shared one
 146 
 147       if DL = 0 then
 148          Reference (Empty_Shared_Wide_Wide_String'Access);
 149          DR := Empty_Shared_Wide_Wide_String'Access;
 150 
 151       --  Left is empty string, return Right string
 152 
 153       elsif Left'Length = 0 then
 154          Reference (RR);
 155          DR := RR;
 156 
 157       --  Otherwise, allocate new shared string and fill it
 158 
 159       else
 160          DR := Allocate (DL);
 161          DR.Data (1 .. Left'Length) := Left;
 162          DR.Data (Left'Length + 1 .. DL) := RR.Data (1 .. RR.Last);
 163          DR.Last := DL;
 164       end if;
 165 
 166       return (AF.Controlled with Reference => DR);
 167    end "&";
 168 
 169    function "&"
 170      (Left  : Unbounded_Wide_Wide_String;
 171       Right : Wide_Wide_Character) return Unbounded_Wide_Wide_String
 172    is
 173       LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
 174       DL : constant Natural := LR.Last + 1;
 175       DR : Shared_Wide_Wide_String_Access;
 176 
 177    begin
 178       DR := Allocate (DL);
 179       DR.Data (1 .. LR.Last) := LR.Data (1 .. LR.Last);
 180       DR.Data (DL) := Right;
 181       DR.Last := DL;
 182 
 183       return (AF.Controlled with Reference => DR);
 184    end "&";
 185 
 186    function "&"
 187      (Left  : Wide_Wide_Character;
 188       Right : Unbounded_Wide_Wide_String) return Unbounded_Wide_Wide_String
 189    is
 190       RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
 191       DL : constant Natural := 1 + RR.Last;
 192       DR : Shared_Wide_Wide_String_Access;
 193 
 194    begin
 195       DR := Allocate (DL);
 196       DR.Data (1) := Left;
 197       DR.Data (2 .. DL) := RR.Data (1 .. RR.Last);
 198       DR.Last := DL;
 199 
 200       return (AF.Controlled with Reference => DR);
 201    end "&";
 202 
 203    ---------
 204    -- "*" --
 205    ---------
 206 
 207    function "*"
 208      (Left  : Natural;
 209       Right : Wide_Wide_Character) return Unbounded_Wide_Wide_String
 210    is
 211       DR : Shared_Wide_Wide_String_Access;
 212 
 213    begin
 214       --  Result is an empty string, reuse shared empty string
 215 
 216       if Left = 0 then
 217          Reference (Empty_Shared_Wide_Wide_String'Access);
 218          DR := Empty_Shared_Wide_Wide_String'Access;
 219 
 220       --  Otherwise, allocate new shared string and fill it
 221 
 222       else
 223          DR := Allocate (Left);
 224 
 225          for J in 1 .. Left loop
 226             DR.Data (J) := Right;
 227          end loop;
 228 
 229          DR.Last := Left;
 230       end if;
 231 
 232       return (AF.Controlled with Reference => DR);
 233    end "*";
 234 
 235    function "*"
 236      (Left  : Natural;
 237       Right : Wide_Wide_String) return Unbounded_Wide_Wide_String
 238    is
 239       DL : constant Natural := Left * Right'Length;
 240       DR : Shared_Wide_Wide_String_Access;
 241       K  : Positive;
 242 
 243    begin
 244       --  Result is an empty string, reuse shared empty string
 245 
 246       if DL = 0 then
 247          Reference (Empty_Shared_Wide_Wide_String'Access);
 248          DR := Empty_Shared_Wide_Wide_String'Access;
 249 
 250       --  Otherwise, allocate new shared string and fill it
 251 
 252       else
 253          DR := Allocate (DL);
 254          K := 1;
 255 
 256          for J in 1 .. Left loop
 257             DR.Data (K .. K + Right'Length - 1) := Right;
 258             K := K + Right'Length;
 259          end loop;
 260 
 261          DR.Last := DL;
 262       end if;
 263 
 264       return (AF.Controlled with Reference => DR);
 265    end "*";
 266 
 267    function "*"
 268      (Left  : Natural;
 269       Right : Unbounded_Wide_Wide_String) return Unbounded_Wide_Wide_String
 270    is
 271       RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
 272       DL : constant Natural := Left * RR.Last;
 273       DR : Shared_Wide_Wide_String_Access;
 274       K  : Positive;
 275 
 276    begin
 277       --  Result is an empty string, reuse shared empty string
 278 
 279       if DL = 0 then
 280          Reference (Empty_Shared_Wide_Wide_String'Access);
 281          DR := Empty_Shared_Wide_Wide_String'Access;
 282 
 283       --  Coefficient is one, just return string itself
 284 
 285       elsif Left = 1 then
 286          Reference (RR);
 287          DR := RR;
 288 
 289       --  Otherwise, allocate new shared string and fill it
 290 
 291       else
 292          DR := Allocate (DL);
 293          K := 1;
 294 
 295          for J in 1 .. Left loop
 296             DR.Data (K .. K + RR.Last - 1) := RR.Data (1 .. RR.Last);
 297             K := K + RR.Last;
 298          end loop;
 299 
 300          DR.Last := DL;
 301       end if;
 302 
 303       return (AF.Controlled with Reference => DR);
 304    end "*";
 305 
 306    ---------
 307    -- "<" --
 308    ---------
 309 
 310    function "<"
 311      (Left  : Unbounded_Wide_Wide_String;
 312       Right : Unbounded_Wide_Wide_String) return Boolean
 313    is
 314       LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
 315       RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
 316    begin
 317       return LR.Data (1 .. LR.Last) < RR.Data (1 .. RR.Last);
 318    end "<";
 319 
 320    function "<"
 321      (Left  : Unbounded_Wide_Wide_String;
 322       Right : Wide_Wide_String) return Boolean
 323    is
 324       LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
 325    begin
 326       return LR.Data (1 .. LR.Last) < Right;
 327    end "<";
 328 
 329    function "<"
 330      (Left  : Wide_Wide_String;
 331       Right : Unbounded_Wide_Wide_String) return Boolean
 332    is
 333       RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
 334    begin
 335       return Left < RR.Data (1 .. RR.Last);
 336    end "<";
 337 
 338    ----------
 339    -- "<=" --
 340    ----------
 341 
 342    function "<="
 343      (Left  : Unbounded_Wide_Wide_String;
 344       Right : Unbounded_Wide_Wide_String) return Boolean
 345    is
 346       LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
 347       RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
 348 
 349    begin
 350       --  LR = RR means two strings shares shared string, thus they are equal
 351 
 352       return LR = RR or else LR.Data (1 .. LR.Last) <= RR.Data (1 .. RR.Last);
 353    end "<=";
 354 
 355    function "<="
 356      (Left  : Unbounded_Wide_Wide_String;
 357       Right : Wide_Wide_String) return Boolean
 358    is
 359       LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
 360    begin
 361       return LR.Data (1 .. LR.Last) <= Right;
 362    end "<=";
 363 
 364    function "<="
 365      (Left  : Wide_Wide_String;
 366       Right : Unbounded_Wide_Wide_String) return Boolean
 367    is
 368       RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
 369    begin
 370       return Left <= RR.Data (1 .. RR.Last);
 371    end "<=";
 372 
 373    ---------
 374    -- "=" --
 375    ---------
 376 
 377    function "="
 378      (Left  : Unbounded_Wide_Wide_String;
 379       Right : Unbounded_Wide_Wide_String) return Boolean
 380    is
 381       LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
 382       RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
 383 
 384    begin
 385       return LR = RR or else LR.Data (1 .. LR.Last) = RR.Data (1 .. RR.Last);
 386       --  LR = RR means two strings shares shared string, thus they are equal
 387    end "=";
 388 
 389    function "="
 390      (Left  : Unbounded_Wide_Wide_String;
 391       Right : Wide_Wide_String) return Boolean
 392    is
 393       LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
 394    begin
 395       return LR.Data (1 .. LR.Last) = Right;
 396    end "=";
 397 
 398    function "="
 399      (Left  : Wide_Wide_String;
 400       Right : Unbounded_Wide_Wide_String) return Boolean
 401    is
 402       RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
 403    begin
 404       return Left = RR.Data (1 .. RR.Last);
 405    end "=";
 406 
 407    ---------
 408    -- ">" --
 409    ---------
 410 
 411    function ">"
 412      (Left  : Unbounded_Wide_Wide_String;
 413       Right : Unbounded_Wide_Wide_String) return Boolean
 414    is
 415       LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
 416       RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
 417    begin
 418       return LR.Data (1 .. LR.Last) > RR.Data (1 .. RR.Last);
 419    end ">";
 420 
 421    function ">"
 422      (Left  : Unbounded_Wide_Wide_String;
 423       Right : Wide_Wide_String) return Boolean
 424    is
 425       LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
 426    begin
 427       return LR.Data (1 .. LR.Last) > Right;
 428    end ">";
 429 
 430    function ">"
 431      (Left  : Wide_Wide_String;
 432       Right : Unbounded_Wide_Wide_String) return Boolean
 433    is
 434       RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
 435    begin
 436       return Left > RR.Data (1 .. RR.Last);
 437    end ">";
 438 
 439    ----------
 440    -- ">=" --
 441    ----------
 442 
 443    function ">="
 444      (Left  : Unbounded_Wide_Wide_String;
 445       Right : Unbounded_Wide_Wide_String) return Boolean
 446    is
 447       LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
 448       RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
 449 
 450    begin
 451       --  LR = RR means two strings shares shared string, thus they are equal
 452 
 453       return LR = RR or else LR.Data (1 .. LR.Last) >= RR.Data (1 .. RR.Last);
 454    end ">=";
 455 
 456    function ">="
 457      (Left  : Unbounded_Wide_Wide_String;
 458       Right : Wide_Wide_String) return Boolean
 459    is
 460       LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
 461    begin
 462       return LR.Data (1 .. LR.Last) >= Right;
 463    end ">=";
 464 
 465    function ">="
 466      (Left  : Wide_Wide_String;
 467       Right : Unbounded_Wide_Wide_String) return Boolean
 468    is
 469       RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
 470    begin
 471       return Left >= RR.Data (1 .. RR.Last);
 472    end ">=";
 473 
 474    ------------
 475    -- Adjust --
 476    ------------
 477 
 478    procedure Adjust (Object : in out Unbounded_Wide_Wide_String) is
 479    begin
 480       Reference (Object.Reference);
 481    end Adjust;
 482 
 483    ------------------------
 484    -- Aligned_Max_Length --
 485    ------------------------
 486 
 487    function Aligned_Max_Length (Max_Length : Natural) return Natural is
 488       Static_Size  : constant Natural :=
 489         Empty_Shared_Wide_Wide_String'Size / Standard'Storage_Unit;
 490       --  Total size of all static components
 491 
 492       Element_Size : constant Natural :=
 493         Wide_Wide_Character'Size / Standard'Storage_Unit;
 494 
 495    begin
 496       return
 497         (((Static_Size + Max_Length * Element_Size - 1) / Min_Mul_Alloc + 2)
 498           * Min_Mul_Alloc - Static_Size) / Element_Size;
 499    end Aligned_Max_Length;
 500 
 501    --------------
 502    -- Allocate --
 503    --------------
 504 
 505    function Allocate
 506      (Max_Length : Natural) return Shared_Wide_Wide_String_Access is
 507    begin
 508       --  Empty string requested, return shared empty string
 509 
 510       if Max_Length = 0 then
 511          Reference (Empty_Shared_Wide_Wide_String'Access);
 512          return Empty_Shared_Wide_Wide_String'Access;
 513 
 514       --  Otherwise, allocate requested space (and probably some more room)
 515 
 516       else
 517          return new Shared_Wide_Wide_String (Aligned_Max_Length (Max_Length));
 518       end if;
 519    end Allocate;
 520 
 521    ------------
 522    -- Append --
 523    ------------
 524 
 525    procedure Append
 526      (Source   : in out Unbounded_Wide_Wide_String;
 527       New_Item : Unbounded_Wide_Wide_String)
 528    is
 529       SR  : constant Shared_Wide_Wide_String_Access := Source.Reference;
 530       NR  : constant Shared_Wide_Wide_String_Access := New_Item.Reference;
 531       DL  : constant Natural              := SR.Last + NR.Last;
 532       DR  : Shared_Wide_Wide_String_Access;
 533 
 534    begin
 535       --  Source is an empty string, reuse New_Item data
 536 
 537       if SR.Last = 0 then
 538          Reference (NR);
 539          Source.Reference := NR;
 540          Unreference (SR);
 541 
 542       --  New_Item is empty string, nothing to do
 543 
 544       elsif NR.Last = 0 then
 545          null;
 546 
 547       --  Try to reuse existent shared string
 548 
 549       elsif Can_Be_Reused (SR, DL) then
 550          SR.Data (SR.Last + 1 .. DL) := NR.Data (1 .. NR.Last);
 551          SR.Last := DL;
 552 
 553       --  Otherwise, allocate new one and fill it
 554 
 555       else
 556          DR := Allocate (DL + DL / Growth_Factor);
 557          DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
 558          DR.Data (SR.Last + 1 .. DL) := NR.Data (1 .. NR.Last);
 559          DR.Last := DL;
 560          Source.Reference := DR;
 561          Unreference (SR);
 562       end if;
 563    end Append;
 564 
 565    procedure Append
 566      (Source   : in out Unbounded_Wide_Wide_String;
 567       New_Item : Wide_Wide_String)
 568    is
 569       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
 570       DL : constant Natural := SR.Last + New_Item'Length;
 571       DR : Shared_Wide_Wide_String_Access;
 572 
 573    begin
 574       --  New_Item is an empty string, nothing to do
 575 
 576       if New_Item'Length = 0 then
 577          null;
 578 
 579       --  Try to reuse existing shared string
 580 
 581       elsif Can_Be_Reused (SR, DL) then
 582          SR.Data (SR.Last + 1 .. DL) := New_Item;
 583          SR.Last := DL;
 584 
 585       --  Otherwise, allocate new one and fill it
 586 
 587       else
 588          DR := Allocate (DL + DL / Growth_Factor);
 589          DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
 590          DR.Data (SR.Last + 1 .. DL) := New_Item;
 591          DR.Last := DL;
 592          Source.Reference := DR;
 593          Unreference (SR);
 594       end if;
 595    end Append;
 596 
 597    procedure Append
 598      (Source   : in out Unbounded_Wide_Wide_String;
 599       New_Item : Wide_Wide_Character)
 600    is
 601       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
 602       DL : constant Natural := SR.Last + 1;
 603       DR : Shared_Wide_Wide_String_Access;
 604 
 605    begin
 606       --  Try to reuse existing shared string
 607 
 608       if Can_Be_Reused (SR, SR.Last + 1) then
 609          SR.Data (SR.Last + 1) := New_Item;
 610          SR.Last := SR.Last + 1;
 611 
 612       --  Otherwise, allocate new one and fill it
 613 
 614       else
 615          DR := Allocate (DL + DL / Growth_Factor);
 616          DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
 617          DR.Data (DL) := New_Item;
 618          DR.Last := DL;
 619          Source.Reference := DR;
 620          Unreference (SR);
 621       end if;
 622    end Append;
 623 
 624    -------------------
 625    -- Can_Be_Reused --
 626    -------------------
 627 
 628    function Can_Be_Reused
 629      (Item   : Shared_Wide_Wide_String_Access;
 630       Length : Natural) return Boolean is
 631    begin
 632       return
 633         System.Atomic_Counters.Is_One (Item.Counter)
 634           and then Item.Max_Length >= Length
 635           and then Item.Max_Length <=
 636                      Aligned_Max_Length (Length + Length / Growth_Factor);
 637    end Can_Be_Reused;
 638 
 639    -----------
 640    -- Count --
 641    -----------
 642 
 643    function Count
 644      (Source  : Unbounded_Wide_Wide_String;
 645       Pattern : Wide_Wide_String;
 646       Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping :=
 647         Wide_Wide_Maps.Identity) return Natural
 648    is
 649       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
 650    begin
 651       return Wide_Wide_Search.Count (SR.Data (1 .. SR.Last), Pattern, Mapping);
 652    end Count;
 653 
 654    function Count
 655      (Source  : Unbounded_Wide_Wide_String;
 656       Pattern : Wide_Wide_String;
 657       Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
 658       return Natural
 659    is
 660       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
 661    begin
 662       return Wide_Wide_Search.Count (SR.Data (1 .. SR.Last), Pattern, Mapping);
 663    end Count;
 664 
 665    function Count
 666      (Source : Unbounded_Wide_Wide_String;
 667       Set    : Wide_Wide_Maps.Wide_Wide_Character_Set) return Natural
 668    is
 669       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
 670    begin
 671       return Wide_Wide_Search.Count (SR.Data (1 .. SR.Last), Set);
 672    end Count;
 673 
 674    ------------
 675    -- Delete --
 676    ------------
 677 
 678    function Delete
 679      (Source  : Unbounded_Wide_Wide_String;
 680       From    : Positive;
 681       Through : Natural) return Unbounded_Wide_Wide_String
 682    is
 683       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
 684       DL : Natural;
 685       DR : Shared_Wide_Wide_String_Access;
 686 
 687    begin
 688       --  Empty slice is deleted, use the same shared string
 689 
 690       if From > Through then
 691          Reference (SR);
 692          DR := SR;
 693 
 694       --  Index is out of range
 695 
 696       elsif Through > SR.Last then
 697          raise Index_Error;
 698 
 699       --  Compute size of the result
 700 
 701       else
 702          DL := SR.Last - (Through - From + 1);
 703 
 704          --  Result is an empty string, reuse shared empty string
 705 
 706          if DL = 0 then
 707             Reference (Empty_Shared_Wide_Wide_String'Access);
 708             DR := Empty_Shared_Wide_Wide_String'Access;
 709 
 710          --  Otherwise, allocate new shared string and fill it
 711 
 712          else
 713             DR := Allocate (DL);
 714             DR.Data (1 .. From - 1) := SR.Data (1 .. From - 1);
 715             DR.Data (From .. DL) := SR.Data (Through + 1 .. SR.Last);
 716             DR.Last := DL;
 717          end if;
 718       end if;
 719 
 720       return (AF.Controlled with Reference => DR);
 721    end Delete;
 722 
 723    procedure Delete
 724      (Source  : in out Unbounded_Wide_Wide_String;
 725       From    : Positive;
 726       Through : Natural)
 727    is
 728       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
 729       DL : Natural;
 730       DR : Shared_Wide_Wide_String_Access;
 731 
 732    begin
 733       --  Nothing changed, return
 734 
 735       if From > Through then
 736          null;
 737 
 738       --  Through is outside of the range
 739 
 740       elsif Through > SR.Last then
 741          raise Index_Error;
 742 
 743       else
 744          DL := SR.Last - (Through - From + 1);
 745 
 746          --  Result is empty, reuse shared empty string
 747 
 748          if DL = 0 then
 749             Reference (Empty_Shared_Wide_Wide_String'Access);
 750             Source.Reference := Empty_Shared_Wide_Wide_String'Access;
 751             Unreference (SR);
 752 
 753          --  Try to reuse existent shared string
 754 
 755          elsif Can_Be_Reused (SR, DL) then
 756             SR.Data (From .. DL) := SR.Data (Through + 1 .. SR.Last);
 757             SR.Last := DL;
 758 
 759          --  Otherwise, allocate new shared string
 760 
 761          else
 762             DR := Allocate (DL);
 763             DR.Data (1 .. From - 1) := SR.Data (1 .. From - 1);
 764             DR.Data (From .. DL) := SR.Data (Through + 1 .. SR.Last);
 765             DR.Last := DL;
 766             Source.Reference := DR;
 767             Unreference (SR);
 768          end if;
 769       end if;
 770    end Delete;
 771 
 772    -------------
 773    -- Element --
 774    -------------
 775 
 776    function Element
 777      (Source : Unbounded_Wide_Wide_String;
 778       Index  : Positive) return Wide_Wide_Character
 779    is
 780       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
 781    begin
 782       if Index <= SR.Last then
 783          return SR.Data (Index);
 784       else
 785          raise Index_Error;
 786       end if;
 787    end Element;
 788 
 789    --------------
 790    -- Finalize --
 791    --------------
 792 
 793    procedure Finalize (Object : in out Unbounded_Wide_Wide_String) is
 794       SR : constant Shared_Wide_Wide_String_Access := Object.Reference;
 795 
 796    begin
 797       if SR /= null then
 798 
 799          --  The same controlled object can be finalized several times for
 800          --  some reason. As per 7.6.1(24) this should have no ill effect,
 801          --  so we need to add a guard for the case of finalizing the same
 802          --  object twice.
 803 
 804          Object.Reference := null;
 805          Unreference (SR);
 806       end if;
 807    end Finalize;
 808 
 809    ----------------
 810    -- Find_Token --
 811    ----------------
 812 
 813    procedure Find_Token
 814      (Source : Unbounded_Wide_Wide_String;
 815       Set    : Wide_Wide_Maps.Wide_Wide_Character_Set;
 816       From   : Positive;
 817       Test   : Strings.Membership;
 818       First  : out Positive;
 819       Last   : out Natural)
 820    is
 821       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
 822    begin
 823       Wide_Wide_Search.Find_Token
 824         (SR.Data (From .. SR.Last), Set, Test, First, Last);
 825    end Find_Token;
 826 
 827    procedure Find_Token
 828      (Source : Unbounded_Wide_Wide_String;
 829       Set    : Wide_Wide_Maps.Wide_Wide_Character_Set;
 830       Test   : Strings.Membership;
 831       First  : out Positive;
 832       Last   : out Natural)
 833    is
 834       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
 835    begin
 836       Wide_Wide_Search.Find_Token
 837         (SR.Data (1 .. SR.Last), Set, Test, First, Last);
 838    end Find_Token;
 839 
 840    ----------
 841    -- Free --
 842    ----------
 843 
 844    procedure Free (X : in out Wide_Wide_String_Access) is
 845       procedure Deallocate is
 846          new Ada.Unchecked_Deallocation
 847                (Wide_Wide_String, Wide_Wide_String_Access);
 848    begin
 849       Deallocate (X);
 850    end Free;
 851 
 852    ----------
 853    -- Head --
 854    ----------
 855 
 856    function Head
 857      (Source : Unbounded_Wide_Wide_String;
 858       Count  : Natural;
 859       Pad    : Wide_Wide_Character := Wide_Wide_Space)
 860       return Unbounded_Wide_Wide_String
 861    is
 862       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
 863       DR : Shared_Wide_Wide_String_Access;
 864 
 865    begin
 866       --  Result is empty, reuse shared empty string
 867 
 868       if Count = 0 then
 869          Reference (Empty_Shared_Wide_Wide_String'Access);
 870          DR := Empty_Shared_Wide_Wide_String'Access;
 871 
 872       --  Length of the string is the same as requested, reuse source shared
 873       --  string.
 874 
 875       elsif Count = SR.Last then
 876          Reference (SR);
 877          DR := SR;
 878 
 879       --  Otherwise, allocate new shared string and fill it
 880 
 881       else
 882          DR := Allocate (Count);
 883 
 884          --  Length of the source string is more than requested, copy
 885          --  corresponding slice.
 886 
 887          if Count < SR.Last then
 888             DR.Data (1 .. Count) := SR.Data (1 .. Count);
 889 
 890          --  Length of the source string is less than requested, copy all
 891          --  contents and fill others by Pad character.
 892 
 893          else
 894             DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
 895 
 896             for J in SR.Last + 1 .. Count loop
 897                DR.Data (J) := Pad;
 898             end loop;
 899          end if;
 900 
 901          DR.Last := Count;
 902       end if;
 903 
 904       return (AF.Controlled with Reference => DR);
 905    end Head;
 906 
 907    procedure Head
 908      (Source : in out Unbounded_Wide_Wide_String;
 909       Count  : Natural;
 910       Pad    : Wide_Wide_Character := Wide_Wide_Space)
 911    is
 912       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
 913       DR : Shared_Wide_Wide_String_Access;
 914 
 915    begin
 916       --  Result is empty, reuse empty shared string
 917 
 918       if Count = 0 then
 919          Reference (Empty_Shared_Wide_Wide_String'Access);
 920          Source.Reference := Empty_Shared_Wide_Wide_String'Access;
 921          Unreference (SR);
 922 
 923       --  Result is same with source string, reuse source shared string
 924 
 925       elsif Count = SR.Last then
 926          null;
 927 
 928       --  Try to reuse existent shared string
 929 
 930       elsif Can_Be_Reused (SR, Count) then
 931          if Count > SR.Last then
 932             for J in SR.Last + 1 .. Count loop
 933                SR.Data (J) := Pad;
 934             end loop;
 935          end if;
 936 
 937          SR.Last := Count;
 938 
 939       --  Otherwise, allocate new shared string and fill it
 940 
 941       else
 942          DR := Allocate (Count);
 943 
 944          --  Length of the source string is greater than requested, copy
 945          --  corresponding slice.
 946 
 947          if Count < SR.Last then
 948             DR.Data (1 .. Count) := SR.Data (1 .. Count);
 949 
 950          --  Length of the source string is less than requested, copy all
 951          --  exists data and fill others by Pad character.
 952 
 953          else
 954             DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
 955 
 956             for J in SR.Last + 1 .. Count loop
 957                DR.Data (J) := Pad;
 958             end loop;
 959          end if;
 960 
 961          DR.Last := Count;
 962          Source.Reference := DR;
 963          Unreference (SR);
 964       end if;
 965    end Head;
 966 
 967    -----------
 968    -- Index --
 969    -----------
 970 
 971    function Index
 972      (Source  : Unbounded_Wide_Wide_String;
 973       Pattern : Wide_Wide_String;
 974       Going   : Strings.Direction := Strings.Forward;
 975       Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping :=
 976         Wide_Wide_Maps.Identity) return Natural
 977    is
 978       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
 979    begin
 980       return Wide_Wide_Search.Index
 981         (SR.Data (1 .. SR.Last), Pattern, Going, Mapping);
 982    end Index;
 983 
 984    function Index
 985      (Source  : Unbounded_Wide_Wide_String;
 986       Pattern : Wide_Wide_String;
 987       Going   : Direction := Forward;
 988       Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
 989       return Natural
 990    is
 991       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
 992    begin
 993       return Wide_Wide_Search.Index
 994         (SR.Data (1 .. SR.Last), Pattern, Going, Mapping);
 995    end Index;
 996 
 997    function Index
 998      (Source : Unbounded_Wide_Wide_String;
 999       Set    : Wide_Wide_Maps.Wide_Wide_Character_Set;
1000       Test   : Strings.Membership := Strings.Inside;
1001       Going  : Strings.Direction  := Strings.Forward) return Natural
1002    is
1003       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1004    begin
1005       return Wide_Wide_Search.Index (SR.Data (1 .. SR.Last), Set, Test, Going);
1006    end Index;
1007 
1008    function Index
1009      (Source  : Unbounded_Wide_Wide_String;
1010       Pattern : Wide_Wide_String;
1011       From    : Positive;
1012       Going   : Direction := Forward;
1013       Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping :=
1014         Wide_Wide_Maps.Identity) return Natural
1015    is
1016       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1017    begin
1018       return Wide_Wide_Search.Index
1019         (SR.Data (1 .. SR.Last), Pattern, From, Going, Mapping);
1020    end Index;
1021 
1022    function Index
1023      (Source  : Unbounded_Wide_Wide_String;
1024       Pattern : Wide_Wide_String;
1025       From    : Positive;
1026       Going   : Direction := Forward;
1027       Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
1028       return Natural
1029    is
1030       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1031    begin
1032       return Wide_Wide_Search.Index
1033         (SR.Data (1 .. SR.Last), Pattern, From, Going, Mapping);
1034    end Index;
1035 
1036    function Index
1037      (Source  : Unbounded_Wide_Wide_String;
1038       Set     : Wide_Wide_Maps.Wide_Wide_Character_Set;
1039       From    : Positive;
1040       Test    : Membership := Inside;
1041       Going   : Direction := Forward) return Natural
1042    is
1043       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1044    begin
1045       return Wide_Wide_Search.Index
1046         (SR.Data (1 .. SR.Last), Set, From, Test, Going);
1047    end Index;
1048 
1049    ---------------------
1050    -- Index_Non_Blank --
1051    ---------------------
1052 
1053    function Index_Non_Blank
1054      (Source : Unbounded_Wide_Wide_String;
1055       Going  : Strings.Direction := Strings.Forward) return Natural
1056    is
1057       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1058    begin
1059       return Wide_Wide_Search.Index_Non_Blank (SR.Data (1 .. SR.Last), Going);
1060    end Index_Non_Blank;
1061 
1062    function Index_Non_Blank
1063      (Source : Unbounded_Wide_Wide_String;
1064       From   : Positive;
1065       Going  : Direction := Forward) return Natural
1066    is
1067       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1068    begin
1069       return Wide_Wide_Search.Index_Non_Blank
1070         (SR.Data (1 .. SR.Last), From, Going);
1071    end Index_Non_Blank;
1072 
1073    ----------------
1074    -- Initialize --
1075    ----------------
1076 
1077    procedure Initialize (Object : in out Unbounded_Wide_Wide_String) is
1078    begin
1079       Reference (Object.Reference);
1080    end Initialize;
1081 
1082    ------------
1083    -- Insert --
1084    ------------
1085 
1086    function Insert
1087      (Source   : Unbounded_Wide_Wide_String;
1088       Before   : Positive;
1089       New_Item : Wide_Wide_String) return Unbounded_Wide_Wide_String
1090    is
1091       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1092       DL : constant Natural := SR.Last + New_Item'Length;
1093       DR : Shared_Wide_Wide_String_Access;
1094 
1095    begin
1096       --  Check index first
1097 
1098       if Before > SR.Last + 1 then
1099          raise Index_Error;
1100       end if;
1101 
1102       --  Result is empty, reuse empty shared string
1103 
1104       if DL = 0 then
1105          Reference (Empty_Shared_Wide_Wide_String'Access);
1106          DR := Empty_Shared_Wide_Wide_String'Access;
1107 
1108       --  Inserted string is empty, reuse source shared string
1109 
1110       elsif New_Item'Length = 0 then
1111          Reference (SR);
1112          DR := SR;
1113 
1114       --  Otherwise, allocate new shared string and fill it
1115 
1116       else
1117          DR := Allocate (DL + DL / Growth_Factor);
1118          DR.Data (1 .. Before - 1) := SR.Data (1 .. Before - 1);
1119          DR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1120          DR.Data (Before + New_Item'Length .. DL) :=
1121            SR.Data (Before .. SR.Last);
1122          DR.Last := DL;
1123       end if;
1124 
1125       return (AF.Controlled with Reference => DR);
1126    end Insert;
1127 
1128    procedure Insert
1129      (Source   : in out Unbounded_Wide_Wide_String;
1130       Before   : Positive;
1131       New_Item : Wide_Wide_String)
1132    is
1133       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1134       DL : constant Natural := SR.Last + New_Item'Length;
1135       DR : Shared_Wide_Wide_String_Access;
1136 
1137    begin
1138       --  Check bounds
1139 
1140       if Before > SR.Last + 1 then
1141          raise Index_Error;
1142       end if;
1143 
1144       --  Result is empty string, reuse empty shared string
1145 
1146       if DL = 0 then
1147          Reference (Empty_Shared_Wide_Wide_String'Access);
1148          Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1149          Unreference (SR);
1150 
1151       --  Inserted string is empty, nothing to do
1152 
1153       elsif New_Item'Length = 0 then
1154          null;
1155 
1156       --  Try to reuse existent shared string first
1157 
1158       elsif Can_Be_Reused (SR, DL) then
1159          SR.Data (Before + New_Item'Length .. DL) :=
1160            SR.Data (Before .. SR.Last);
1161          SR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1162          SR.Last := DL;
1163 
1164       --  Otherwise, allocate new shared string and fill it
1165 
1166       else
1167          DR := Allocate (DL + DL / Growth_Factor);
1168          DR.Data (1 .. Before - 1) := SR.Data (1 .. Before - 1);
1169          DR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1170          DR.Data (Before + New_Item'Length .. DL) :=
1171            SR.Data (Before .. SR.Last);
1172          DR.Last := DL;
1173          Source.Reference := DR;
1174          Unreference (SR);
1175       end if;
1176    end Insert;
1177 
1178    ------------
1179    -- Length --
1180    ------------
1181 
1182    function Length (Source : Unbounded_Wide_Wide_String) return Natural is
1183    begin
1184       return Source.Reference.Last;
1185    end Length;
1186 
1187    ---------------
1188    -- Overwrite --
1189    ---------------
1190 
1191    function Overwrite
1192      (Source   : Unbounded_Wide_Wide_String;
1193       Position : Positive;
1194       New_Item : Wide_Wide_String) return Unbounded_Wide_Wide_String
1195    is
1196       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1197       DL : Natural;
1198       DR : Shared_Wide_Wide_String_Access;
1199 
1200    begin
1201       --  Check bounds
1202 
1203       if Position > SR.Last + 1 then
1204          raise Index_Error;
1205       end if;
1206 
1207       DL := Integer'Max (SR.Last, Position + New_Item'Length - 1);
1208 
1209       --  Result is empty string, reuse empty shared string
1210 
1211       if DL = 0 then
1212          Reference (Empty_Shared_Wide_Wide_String'Access);
1213          DR := Empty_Shared_Wide_Wide_String'Access;
1214 
1215       --  Result is same with source string, reuse source shared string
1216 
1217       elsif New_Item'Length = 0 then
1218          Reference (SR);
1219          DR := SR;
1220 
1221       --  Otherwise, allocate new shared string and fill it
1222 
1223       else
1224          DR := Allocate (DL);
1225          DR.Data (1 .. Position - 1) := SR.Data (1 .. Position - 1);
1226          DR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1227          DR.Data (Position + New_Item'Length .. DL) :=
1228            SR.Data (Position + New_Item'Length .. SR.Last);
1229          DR.Last := DL;
1230       end if;
1231 
1232       return (AF.Controlled with Reference => DR);
1233    end Overwrite;
1234 
1235    procedure Overwrite
1236      (Source    : in out Unbounded_Wide_Wide_String;
1237       Position  : Positive;
1238       New_Item  : Wide_Wide_String)
1239    is
1240       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1241       DL : Natural;
1242       DR : Shared_Wide_Wide_String_Access;
1243 
1244    begin
1245       --  Bounds check
1246 
1247       if Position > SR.Last + 1 then
1248          raise Index_Error;
1249       end if;
1250 
1251       DL := Integer'Max (SR.Last, Position + New_Item'Length - 1);
1252 
1253       --  Result is empty string, reuse empty shared string
1254 
1255       if DL = 0 then
1256          Reference (Empty_Shared_Wide_Wide_String'Access);
1257          Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1258          Unreference (SR);
1259 
1260       --  String unchanged, nothing to do
1261 
1262       elsif New_Item'Length = 0 then
1263          null;
1264 
1265       --  Try to reuse existent shared string
1266 
1267       elsif Can_Be_Reused (SR, DL) then
1268          SR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1269          SR.Last := DL;
1270 
1271       --  Otherwise allocate new shared string and fill it
1272 
1273       else
1274          DR := Allocate (DL);
1275          DR.Data (1 .. Position - 1) := SR.Data (1 .. Position - 1);
1276          DR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1277          DR.Data (Position + New_Item'Length .. DL) :=
1278            SR.Data (Position + New_Item'Length .. SR.Last);
1279          DR.Last := DL;
1280          Source.Reference := DR;
1281          Unreference (SR);
1282       end if;
1283    end Overwrite;
1284 
1285    ---------------
1286    -- Reference --
1287    ---------------
1288 
1289    procedure Reference (Item : not null Shared_Wide_Wide_String_Access) is
1290    begin
1291       System.Atomic_Counters.Increment (Item.Counter);
1292    end Reference;
1293 
1294    ---------------------
1295    -- Replace_Element --
1296    ---------------------
1297 
1298    procedure Replace_Element
1299      (Source : in out Unbounded_Wide_Wide_String;
1300       Index  : Positive;
1301       By     : Wide_Wide_Character)
1302    is
1303       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1304       DR : Shared_Wide_Wide_String_Access;
1305 
1306    begin
1307       --  Bounds check
1308 
1309       if Index <= SR.Last then
1310 
1311          --  Try to reuse existent shared string
1312 
1313          if Can_Be_Reused (SR, SR.Last) then
1314             SR.Data (Index) := By;
1315 
1316          --  Otherwise allocate new shared string and fill it
1317 
1318          else
1319             DR := Allocate (SR.Last);
1320             DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
1321             DR.Data (Index) := By;
1322             DR.Last := SR.Last;
1323             Source.Reference := DR;
1324             Unreference (SR);
1325          end if;
1326 
1327       else
1328          raise Index_Error;
1329       end if;
1330    end Replace_Element;
1331 
1332    -------------------
1333    -- Replace_Slice --
1334    -------------------
1335 
1336    function Replace_Slice
1337      (Source : Unbounded_Wide_Wide_String;
1338       Low    : Positive;
1339       High   : Natural;
1340       By     : Wide_Wide_String) return Unbounded_Wide_Wide_String
1341    is
1342       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1343       DL : Natural;
1344       DR : Shared_Wide_Wide_String_Access;
1345 
1346    begin
1347       --  Check bounds
1348 
1349       if Low > SR.Last + 1 then
1350          raise Index_Error;
1351       end if;
1352 
1353       --  Do replace operation when removed slice is not empty
1354 
1355       if High >= Low then
1356          DL := By'Length + SR.Last + Low - Integer'Min (High, SR.Last) - 1;
1357          --  This is the number of characters remaining in the string after
1358          --  replacing the slice.
1359 
1360          --  Result is empty string, reuse empty shared string
1361 
1362          if DL = 0 then
1363             Reference (Empty_Shared_Wide_Wide_String'Access);
1364             DR := Empty_Shared_Wide_Wide_String'Access;
1365 
1366          --  Otherwise allocate new shared string and fill it
1367 
1368          else
1369             DR := Allocate (DL);
1370             DR.Data (1 .. Low - 1) := SR.Data (1 .. Low - 1);
1371             DR.Data (Low .. Low + By'Length - 1) := By;
1372             DR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1373             DR.Last := DL;
1374          end if;
1375 
1376          return (AF.Controlled with Reference => DR);
1377 
1378       --  Otherwise just insert string
1379 
1380       else
1381          return Insert (Source, Low, By);
1382       end if;
1383    end Replace_Slice;
1384 
1385    procedure Replace_Slice
1386      (Source : in out Unbounded_Wide_Wide_String;
1387       Low    : Positive;
1388       High   : Natural;
1389       By     : Wide_Wide_String)
1390    is
1391       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1392       DL : Natural;
1393       DR : Shared_Wide_Wide_String_Access;
1394 
1395    begin
1396       --  Bounds check
1397 
1398       if Low > SR.Last + 1 then
1399          raise Index_Error;
1400       end if;
1401 
1402       --  Do replace operation only when replaced slice is not empty
1403 
1404       if High >= Low then
1405          DL := By'Length + SR.Last + Low - Integer'Min (High, SR.Last) - 1;
1406          --  This is the number of characters remaining in the string after
1407          --  replacing the slice.
1408 
1409          --  Result is empty string, reuse empty shared string
1410 
1411          if DL = 0 then
1412             Reference (Empty_Shared_Wide_Wide_String'Access);
1413             Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1414             Unreference (SR);
1415 
1416          --  Try to reuse existent shared string
1417 
1418          elsif Can_Be_Reused (SR, DL) then
1419             SR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1420             SR.Data (Low .. Low + By'Length - 1) := By;
1421             SR.Last := DL;
1422 
1423          --  Otherwise allocate new shared string and fill it
1424 
1425          else
1426             DR := Allocate (DL);
1427             DR.Data (1 .. Low - 1) := SR.Data (1 .. Low - 1);
1428             DR.Data (Low .. Low + By'Length - 1) := By;
1429             DR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1430             DR.Last := DL;
1431             Source.Reference := DR;
1432             Unreference (SR);
1433          end if;
1434 
1435       --  Otherwise just insert item
1436 
1437       else
1438          Insert (Source, Low, By);
1439       end if;
1440    end Replace_Slice;
1441 
1442    -------------------------------
1443    -- Set_Unbounded_Wide_Wide_String --
1444    -------------------------------
1445 
1446    procedure Set_Unbounded_Wide_Wide_String
1447      (Target : out Unbounded_Wide_Wide_String;
1448       Source : Wide_Wide_String)
1449    is
1450       TR : constant Shared_Wide_Wide_String_Access := Target.Reference;
1451       DR : Shared_Wide_Wide_String_Access;
1452 
1453    begin
1454       --  In case of empty string, reuse empty shared string
1455 
1456       if Source'Length = 0 then
1457          Reference (Empty_Shared_Wide_Wide_String'Access);
1458          Target.Reference := Empty_Shared_Wide_Wide_String'Access;
1459 
1460       else
1461          --  Try to reuse existent shared string
1462 
1463          if Can_Be_Reused (TR, Source'Length) then
1464             Reference (TR);
1465             DR := TR;
1466 
1467          --  Otherwise allocate new shared string
1468 
1469          else
1470             DR := Allocate (Source'Length);
1471             Target.Reference := DR;
1472          end if;
1473 
1474          DR.Data (1 .. Source'Length) := Source;
1475          DR.Last := Source'Length;
1476       end if;
1477 
1478       Unreference (TR);
1479    end Set_Unbounded_Wide_Wide_String;
1480 
1481    -----------
1482    -- Slice --
1483    -----------
1484 
1485    function Slice
1486      (Source : Unbounded_Wide_Wide_String;
1487       Low    : Positive;
1488       High   : Natural) return Wide_Wide_String
1489    is
1490       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1491 
1492    begin
1493       --  Note: test of High > Length is in accordance with AI95-00128
1494 
1495       if Low > SR.Last + 1 or else High > SR.Last then
1496          raise Index_Error;
1497 
1498       else
1499          return SR.Data (Low .. High);
1500       end if;
1501    end Slice;
1502 
1503    ----------
1504    -- Tail --
1505    ----------
1506 
1507    function Tail
1508      (Source : Unbounded_Wide_Wide_String;
1509       Count  : Natural;
1510       Pad    : Wide_Wide_Character := Wide_Wide_Space)
1511       return Unbounded_Wide_Wide_String
1512    is
1513       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1514       DR : Shared_Wide_Wide_String_Access;
1515 
1516    begin
1517       --  For empty result reuse empty shared string
1518 
1519       if Count = 0 then
1520          Reference (Empty_Shared_Wide_Wide_String'Access);
1521          DR := Empty_Shared_Wide_Wide_String'Access;
1522 
1523       --  Result is hole source string, reuse source shared string
1524 
1525       elsif Count = SR.Last then
1526          Reference (SR);
1527          DR := SR;
1528 
1529       --  Otherwise allocate new shared string and fill it
1530 
1531       else
1532          DR := Allocate (Count);
1533 
1534          if Count < SR.Last then
1535             DR.Data (1 .. Count) := SR.Data (SR.Last - Count + 1 .. SR.Last);
1536 
1537          else
1538             for J in 1 .. Count - SR.Last loop
1539                DR.Data (J) := Pad;
1540             end loop;
1541 
1542             DR.Data (Count - SR.Last + 1 .. Count) := SR.Data (1 .. SR.Last);
1543          end if;
1544 
1545          DR.Last := Count;
1546       end if;
1547 
1548       return (AF.Controlled with Reference => DR);
1549    end Tail;
1550 
1551    procedure Tail
1552      (Source : in out Unbounded_Wide_Wide_String;
1553       Count  : Natural;
1554       Pad    : Wide_Wide_Character := Wide_Wide_Space)
1555    is
1556       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1557       DR : Shared_Wide_Wide_String_Access;
1558 
1559       procedure Common
1560         (SR    : Shared_Wide_Wide_String_Access;
1561          DR    : Shared_Wide_Wide_String_Access;
1562          Count : Natural);
1563       --  Common code of tail computation. SR/DR can point to the same object
1564 
1565       ------------
1566       -- Common --
1567       ------------
1568 
1569       procedure Common
1570         (SR    : Shared_Wide_Wide_String_Access;
1571          DR    : Shared_Wide_Wide_String_Access;
1572          Count : Natural) is
1573       begin
1574          if Count < SR.Last then
1575             DR.Data (1 .. Count) := SR.Data (SR.Last - Count + 1 .. SR.Last);
1576 
1577          else
1578             DR.Data (Count - SR.Last + 1 .. Count) := SR.Data (1 .. SR.Last);
1579 
1580             for J in 1 .. Count - SR.Last loop
1581                DR.Data (J) := Pad;
1582             end loop;
1583          end if;
1584 
1585          DR.Last := Count;
1586       end Common;
1587 
1588    begin
1589       --  Result is empty string, reuse empty shared string
1590 
1591       if Count = 0 then
1592          Reference (Empty_Shared_Wide_Wide_String'Access);
1593          Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1594          Unreference (SR);
1595 
1596       --  Length of the result is the same with length of the source string,
1597       --  reuse source shared string.
1598 
1599       elsif Count = SR.Last then
1600          null;
1601 
1602       --  Try to reuse existent shared string
1603 
1604       elsif Can_Be_Reused (SR, Count) then
1605          Common (SR, SR, Count);
1606 
1607       --  Otherwise allocate new shared string and fill it
1608 
1609       else
1610          DR := Allocate (Count);
1611          Common (SR, DR, Count);
1612          Source.Reference := DR;
1613          Unreference (SR);
1614       end if;
1615    end Tail;
1616 
1617    -------------------------
1618    -- To_Wide_Wide_String --
1619    -------------------------
1620 
1621    function To_Wide_Wide_String
1622      (Source : Unbounded_Wide_Wide_String) return Wide_Wide_String is
1623    begin
1624       return Source.Reference.Data (1 .. Source.Reference.Last);
1625    end To_Wide_Wide_String;
1626 
1627    -----------------------------------
1628    -- To_Unbounded_Wide_Wide_String --
1629    -----------------------------------
1630 
1631    function To_Unbounded_Wide_Wide_String
1632      (Source : Wide_Wide_String) return Unbounded_Wide_Wide_String
1633    is
1634       DR : Shared_Wide_Wide_String_Access;
1635 
1636    begin
1637       if Source'Length = 0 then
1638          Reference (Empty_Shared_Wide_Wide_String'Access);
1639          DR := Empty_Shared_Wide_Wide_String'Access;
1640 
1641       else
1642          DR := Allocate (Source'Length);
1643          DR.Data (1 .. Source'Length) := Source;
1644          DR.Last := Source'Length;
1645       end if;
1646 
1647       return (AF.Controlled with Reference => DR);
1648    end To_Unbounded_Wide_Wide_String;
1649 
1650    function To_Unbounded_Wide_Wide_String
1651      (Length : Natural) return Unbounded_Wide_Wide_String
1652    is
1653       DR : Shared_Wide_Wide_String_Access;
1654 
1655    begin
1656       if Length = 0 then
1657          Reference (Empty_Shared_Wide_Wide_String'Access);
1658          DR := Empty_Shared_Wide_Wide_String'Access;
1659 
1660       else
1661          DR := Allocate (Length);
1662          DR.Last := Length;
1663       end if;
1664 
1665       return (AF.Controlled with Reference => DR);
1666    end To_Unbounded_Wide_Wide_String;
1667 
1668    ---------------
1669    -- Translate --
1670    ---------------
1671 
1672    function Translate
1673      (Source  : Unbounded_Wide_Wide_String;
1674       Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping)
1675       return Unbounded_Wide_Wide_String
1676    is
1677       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1678       DR : Shared_Wide_Wide_String_Access;
1679 
1680    begin
1681       --  Nothing to translate, reuse empty shared string
1682 
1683       if SR.Last = 0 then
1684          Reference (Empty_Shared_Wide_Wide_String'Access);
1685          DR := Empty_Shared_Wide_Wide_String'Access;
1686 
1687       --  Otherwise, allocate new shared string and fill it
1688 
1689       else
1690          DR := Allocate (SR.Last);
1691 
1692          for J in 1 .. SR.Last loop
1693             DR.Data (J) := Value (Mapping, SR.Data (J));
1694          end loop;
1695 
1696          DR.Last := SR.Last;
1697       end if;
1698 
1699       return (AF.Controlled with Reference => DR);
1700    end Translate;
1701 
1702    procedure Translate
1703      (Source  : in out Unbounded_Wide_Wide_String;
1704       Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping)
1705    is
1706       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1707       DR : Shared_Wide_Wide_String_Access;
1708 
1709    begin
1710       --  Nothing to translate
1711 
1712       if SR.Last = 0 then
1713          null;
1714 
1715       --  Try to reuse shared string
1716 
1717       elsif Can_Be_Reused (SR, SR.Last) then
1718          for J in 1 .. SR.Last loop
1719             SR.Data (J) := Value (Mapping, SR.Data (J));
1720          end loop;
1721 
1722       --  Otherwise, allocate new shared string
1723 
1724       else
1725          DR := Allocate (SR.Last);
1726 
1727          for J in 1 .. SR.Last loop
1728             DR.Data (J) := Value (Mapping, SR.Data (J));
1729          end loop;
1730 
1731          DR.Last := SR.Last;
1732          Source.Reference := DR;
1733          Unreference (SR);
1734       end if;
1735    end Translate;
1736 
1737    function Translate
1738      (Source  : Unbounded_Wide_Wide_String;
1739       Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
1740       return Unbounded_Wide_Wide_String
1741    is
1742       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1743       DR : Shared_Wide_Wide_String_Access;
1744 
1745    begin
1746       --  Nothing to translate, reuse empty shared string
1747 
1748       if SR.Last = 0 then
1749          Reference (Empty_Shared_Wide_Wide_String'Access);
1750          DR := Empty_Shared_Wide_Wide_String'Access;
1751 
1752       --  Otherwise, allocate new shared string and fill it
1753 
1754       else
1755          DR := Allocate (SR.Last);
1756 
1757          for J in 1 .. SR.Last loop
1758             DR.Data (J) := Mapping.all (SR.Data (J));
1759          end loop;
1760 
1761          DR.Last := SR.Last;
1762       end if;
1763 
1764       return (AF.Controlled with Reference => DR);
1765 
1766    exception
1767       when others =>
1768          Unreference (DR);
1769 
1770          raise;
1771    end Translate;
1772 
1773    procedure Translate
1774      (Source  : in out Unbounded_Wide_Wide_String;
1775       Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
1776    is
1777       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1778       DR : Shared_Wide_Wide_String_Access;
1779 
1780    begin
1781       --  Nothing to translate
1782 
1783       if SR.Last = 0 then
1784          null;
1785 
1786       --  Try to reuse shared string
1787 
1788       elsif Can_Be_Reused (SR, SR.Last) then
1789          for J in 1 .. SR.Last loop
1790             SR.Data (J) := Mapping.all (SR.Data (J));
1791          end loop;
1792 
1793       --  Otherwise allocate new shared string and fill it
1794 
1795       else
1796          DR := Allocate (SR.Last);
1797 
1798          for J in 1 .. SR.Last loop
1799             DR.Data (J) := Mapping.all (SR.Data (J));
1800          end loop;
1801 
1802          DR.Last := SR.Last;
1803          Source.Reference := DR;
1804          Unreference (SR);
1805       end if;
1806 
1807    exception
1808       when others =>
1809          if DR /= null then
1810             Unreference (DR);
1811          end if;
1812 
1813          raise;
1814    end Translate;
1815 
1816    ----------
1817    -- Trim --
1818    ----------
1819 
1820    function Trim
1821      (Source : Unbounded_Wide_Wide_String;
1822       Side   : Trim_End) return Unbounded_Wide_Wide_String
1823    is
1824       SR   : constant Shared_Wide_Wide_String_Access := Source.Reference;
1825       DL   : Natural;
1826       DR   : Shared_Wide_Wide_String_Access;
1827       Low  : Natural;
1828       High : Natural;
1829 
1830    begin
1831       Low := Index_Non_Blank (Source, Forward);
1832 
1833       --  All blanks, reuse empty shared string
1834 
1835       if Low = 0 then
1836          Reference (Empty_Shared_Wide_Wide_String'Access);
1837          DR := Empty_Shared_Wide_Wide_String'Access;
1838 
1839       else
1840          case Side is
1841             when Left =>
1842                High := SR.Last;
1843                DL   := SR.Last - Low + 1;
1844 
1845             when Right =>
1846                Low  := 1;
1847                High := Index_Non_Blank (Source, Backward);
1848                DL   := High;
1849 
1850             when Both =>
1851                High := Index_Non_Blank (Source, Backward);
1852                DL   := High - Low + 1;
1853          end case;
1854 
1855          --  Length of the result is the same as length of the source string,
1856          --  reuse source shared string.
1857 
1858          if DL = SR.Last then
1859             Reference (SR);
1860             DR := SR;
1861 
1862          --  Otherwise, allocate new shared string
1863 
1864          else
1865             DR := Allocate (DL);
1866             DR.Data (1 .. DL) := SR.Data (Low .. High);
1867             DR.Last := DL;
1868          end if;
1869       end if;
1870 
1871       return (AF.Controlled with Reference => DR);
1872    end Trim;
1873 
1874    procedure Trim
1875      (Source : in out Unbounded_Wide_Wide_String;
1876       Side   : Trim_End)
1877    is
1878       SR   : constant Shared_Wide_Wide_String_Access := Source.Reference;
1879       DL   : Natural;
1880       DR   : Shared_Wide_Wide_String_Access;
1881       Low  : Natural;
1882       High : Natural;
1883 
1884    begin
1885       Low := Index_Non_Blank (Source, Forward);
1886 
1887       --  All blanks, reuse empty shared string
1888 
1889       if Low = 0 then
1890          Reference (Empty_Shared_Wide_Wide_String'Access);
1891          Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1892          Unreference (SR);
1893 
1894       else
1895          case Side is
1896             when Left =>
1897                High := SR.Last;
1898                DL   := SR.Last - Low + 1;
1899 
1900             when Right =>
1901                Low  := 1;
1902                High := Index_Non_Blank (Source, Backward);
1903                DL   := High;
1904 
1905             when Both =>
1906                High := Index_Non_Blank (Source, Backward);
1907                DL   := High - Low + 1;
1908          end case;
1909 
1910          --  Length of the result is the same as length of the source string,
1911          --  nothing to do.
1912 
1913          if DL = SR.Last then
1914             null;
1915 
1916          --  Try to reuse existent shared string
1917 
1918          elsif Can_Be_Reused (SR, DL) then
1919             SR.Data (1 .. DL) := SR.Data (Low .. High);
1920             SR.Last := DL;
1921 
1922          --  Otherwise, allocate new shared string
1923 
1924          else
1925             DR := Allocate (DL);
1926             DR.Data (1 .. DL) := SR.Data (Low .. High);
1927             DR.Last := DL;
1928             Source.Reference := DR;
1929             Unreference (SR);
1930          end if;
1931       end if;
1932    end Trim;
1933 
1934    function Trim
1935      (Source : Unbounded_Wide_Wide_String;
1936       Left   : Wide_Wide_Maps.Wide_Wide_Character_Set;
1937       Right  : Wide_Wide_Maps.Wide_Wide_Character_Set)
1938       return Unbounded_Wide_Wide_String
1939    is
1940       SR   : constant Shared_Wide_Wide_String_Access := Source.Reference;
1941       DL   : Natural;
1942       DR   : Shared_Wide_Wide_String_Access;
1943       Low  : Natural;
1944       High : Natural;
1945 
1946    begin
1947       Low := Index (Source, Left, Outside, Forward);
1948 
1949       --  Source includes only characters from Left set, reuse empty shared
1950       --  string.
1951 
1952       if Low = 0 then
1953          Reference (Empty_Shared_Wide_Wide_String'Access);
1954          DR := Empty_Shared_Wide_Wide_String'Access;
1955 
1956       else
1957          High := Index (Source, Right, Outside, Backward);
1958          DL   := Integer'Max (0, High - Low + 1);
1959 
1960          --  Source includes only characters from Right set or result string
1961          --  is empty, reuse empty shared string.
1962 
1963          if High = 0 or else DL = 0 then
1964             Reference (Empty_Shared_Wide_Wide_String'Access);
1965             DR := Empty_Shared_Wide_Wide_String'Access;
1966 
1967          --  Otherwise, allocate new shared string and fill it
1968 
1969          else
1970             DR := Allocate (DL);
1971             DR.Data (1 .. DL) := SR.Data (Low .. High);
1972             DR.Last := DL;
1973          end if;
1974       end if;
1975 
1976       return (AF.Controlled with Reference => DR);
1977    end Trim;
1978 
1979    procedure Trim
1980      (Source : in out Unbounded_Wide_Wide_String;
1981       Left   : Wide_Wide_Maps.Wide_Wide_Character_Set;
1982       Right  : Wide_Wide_Maps.Wide_Wide_Character_Set)
1983    is
1984       SR   : constant Shared_Wide_Wide_String_Access := Source.Reference;
1985       DL   : Natural;
1986       DR   : Shared_Wide_Wide_String_Access;
1987       Low  : Natural;
1988       High : Natural;
1989 
1990    begin
1991       Low := Index (Source, Left, Outside, Forward);
1992 
1993       --  Source includes only characters from Left set, reuse empty shared
1994       --  string.
1995 
1996       if Low = 0 then
1997          Reference (Empty_Shared_Wide_Wide_String'Access);
1998          Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1999          Unreference (SR);
2000 
2001       else
2002          High := Index (Source, Right, Outside, Backward);
2003          DL   := Integer'Max (0, High - Low + 1);
2004 
2005          --  Source includes only characters from Right set or result string
2006          --  is empty, reuse empty shared string.
2007 
2008          if High = 0 or else DL = 0 then
2009             Reference (Empty_Shared_Wide_Wide_String'Access);
2010             Source.Reference := Empty_Shared_Wide_Wide_String'Access;
2011             Unreference (SR);
2012 
2013          --  Try to reuse existent shared string
2014 
2015          elsif Can_Be_Reused (SR, DL) then
2016             SR.Data (1 .. DL) := SR.Data (Low .. High);
2017             SR.Last := DL;
2018 
2019          --  Otherwise, allocate new shared string and fill it
2020 
2021          else
2022             DR := Allocate (DL);
2023             DR.Data (1 .. DL) := SR.Data (Low .. High);
2024             DR.Last := DL;
2025             Source.Reference := DR;
2026             Unreference (SR);
2027          end if;
2028       end if;
2029    end Trim;
2030 
2031    ---------------------
2032    -- Unbounded_Slice --
2033    ---------------------
2034 
2035    function Unbounded_Slice
2036      (Source : Unbounded_Wide_Wide_String;
2037       Low    : Positive;
2038       High   : Natural) return Unbounded_Wide_Wide_String
2039    is
2040       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
2041       DL : Natural;
2042       DR : Shared_Wide_Wide_String_Access;
2043 
2044    begin
2045       --  Check bounds
2046 
2047       if Low > SR.Last + 1 or else High > SR.Last then
2048          raise Index_Error;
2049 
2050       --  Result is empty slice, reuse empty shared string
2051 
2052       elsif Low > High then
2053          Reference (Empty_Shared_Wide_Wide_String'Access);
2054          DR := Empty_Shared_Wide_Wide_String'Access;
2055 
2056       --  Otherwise, allocate new shared string and fill it
2057 
2058       else
2059          DL := High - Low + 1;
2060          DR := Allocate (DL);
2061          DR.Data (1 .. DL) := SR.Data (Low .. High);
2062          DR.Last := DL;
2063       end if;
2064 
2065       return (AF.Controlled with Reference => DR);
2066    end Unbounded_Slice;
2067 
2068    procedure Unbounded_Slice
2069      (Source : Unbounded_Wide_Wide_String;
2070       Target : out Unbounded_Wide_Wide_String;
2071       Low    : Positive;
2072       High   : Natural)
2073    is
2074       SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
2075       TR : constant Shared_Wide_Wide_String_Access := Target.Reference;
2076       DL : Natural;
2077       DR : Shared_Wide_Wide_String_Access;
2078 
2079    begin
2080       --  Check bounds
2081 
2082       if Low > SR.Last + 1 or else High > SR.Last then
2083          raise Index_Error;
2084 
2085       --  Result is empty slice, reuse empty shared string
2086 
2087       elsif Low > High then
2088          Reference (Empty_Shared_Wide_Wide_String'Access);
2089          Target.Reference := Empty_Shared_Wide_Wide_String'Access;
2090          Unreference (TR);
2091 
2092       else
2093          DL := High - Low + 1;
2094 
2095          --  Try to reuse existent shared string
2096 
2097          if Can_Be_Reused (TR, DL) then
2098             TR.Data (1 .. DL) := SR.Data (Low .. High);
2099             TR.Last := DL;
2100 
2101          --  Otherwise, allocate new shared string and fill it
2102 
2103          else
2104             DR := Allocate (DL);
2105             DR.Data (1 .. DL) := SR.Data (Low .. High);
2106             DR.Last := DL;
2107             Target.Reference := DR;
2108             Unreference (TR);
2109          end if;
2110       end if;
2111    end Unbounded_Slice;
2112 
2113    -----------------
2114    -- Unreference --
2115    -----------------
2116 
2117    procedure Unreference (Item : not null Shared_Wide_Wide_String_Access) is
2118 
2119       procedure Free is
2120         new Ada.Unchecked_Deallocation
2121               (Shared_Wide_Wide_String, Shared_Wide_Wide_String_Access);
2122 
2123       Aux : Shared_Wide_Wide_String_Access := Item;
2124 
2125    begin
2126       if System.Atomic_Counters.Decrement (Aux.Counter) then
2127 
2128          --  Reference counter of Empty_Shared_Wide_Wide_String must never
2129          --  reach zero.
2130 
2131          pragma Assert (Aux /= Empty_Shared_Wide_Wide_String'Access);
2132 
2133          Free (Aux);
2134       end if;
2135    end Unreference;
2136 
2137 end Ada.Strings.Wide_Wide_Unbounded;