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

Subversion Repositories openrisc

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

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

powered by: WebSVN 2.1.0

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