OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [ada/] [a-stzunb-shared.adb] - Blame information for rev 706

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 706 jeremybenn
------------------------------------------------------------------------------
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-2011, 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
   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 (LR.Last + RR.Last);
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
490
                         / Standard'Storage_Unit;
491
      --  Total size of all static components
492
 
493
      Element_Size : constant Natural :=
494
                       Wide_Wide_Character'Size / Standard'Storage_Unit;
495
 
496
   begin
497
      return
498
        (((Static_Size + Max_Length * Element_Size - 1) / Min_Mul_Alloc + 2)
499
          * Min_Mul_Alloc - Static_Size) / Element_Size;
500
   end Aligned_Max_Length;
501
 
502
   --------------
503
   -- Allocate --
504
   --------------
505
 
506
   function Allocate
507
     (Max_Length : Natural) return Shared_Wide_Wide_String_Access is
508
   begin
509
      --  Empty string requested, return shared empty string
510
 
511
      if Max_Length = 0 then
512
         Reference (Empty_Shared_Wide_Wide_String'Access);
513
         return Empty_Shared_Wide_Wide_String'Access;
514
 
515
      --  Otherwise, allocate requested space (and probably some more room)
516
 
517
      else
518
         return new Shared_Wide_Wide_String (Aligned_Max_Length (Max_Length));
519
      end if;
520
   end Allocate;
521
 
522
   ------------
523
   -- Append --
524
   ------------
525
 
526
   procedure Append
527
     (Source   : in out Unbounded_Wide_Wide_String;
528
      New_Item : Unbounded_Wide_Wide_String)
529
   is
530
      SR  : constant Shared_Wide_Wide_String_Access := Source.Reference;
531
      NR  : constant Shared_Wide_Wide_String_Access := New_Item.Reference;
532
      DL  : constant Natural              := SR.Last + NR.Last;
533
      DR  : Shared_Wide_Wide_String_Access;
534
 
535
   begin
536
      --  Source is an empty string, reuse New_Item data
537
 
538
      if SR.Last = 0 then
539
         Reference (NR);
540
         Source.Reference := NR;
541
         Unreference (SR);
542
 
543
      --  New_Item is empty string, nothing to do
544
 
545
      elsif NR.Last = 0 then
546
         null;
547
 
548
      --  Try to reuse existent shared string
549
 
550
      elsif Can_Be_Reused (SR, DL) then
551
         SR.Data (SR.Last + 1 .. DL) := NR.Data (1 .. NR.Last);
552
         SR.Last := DL;
553
 
554
      --  Otherwise, allocate new one and fill it
555
 
556
      else
557
         DR := Allocate (DL + DL / Growth_Factor);
558
         DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
559
         DR.Data (SR.Last + 1 .. DL) := NR.Data (1 .. NR.Last);
560
         DR.Last := DL;
561
         Source.Reference := DR;
562
         Unreference (SR);
563
      end if;
564
   end Append;
565
 
566
   procedure Append
567
     (Source   : in out Unbounded_Wide_Wide_String;
568
      New_Item : Wide_Wide_String)
569
   is
570
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
571
      DL : constant Natural := SR.Last + New_Item'Length;
572
      DR : Shared_Wide_Wide_String_Access;
573
 
574
   begin
575
      --  New_Item is an empty string, nothing to do
576
 
577
      if New_Item'Length = 0 then
578
         null;
579
 
580
      --  Try to reuse existing shared string
581
 
582
      elsif Can_Be_Reused (SR, DL) then
583
         SR.Data (SR.Last + 1 .. DL) := New_Item;
584
         SR.Last := DL;
585
 
586
      --  Otherwise, allocate new one and fill it
587
 
588
      else
589
         DR := Allocate (DL + DL / Growth_Factor);
590
         DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
591
         DR.Data (SR.Last + 1 .. DL) := New_Item;
592
         DR.Last := DL;
593
         Source.Reference := DR;
594
         Unreference (SR);
595
      end if;
596
   end Append;
597
 
598
   procedure Append
599
     (Source   : in out Unbounded_Wide_Wide_String;
600
      New_Item : Wide_Wide_Character)
601
   is
602
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
603
      DL : constant Natural := SR.Last + 1;
604
      DR : Shared_Wide_Wide_String_Access;
605
 
606
   begin
607
      --  Try to reuse existing shared string
608
 
609
      if Can_Be_Reused (SR, SR.Last + 1) then
610
         SR.Data (SR.Last + 1) := New_Item;
611
         SR.Last := SR.Last + 1;
612
 
613
      --  Otherwise, allocate new one and fill it
614
 
615
      else
616
         DR := Allocate (DL + DL / Growth_Factor);
617
         DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
618
         DR.Data (DL) := New_Item;
619
         DR.Last := DL;
620
         Source.Reference := DR;
621
         Unreference (SR);
622
      end if;
623
   end Append;
624
 
625
   -------------------
626
   -- Can_Be_Reused --
627
   -------------------
628
 
629
   function Can_Be_Reused
630
     (Item   : Shared_Wide_Wide_String_Access;
631
      Length : Natural) return Boolean is
632
   begin
633
      return
634
        System.Atomic_Counters.Is_One (Item.Counter)
635
          and then Item.Max_Length >= Length
636
          and then Item.Max_Length <=
637
                     Aligned_Max_Length (Length + Length / Growth_Factor);
638
   end Can_Be_Reused;
639
 
640
   -----------
641
   -- Count --
642
   -----------
643
 
644
   function Count
645
     (Source  : Unbounded_Wide_Wide_String;
646
      Pattern : Wide_Wide_String;
647
      Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping :=
648
                  Wide_Wide_Maps.Identity)
649
      return Natural
650
   is
651
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
652
   begin
653
      return Wide_Wide_Search.Count (SR.Data (1 .. SR.Last), Pattern, Mapping);
654
   end Count;
655
 
656
   function Count
657
     (Source  : Unbounded_Wide_Wide_String;
658
      Pattern : Wide_Wide_String;
659
      Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
660
      return Natural
661
   is
662
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
663
   begin
664
      return Wide_Wide_Search.Count (SR.Data (1 .. SR.Last), Pattern, Mapping);
665
   end Count;
666
 
667
   function Count
668
     (Source : Unbounded_Wide_Wide_String;
669
      Set    : Wide_Wide_Maps.Wide_Wide_Character_Set) return Natural
670
   is
671
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
672
   begin
673
      return Wide_Wide_Search.Count (SR.Data (1 .. SR.Last), Set);
674
   end Count;
675
 
676
   ------------
677
   -- Delete --
678
   ------------
679
 
680
   function Delete
681
     (Source  : Unbounded_Wide_Wide_String;
682
      From    : Positive;
683
      Through : Natural) return Unbounded_Wide_Wide_String
684
   is
685
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
686
      DL : Natural;
687
      DR : Shared_Wide_Wide_String_Access;
688
 
689
   begin
690
      --  Empty slice is deleted, use the same shared string
691
 
692
      if From > Through then
693
         Reference (SR);
694
         DR := SR;
695
 
696
      --  Index is out of range
697
 
698
      elsif Through > SR.Last then
699
         raise Index_Error;
700
 
701
      --  Compute size of the result
702
 
703
      else
704
         DL := SR.Last - (Through - From + 1);
705
 
706
         --  Result is an empty string, reuse shared empty string
707
 
708
         if DL = 0 then
709
            Reference (Empty_Shared_Wide_Wide_String'Access);
710
            DR := Empty_Shared_Wide_Wide_String'Access;
711
 
712
         --  Otherwise, allocate new shared string and fill it
713
 
714
         else
715
            DR := Allocate (DL);
716
            DR.Data (1 .. From - 1) := SR.Data (1 .. From - 1);
717
            DR.Data (From .. DL) := SR.Data (Through + 1 .. SR.Last);
718
            DR.Last := DL;
719
         end if;
720
      end if;
721
 
722
      return (AF.Controlled with Reference => DR);
723
   end Delete;
724
 
725
   procedure Delete
726
     (Source  : in out Unbounded_Wide_Wide_String;
727
      From    : Positive;
728
      Through : Natural)
729
   is
730
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
731
      DL : Natural;
732
      DR : Shared_Wide_Wide_String_Access;
733
 
734
   begin
735
      --  Nothing changed, return
736
 
737
      if From > Through then
738
         null;
739
 
740
      --  Through is outside of the range
741
 
742
      elsif Through > SR.Last then
743
         raise Index_Error;
744
 
745
      else
746
         DL := SR.Last - (Through - From + 1);
747
 
748
         --  Result is empty, reuse shared empty string
749
 
750
         if DL = 0 then
751
            Reference (Empty_Shared_Wide_Wide_String'Access);
752
            Source.Reference := Empty_Shared_Wide_Wide_String'Access;
753
            Unreference (SR);
754
 
755
         --  Try to reuse existent shared string
756
 
757
         elsif Can_Be_Reused (SR, DL) then
758
            SR.Data (From .. DL) := SR.Data (Through + 1 .. SR.Last);
759
            SR.Last := DL;
760
 
761
         --  Otherwise, allocate new shared string
762
 
763
         else
764
            DR := Allocate (DL);
765
            DR.Data (1 .. From - 1) := SR.Data (1 .. From - 1);
766
            DR.Data (From .. DL) := SR.Data (Through + 1 .. SR.Last);
767
            DR.Last := DL;
768
            Source.Reference := DR;
769
            Unreference (SR);
770
         end if;
771
      end if;
772
   end Delete;
773
 
774
   -------------
775
   -- Element --
776
   -------------
777
 
778
   function Element
779
     (Source : Unbounded_Wide_Wide_String;
780
      Index  : Positive) return Wide_Wide_Character
781
   is
782
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
783
   begin
784
      if Index <= SR.Last then
785
         return SR.Data (Index);
786
      else
787
         raise Index_Error;
788
      end if;
789
   end Element;
790
 
791
   --------------
792
   -- Finalize --
793
   --------------
794
 
795
   procedure Finalize (Object : in out Unbounded_Wide_Wide_String) is
796
      SR : constant Shared_Wide_Wide_String_Access := Object.Reference;
797
 
798
   begin
799
      if SR /= null then
800
 
801
         --  The same controlled object can be finalized several times for
802
         --  some reason. As per 7.6.1(24) this should have no ill effect,
803
         --  so we need to add a guard for the case of finalizing the same
804
         --  object twice.
805
 
806
         Object.Reference := null;
807
         Unreference (SR);
808
      end if;
809
   end Finalize;
810
 
811
   ----------------
812
   -- Find_Token --
813
   ----------------
814
 
815
   procedure Find_Token
816
     (Source : Unbounded_Wide_Wide_String;
817
      Set    : Wide_Wide_Maps.Wide_Wide_Character_Set;
818
      From   : Positive;
819
      Test   : Strings.Membership;
820
      First  : out Positive;
821
      Last   : out Natural)
822
   is
823
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
824
   begin
825
      Wide_Wide_Search.Find_Token
826
        (SR.Data (From .. SR.Last), Set, Test, First, Last);
827
   end Find_Token;
828
 
829
   procedure Find_Token
830
     (Source : Unbounded_Wide_Wide_String;
831
      Set    : Wide_Wide_Maps.Wide_Wide_Character_Set;
832
      Test   : Strings.Membership;
833
      First  : out Positive;
834
      Last   : out Natural)
835
   is
836
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
837
   begin
838
      Wide_Wide_Search.Find_Token
839
        (SR.Data (1 .. SR.Last), Set, Test, First, Last);
840
   end Find_Token;
841
 
842
   ----------
843
   -- Free --
844
   ----------
845
 
846
   procedure Free (X : in out Wide_Wide_String_Access) is
847
      procedure Deallocate is
848
         new Ada.Unchecked_Deallocation
849
               (Wide_Wide_String, Wide_Wide_String_Access);
850
   begin
851
      Deallocate (X);
852
   end Free;
853
 
854
   ----------
855
   -- Head --
856
   ----------
857
 
858
   function Head
859
     (Source : Unbounded_Wide_Wide_String;
860
      Count  : Natural;
861
      Pad    : Wide_Wide_Character := Wide_Wide_Space)
862
      return Unbounded_Wide_Wide_String
863
   is
864
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
865
      DR : Shared_Wide_Wide_String_Access;
866
 
867
   begin
868
      --  Result is empty, reuse shared empty string
869
 
870
      if Count = 0 then
871
         Reference (Empty_Shared_Wide_Wide_String'Access);
872
         DR := Empty_Shared_Wide_Wide_String'Access;
873
 
874
      --  Length of the string is the same as requested, reuse source shared
875
      --  string.
876
 
877
      elsif Count = SR.Last then
878
         Reference (SR);
879
         DR := SR;
880
 
881
      --  Otherwise, allocate new shared string and fill it
882
 
883
      else
884
         DR := Allocate (Count);
885
 
886
         --  Length of the source string is more than requested, copy
887
         --  corresponding slice.
888
 
889
         if Count < SR.Last then
890
            DR.Data (1 .. Count) := SR.Data (1 .. Count);
891
 
892
         --  Length of the source string is less then requested, copy all
893
         --  contents and fill others by Pad character.
894
 
895
         else
896
            DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
897
 
898
            for J in SR.Last + 1 .. Count loop
899
               DR.Data (J) := Pad;
900
            end loop;
901
         end if;
902
 
903
         DR.Last := Count;
904
      end if;
905
 
906
      return (AF.Controlled with Reference => DR);
907
   end Head;
908
 
909
   procedure Head
910
     (Source : in out Unbounded_Wide_Wide_String;
911
      Count  : Natural;
912
      Pad    : Wide_Wide_Character := Wide_Wide_Space)
913
   is
914
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
915
      DR : Shared_Wide_Wide_String_Access;
916
 
917
   begin
918
      --  Result is empty, reuse empty shared string
919
 
920
      if Count = 0 then
921
         Reference (Empty_Shared_Wide_Wide_String'Access);
922
         Source.Reference := Empty_Shared_Wide_Wide_String'Access;
923
         Unreference (SR);
924
 
925
      --  Result is same with source string, reuse source shared string
926
 
927
      elsif Count = SR.Last then
928
         null;
929
 
930
      --  Try to reuse existent shared string
931
 
932
      elsif Can_Be_Reused (SR, Count) then
933
         if Count > SR.Last then
934
            for J in SR.Last + 1 .. Count loop
935
               SR.Data (J) := Pad;
936
            end loop;
937
         end if;
938
 
939
         SR.Last := Count;
940
 
941
      --  Otherwise, allocate new shared string and fill it
942
 
943
      else
944
         DR := Allocate (Count);
945
 
946
         --  Length of the source string is greater then requested, copy
947
         --  corresponding slice.
948
 
949
         if Count < SR.Last then
950
            DR.Data (1 .. Count) := SR.Data (1 .. Count);
951
 
952
         --  Length of the source string is less the requested, copy all
953
         --  exists data and fill others by Pad character.
954
 
955
         else
956
            DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
957
 
958
            for J in SR.Last + 1 .. Count loop
959
               DR.Data (J) := Pad;
960
            end loop;
961
         end if;
962
 
963
         DR.Last := Count;
964
         Source.Reference := DR;
965
         Unreference (SR);
966
      end if;
967
   end Head;
968
 
969
   -----------
970
   -- Index --
971
   -----------
972
 
973
   function Index
974
     (Source  : Unbounded_Wide_Wide_String;
975
      Pattern : Wide_Wide_String;
976
      Going   : Strings.Direction := Strings.Forward;
977
      Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping :=
978
                  Wide_Wide_Maps.Identity)
979
      return Natural
980
   is
981
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
982
   begin
983
      return Wide_Wide_Search.Index
984
        (SR.Data (1 .. SR.Last), Pattern, Going, Mapping);
985
   end Index;
986
 
987
   function Index
988
     (Source  : Unbounded_Wide_Wide_String;
989
      Pattern : Wide_Wide_String;
990
      Going   : Direction := Forward;
991
      Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
992
      return Natural
993
   is
994
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
995
   begin
996
      return Wide_Wide_Search.Index
997
        (SR.Data (1 .. SR.Last), Pattern, Going, Mapping);
998
   end Index;
999
 
1000
   function Index
1001
     (Source : Unbounded_Wide_Wide_String;
1002
      Set    : Wide_Wide_Maps.Wide_Wide_Character_Set;
1003
      Test   : Strings.Membership := Strings.Inside;
1004
      Going  : Strings.Direction  := Strings.Forward) return Natural
1005
   is
1006
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1007
   begin
1008
      return Wide_Wide_Search.Index (SR.Data (1 .. SR.Last), Set, Test, Going);
1009
   end Index;
1010
 
1011
   function Index
1012
     (Source  : Unbounded_Wide_Wide_String;
1013
      Pattern : Wide_Wide_String;
1014
      From    : Positive;
1015
      Going   : Direction := Forward;
1016
      Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping :=
1017
                  Wide_Wide_Maps.Identity)
1018
      return Natural
1019
   is
1020
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1021
   begin
1022
      return Wide_Wide_Search.Index
1023
        (SR.Data (1 .. SR.Last), Pattern, From, Going, Mapping);
1024
   end Index;
1025
 
1026
   function Index
1027
     (Source  : Unbounded_Wide_Wide_String;
1028
      Pattern : Wide_Wide_String;
1029
      From    : Positive;
1030
      Going   : Direction := Forward;
1031
      Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
1032
      return Natural
1033
   is
1034
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1035
   begin
1036
      return Wide_Wide_Search.Index
1037
        (SR.Data (1 .. SR.Last), Pattern, From, Going, Mapping);
1038
   end Index;
1039
 
1040
   function Index
1041
     (Source  : Unbounded_Wide_Wide_String;
1042
      Set     : Wide_Wide_Maps.Wide_Wide_Character_Set;
1043
      From    : Positive;
1044
      Test    : Membership := Inside;
1045
      Going   : Direction := Forward) return Natural
1046
   is
1047
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1048
   begin
1049
      return Wide_Wide_Search.Index
1050
        (SR.Data (1 .. SR.Last), Set, From, Test, Going);
1051
   end Index;
1052
 
1053
   ---------------------
1054
   -- Index_Non_Blank --
1055
   ---------------------
1056
 
1057
   function Index_Non_Blank
1058
     (Source : Unbounded_Wide_Wide_String;
1059
      Going  : Strings.Direction := Strings.Forward) return Natural
1060
   is
1061
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1062
   begin
1063
      return Wide_Wide_Search.Index_Non_Blank (SR.Data (1 .. SR.Last), Going);
1064
   end Index_Non_Blank;
1065
 
1066
   function Index_Non_Blank
1067
     (Source : Unbounded_Wide_Wide_String;
1068
      From   : Positive;
1069
      Going  : Direction := Forward) return Natural
1070
   is
1071
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1072
   begin
1073
      return Wide_Wide_Search.Index_Non_Blank
1074
        (SR.Data (1 .. SR.Last), From, Going);
1075
   end Index_Non_Blank;
1076
 
1077
   ----------------
1078
   -- Initialize --
1079
   ----------------
1080
 
1081
   procedure Initialize (Object : in out Unbounded_Wide_Wide_String) is
1082
   begin
1083
      Reference (Object.Reference);
1084
   end Initialize;
1085
 
1086
   ------------
1087
   -- Insert --
1088
   ------------
1089
 
1090
   function Insert
1091
     (Source   : Unbounded_Wide_Wide_String;
1092
      Before   : Positive;
1093
      New_Item : Wide_Wide_String) return Unbounded_Wide_Wide_String
1094
   is
1095
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1096
      DL : constant Natural := SR.Last + New_Item'Length;
1097
      DR : Shared_Wide_Wide_String_Access;
1098
 
1099
   begin
1100
      --  Check index first
1101
 
1102
      if Before > SR.Last + 1 then
1103
         raise Index_Error;
1104
      end if;
1105
 
1106
      --  Result is empty, reuse empty shared string
1107
 
1108
      if DL = 0 then
1109
         Reference (Empty_Shared_Wide_Wide_String'Access);
1110
         DR := Empty_Shared_Wide_Wide_String'Access;
1111
 
1112
      --  Inserted string is empty, reuse source shared string
1113
 
1114
      elsif New_Item'Length = 0 then
1115
         Reference (SR);
1116
         DR := SR;
1117
 
1118
      --  Otherwise, allocate new shared string and fill it
1119
 
1120
      else
1121
         DR := Allocate (DL + DL / Growth_Factor);
1122
         DR.Data (1 .. Before - 1) := SR.Data (1 .. Before - 1);
1123
         DR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1124
         DR.Data (Before + New_Item'Length .. DL) :=
1125
           SR.Data (Before .. SR.Last);
1126
         DR.Last := DL;
1127
      end if;
1128
 
1129
      return (AF.Controlled with Reference => DR);
1130
   end Insert;
1131
 
1132
   procedure Insert
1133
     (Source   : in out Unbounded_Wide_Wide_String;
1134
      Before   : Positive;
1135
      New_Item : Wide_Wide_String)
1136
   is
1137
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1138
      DL : constant Natural := SR.Last + New_Item'Length;
1139
      DR : Shared_Wide_Wide_String_Access;
1140
 
1141
   begin
1142
      --  Check bounds
1143
 
1144
      if Before > SR.Last + 1 then
1145
         raise Index_Error;
1146
      end if;
1147
 
1148
      --  Result is empty string, reuse empty shared string
1149
 
1150
      if DL = 0 then
1151
         Reference (Empty_Shared_Wide_Wide_String'Access);
1152
         Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1153
         Unreference (SR);
1154
 
1155
      --  Inserted string is empty, nothing to do
1156
 
1157
      elsif New_Item'Length = 0 then
1158
         null;
1159
 
1160
      --  Try to reuse existent shared string first
1161
 
1162
      elsif Can_Be_Reused (SR, DL) then
1163
         SR.Data (Before + New_Item'Length .. DL) :=
1164
           SR.Data (Before .. SR.Last);
1165
         SR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1166
         SR.Last := DL;
1167
 
1168
      --  Otherwise, allocate new shared string and fill it
1169
 
1170
      else
1171
         DR := Allocate (DL + DL / Growth_Factor);
1172
         DR.Data (1 .. Before - 1) := SR.Data (1 .. Before - 1);
1173
         DR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1174
         DR.Data (Before + New_Item'Length .. DL) :=
1175
           SR.Data (Before .. SR.Last);
1176
         DR.Last := DL;
1177
         Source.Reference := DR;
1178
         Unreference (SR);
1179
      end if;
1180
   end Insert;
1181
 
1182
   ------------
1183
   -- Length --
1184
   ------------
1185
 
1186
   function Length (Source : Unbounded_Wide_Wide_String) return Natural is
1187
   begin
1188
      return Source.Reference.Last;
1189
   end Length;
1190
 
1191
   ---------------
1192
   -- Overwrite --
1193
   ---------------
1194
 
1195
   function Overwrite
1196
     (Source   : Unbounded_Wide_Wide_String;
1197
      Position : Positive;
1198
      New_Item : Wide_Wide_String) return Unbounded_Wide_Wide_String
1199
   is
1200
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1201
      DL : Natural;
1202
      DR : Shared_Wide_Wide_String_Access;
1203
 
1204
   begin
1205
      --  Check bounds
1206
 
1207
      if Position > SR.Last + 1 then
1208
         raise Index_Error;
1209
      end if;
1210
 
1211
      DL := Integer'Max (SR.Last, Position + New_Item'Length - 1);
1212
 
1213
      --  Result is empty string, reuse empty shared string
1214
 
1215
      if DL = 0 then
1216
         Reference (Empty_Shared_Wide_Wide_String'Access);
1217
         DR := Empty_Shared_Wide_Wide_String'Access;
1218
 
1219
      --  Result is same with source string, reuse source shared string
1220
 
1221
      elsif New_Item'Length = 0 then
1222
         Reference (SR);
1223
         DR := SR;
1224
 
1225
      --  Otherwise, allocate new shared string and fill it
1226
 
1227
      else
1228
         DR := Allocate (DL);
1229
         DR.Data (1 .. Position - 1) := SR.Data (1 .. Position - 1);
1230
         DR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1231
         DR.Data (Position + New_Item'Length .. DL) :=
1232
           SR.Data (Position + New_Item'Length .. SR.Last);
1233
         DR.Last := DL;
1234
      end if;
1235
 
1236
      return (AF.Controlled with Reference => DR);
1237
   end Overwrite;
1238
 
1239
   procedure Overwrite
1240
     (Source    : in out Unbounded_Wide_Wide_String;
1241
      Position  : Positive;
1242
      New_Item  : Wide_Wide_String)
1243
   is
1244
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1245
      DL : Natural;
1246
      DR : Shared_Wide_Wide_String_Access;
1247
 
1248
   begin
1249
      --  Bounds check
1250
 
1251
      if Position > SR.Last + 1 then
1252
         raise Index_Error;
1253
      end if;
1254
 
1255
      DL := Integer'Max (SR.Last, Position + New_Item'Length - 1);
1256
 
1257
      --  Result is empty string, reuse empty shared string
1258
 
1259
      if DL = 0 then
1260
         Reference (Empty_Shared_Wide_Wide_String'Access);
1261
         Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1262
         Unreference (SR);
1263
 
1264
      --  String unchanged, nothing to do
1265
 
1266
      elsif New_Item'Length = 0 then
1267
         null;
1268
 
1269
      --  Try to reuse existent shared string
1270
 
1271
      elsif Can_Be_Reused (SR, DL) then
1272
         SR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1273
         SR.Last := DL;
1274
 
1275
      --  Otherwise allocate new shared string and fill it
1276
 
1277
      else
1278
         DR := Allocate (DL);
1279
         DR.Data (1 .. Position - 1) := SR.Data (1 .. Position - 1);
1280
         DR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1281
         DR.Data (Position + New_Item'Length .. DL) :=
1282
           SR.Data (Position + New_Item'Length .. SR.Last);
1283
         DR.Last := DL;
1284
         Source.Reference := DR;
1285
         Unreference (SR);
1286
      end if;
1287
   end Overwrite;
1288
 
1289
   ---------------
1290
   -- Reference --
1291
   ---------------
1292
 
1293
   procedure Reference (Item : not null Shared_Wide_Wide_String_Access) is
1294
   begin
1295
      System.Atomic_Counters.Increment (Item.Counter);
1296
   end Reference;
1297
 
1298
   ---------------------
1299
   -- Replace_Element --
1300
   ---------------------
1301
 
1302
   procedure Replace_Element
1303
     (Source : in out Unbounded_Wide_Wide_String;
1304
      Index  : Positive;
1305
      By     : Wide_Wide_Character)
1306
   is
1307
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1308
      DR : Shared_Wide_Wide_String_Access;
1309
 
1310
   begin
1311
      --  Bounds check
1312
 
1313
      if Index <= SR.Last then
1314
 
1315
         --  Try to reuse existent shared string
1316
 
1317
         if Can_Be_Reused (SR, SR.Last) then
1318
            SR.Data (Index) := By;
1319
 
1320
         --  Otherwise allocate new shared string and fill it
1321
 
1322
         else
1323
            DR := Allocate (SR.Last);
1324
            DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
1325
            DR.Data (Index) := By;
1326
            DR.Last := SR.Last;
1327
            Source.Reference := DR;
1328
            Unreference (SR);
1329
         end if;
1330
 
1331
      else
1332
         raise Index_Error;
1333
      end if;
1334
   end Replace_Element;
1335
 
1336
   -------------------
1337
   -- Replace_Slice --
1338
   -------------------
1339
 
1340
   function Replace_Slice
1341
     (Source : Unbounded_Wide_Wide_String;
1342
      Low    : Positive;
1343
      High   : Natural;
1344
      By     : Wide_Wide_String) return Unbounded_Wide_Wide_String
1345
   is
1346
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1347
      DL : Natural;
1348
      DR : Shared_Wide_Wide_String_Access;
1349
 
1350
   begin
1351
      --  Check bounds
1352
 
1353
      if Low > SR.Last + 1 then
1354
         raise Index_Error;
1355
      end if;
1356
 
1357
      --  Do replace operation when removed slice is not empty
1358
 
1359
      if High >= Low then
1360
         DL := By'Length + SR.Last + Low - Integer'Min (High, SR.Last) - 1;
1361
         --  This is the number of characters remaining in the string after
1362
         --  replacing the slice.
1363
 
1364
         --  Result is empty string, reuse empty shared string
1365
 
1366
         if DL = 0 then
1367
            Reference (Empty_Shared_Wide_Wide_String'Access);
1368
            DR := Empty_Shared_Wide_Wide_String'Access;
1369
 
1370
         --  Otherwise allocate new shared string and fill it
1371
 
1372
         else
1373
            DR := Allocate (DL);
1374
            DR.Data (1 .. Low - 1) := SR.Data (1 .. Low - 1);
1375
            DR.Data (Low .. Low + By'Length - 1) := By;
1376
            DR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1377
            DR.Last := DL;
1378
         end if;
1379
 
1380
         return (AF.Controlled with Reference => DR);
1381
 
1382
      --  Otherwise just insert string
1383
 
1384
      else
1385
         return Insert (Source, Low, By);
1386
      end if;
1387
   end Replace_Slice;
1388
 
1389
   procedure Replace_Slice
1390
     (Source : in out Unbounded_Wide_Wide_String;
1391
      Low    : Positive;
1392
      High   : Natural;
1393
      By     : Wide_Wide_String)
1394
   is
1395
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1396
      DL : Natural;
1397
      DR : Shared_Wide_Wide_String_Access;
1398
 
1399
   begin
1400
      --  Bounds check
1401
 
1402
      if Low > SR.Last + 1 then
1403
         raise Index_Error;
1404
      end if;
1405
 
1406
      --  Do replace operation only when replaced slice is not empty
1407
 
1408
      if High >= Low then
1409
         DL := By'Length + SR.Last + Low - Integer'Min (High, SR.Last) - 1;
1410
         --  This is the number of characters remaining in the string after
1411
         --  replacing the slice.
1412
 
1413
         --  Result is empty string, reuse empty shared string
1414
 
1415
         if DL = 0 then
1416
            Reference (Empty_Shared_Wide_Wide_String'Access);
1417
            Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1418
            Unreference (SR);
1419
 
1420
         --  Try to reuse existent shared string
1421
 
1422
         elsif Can_Be_Reused (SR, DL) then
1423
            SR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1424
            SR.Data (Low .. Low + By'Length - 1) := By;
1425
            SR.Last := DL;
1426
 
1427
         --  Otherwise allocate new shared string and fill it
1428
 
1429
         else
1430
            DR := Allocate (DL);
1431
            DR.Data (1 .. Low - 1) := SR.Data (1 .. Low - 1);
1432
            DR.Data (Low .. Low + By'Length - 1) := By;
1433
            DR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1434
            DR.Last := DL;
1435
            Source.Reference := DR;
1436
            Unreference (SR);
1437
         end if;
1438
 
1439
      --  Otherwise just insert item
1440
 
1441
      else
1442
         Insert (Source, Low, By);
1443
      end if;
1444
   end Replace_Slice;
1445
 
1446
   -------------------------------
1447
   -- Set_Unbounded_Wide_Wide_String --
1448
   -------------------------------
1449
 
1450
   procedure Set_Unbounded_Wide_Wide_String
1451
     (Target : out Unbounded_Wide_Wide_String;
1452
      Source : Wide_Wide_String)
1453
   is
1454
      TR : constant Shared_Wide_Wide_String_Access := Target.Reference;
1455
      DR : Shared_Wide_Wide_String_Access;
1456
 
1457
   begin
1458
      --  In case of empty string, reuse empty shared string
1459
 
1460
      if Source'Length = 0 then
1461
         Reference (Empty_Shared_Wide_Wide_String'Access);
1462
         Target.Reference := Empty_Shared_Wide_Wide_String'Access;
1463
 
1464
      else
1465
         --  Try to reuse existent shared string
1466
 
1467
         if Can_Be_Reused (TR, Source'Length) then
1468
            Reference (TR);
1469
            DR := TR;
1470
 
1471
         --  Otherwise allocate new shared string
1472
 
1473
         else
1474
            DR := Allocate (Source'Length);
1475
            Target.Reference := DR;
1476
         end if;
1477
 
1478
         DR.Data (1 .. Source'Length) := Source;
1479
         DR.Last := Source'Length;
1480
      end if;
1481
 
1482
      Unreference (TR);
1483
   end Set_Unbounded_Wide_Wide_String;
1484
 
1485
   -----------
1486
   -- Slice --
1487
   -----------
1488
 
1489
   function Slice
1490
     (Source : Unbounded_Wide_Wide_String;
1491
      Low    : Positive;
1492
      High   : Natural) return Wide_Wide_String
1493
   is
1494
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1495
 
1496
   begin
1497
      --  Note: test of High > Length is in accordance with AI95-00128
1498
 
1499
      if Low > SR.Last + 1 or else High > SR.Last then
1500
         raise Index_Error;
1501
 
1502
      else
1503
         return SR.Data (Low .. High);
1504
      end if;
1505
   end Slice;
1506
 
1507
   ----------
1508
   -- Tail --
1509
   ----------
1510
 
1511
   function Tail
1512
     (Source : Unbounded_Wide_Wide_String;
1513
      Count  : Natural;
1514
      Pad    : Wide_Wide_Character := Wide_Wide_Space)
1515
      return Unbounded_Wide_Wide_String
1516
   is
1517
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1518
      DR : Shared_Wide_Wide_String_Access;
1519
 
1520
   begin
1521
      --  For empty result reuse empty shared string
1522
 
1523
      if Count = 0 then
1524
         Reference (Empty_Shared_Wide_Wide_String'Access);
1525
         DR := Empty_Shared_Wide_Wide_String'Access;
1526
 
1527
      --  Result is hole source string, reuse source shared string
1528
 
1529
      elsif Count = SR.Last then
1530
         Reference (SR);
1531
         DR := SR;
1532
 
1533
      --  Otherwise allocate new shared string and fill it
1534
 
1535
      else
1536
         DR := Allocate (Count);
1537
 
1538
         if Count < SR.Last then
1539
            DR.Data (1 .. Count) := SR.Data (SR.Last - Count + 1 .. SR.Last);
1540
 
1541
         else
1542
            for J in 1 .. Count - SR.Last loop
1543
               DR.Data (J) := Pad;
1544
            end loop;
1545
 
1546
            DR.Data (Count - SR.Last + 1 .. Count) := SR.Data (1 .. SR.Last);
1547
         end if;
1548
 
1549
         DR.Last := Count;
1550
      end if;
1551
 
1552
      return (AF.Controlled with Reference => DR);
1553
   end Tail;
1554
 
1555
   procedure Tail
1556
     (Source : in out Unbounded_Wide_Wide_String;
1557
      Count  : Natural;
1558
      Pad    : Wide_Wide_Character := Wide_Wide_Space)
1559
   is
1560
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1561
      DR : Shared_Wide_Wide_String_Access;
1562
 
1563
      procedure Common
1564
        (SR    : Shared_Wide_Wide_String_Access;
1565
         DR    : Shared_Wide_Wide_String_Access;
1566
         Count : Natural);
1567
      --  Common code of tail computation. SR/DR can point to the same object
1568
 
1569
      ------------
1570
      -- Common --
1571
      ------------
1572
 
1573
      procedure Common
1574
        (SR    : Shared_Wide_Wide_String_Access;
1575
         DR    : Shared_Wide_Wide_String_Access;
1576
         Count : Natural) is
1577
      begin
1578
         if Count < SR.Last then
1579
            DR.Data (1 .. Count) := SR.Data (SR.Last - Count + 1 .. SR.Last);
1580
 
1581
         else
1582
            DR.Data (Count - SR.Last + 1 .. Count) := SR.Data (1 .. SR.Last);
1583
 
1584
            for J in 1 .. Count - SR.Last loop
1585
               DR.Data (J) := Pad;
1586
            end loop;
1587
         end if;
1588
 
1589
         DR.Last := Count;
1590
      end Common;
1591
 
1592
   begin
1593
      --  Result is empty string, reuse empty shared string
1594
 
1595
      if Count = 0 then
1596
         Reference (Empty_Shared_Wide_Wide_String'Access);
1597
         Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1598
         Unreference (SR);
1599
 
1600
      --  Length of the result is the same with length of the source string,
1601
      --  reuse source shared string.
1602
 
1603
      elsif Count = SR.Last then
1604
         null;
1605
 
1606
      --  Try to reuse existent shared string
1607
 
1608
      elsif Can_Be_Reused (SR, Count) then
1609
         Common (SR, SR, Count);
1610
 
1611
      --  Otherwise allocate new shared string and fill it
1612
 
1613
      else
1614
         DR := Allocate (Count);
1615
         Common (SR, DR, Count);
1616
         Source.Reference := DR;
1617
         Unreference (SR);
1618
      end if;
1619
   end Tail;
1620
 
1621
   --------------------
1622
   -- To_Wide_Wide_String --
1623
   --------------------
1624
 
1625
   function To_Wide_Wide_String
1626
     (Source : Unbounded_Wide_Wide_String) return Wide_Wide_String is
1627
   begin
1628
      return Source.Reference.Data (1 .. Source.Reference.Last);
1629
   end To_Wide_Wide_String;
1630
 
1631
   ------------------------------
1632
   -- To_Unbounded_Wide_Wide_String --
1633
   ------------------------------
1634
 
1635
   function To_Unbounded_Wide_Wide_String
1636
     (Source : Wide_Wide_String) return Unbounded_Wide_Wide_String
1637
   is
1638
      DR : constant Shared_Wide_Wide_String_Access := Allocate (Source'Length);
1639
   begin
1640
      DR.Data (1 .. Source'Length) := Source;
1641
      DR.Last := Source'Length;
1642
      return (AF.Controlled with Reference => DR);
1643
   end To_Unbounded_Wide_Wide_String;
1644
 
1645
   function To_Unbounded_Wide_Wide_String
1646
     (Length : Natural) return Unbounded_Wide_Wide_String
1647
   is
1648
      DR : constant Shared_Wide_Wide_String_Access := Allocate (Length);
1649
   begin
1650
      DR.Last := Length;
1651
      return (AF.Controlled with Reference => DR);
1652
   end To_Unbounded_Wide_Wide_String;
1653
 
1654
   ---------------
1655
   -- Translate --
1656
   ---------------
1657
 
1658
   function Translate
1659
     (Source  : Unbounded_Wide_Wide_String;
1660
      Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping)
1661
      return Unbounded_Wide_Wide_String
1662
   is
1663
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1664
      DR : Shared_Wide_Wide_String_Access;
1665
 
1666
   begin
1667
      --  Nothing to translate, reuse empty shared string
1668
 
1669
      if SR.Last = 0 then
1670
         Reference (Empty_Shared_Wide_Wide_String'Access);
1671
         DR := Empty_Shared_Wide_Wide_String'Access;
1672
 
1673
      --  Otherwise, allocate new shared string and fill it
1674
 
1675
      else
1676
         DR := Allocate (SR.Last);
1677
 
1678
         for J in 1 .. SR.Last loop
1679
            DR.Data (J) := Value (Mapping, SR.Data (J));
1680
         end loop;
1681
 
1682
         DR.Last := SR.Last;
1683
      end if;
1684
 
1685
      return (AF.Controlled with Reference => DR);
1686
   end Translate;
1687
 
1688
   procedure Translate
1689
     (Source  : in out Unbounded_Wide_Wide_String;
1690
      Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping)
1691
   is
1692
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1693
      DR : Shared_Wide_Wide_String_Access;
1694
 
1695
   begin
1696
      --  Nothing to translate
1697
 
1698
      if SR.Last = 0 then
1699
         null;
1700
 
1701
      --  Try to reuse shared string
1702
 
1703
      elsif Can_Be_Reused (SR, SR.Last) then
1704
         for J in 1 .. SR.Last loop
1705
            SR.Data (J) := Value (Mapping, SR.Data (J));
1706
         end loop;
1707
 
1708
      --  Otherwise, allocate new shared string
1709
 
1710
      else
1711
         DR := Allocate (SR.Last);
1712
 
1713
         for J in 1 .. SR.Last loop
1714
            DR.Data (J) := Value (Mapping, SR.Data (J));
1715
         end loop;
1716
 
1717
         DR.Last := SR.Last;
1718
         Source.Reference := DR;
1719
         Unreference (SR);
1720
      end if;
1721
   end Translate;
1722
 
1723
   function Translate
1724
     (Source  : Unbounded_Wide_Wide_String;
1725
      Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
1726
      return Unbounded_Wide_Wide_String
1727
   is
1728
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1729
      DR : Shared_Wide_Wide_String_Access;
1730
 
1731
   begin
1732
      --  Nothing to translate, reuse empty shared string
1733
 
1734
      if SR.Last = 0 then
1735
         Reference (Empty_Shared_Wide_Wide_String'Access);
1736
         DR := Empty_Shared_Wide_Wide_String'Access;
1737
 
1738
      --  Otherwise, allocate new shared string and fill it
1739
 
1740
      else
1741
         DR := Allocate (SR.Last);
1742
 
1743
         for J in 1 .. SR.Last loop
1744
            DR.Data (J) := Mapping.all (SR.Data (J));
1745
         end loop;
1746
 
1747
         DR.Last := SR.Last;
1748
      end if;
1749
 
1750
      return (AF.Controlled with Reference => DR);
1751
 
1752
   exception
1753
      when others =>
1754
         Unreference (DR);
1755
 
1756
         raise;
1757
   end Translate;
1758
 
1759
   procedure Translate
1760
     (Source  : in out Unbounded_Wide_Wide_String;
1761
      Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
1762
   is
1763
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1764
      DR : Shared_Wide_Wide_String_Access;
1765
 
1766
   begin
1767
      --  Nothing to translate
1768
 
1769
      if SR.Last = 0 then
1770
         null;
1771
 
1772
      --  Try to reuse shared string
1773
 
1774
      elsif Can_Be_Reused (SR, SR.Last) then
1775
         for J in 1 .. SR.Last loop
1776
            SR.Data (J) := Mapping.all (SR.Data (J));
1777
         end loop;
1778
 
1779
      --  Otherwise allocate new shared string and fill it
1780
 
1781
      else
1782
         DR := Allocate (SR.Last);
1783
 
1784
         for J in 1 .. SR.Last loop
1785
            DR.Data (J) := Mapping.all (SR.Data (J));
1786
         end loop;
1787
 
1788
         DR.Last := SR.Last;
1789
         Source.Reference := DR;
1790
         Unreference (SR);
1791
      end if;
1792
 
1793
   exception
1794
      when others =>
1795
         if DR /= null then
1796
            Unreference (DR);
1797
         end if;
1798
 
1799
         raise;
1800
   end Translate;
1801
 
1802
   ----------
1803
   -- Trim --
1804
   ----------
1805
 
1806
   function Trim
1807
     (Source : Unbounded_Wide_Wide_String;
1808
      Side   : Trim_End) return Unbounded_Wide_Wide_String
1809
   is
1810
      SR   : constant Shared_Wide_Wide_String_Access := Source.Reference;
1811
      DL   : Natural;
1812
      DR   : Shared_Wide_Wide_String_Access;
1813
      Low  : Natural;
1814
      High : Natural;
1815
 
1816
   begin
1817
      Low := Index_Non_Blank (Source, Forward);
1818
 
1819
      --  All blanks, reuse empty shared string
1820
 
1821
      if Low = 0 then
1822
         Reference (Empty_Shared_Wide_Wide_String'Access);
1823
         DR := Empty_Shared_Wide_Wide_String'Access;
1824
 
1825
      else
1826
         case Side is
1827
            when Left =>
1828
               High := SR.Last;
1829
               DL   := SR.Last - Low + 1;
1830
 
1831
            when Right =>
1832
               Low  := 1;
1833
               High := Index_Non_Blank (Source, Backward);
1834
               DL   := High;
1835
 
1836
            when Both =>
1837
               High := Index_Non_Blank (Source, Backward);
1838
               DL   := High - Low + 1;
1839
         end case;
1840
 
1841
         --  Length of the result is the same as length of the source string,
1842
         --  reuse source shared string.
1843
 
1844
         if DL = SR.Last then
1845
            Reference (SR);
1846
            DR := SR;
1847
 
1848
         --  Otherwise, allocate new shared string
1849
 
1850
         else
1851
            DR := Allocate (DL);
1852
            DR.Data (1 .. DL) := SR.Data (Low .. High);
1853
            DR.Last := DL;
1854
         end if;
1855
      end if;
1856
 
1857
      return (AF.Controlled with Reference => DR);
1858
   end Trim;
1859
 
1860
   procedure Trim
1861
     (Source : in out Unbounded_Wide_Wide_String;
1862
      Side   : Trim_End)
1863
   is
1864
      SR   : constant Shared_Wide_Wide_String_Access := Source.Reference;
1865
      DL   : Natural;
1866
      DR   : Shared_Wide_Wide_String_Access;
1867
      Low  : Natural;
1868
      High : Natural;
1869
 
1870
   begin
1871
      Low := Index_Non_Blank (Source, Forward);
1872
 
1873
      --  All blanks, reuse empty shared string
1874
 
1875
      if Low = 0 then
1876
         Reference (Empty_Shared_Wide_Wide_String'Access);
1877
         Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1878
         Unreference (SR);
1879
 
1880
      else
1881
         case Side is
1882
            when Left =>
1883
               High := SR.Last;
1884
               DL   := SR.Last - Low + 1;
1885
 
1886
            when Right =>
1887
               Low  := 1;
1888
               High := Index_Non_Blank (Source, Backward);
1889
               DL   := High;
1890
 
1891
            when Both =>
1892
               High := Index_Non_Blank (Source, Backward);
1893
               DL   := High - Low + 1;
1894
         end case;
1895
 
1896
         --  Length of the result is the same as length of the source string,
1897
         --  nothing to do.
1898
 
1899
         if DL = SR.Last then
1900
            null;
1901
 
1902
         --  Try to reuse existent shared string
1903
 
1904
         elsif Can_Be_Reused (SR, DL) then
1905
            SR.Data (1 .. DL) := SR.Data (Low .. High);
1906
            SR.Last := DL;
1907
 
1908
         --  Otherwise, allocate new shared string
1909
 
1910
         else
1911
            DR := Allocate (DL);
1912
            DR.Data (1 .. DL) := SR.Data (Low .. High);
1913
            DR.Last := DL;
1914
            Source.Reference := DR;
1915
            Unreference (SR);
1916
         end if;
1917
      end if;
1918
   end Trim;
1919
 
1920
   function Trim
1921
     (Source : Unbounded_Wide_Wide_String;
1922
      Left   : Wide_Wide_Maps.Wide_Wide_Character_Set;
1923
      Right  : Wide_Wide_Maps.Wide_Wide_Character_Set)
1924
      return Unbounded_Wide_Wide_String
1925
   is
1926
      SR   : constant Shared_Wide_Wide_String_Access := Source.Reference;
1927
      DL   : Natural;
1928
      DR   : Shared_Wide_Wide_String_Access;
1929
      Low  : Natural;
1930
      High : Natural;
1931
 
1932
   begin
1933
      Low := Index (Source, Left, Outside, Forward);
1934
 
1935
      --  Source includes only characters from Left set, reuse empty shared
1936
      --  string.
1937
 
1938
      if Low = 0 then
1939
         Reference (Empty_Shared_Wide_Wide_String'Access);
1940
         DR := Empty_Shared_Wide_Wide_String'Access;
1941
 
1942
      else
1943
         High := Index (Source, Right, Outside, Backward);
1944
         DL   := Integer'Max (0, High - Low + 1);
1945
 
1946
         --  Source includes only characters from Right set or result string
1947
         --  is empty, reuse empty shared string.
1948
 
1949
         if High = 0 or else DL = 0 then
1950
            Reference (Empty_Shared_Wide_Wide_String'Access);
1951
            DR := Empty_Shared_Wide_Wide_String'Access;
1952
 
1953
         --  Otherwise, allocate new shared string and fill it
1954
 
1955
         else
1956
            DR := Allocate (DL);
1957
            DR.Data (1 .. DL) := SR.Data (Low .. High);
1958
            DR.Last := DL;
1959
         end if;
1960
      end if;
1961
 
1962
      return (AF.Controlled with Reference => DR);
1963
   end Trim;
1964
 
1965
   procedure Trim
1966
     (Source : in out Unbounded_Wide_Wide_String;
1967
      Left   : Wide_Wide_Maps.Wide_Wide_Character_Set;
1968
      Right  : Wide_Wide_Maps.Wide_Wide_Character_Set)
1969
   is
1970
      SR   : constant Shared_Wide_Wide_String_Access := Source.Reference;
1971
      DL   : Natural;
1972
      DR   : Shared_Wide_Wide_String_Access;
1973
      Low  : Natural;
1974
      High : Natural;
1975
 
1976
   begin
1977
      Low := Index (Source, Left, Outside, Forward);
1978
 
1979
      --  Source includes only characters from Left set, reuse empty shared
1980
      --  string.
1981
 
1982
      if Low = 0 then
1983
         Reference (Empty_Shared_Wide_Wide_String'Access);
1984
         Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1985
         Unreference (SR);
1986
 
1987
      else
1988
         High := Index (Source, Right, Outside, Backward);
1989
         DL   := Integer'Max (0, High - Low + 1);
1990
 
1991
         --  Source includes only characters from Right set or result string
1992
         --  is empty, reuse empty shared string.
1993
 
1994
         if High = 0 or else DL = 0 then
1995
            Reference (Empty_Shared_Wide_Wide_String'Access);
1996
            Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1997
            Unreference (SR);
1998
 
1999
         --  Try to reuse existent shared string
2000
 
2001
         elsif Can_Be_Reused (SR, DL) then
2002
            SR.Data (1 .. DL) := SR.Data (Low .. High);
2003
            SR.Last := DL;
2004
 
2005
         --  Otherwise, allocate new shared string and fill it
2006
 
2007
         else
2008
            DR := Allocate (DL);
2009
            DR.Data (1 .. DL) := SR.Data (Low .. High);
2010
            DR.Last := DL;
2011
            Source.Reference := DR;
2012
            Unreference (SR);
2013
         end if;
2014
      end if;
2015
   end Trim;
2016
 
2017
   ---------------------
2018
   -- Unbounded_Slice --
2019
   ---------------------
2020
 
2021
   function Unbounded_Slice
2022
     (Source : Unbounded_Wide_Wide_String;
2023
      Low    : Positive;
2024
      High   : Natural) return Unbounded_Wide_Wide_String
2025
   is
2026
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
2027
      DL : Natural;
2028
      DR : Shared_Wide_Wide_String_Access;
2029
 
2030
   begin
2031
      --  Check bounds
2032
 
2033
      if Low > SR.Last + 1 or else High > SR.Last then
2034
         raise Index_Error;
2035
 
2036
      --  Result is empty slice, reuse empty shared string
2037
 
2038
      elsif Low > High then
2039
         Reference (Empty_Shared_Wide_Wide_String'Access);
2040
         DR := Empty_Shared_Wide_Wide_String'Access;
2041
 
2042
      --  Otherwise, allocate new shared string and fill it
2043
 
2044
      else
2045
         DL := High - Low + 1;
2046
         DR := Allocate (DL);
2047
         DR.Data (1 .. DL) := SR.Data (Low .. High);
2048
         DR.Last := DL;
2049
      end if;
2050
 
2051
      return (AF.Controlled with Reference => DR);
2052
   end Unbounded_Slice;
2053
 
2054
   procedure Unbounded_Slice
2055
     (Source : Unbounded_Wide_Wide_String;
2056
      Target : out Unbounded_Wide_Wide_String;
2057
      Low    : Positive;
2058
      High   : Natural)
2059
   is
2060
      SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
2061
      TR : constant Shared_Wide_Wide_String_Access := Target.Reference;
2062
      DL : Natural;
2063
      DR : Shared_Wide_Wide_String_Access;
2064
 
2065
   begin
2066
      --  Check bounds
2067
 
2068
      if Low > SR.Last + 1 or else High > SR.Last then
2069
         raise Index_Error;
2070
 
2071
      --  Result is empty slice, reuse empty shared string
2072
 
2073
      elsif Low > High then
2074
         Reference (Empty_Shared_Wide_Wide_String'Access);
2075
         Target.Reference := Empty_Shared_Wide_Wide_String'Access;
2076
         Unreference (TR);
2077
 
2078
      else
2079
         DL := High - Low + 1;
2080
 
2081
         --  Try to reuse existent shared string
2082
 
2083
         if Can_Be_Reused (TR, DL) then
2084
            TR.Data (1 .. DL) := SR.Data (Low .. High);
2085
            TR.Last := DL;
2086
 
2087
         --  Otherwise, allocate new shared string and fill it
2088
 
2089
         else
2090
            DR := Allocate (DL);
2091
            DR.Data (1 .. DL) := SR.Data (Low .. High);
2092
            DR.Last := DL;
2093
            Target.Reference := DR;
2094
            Unreference (TR);
2095
         end if;
2096
      end if;
2097
   end Unbounded_Slice;
2098
 
2099
   -----------------
2100
   -- Unreference --
2101
   -----------------
2102
 
2103
   procedure Unreference (Item : not null Shared_Wide_Wide_String_Access) is
2104
 
2105
      procedure Free is
2106
        new Ada.Unchecked_Deallocation
2107
              (Shared_Wide_Wide_String, Shared_Wide_Wide_String_Access);
2108
 
2109
      Aux : Shared_Wide_Wide_String_Access := Item;
2110
 
2111
   begin
2112
      if System.Atomic_Counters.Decrement (Aux.Counter) then
2113
 
2114
         --  Reference counter of Empty_Shared_Wide_Wide_String must never
2115
         --  reach zero.
2116
 
2117
         pragma Assert (Aux /= Empty_Shared_Wide_Wide_String'Access);
2118
 
2119
         Free (Aux);
2120
      end if;
2121
   end Unreference;
2122
 
2123
end Ada.Strings.Wide_Wide_Unbounded;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.