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

Subversion Repositories openrisc

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

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

powered by: WebSVN 2.1.0

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