OSDN Git Service

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