c++: Mostly concepts related formatting fixes
[official-gcc.git] / gcc / ada / libgnat / a-strunb__shared.adb
blobecc0e4af11758f256c1d2ee27ca91a6f4ecb83a0
1 ------------------------------------------------------------------------------
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-2024, 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 ------------------------------------------------------------------------------
32 with Ada.Strings.Search;
33 with Ada.Unchecked_Deallocation;
35 package body Ada.Strings.Unbounded is
37 use Ada.Strings.Maps;
39 Growth_Factor : constant := 2;
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 -- 2 means add 1/2 of the length of the string as growth space.
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.
53 function Aligned_Max_Length
54 (Required_Length : Natural;
55 Reserved_Length : Natural) return Natural;
56 -- Returns recommended length of the shared string which is greater or
57 -- equal to specified required length and desired reserved length.
58 -- Calculation takes into account alignment of the allocated memory
59 -- segments to use memory effectively by Append/Insert/etc operations.
61 function Sum (Left : Natural; Right : Integer) return Natural with Inline;
62 -- Returns summary of Left and Right, raise Constraint_Error on overflow
64 function Mul (Left, Right : Natural) return Natural with Inline;
65 -- Returns multiplication of Left and Right, raise Constraint_Error on
66 -- overflow
68 ---------
69 -- "&" --
70 ---------
72 function "&"
73 (Left : Unbounded_String;
74 Right : Unbounded_String) return Unbounded_String
76 LR : constant Shared_String_Access := Left.Reference;
77 RR : constant Shared_String_Access := Right.Reference;
78 DL : constant Natural := Sum (LR.Last, RR.Last);
79 DR : Shared_String_Access;
81 begin
82 -- Result is an empty string, reuse shared empty string
84 if DL = 0 then
85 DR := Empty_Shared_String'Access;
87 -- Left string is empty, return Right string
89 elsif LR.Last = 0 then
90 Reference (RR);
91 DR := RR;
93 -- Right string is empty, return Left string
95 elsif RR.Last = 0 then
96 Reference (LR);
97 DR := LR;
99 -- Otherwise, allocate new shared string and fill data
101 else
102 DR := Allocate (DL);
103 DR.Data (1 .. LR.Last) := LR.Data (1 .. LR.Last);
104 DR.Data (LR.Last + 1 .. DL) := RR.Data (1 .. RR.Last);
105 DR.Last := DL;
106 end if;
108 return (AF.Controlled with Reference => DR);
109 end "&";
111 function "&"
112 (Left : Unbounded_String;
113 Right : String) return Unbounded_String
115 LR : constant Shared_String_Access := Left.Reference;
116 DL : constant Natural := Sum (LR.Last, Right'Length);
117 DR : Shared_String_Access;
119 begin
120 -- Result is an empty string, reuse shared empty string
122 if DL = 0 then
123 DR := Empty_Shared_String'Access;
125 -- Right is an empty string, return Left string
127 elsif Right'Length = 0 then
128 Reference (LR);
129 DR := LR;
131 -- Otherwise, allocate new shared string and fill it
133 else
134 DR := Allocate (DL);
135 DR.Data (1 .. LR.Last) := LR.Data (1 .. LR.Last);
136 DR.Data (LR.Last + 1 .. DL) := Right;
137 DR.Last := DL;
138 end if;
140 return (AF.Controlled with Reference => DR);
141 end "&";
143 function "&"
144 (Left : String;
145 Right : Unbounded_String) return Unbounded_String
147 RR : constant Shared_String_Access := Right.Reference;
148 DL : constant Natural := Sum (Left'Length, RR.Last);
149 DR : Shared_String_Access;
151 begin
152 -- Result is an empty string, reuse shared one
154 if DL = 0 then
155 DR := Empty_Shared_String'Access;
157 -- Left is empty string, return Right string
159 elsif Left'Length = 0 then
160 Reference (RR);
161 DR := RR;
163 -- Otherwise, allocate new shared string and fill it
165 else
166 DR := Allocate (DL);
167 DR.Data (1 .. Left'Length) := Left;
168 DR.Data (Left'Length + 1 .. DL) := RR.Data (1 .. RR.Last);
169 DR.Last := DL;
170 end if;
172 return (AF.Controlled with Reference => DR);
173 end "&";
175 function "&"
176 (Left : Unbounded_String;
177 Right : Character) return Unbounded_String
179 LR : constant Shared_String_Access := Left.Reference;
180 DL : constant Natural := Sum (LR.Last, 1);
181 DR : Shared_String_Access;
183 begin
184 DR := Allocate (DL);
185 DR.Data (1 .. LR.Last) := LR.Data (1 .. LR.Last);
186 DR.Data (DL) := Right;
187 DR.Last := DL;
189 return (AF.Controlled with Reference => DR);
190 end "&";
192 function "&"
193 (Left : Character;
194 Right : Unbounded_String) return Unbounded_String
196 RR : constant Shared_String_Access := Right.Reference;
197 DL : constant Natural := Sum (1, RR.Last);
198 DR : Shared_String_Access;
200 begin
201 DR := Allocate (DL);
202 DR.Data (1) := Left;
203 DR.Data (2 .. DL) := RR.Data (1 .. RR.Last);
204 DR.Last := DL;
206 return (AF.Controlled with Reference => DR);
207 end "&";
209 ---------
210 -- "*" --
211 ---------
213 function "*"
214 (Left : Natural;
215 Right : Character) return Unbounded_String
217 DR : Shared_String_Access;
219 begin
220 -- Result is an empty string, reuse shared empty string
222 if Left = 0 then
223 DR := Empty_Shared_String'Access;
225 -- Otherwise, allocate new shared string and fill it
227 else
228 DR := Allocate (Left);
230 for J in 1 .. Left loop
231 DR.Data (J) := Right;
232 end loop;
234 DR.Last := Left;
235 end if;
237 return (AF.Controlled with Reference => DR);
238 end "*";
240 function "*"
241 (Left : Natural;
242 Right : String) return Unbounded_String
244 DL : constant Natural := Mul (Left, Right'Length);
245 DR : Shared_String_Access;
246 K : Positive;
248 begin
249 -- Result is an empty string, reuse shared empty string
251 if DL = 0 then
252 DR := Empty_Shared_String'Access;
254 -- Otherwise, allocate new shared string and fill it
256 else
257 DR := Allocate (DL);
258 K := 1;
260 for J in 1 .. Left loop
261 DR.Data (K .. K + Right'Length - 1) := Right;
262 K := K + Right'Length;
263 end loop;
265 DR.Last := DL;
266 end if;
268 return (AF.Controlled with Reference => DR);
269 end "*";
271 function "*"
272 (Left : Natural;
273 Right : Unbounded_String) return Unbounded_String
275 RR : constant Shared_String_Access := Right.Reference;
276 DL : constant Natural := Mul (Left, RR.Last);
277 DR : Shared_String_Access;
278 K : Positive;
280 begin
281 -- Result is an empty string, reuse shared empty string
283 if DL = 0 then
284 DR := Empty_Shared_String'Access;
286 -- Coefficient is one, just return string itself
288 elsif Left = 1 then
289 Reference (RR);
290 DR := RR;
292 -- Otherwise, allocate new shared string and fill it
294 else
295 DR := Allocate (DL);
296 K := 1;
298 for J in 1 .. Left loop
299 DR.Data (K .. K + RR.Last - 1) := RR.Data (1 .. RR.Last);
300 K := K + RR.Last;
301 end loop;
303 DR.Last := DL;
304 end if;
306 return (AF.Controlled with Reference => DR);
307 end "*";
309 ---------
310 -- "<" --
311 ---------
313 function "<"
314 (Left : Unbounded_String;
315 Right : Unbounded_String) return Boolean
317 LR : constant Shared_String_Access := Left.Reference;
318 RR : constant Shared_String_Access := Right.Reference;
319 begin
320 return LR.Data (1 .. LR.Last) < RR.Data (1 .. RR.Last);
321 end "<";
323 function "<"
324 (Left : Unbounded_String;
325 Right : String) return Boolean
327 LR : constant Shared_String_Access := Left.Reference;
328 begin
329 return LR.Data (1 .. LR.Last) < Right;
330 end "<";
332 function "<"
333 (Left : String;
334 Right : Unbounded_String) return Boolean
336 RR : constant Shared_String_Access := Right.Reference;
337 begin
338 return Left < RR.Data (1 .. RR.Last);
339 end "<";
341 ----------
342 -- "<=" --
343 ----------
345 function "<="
346 (Left : Unbounded_String;
347 Right : Unbounded_String) return Boolean
349 LR : constant Shared_String_Access := Left.Reference;
350 RR : constant Shared_String_Access := Right.Reference;
352 begin
353 -- LR = RR means two strings shares shared string, thus they are equal
355 return LR = RR or else LR.Data (1 .. LR.Last) <= RR.Data (1 .. RR.Last);
356 end "<=";
358 function "<="
359 (Left : Unbounded_String;
360 Right : String) return Boolean
362 LR : constant Shared_String_Access := Left.Reference;
363 begin
364 return LR.Data (1 .. LR.Last) <= Right;
365 end "<=";
367 function "<="
368 (Left : String;
369 Right : Unbounded_String) return Boolean
371 RR : constant Shared_String_Access := Right.Reference;
372 begin
373 return Left <= RR.Data (1 .. RR.Last);
374 end "<=";
376 ---------
377 -- "=" --
378 ---------
380 function "="
381 (Left : Unbounded_String;
382 Right : Unbounded_String) return Boolean
384 LR : constant Shared_String_Access := Left.Reference;
385 RR : constant Shared_String_Access := Right.Reference;
387 begin
388 return LR = RR or else LR.Data (1 .. LR.Last) = RR.Data (1 .. RR.Last);
389 -- LR = RR means two strings shares shared string, thus they are equal
390 end "=";
392 function "="
393 (Left : Unbounded_String;
394 Right : String) return Boolean
396 LR : constant Shared_String_Access := Left.Reference;
397 begin
398 return LR.Data (1 .. LR.Last) = Right;
399 end "=";
401 function "="
402 (Left : String;
403 Right : Unbounded_String) return Boolean
405 RR : constant Shared_String_Access := Right.Reference;
406 begin
407 return Left = RR.Data (1 .. RR.Last);
408 end "=";
410 ---------
411 -- ">" --
412 ---------
414 function ">"
415 (Left : Unbounded_String;
416 Right : Unbounded_String) return Boolean
418 LR : constant Shared_String_Access := Left.Reference;
419 RR : constant Shared_String_Access := Right.Reference;
420 begin
421 return LR.Data (1 .. LR.Last) > RR.Data (1 .. RR.Last);
422 end ">";
424 function ">"
425 (Left : Unbounded_String;
426 Right : String) return Boolean
428 LR : constant Shared_String_Access := Left.Reference;
429 begin
430 return LR.Data (1 .. LR.Last) > Right;
431 end ">";
433 function ">"
434 (Left : String;
435 Right : Unbounded_String) return Boolean
437 RR : constant Shared_String_Access := Right.Reference;
438 begin
439 return Left > RR.Data (1 .. RR.Last);
440 end ">";
442 ----------
443 -- ">=" --
444 ----------
446 function ">="
447 (Left : Unbounded_String;
448 Right : Unbounded_String) return Boolean
450 LR : constant Shared_String_Access := Left.Reference;
451 RR : constant Shared_String_Access := Right.Reference;
453 begin
454 -- LR = RR means two strings shares shared string, thus they are equal
456 return LR = RR or else LR.Data (1 .. LR.Last) >= RR.Data (1 .. RR.Last);
457 end ">=";
459 function ">="
460 (Left : Unbounded_String;
461 Right : String) return Boolean
463 LR : constant Shared_String_Access := Left.Reference;
464 begin
465 return LR.Data (1 .. LR.Last) >= Right;
466 end ">=";
468 function ">="
469 (Left : String;
470 Right : Unbounded_String) return Boolean
472 RR : constant Shared_String_Access := Right.Reference;
473 begin
474 return Left >= RR.Data (1 .. RR.Last);
475 end ">=";
477 ------------
478 -- Adjust --
479 ------------
481 procedure Adjust (Object : in out Unbounded_String) is
482 begin
483 Reference (Object.Reference);
484 end Adjust;
486 ------------------------
487 -- Aligned_Max_Length --
488 ------------------------
490 function Aligned_Max_Length
491 (Required_Length : Natural;
492 Reserved_Length : Natural) return Natural
494 Static_Size : constant Natural :=
495 Empty_Shared_String'Size / Standard'Storage_Unit;
496 -- Total size of all Shared_String static components
497 begin
498 if Required_Length > Natural'Last - Static_Size - Reserved_Length then
499 -- Total requested length is larger than maximum possible length.
500 -- Use of Static_Size needed to avoid overflows in expression to
501 -- compute aligned length.
502 return Natural'Last;
504 else
505 return
506 ((Static_Size + Required_Length + Reserved_Length - 1)
507 / Min_Mul_Alloc + 2) * Min_Mul_Alloc - Static_Size;
508 end if;
509 end Aligned_Max_Length;
511 --------------
512 -- Allocate --
513 --------------
515 function Allocate
516 (Required_Length : Natural;
517 Reserved_Length : Natural := 0) return not null Shared_String_Access
519 begin
520 -- Empty string requested, return shared empty string
522 if Required_Length = 0 then
523 return Empty_Shared_String'Access;
525 -- Otherwise, allocate requested space (and probably some more room)
527 else
528 return
529 new Shared_String
530 (Aligned_Max_Length (Required_Length, Reserved_Length));
531 end if;
532 end Allocate;
534 ------------
535 -- Append --
536 ------------
538 procedure Append
539 (Source : in out Unbounded_String;
540 New_Item : Unbounded_String)
542 SR : constant Shared_String_Access := Source.Reference;
543 NR : constant Shared_String_Access := New_Item.Reference;
544 DL : constant Natural := Sum (SR.Last, NR.Last);
545 DR : Shared_String_Access;
547 begin
548 -- Source is an empty string, reuse New_Item data
550 if SR.Last = 0 then
551 Reference (NR);
552 Source.Reference := NR;
553 Unreference (SR);
555 -- New_Item is empty string, nothing to do
557 elsif NR.Last = 0 then
558 null;
560 -- Try to reuse existing shared string
562 elsif Can_Be_Reused (SR, DL) then
563 SR.Data (SR.Last + 1 .. DL) := NR.Data (1 .. NR.Last);
564 SR.Last := DL;
566 -- Otherwise, allocate new one and fill it
568 else
569 DR := Allocate (DL, DL / Growth_Factor);
570 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
571 DR.Data (SR.Last + 1 .. DL) := NR.Data (1 .. NR.Last);
572 DR.Last := DL;
573 Source.Reference := DR;
574 Unreference (SR);
575 end if;
576 end Append;
578 procedure Append
579 (Source : in out Unbounded_String;
580 New_Item : String)
582 SR : constant Shared_String_Access := Source.Reference;
583 DL : constant Natural := Sum (SR.Last, New_Item'Length);
584 DR : Shared_String_Access;
586 begin
587 -- New_Item is an empty string, nothing to do
589 if New_Item'Length = 0 then
590 null;
592 -- Try to reuse existing shared string
594 elsif Can_Be_Reused (SR, DL) then
595 SR.Data (SR.Last + 1 .. DL) := New_Item;
596 SR.Last := DL;
598 -- Otherwise, allocate new one and fill it
600 else
601 DR := Allocate (DL, DL / Growth_Factor);
602 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
603 DR.Data (SR.Last + 1 .. DL) := New_Item;
604 DR.Last := DL;
605 Source.Reference := DR;
606 Unreference (SR);
607 end if;
608 end Append;
610 procedure Append
611 (Source : in out Unbounded_String;
612 New_Item : Character)
614 SR : constant Shared_String_Access := Source.Reference;
615 DL : constant Natural := Sum (SR.Last, 1);
616 DR : Shared_String_Access;
618 begin
619 -- Try to reuse existing shared string
621 if Can_Be_Reused (SR, DL) then
622 SR.Data (SR.Last + 1) := New_Item;
623 SR.Last := SR.Last + 1;
625 -- Otherwise, allocate new one and fill it
627 else
628 DR := Allocate (DL, DL / Growth_Factor);
629 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
630 DR.Data (DL) := New_Item;
631 DR.Last := DL;
632 Source.Reference := DR;
633 Unreference (SR);
634 end if;
635 end Append;
637 -------------------
638 -- Can_Be_Reused --
639 -------------------
641 function Can_Be_Reused
642 (Item : not null Shared_String_Access;
643 Length : Natural) return Boolean
645 begin
646 return
647 System.Atomic_Counters.Is_One (Item.Counter)
648 and then Item.Max_Length >= Length
649 and then Item.Max_Length <=
650 Aligned_Max_Length (Length, Length / Growth_Factor);
651 end Can_Be_Reused;
653 -----------
654 -- Count --
655 -----------
657 function Count
658 (Source : Unbounded_String;
659 Pattern : String;
660 Mapping : Maps.Character_Mapping := Maps.Identity) return Natural
662 SR : constant Shared_String_Access := Source.Reference;
663 begin
664 return Search.Count (SR.Data (1 .. SR.Last), Pattern, Mapping);
665 end Count;
667 function Count
668 (Source : Unbounded_String;
669 Pattern : String;
670 Mapping : Maps.Character_Mapping_Function) return Natural
672 SR : constant Shared_String_Access := Source.Reference;
673 begin
674 return Search.Count (SR.Data (1 .. SR.Last), Pattern, Mapping);
675 end Count;
677 function Count
678 (Source : Unbounded_String;
679 Set : Maps.Character_Set) return Natural
681 SR : constant Shared_String_Access := Source.Reference;
682 begin
683 return Search.Count (SR.Data (1 .. SR.Last), Set);
684 end Count;
686 ------------
687 -- Delete --
688 ------------
690 function Delete
691 (Source : Unbounded_String;
692 From : Positive;
693 Through : Natural) return Unbounded_String
695 SR : constant Shared_String_Access := Source.Reference;
696 DL : Natural;
697 DR : Shared_String_Access;
699 begin
700 -- Empty slice is deleted, use the same shared string
702 if From > Through then
703 Reference (SR);
704 DR := SR;
706 -- Index is out of range
708 elsif Through > SR.Last then
709 raise Index_Error;
711 -- Compute size of the result
713 else
714 DL := SR.Last - (Through - From + 1);
716 -- Result is an empty string, reuse shared empty string
718 if DL = 0 then
719 DR := Empty_Shared_String'Access;
721 -- Otherwise, allocate new shared string and fill it
723 else
724 DR := Allocate (DL);
725 DR.Data (1 .. From - 1) := SR.Data (1 .. From - 1);
726 DR.Data (From .. DL) := SR.Data (Through + 1 .. SR.Last);
727 DR.Last := DL;
728 end if;
729 end if;
731 return (AF.Controlled with Reference => DR);
732 end Delete;
734 procedure Delete
735 (Source : in out Unbounded_String;
736 From : Positive;
737 Through : Natural)
739 SR : constant Shared_String_Access := Source.Reference;
740 DL : Natural;
741 DR : Shared_String_Access;
743 begin
744 -- Nothing changed, return
746 if From > Through then
747 null;
749 -- Through is outside of the range
751 elsif Through > SR.Last then
752 raise Index_Error;
754 else
755 DL := SR.Last - (Through - From + 1);
757 -- Result is empty, reuse shared empty string
759 if DL = 0 then
760 Source.Reference := Empty_Shared_String'Access;
761 Unreference (SR);
763 -- Try to reuse existing shared string
765 elsif Can_Be_Reused (SR, DL) then
766 SR.Data (From .. DL) := SR.Data (Through + 1 .. SR.Last);
767 SR.Last := DL;
769 -- Otherwise, allocate new shared string
771 else
772 DR := Allocate (DL);
773 DR.Data (1 .. From - 1) := SR.Data (1 .. From - 1);
774 DR.Data (From .. DL) := SR.Data (Through + 1 .. SR.Last);
775 DR.Last := DL;
776 Source.Reference := DR;
777 Unreference (SR);
778 end if;
779 end if;
780 end Delete;
782 -------------
783 -- Element --
784 -------------
786 function Element
787 (Source : Unbounded_String;
788 Index : Positive) return Character
790 SR : constant Shared_String_Access := Source.Reference;
791 begin
792 if Index <= SR.Last then
793 return SR.Data (Index);
794 else
795 raise Index_Error;
796 end if;
797 end Element;
799 --------------
800 -- Finalize --
801 --------------
803 procedure Finalize (Object : in out Unbounded_String) is
804 SR : constant not null Shared_String_Access := Object.Reference;
805 begin
806 if SR /= Null_Unbounded_String.Reference then
808 -- The same controlled object can be finalized several times for
809 -- some reason. As per 7.6.1(24) this should have no ill effect,
810 -- so we need to add a guard for the case of finalizing the same
811 -- object twice.
813 -- We set the Object to the empty string so there will be no ill
814 -- effects if a program references an already-finalized object.
816 Object.Reference := Null_Unbounded_String.Reference;
817 Unreference (SR);
818 end if;
819 end Finalize;
821 ----------------
822 -- Find_Token --
823 ----------------
825 procedure Find_Token
826 (Source : Unbounded_String;
827 Set : Maps.Character_Set;
828 From : Positive;
829 Test : Strings.Membership;
830 First : out Positive;
831 Last : out Natural)
833 SR : constant Shared_String_Access := Source.Reference;
834 begin
835 Search.Find_Token (SR.Data (From .. SR.Last), Set, Test, First, Last);
836 end Find_Token;
838 procedure Find_Token
839 (Source : Unbounded_String;
840 Set : Maps.Character_Set;
841 Test : Strings.Membership;
842 First : out Positive;
843 Last : out Natural)
845 SR : constant Shared_String_Access := Source.Reference;
846 begin
847 Search.Find_Token (SR.Data (1 .. SR.Last), Set, Test, First, Last);
848 end Find_Token;
850 ----------
851 -- Free --
852 ----------
854 procedure Free (X : in out String_Access) is
855 procedure Deallocate is
856 new Ada.Unchecked_Deallocation (String, String_Access);
857 begin
858 Deallocate (X);
859 end Free;
861 ----------
862 -- Head --
863 ----------
865 function Head
866 (Source : Unbounded_String;
867 Count : Natural;
868 Pad : Character := Space) return Unbounded_String
870 SR : constant Shared_String_Access := Source.Reference;
871 DR : Shared_String_Access;
873 begin
874 -- Result is empty, reuse shared empty string
876 if Count = 0 then
877 DR := Empty_Shared_String'Access;
879 -- Length of the string is the same as requested, reuse source shared
880 -- string.
882 elsif Count = SR.Last then
883 Reference (SR);
884 DR := SR;
886 -- Otherwise, allocate new shared string and fill it
888 else
889 DR := Allocate (Count);
891 -- Length of the source string is more than requested, copy
892 -- corresponding slice.
894 if Count < SR.Last then
895 DR.Data (1 .. Count) := SR.Data (1 .. Count);
897 -- Length of the source string is less than requested, copy all
898 -- contents and fill others by Pad character.
900 else
901 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
903 for J in SR.Last + 1 .. Count loop
904 DR.Data (J) := Pad;
905 end loop;
906 end if;
908 DR.Last := Count;
909 end if;
911 return (AF.Controlled with Reference => DR);
912 end Head;
914 procedure Head
915 (Source : in out Unbounded_String;
916 Count : Natural;
917 Pad : Character := Space)
919 SR : constant Shared_String_Access := Source.Reference;
920 DR : Shared_String_Access;
922 begin
923 -- Result is empty, reuse empty shared string
925 if Count = 0 then
926 Source.Reference := Empty_Shared_String'Access;
927 Unreference (SR);
929 -- Result is same as source string, reuse source shared string
931 elsif Count = SR.Last then
932 null;
934 -- Try to reuse existing shared string
936 elsif Can_Be_Reused (SR, Count) then
937 if Count > SR.Last then
938 for J in SR.Last + 1 .. Count loop
939 SR.Data (J) := Pad;
940 end loop;
941 end if;
943 SR.Last := Count;
945 -- Otherwise, allocate new shared string and fill it
947 else
948 DR := Allocate (Count);
950 -- Length of the source string is greater than requested, copy
951 -- corresponding slice.
953 if Count < SR.Last then
954 DR.Data (1 .. Count) := SR.Data (1 .. Count);
956 -- Length of the source string is less than requested, copy all
957 -- existing data and fill remaining positions with Pad characters.
959 else
960 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
962 for J in SR.Last + 1 .. Count loop
963 DR.Data (J) := Pad;
964 end loop;
965 end if;
967 DR.Last := Count;
968 Source.Reference := DR;
969 Unreference (SR);
970 end if;
971 end Head;
973 -----------
974 -- Index --
975 -----------
977 function Index
978 (Source : Unbounded_String;
979 Pattern : String;
980 Going : Strings.Direction := Strings.Forward;
981 Mapping : Maps.Character_Mapping := Maps.Identity) return Natural
983 SR : constant Shared_String_Access := Source.Reference;
984 begin
985 return Search.Index (SR.Data (1 .. SR.Last), Pattern, Going, Mapping);
986 end Index;
988 function Index
989 (Source : Unbounded_String;
990 Pattern : String;
991 Going : Direction := Forward;
992 Mapping : Maps.Character_Mapping_Function) return Natural
994 SR : constant Shared_String_Access := Source.Reference;
995 begin
996 return Search.Index (SR.Data (1 .. SR.Last), Pattern, Going, Mapping);
997 end Index;
999 function Index
1000 (Source : Unbounded_String;
1001 Set : Maps.Character_Set;
1002 Test : Strings.Membership := Strings.Inside;
1003 Going : Strings.Direction := Strings.Forward) return Natural
1005 SR : constant Shared_String_Access := Source.Reference;
1006 begin
1007 return Search.Index (SR.Data (1 .. SR.Last), Set, Test, Going);
1008 end Index;
1010 function Index
1011 (Source : Unbounded_String;
1012 Pattern : String;
1013 From : Positive;
1014 Going : Direction := Forward;
1015 Mapping : Maps.Character_Mapping := Maps.Identity) return Natural
1017 SR : constant Shared_String_Access := Source.Reference;
1018 begin
1019 return Search.Index
1020 (SR.Data (1 .. SR.Last), Pattern, From, Going, Mapping);
1021 end Index;
1023 function Index
1024 (Source : Unbounded_String;
1025 Pattern : String;
1026 From : Positive;
1027 Going : Direction := Forward;
1028 Mapping : Maps.Character_Mapping_Function) return Natural
1030 SR : constant Shared_String_Access := Source.Reference;
1031 begin
1032 return Search.Index
1033 (SR.Data (1 .. SR.Last), Pattern, From, Going, Mapping);
1034 end Index;
1036 function Index
1037 (Source : Unbounded_String;
1038 Set : Maps.Character_Set;
1039 From : Positive;
1040 Test : Membership := Inside;
1041 Going : Direction := Forward) return Natural
1043 SR : constant Shared_String_Access := Source.Reference;
1044 begin
1045 return Search.Index (SR.Data (1 .. SR.Last), Set, From, Test, Going);
1046 end Index;
1048 ---------------------
1049 -- Index_Non_Blank --
1050 ---------------------
1052 function Index_Non_Blank
1053 (Source : Unbounded_String;
1054 Going : Strings.Direction := Strings.Forward) return Natural
1056 SR : constant Shared_String_Access := Source.Reference;
1057 begin
1058 return Search.Index_Non_Blank (SR.Data (1 .. SR.Last), Going);
1059 end Index_Non_Blank;
1061 function Index_Non_Blank
1062 (Source : Unbounded_String;
1063 From : Positive;
1064 Going : Direction := Forward) return Natural
1066 SR : constant Shared_String_Access := Source.Reference;
1067 begin
1068 return Search.Index_Non_Blank (SR.Data (1 .. SR.Last), From, Going);
1069 end Index_Non_Blank;
1071 ----------------
1072 -- Initialize --
1073 ----------------
1075 procedure Initialize (Object : in out Unbounded_String) is
1076 begin
1077 Reference (Object.Reference);
1078 end Initialize;
1080 ------------
1081 -- Insert --
1082 ------------
1084 function Insert
1085 (Source : Unbounded_String;
1086 Before : Positive;
1087 New_Item : String) return Unbounded_String
1089 SR : constant Shared_String_Access := Source.Reference;
1090 DL : constant Natural := SR.Last + New_Item'Length;
1091 DR : Shared_String_Access;
1093 begin
1094 -- Check index first
1096 if Before > SR.Last + 1 then
1097 raise Index_Error;
1098 end if;
1100 -- Result is empty, reuse empty shared string
1102 if DL = 0 then
1103 DR := Empty_Shared_String'Access;
1105 -- Inserted string is empty, reuse source shared string
1107 elsif New_Item'Length = 0 then
1108 Reference (SR);
1109 DR := SR;
1111 -- Otherwise, allocate new shared string and fill it
1113 else
1114 DR := Allocate (DL, DL / Growth_Factor);
1115 DR.Data (1 .. Before - 1) := SR.Data (1 .. Before - 1);
1116 DR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1117 DR.Data (Before + New_Item'Length .. DL) :=
1118 SR.Data (Before .. SR.Last);
1119 DR.Last := DL;
1120 end if;
1122 return (AF.Controlled with Reference => DR);
1123 end Insert;
1125 procedure Insert
1126 (Source : in out Unbounded_String;
1127 Before : Positive;
1128 New_Item : String)
1130 SR : constant Shared_String_Access := Source.Reference;
1131 DL : constant Natural := SR.Last + New_Item'Length;
1132 DR : Shared_String_Access;
1134 begin
1135 -- Check bounds
1137 if Before > SR.Last + 1 then
1138 raise Index_Error;
1139 end if;
1141 -- Result is empty string, reuse empty shared string
1143 if DL = 0 then
1144 Source.Reference := Empty_Shared_String'Access;
1145 Unreference (SR);
1147 -- Inserted string is empty, nothing to do
1149 elsif New_Item'Length = 0 then
1150 null;
1152 -- Try to reuse existing shared string first
1154 elsif Can_Be_Reused (SR, DL) then
1155 SR.Data (Before + New_Item'Length .. DL) :=
1156 SR.Data (Before .. SR.Last);
1157 SR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1158 SR.Last := DL;
1160 -- Otherwise, allocate new shared string and fill it
1162 else
1163 DR := Allocate (DL, DL / Growth_Factor);
1164 DR.Data (1 .. Before - 1) := SR.Data (1 .. Before - 1);
1165 DR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1166 DR.Data (Before + New_Item'Length .. DL) :=
1167 SR.Data (Before .. SR.Last);
1168 DR.Last := DL;
1169 Source.Reference := DR;
1170 Unreference (SR);
1171 end if;
1172 end Insert;
1174 ------------
1175 -- Length --
1176 ------------
1178 function Length (Source : Unbounded_String) return Natural is
1179 begin
1180 return Source.Reference.Last;
1181 end Length;
1183 ---------
1184 -- Mul --
1185 ---------
1187 function Mul (Left, Right : Natural) return Natural is
1188 pragma Unsuppress (Overflow_Check);
1189 begin
1190 return Left * Right;
1191 end Mul;
1193 ---------------
1194 -- Overwrite --
1195 ---------------
1197 function Overwrite
1198 (Source : Unbounded_String;
1199 Position : Positive;
1200 New_Item : String) return Unbounded_String
1202 SR : constant Shared_String_Access := Source.Reference;
1203 DL : Natural;
1204 DR : Shared_String_Access;
1206 begin
1207 -- Check bounds
1209 if Position > SR.Last + 1 then
1210 raise Index_Error;
1211 end if;
1213 DL := Integer'Max (SR.Last, Sum (Position - 1, New_Item'Length));
1215 -- Result is empty string, reuse empty shared string
1217 if DL = 0 then
1218 DR := Empty_Shared_String'Access;
1220 -- Result is same as source string, reuse source shared string
1222 elsif New_Item'Length = 0 then
1223 Reference (SR);
1224 DR := SR;
1226 -- Otherwise, allocate new shared string and fill it
1228 else
1229 DR := Allocate (DL);
1230 DR.Data (1 .. Position - 1) := SR.Data (1 .. Position - 1);
1231 DR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1232 DR.Data (Position + New_Item'Length .. DL) :=
1233 SR.Data (Position + New_Item'Length .. SR.Last);
1234 DR.Last := DL;
1235 end if;
1237 return (AF.Controlled with Reference => DR);
1238 end Overwrite;
1240 procedure Overwrite
1241 (Source : in out Unbounded_String;
1242 Position : Positive;
1243 New_Item : String)
1245 SR : constant Shared_String_Access := Source.Reference;
1246 DL : Natural;
1247 DR : Shared_String_Access;
1249 begin
1250 -- Bounds check
1252 if Position > SR.Last + 1 then
1253 raise Index_Error;
1254 end if;
1256 DL := Integer'Max (SR.Last, Position + New_Item'Length - 1);
1258 -- Result is empty string, reuse empty shared string
1260 if DL = 0 then
1261 Source.Reference := Empty_Shared_String'Access;
1262 Unreference (SR);
1264 -- String unchanged, nothing to do
1266 elsif New_Item'Length = 0 then
1267 null;
1269 -- Try to reuse existing shared string
1271 elsif Can_Be_Reused (SR, DL) then
1272 SR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1273 SR.Last := DL;
1275 -- Otherwise allocate new shared string and fill it
1277 else
1278 DR := Allocate (DL);
1279 DR.Data (1 .. Position - 1) := SR.Data (1 .. Position - 1);
1280 DR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1281 DR.Data (Position + New_Item'Length .. DL) :=
1282 SR.Data (Position + New_Item'Length .. SR.Last);
1283 DR.Last := DL;
1284 Source.Reference := DR;
1285 Unreference (SR);
1286 end if;
1287 end Overwrite;
1289 ---------------
1290 -- Put_Image --
1291 ---------------
1293 procedure Put_Image
1294 (S : in out Ada.Strings.Text_Buffers.Root_Buffer_Type'Class;
1295 V : Unbounded_String) is
1296 begin
1297 String'Put_Image (S, To_String (V));
1298 end Put_Image;
1300 ---------------
1301 -- Reference --
1302 ---------------
1304 procedure Reference (Item : not null Shared_String_Access) is
1305 begin
1306 if Item = Empty_Shared_String'Access then
1307 return;
1308 end if;
1310 System.Atomic_Counters.Increment (Item.Counter);
1311 end Reference;
1313 ---------------------
1314 -- Replace_Element --
1315 ---------------------
1317 procedure Replace_Element
1318 (Source : in out Unbounded_String;
1319 Index : Positive;
1320 By : Character)
1322 SR : constant Shared_String_Access := Source.Reference;
1323 DR : Shared_String_Access;
1325 begin
1326 -- Bounds check
1328 if Index <= SR.Last then
1330 -- Try to reuse existing shared string
1332 if Can_Be_Reused (SR, SR.Last) then
1333 SR.Data (Index) := By;
1335 -- Otherwise allocate new shared string and fill it
1337 else
1338 DR := Allocate (SR.Last);
1339 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
1340 DR.Data (Index) := By;
1341 DR.Last := SR.Last;
1342 Source.Reference := DR;
1343 Unreference (SR);
1344 end if;
1346 else
1347 raise Index_Error;
1348 end if;
1349 end Replace_Element;
1351 -------------------
1352 -- Replace_Slice --
1353 -------------------
1355 function Replace_Slice
1356 (Source : Unbounded_String;
1357 Low : Positive;
1358 High : Natural;
1359 By : String) return Unbounded_String
1361 SR : constant Shared_String_Access := Source.Reference;
1362 DL : Natural;
1363 DR : Shared_String_Access;
1365 begin
1366 -- Check bounds
1368 if Low > SR.Last + 1 then
1369 raise Index_Error;
1370 end if;
1372 -- Do replace operation when removed slice is not empty
1374 if High >= Low then
1375 DL := Sum (SR.Last,
1376 By'Length + Low - Integer'Min (High, SR.Last) - 1);
1377 -- This is the number of characters remaining in the string after
1378 -- replacing the slice.
1380 -- Result is empty string, reuse empty shared string
1382 if DL = 0 then
1383 DR := Empty_Shared_String'Access;
1385 -- Otherwise allocate new shared string and fill it
1387 else
1388 DR := Allocate (DL);
1389 DR.Data (1 .. Low - 1) := SR.Data (1 .. Low - 1);
1390 DR.Data (Low .. Low + By'Length - 1) := By;
1391 DR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1392 DR.Last := DL;
1393 end if;
1395 return (AF.Controlled with Reference => DR);
1397 -- Otherwise just insert string
1399 else
1400 return Insert (Source, Low, By);
1401 end if;
1402 end Replace_Slice;
1404 procedure Replace_Slice
1405 (Source : in out Unbounded_String;
1406 Low : Positive;
1407 High : Natural;
1408 By : String)
1410 SR : constant Shared_String_Access := Source.Reference;
1411 DL : Natural;
1412 DR : Shared_String_Access;
1414 begin
1415 -- Bounds check
1417 if Low > SR.Last + 1 then
1418 raise Index_Error;
1419 end if;
1421 -- Do replace operation only when replaced slice is not empty
1423 if High >= Low then
1424 DL := By'Length + SR.Last + Low - Integer'Min (High, SR.Last) - 1;
1425 -- This is the number of characters remaining in the string after
1426 -- replacing the slice.
1428 -- Result is empty string, reuse empty shared string
1430 if DL = 0 then
1431 Source.Reference := Empty_Shared_String'Access;
1432 Unreference (SR);
1434 -- Try to reuse existing shared string
1436 elsif Can_Be_Reused (SR, DL) then
1437 SR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1438 SR.Data (Low .. Low + By'Length - 1) := By;
1439 SR.Last := DL;
1441 -- Otherwise allocate new shared string and fill it
1443 else
1444 DR := Allocate (DL);
1445 DR.Data (1 .. Low - 1) := SR.Data (1 .. Low - 1);
1446 DR.Data (Low .. Low + By'Length - 1) := By;
1447 DR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1448 DR.Last := DL;
1449 Source.Reference := DR;
1450 Unreference (SR);
1451 end if;
1453 -- Otherwise just insert item
1455 else
1456 Insert (Source, Low, By);
1457 end if;
1458 end Replace_Slice;
1460 --------------------------
1461 -- Set_Unbounded_String --
1462 --------------------------
1464 procedure Set_Unbounded_String
1465 (Target : out Unbounded_String;
1466 Source : String)
1468 TR : constant Shared_String_Access := Target.Reference;
1469 DR : Shared_String_Access;
1471 begin
1472 -- In case of empty string, reuse empty shared string
1474 if Source'Length = 0 then
1475 Target.Reference := Empty_Shared_String'Access;
1477 else
1478 -- Try to reuse existing shared string
1480 if Can_Be_Reused (TR, Source'Length) then
1481 Reference (TR);
1482 DR := TR;
1484 -- Otherwise allocate new shared string
1486 else
1487 DR := Allocate (Source'Length);
1488 Target.Reference := DR;
1489 end if;
1491 DR.Data (1 .. Source'Length) := Source;
1492 DR.Last := Source'Length;
1493 end if;
1495 Unreference (TR);
1496 end Set_Unbounded_String;
1498 -----------
1499 -- Slice --
1500 -----------
1502 function Slice
1503 (Source : Unbounded_String;
1504 Low : Positive;
1505 High : Natural) return String
1507 SR : constant Shared_String_Access := Source.Reference;
1509 begin
1510 -- Note: test of High > Length is in accordance with AI95-00128
1512 if Low > SR.Last + 1 or else High > SR.Last then
1513 raise Index_Error;
1515 else
1516 return SR.Data (Low .. High);
1517 end if;
1518 end Slice;
1520 ---------
1521 -- Sum --
1522 ---------
1524 function Sum (Left : Natural; Right : Integer) return Natural is
1525 pragma Unsuppress (Overflow_Check);
1526 begin
1527 return Left + Right;
1528 end Sum;
1530 ----------
1531 -- Tail --
1532 ----------
1534 function Tail
1535 (Source : Unbounded_String;
1536 Count : Natural;
1537 Pad : Character := Space) return Unbounded_String
1539 SR : constant Shared_String_Access := Source.Reference;
1540 DR : Shared_String_Access;
1542 begin
1543 -- For empty result reuse empty shared string
1545 if Count = 0 then
1546 DR := Empty_Shared_String'Access;
1548 -- Result is whole source string, reuse source shared string
1550 elsif Count = SR.Last then
1551 Reference (SR);
1552 DR := SR;
1554 -- Otherwise allocate new shared string and fill it
1556 else
1557 DR := Allocate (Count);
1559 if Count < SR.Last then
1560 DR.Data (1 .. Count) := SR.Data (SR.Last - Count + 1 .. SR.Last);
1562 else
1563 for J in 1 .. Count - SR.Last loop
1564 DR.Data (J) := Pad;
1565 end loop;
1567 DR.Data (Count - SR.Last + 1 .. Count) := SR.Data (1 .. SR.Last);
1568 end if;
1570 DR.Last := Count;
1571 end if;
1573 return (AF.Controlled with Reference => DR);
1574 end Tail;
1576 procedure Tail
1577 (Source : in out Unbounded_String;
1578 Count : Natural;
1579 Pad : Character := Space)
1581 SR : constant Shared_String_Access := Source.Reference;
1582 DR : Shared_String_Access;
1584 procedure Common
1585 (SR : Shared_String_Access;
1586 DR : Shared_String_Access;
1587 Count : Natural);
1588 -- Common code of tail computation. SR/DR can point to the same object
1590 ------------
1591 -- Common --
1592 ------------
1594 procedure Common
1595 (SR : Shared_String_Access;
1596 DR : Shared_String_Access;
1597 Count : Natural) is
1598 begin
1599 if Count < SR.Last then
1600 DR.Data (1 .. Count) := SR.Data (SR.Last - Count + 1 .. SR.Last);
1602 else
1603 DR.Data (Count - SR.Last + 1 .. Count) := SR.Data (1 .. SR.Last);
1605 for J in 1 .. Count - SR.Last loop
1606 DR.Data (J) := Pad;
1607 end loop;
1608 end if;
1610 DR.Last := Count;
1611 end Common;
1613 begin
1614 -- Result is empty string, reuse empty shared string
1616 if Count = 0 then
1617 Source.Reference := Empty_Shared_String'Access;
1618 Unreference (SR);
1620 -- Length of the result is the same as length of the source string,
1621 -- reuse source shared string.
1623 elsif Count = SR.Last then
1624 null;
1626 -- Try to reuse existing shared string
1628 elsif Can_Be_Reused (SR, Count) then
1629 Common (SR, SR, Count);
1631 -- Otherwise allocate new shared string and fill it
1633 else
1634 DR := Allocate (Count);
1635 Common (SR, DR, Count);
1636 Source.Reference := DR;
1637 Unreference (SR);
1638 end if;
1639 end Tail;
1641 ---------------
1642 -- To_String --
1643 ---------------
1645 function To_String (Source : Unbounded_String) return String is
1646 begin
1647 return Source.Reference.Data (1 .. Source.Reference.Last);
1648 end To_String;
1650 -------------------------
1651 -- To_Unbounded_String --
1652 -------------------------
1654 function To_Unbounded_String (Source : String) return Unbounded_String is
1655 DR : Shared_String_Access;
1657 begin
1658 if Source'Length = 0 then
1659 DR := Empty_Shared_String'Access;
1661 else
1662 DR := Allocate (Source'Length);
1663 DR.Data (1 .. Source'Length) := Source;
1664 DR.Last := Source'Length;
1665 end if;
1667 return (AF.Controlled with Reference => DR);
1668 end To_Unbounded_String;
1670 function To_Unbounded_String (Length : Natural) return Unbounded_String is
1671 DR : Shared_String_Access;
1673 begin
1674 if Length = 0 then
1675 DR := Empty_Shared_String'Access;
1677 else
1678 DR := Allocate (Length);
1679 DR.Last := Length;
1680 end if;
1682 return (AF.Controlled with Reference => DR);
1683 end To_Unbounded_String;
1685 ---------------
1686 -- Translate --
1687 ---------------
1689 function Translate
1690 (Source : Unbounded_String;
1691 Mapping : Maps.Character_Mapping) return Unbounded_String
1693 SR : constant Shared_String_Access := Source.Reference;
1694 DR : Shared_String_Access;
1696 begin
1697 -- Nothing to translate, reuse empty shared string
1699 if SR.Last = 0 then
1700 DR := Empty_Shared_String'Access;
1702 -- Otherwise, allocate new shared string and fill it
1704 else
1705 DR := Allocate (SR.Last);
1707 for J in 1 .. SR.Last loop
1708 DR.Data (J) := Value (Mapping, SR.Data (J));
1709 end loop;
1711 DR.Last := SR.Last;
1712 end if;
1714 return (AF.Controlled with Reference => DR);
1715 end Translate;
1717 procedure Translate
1718 (Source : in out Unbounded_String;
1719 Mapping : Maps.Character_Mapping)
1721 SR : constant Shared_String_Access := Source.Reference;
1722 DR : Shared_String_Access;
1724 begin
1725 -- Nothing to translate
1727 if SR.Last = 0 then
1728 null;
1730 -- Try to reuse shared string
1732 elsif Can_Be_Reused (SR, SR.Last) then
1733 for J in 1 .. SR.Last loop
1734 SR.Data (J) := Value (Mapping, SR.Data (J));
1735 end loop;
1737 -- Otherwise, allocate new shared string
1739 else
1740 DR := Allocate (SR.Last);
1742 for J in 1 .. SR.Last loop
1743 DR.Data (J) := Value (Mapping, SR.Data (J));
1744 end loop;
1746 DR.Last := SR.Last;
1747 Source.Reference := DR;
1748 Unreference (SR);
1749 end if;
1750 end Translate;
1752 function Translate
1753 (Source : Unbounded_String;
1754 Mapping : Maps.Character_Mapping_Function) return Unbounded_String
1756 SR : constant Shared_String_Access := Source.Reference;
1757 DR : Shared_String_Access;
1759 begin
1760 -- Nothing to translate, reuse empty shared string
1762 if SR.Last = 0 then
1763 DR := Empty_Shared_String'Access;
1765 -- Otherwise, allocate new shared string and fill it
1767 else
1768 DR := Allocate (SR.Last);
1770 for J in 1 .. SR.Last loop
1771 DR.Data (J) := Mapping.all (SR.Data (J));
1772 end loop;
1774 DR.Last := SR.Last;
1775 end if;
1777 return (AF.Controlled with Reference => DR);
1779 exception
1780 when others =>
1781 Unreference (DR);
1783 raise;
1784 end Translate;
1786 procedure Translate
1787 (Source : in out Unbounded_String;
1788 Mapping : Maps.Character_Mapping_Function)
1790 SR : constant Shared_String_Access := Source.Reference;
1791 DR : Shared_String_Access;
1793 begin
1794 -- Nothing to translate
1796 if SR.Last = 0 then
1797 null;
1799 -- Try to reuse shared string
1801 elsif Can_Be_Reused (SR, SR.Last) then
1802 for J in 1 .. SR.Last loop
1803 SR.Data (J) := Mapping.all (SR.Data (J));
1804 end loop;
1806 -- Otherwise allocate new shared string and fill it
1808 else
1809 DR := Allocate (SR.Last);
1811 for J in 1 .. SR.Last loop
1812 DR.Data (J) := Mapping.all (SR.Data (J));
1813 end loop;
1815 DR.Last := SR.Last;
1816 Source.Reference := DR;
1817 Unreference (SR);
1818 end if;
1820 exception
1821 when others =>
1822 if DR /= null then
1823 Unreference (DR);
1824 end if;
1826 raise;
1827 end Translate;
1829 ----------
1830 -- Trim --
1831 ----------
1833 function Trim
1834 (Source : Unbounded_String;
1835 Side : Trim_End) return Unbounded_String
1837 SR : constant Shared_String_Access := Source.Reference;
1838 DL : Natural;
1839 DR : Shared_String_Access;
1840 Low : Natural;
1841 High : Natural;
1843 begin
1844 Low := Index_Non_Blank (Source, Forward);
1846 -- All blanks, reuse empty shared string
1848 if Low = 0 then
1849 DR := Empty_Shared_String'Access;
1851 else
1852 case Side is
1853 when Left =>
1854 High := SR.Last;
1855 DL := SR.Last - Low + 1;
1857 when Right =>
1858 Low := 1;
1859 High := Index_Non_Blank (Source, Backward);
1860 DL := High;
1862 when Both =>
1863 High := Index_Non_Blank (Source, Backward);
1864 DL := High - Low + 1;
1865 end case;
1867 -- Length of the result is the same as length of the source string,
1868 -- reuse source shared string.
1870 if DL = SR.Last then
1871 Reference (SR);
1872 DR := SR;
1874 -- Otherwise, allocate new shared string
1876 else
1877 DR := Allocate (DL);
1878 DR.Data (1 .. DL) := SR.Data (Low .. High);
1879 DR.Last := DL;
1880 end if;
1881 end if;
1883 return (AF.Controlled with Reference => DR);
1884 end Trim;
1886 procedure Trim
1887 (Source : in out Unbounded_String;
1888 Side : Trim_End)
1890 SR : constant Shared_String_Access := Source.Reference;
1891 DL : Natural;
1892 DR : Shared_String_Access;
1893 Low : Natural;
1894 High : Natural;
1896 begin
1897 Low := Index_Non_Blank (Source, Forward);
1899 -- All blanks, reuse empty shared string
1901 if Low = 0 then
1902 Source.Reference := Empty_Shared_String'Access;
1903 Unreference (SR);
1905 else
1906 case Side is
1907 when Left =>
1908 High := SR.Last;
1909 DL := SR.Last - Low + 1;
1911 when Right =>
1912 Low := 1;
1913 High := Index_Non_Blank (Source, Backward);
1914 DL := High;
1916 when Both =>
1917 High := Index_Non_Blank (Source, Backward);
1918 DL := High - Low + 1;
1919 end case;
1921 -- Length of the result is the same as length of the source string,
1922 -- nothing to do.
1924 if DL = SR.Last then
1925 null;
1927 -- Try to reuse existing shared string
1929 elsif Can_Be_Reused (SR, DL) then
1930 SR.Data (1 .. DL) := SR.Data (Low .. High);
1931 SR.Last := DL;
1933 -- Otherwise, allocate new shared string
1935 else
1936 DR := Allocate (DL);
1937 DR.Data (1 .. DL) := SR.Data (Low .. High);
1938 DR.Last := DL;
1939 Source.Reference := DR;
1940 Unreference (SR);
1941 end if;
1942 end if;
1943 end Trim;
1945 function Trim
1946 (Source : Unbounded_String;
1947 Left : Maps.Character_Set;
1948 Right : Maps.Character_Set) return Unbounded_String
1950 SR : constant Shared_String_Access := Source.Reference;
1951 DL : Natural;
1952 DR : Shared_String_Access;
1953 Low : Natural;
1954 High : Natural;
1956 begin
1957 Low := Index (Source, Left, Outside, Forward);
1959 -- Source includes only characters from Left set, reuse empty shared
1960 -- string.
1962 if Low = 0 then
1963 DR := Empty_Shared_String'Access;
1965 else
1966 High := Index (Source, Right, Outside, Backward);
1967 DL := Integer'Max (0, High - Low + 1);
1969 -- Source includes only characters from Right set or result string
1970 -- is empty, reuse empty shared string.
1972 if High = 0 or else DL = 0 then
1973 DR := Empty_Shared_String'Access;
1975 -- Otherwise, allocate new shared string and fill it
1977 else
1978 DR := Allocate (DL);
1979 DR.Data (1 .. DL) := SR.Data (Low .. High);
1980 DR.Last := DL;
1981 end if;
1982 end if;
1984 return (AF.Controlled with Reference => DR);
1985 end Trim;
1987 procedure Trim
1988 (Source : in out Unbounded_String;
1989 Left : Maps.Character_Set;
1990 Right : Maps.Character_Set)
1992 SR : constant Shared_String_Access := Source.Reference;
1993 DL : Natural;
1994 DR : Shared_String_Access;
1995 Low : Natural;
1996 High : Natural;
1998 begin
1999 Low := Index (Source, Left, Outside, Forward);
2001 -- Source includes only characters from Left set, reuse empty shared
2002 -- string.
2004 if Low = 0 then
2005 Source.Reference := Empty_Shared_String'Access;
2006 Unreference (SR);
2008 else
2009 High := Index (Source, Right, Outside, Backward);
2010 DL := Integer'Max (0, High - Low + 1);
2012 -- Source includes only characters from Right set or result string
2013 -- is empty, reuse empty shared string.
2015 if High = 0 or else DL = 0 then
2016 Source.Reference := Empty_Shared_String'Access;
2017 Unreference (SR);
2019 -- Try to reuse existing shared string
2021 elsif Can_Be_Reused (SR, DL) then
2022 SR.Data (1 .. DL) := SR.Data (Low .. High);
2023 SR.Last := DL;
2025 -- Otherwise, allocate new shared string and fill it
2027 else
2028 DR := Allocate (DL);
2029 DR.Data (1 .. DL) := SR.Data (Low .. High);
2030 DR.Last := DL;
2031 Source.Reference := DR;
2032 Unreference (SR);
2033 end if;
2034 end if;
2035 end Trim;
2037 ---------------------
2038 -- Unbounded_Slice --
2039 ---------------------
2041 function Unbounded_Slice
2042 (Source : Unbounded_String;
2043 Low : Positive;
2044 High : Natural) return Unbounded_String
2046 SR : constant Shared_String_Access := Source.Reference;
2047 DL : Natural;
2048 DR : Shared_String_Access;
2050 begin
2051 -- Check bounds
2053 if Low - 1 > SR.Last or else High > SR.Last then
2054 raise Index_Error;
2056 -- Result is empty slice, reuse empty shared string
2058 elsif Low > High then
2059 DR := Empty_Shared_String'Access;
2061 -- Otherwise, allocate new shared string and fill it
2063 else
2064 DL := High - Low + 1;
2065 DR := Allocate (DL);
2066 DR.Data (1 .. DL) := SR.Data (Low .. High);
2067 DR.Last := DL;
2068 end if;
2070 return (AF.Controlled with Reference => DR);
2071 end Unbounded_Slice;
2073 procedure Unbounded_Slice
2074 (Source : Unbounded_String;
2075 Target : out Unbounded_String;
2076 Low : Positive;
2077 High : Natural)
2079 SR : constant Shared_String_Access := Source.Reference;
2080 TR : constant Shared_String_Access := Target.Reference;
2081 DL : Natural;
2082 DR : Shared_String_Access;
2084 begin
2085 -- Check bounds
2087 if Low - 1 > SR.Last or else High > SR.Last then
2088 raise Index_Error;
2090 -- Result is empty slice, reuse empty shared string
2092 elsif Low > High then
2093 Target.Reference := Empty_Shared_String'Access;
2094 Unreference (TR);
2096 else
2097 DL := High - Low + 1;
2099 -- Try to reuse existing shared string
2101 if Can_Be_Reused (TR, DL) then
2102 TR.Data (1 .. DL) := SR.Data (Low .. High);
2103 TR.Last := DL;
2105 -- Otherwise, allocate new shared string and fill it
2107 else
2108 DR := Allocate (DL);
2109 DR.Data (1 .. DL) := SR.Data (Low .. High);
2110 DR.Last := DL;
2111 Target.Reference := DR;
2112 Unreference (TR);
2113 end if;
2114 end if;
2115 end Unbounded_Slice;
2117 -----------------
2118 -- Unreference --
2119 -----------------
2121 procedure Unreference (Item : not null Shared_String_Access) is
2123 procedure Free is
2124 new Ada.Unchecked_Deallocation (Shared_String, Shared_String_Access);
2126 Aux : Shared_String_Access := Item;
2128 begin
2129 if Aux = Empty_Shared_String'Access then
2130 return;
2131 end if;
2133 if System.Atomic_Counters.Decrement (Aux.Counter) then
2134 Free (Aux);
2135 end if;
2136 end Unreference;
2138 end Ada.Strings.Unbounded;