1 ------------------------------------------------------------------------------
3 -- GNAT RUN-TIME COMPONENTS --
5 -- A D A . S T R I N G S . U N B O U N D E D --
9 -- Copyright (C) 1992-2024, Free Software Foundation, Inc. --
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. --
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. --
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/>. --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
30 ------------------------------------------------------------------------------
32 with Ada
.Strings
.Search
;
33 with Ada
.Unchecked_Deallocation
;
35 package body Ada
.Strings
.Unbounded
is
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
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
;
82 -- Result is an empty string, reuse shared empty string
85 DR
:= Empty_Shared_String
'Access;
87 -- Left string is empty, return Right string
89 elsif LR
.Last
= 0 then
93 -- Right string is empty, return Left string
95 elsif RR
.Last
= 0 then
99 -- Otherwise, allocate new shared string and fill data
103 DR
.Data
(1 .. LR
.Last
) := LR
.Data
(1 .. LR
.Last
);
104 DR
.Data
(LR
.Last
+ 1 .. DL
) := RR
.Data
(1 .. RR
.Last
);
108 return (AF
.Controlled
with Reference
=> DR
);
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
;
120 -- Result is an empty string, reuse shared empty string
123 DR
:= Empty_Shared_String
'Access;
125 -- Right is an empty string, return Left string
127 elsif Right
'Length = 0 then
131 -- Otherwise, allocate new shared string and fill it
135 DR
.Data
(1 .. LR
.Last
) := LR
.Data
(1 .. LR
.Last
);
136 DR
.Data
(LR
.Last
+ 1 .. DL
) := Right
;
140 return (AF
.Controlled
with Reference
=> DR
);
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
;
152 -- Result is an empty string, reuse shared one
155 DR
:= Empty_Shared_String
'Access;
157 -- Left is empty string, return Right string
159 elsif Left
'Length = 0 then
163 -- Otherwise, allocate new shared string and fill it
167 DR
.Data
(1 .. Left
'Length) := Left
;
168 DR
.Data
(Left
'Length + 1 .. DL
) := RR
.Data
(1 .. RR
.Last
);
172 return (AF
.Controlled
with Reference
=> DR
);
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
;
185 DR
.Data
(1 .. LR
.Last
) := LR
.Data
(1 .. LR
.Last
);
186 DR
.Data
(DL
) := Right
;
189 return (AF
.Controlled
with Reference
=> DR
);
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
;
203 DR
.Data
(2 .. DL
) := RR
.Data
(1 .. RR
.Last
);
206 return (AF
.Controlled
with Reference
=> DR
);
215 Right
: Character) return Unbounded_String
217 DR
: Shared_String_Access
;
220 -- Result is an empty string, reuse shared empty string
223 DR
:= Empty_Shared_String
'Access;
225 -- Otherwise, allocate new shared string and fill it
228 DR
:= Allocate
(Left
);
230 for J
in 1 .. Left
loop
231 DR
.Data
(J
) := Right
;
237 return (AF
.Controlled
with Reference
=> DR
);
242 Right
: String) return Unbounded_String
244 DL
: constant Natural := Mul
(Left
, Right
'Length);
245 DR
: Shared_String_Access
;
249 -- Result is an empty string, reuse shared empty string
252 DR
:= Empty_Shared_String
'Access;
254 -- Otherwise, allocate new shared string and fill it
260 for J
in 1 .. Left
loop
261 DR
.Data
(K
.. K
+ Right
'Length - 1) := Right
;
262 K
:= K
+ Right
'Length;
268 return (AF
.Controlled
with Reference
=> DR
);
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
;
281 -- Result is an empty string, reuse shared empty string
284 DR
:= Empty_Shared_String
'Access;
286 -- Coefficient is one, just return string itself
292 -- Otherwise, allocate new shared string and fill it
298 for J
in 1 .. Left
loop
299 DR
.Data
(K
.. K
+ RR
.Last
- 1) := RR
.Data
(1 .. RR
.Last
);
306 return (AF
.Controlled
with Reference
=> DR
);
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
;
320 return LR
.Data
(1 .. LR
.Last
) < RR
.Data
(1 .. RR
.Last
);
324 (Left
: Unbounded_String
;
325 Right
: String) return Boolean
327 LR
: constant Shared_String_Access
:= Left
.Reference
;
329 return LR
.Data
(1 .. LR
.Last
) < Right
;
334 Right
: Unbounded_String
) return Boolean
336 RR
: constant Shared_String_Access
:= Right
.Reference
;
338 return Left
< RR
.Data
(1 .. RR
.Last
);
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
;
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
);
359 (Left
: Unbounded_String
;
360 Right
: String) return Boolean
362 LR
: constant Shared_String_Access
:= Left
.Reference
;
364 return LR
.Data
(1 .. LR
.Last
) <= Right
;
369 Right
: Unbounded_String
) return Boolean
371 RR
: constant Shared_String_Access
:= Right
.Reference
;
373 return Left
<= RR
.Data
(1 .. RR
.Last
);
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
;
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
393 (Left
: Unbounded_String
;
394 Right
: String) return Boolean
396 LR
: constant Shared_String_Access
:= Left
.Reference
;
398 return LR
.Data
(1 .. LR
.Last
) = Right
;
403 Right
: Unbounded_String
) return Boolean
405 RR
: constant Shared_String_Access
:= Right
.Reference
;
407 return Left
= RR
.Data
(1 .. RR
.Last
);
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
;
421 return LR
.Data
(1 .. LR
.Last
) > RR
.Data
(1 .. RR
.Last
);
425 (Left
: Unbounded_String
;
426 Right
: String) return Boolean
428 LR
: constant Shared_String_Access
:= Left
.Reference
;
430 return LR
.Data
(1 .. LR
.Last
) > Right
;
435 Right
: Unbounded_String
) return Boolean
437 RR
: constant Shared_String_Access
:= Right
.Reference
;
439 return Left
> RR
.Data
(1 .. RR
.Last
);
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
;
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
);
460 (Left
: Unbounded_String
;
461 Right
: String) return Boolean
463 LR
: constant Shared_String_Access
:= Left
.Reference
;
465 return LR
.Data
(1 .. LR
.Last
) >= Right
;
470 Right
: Unbounded_String
) return Boolean
472 RR
: constant Shared_String_Access
:= Right
.Reference
;
474 return Left
>= RR
.Data
(1 .. RR
.Last
);
481 procedure Adjust
(Object
: in out Unbounded_String
) is
483 Reference
(Object
.Reference
);
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
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.
506 ((Static_Size
+ Required_Length
+ Reserved_Length
- 1)
507 / Min_Mul_Alloc
+ 2) * Min_Mul_Alloc
- Static_Size
;
509 end Aligned_Max_Length
;
516 (Required_Length
: Natural;
517 Reserved_Length
: Natural := 0) return not null Shared_String_Access
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)
530 (Aligned_Max_Length
(Required_Length
, Reserved_Length
));
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
;
548 -- Source is an empty string, reuse New_Item data
552 Source
.Reference
:= NR
;
555 -- New_Item is empty string, nothing to do
557 elsif NR
.Last
= 0 then
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
);
566 -- Otherwise, allocate new one and fill it
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
);
573 Source
.Reference
:= DR
;
579 (Source
: in out Unbounded_String
;
582 SR
: constant Shared_String_Access
:= Source
.Reference
;
583 DL
: constant Natural := Sum
(SR
.Last
, New_Item
'Length);
584 DR
: Shared_String_Access
;
587 -- New_Item is an empty string, nothing to do
589 if New_Item
'Length = 0 then
592 -- Try to reuse existing shared string
594 elsif Can_Be_Reused
(SR
, DL
) then
595 SR
.Data
(SR
.Last
+ 1 .. DL
) := New_Item
;
598 -- Otherwise, allocate new one and fill it
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
;
605 Source
.Reference
:= DR
;
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
;
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
628 DR
:= Allocate
(DL
, DL
/ Growth_Factor
);
629 DR
.Data
(1 .. SR
.Last
) := SR
.Data
(1 .. SR
.Last
);
630 DR
.Data
(DL
) := New_Item
;
632 Source
.Reference
:= DR
;
641 function Can_Be_Reused
642 (Item
: not null Shared_String_Access
;
643 Length
: Natural) return Boolean
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
);
658 (Source
: Unbounded_String
;
660 Mapping
: Maps
.Character_Mapping
:= Maps
.Identity
) return Natural
662 SR
: constant Shared_String_Access
:= Source
.Reference
;
664 return Search
.Count
(SR
.Data
(1 .. SR
.Last
), Pattern
, Mapping
);
668 (Source
: Unbounded_String
;
670 Mapping
: Maps
.Character_Mapping_Function
) return Natural
672 SR
: constant Shared_String_Access
:= Source
.Reference
;
674 return Search
.Count
(SR
.Data
(1 .. SR
.Last
), Pattern
, Mapping
);
678 (Source
: Unbounded_String
;
679 Set
: Maps
.Character_Set
) return Natural
681 SR
: constant Shared_String_Access
:= Source
.Reference
;
683 return Search
.Count
(SR
.Data
(1 .. SR
.Last
), Set
);
691 (Source
: Unbounded_String
;
693 Through
: Natural) return Unbounded_String
695 SR
: constant Shared_String_Access
:= Source
.Reference
;
697 DR
: Shared_String_Access
;
700 -- Empty slice is deleted, use the same shared string
702 if From
> Through
then
706 -- Index is out of range
708 elsif Through
> SR
.Last
then
711 -- Compute size of the result
714 DL
:= SR
.Last
- (Through
- From
+ 1);
716 -- Result is an empty string, reuse shared empty string
719 DR
:= Empty_Shared_String
'Access;
721 -- Otherwise, allocate new shared string and fill it
725 DR
.Data
(1 .. From
- 1) := SR
.Data
(1 .. From
- 1);
726 DR
.Data
(From
.. DL
) := SR
.Data
(Through
+ 1 .. SR
.Last
);
731 return (AF
.Controlled
with Reference
=> DR
);
735 (Source
: in out Unbounded_String
;
739 SR
: constant Shared_String_Access
:= Source
.Reference
;
741 DR
: Shared_String_Access
;
744 -- Nothing changed, return
746 if From
> Through
then
749 -- Through is outside of the range
751 elsif Through
> SR
.Last
then
755 DL
:= SR
.Last
- (Through
- From
+ 1);
757 -- Result is empty, reuse shared empty string
760 Source
.Reference
:= Empty_Shared_String
'Access;
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
);
769 -- Otherwise, allocate new shared string
773 DR
.Data
(1 .. From
- 1) := SR
.Data
(1 .. From
- 1);
774 DR
.Data
(From
.. DL
) := SR
.Data
(Through
+ 1 .. SR
.Last
);
776 Source
.Reference
:= DR
;
787 (Source
: Unbounded_String
;
788 Index
: Positive) return Character
790 SR
: constant Shared_String_Access
:= Source
.Reference
;
792 if Index
<= SR
.Last
then
793 return SR
.Data
(Index
);
803 procedure Finalize
(Object
: in out Unbounded_String
) is
804 SR
: constant not null Shared_String_Access
:= Object
.Reference
;
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
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
;
826 (Source
: Unbounded_String
;
827 Set
: Maps
.Character_Set
;
829 Test
: Strings
.Membership
;
830 First
: out Positive;
833 SR
: constant Shared_String_Access
:= Source
.Reference
;
835 Search
.Find_Token
(SR
.Data
(From
.. SR
.Last
), Set
, Test
, First
, Last
);
839 (Source
: Unbounded_String
;
840 Set
: Maps
.Character_Set
;
841 Test
: Strings
.Membership
;
842 First
: out Positive;
845 SR
: constant Shared_String_Access
:= Source
.Reference
;
847 Search
.Find_Token
(SR
.Data
(1 .. SR
.Last
), Set
, Test
, First
, Last
);
854 procedure Free
(X
: in out String_Access
) is
855 procedure Deallocate
is
856 new Ada
.Unchecked_Deallocation
(String, String_Access
);
866 (Source
: Unbounded_String
;
868 Pad
: Character := Space
) return Unbounded_String
870 SR
: constant Shared_String_Access
:= Source
.Reference
;
871 DR
: Shared_String_Access
;
874 -- Result is empty, reuse shared empty string
877 DR
:= Empty_Shared_String
'Access;
879 -- Length of the string is the same as requested, reuse source shared
882 elsif Count
= SR
.Last
then
886 -- Otherwise, allocate new shared string and fill it
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.
901 DR
.Data
(1 .. SR
.Last
) := SR
.Data
(1 .. SR
.Last
);
903 for J
in SR
.Last
+ 1 .. Count
loop
911 return (AF
.Controlled
with Reference
=> DR
);
915 (Source
: in out Unbounded_String
;
917 Pad
: Character := Space
)
919 SR
: constant Shared_String_Access
:= Source
.Reference
;
920 DR
: Shared_String_Access
;
923 -- Result is empty, reuse empty shared string
926 Source
.Reference
:= Empty_Shared_String
'Access;
929 -- Result is same as source string, reuse source shared string
931 elsif Count
= SR
.Last
then
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
945 -- Otherwise, allocate new shared string and fill it
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.
960 DR
.Data
(1 .. SR
.Last
) := SR
.Data
(1 .. SR
.Last
);
962 for J
in SR
.Last
+ 1 .. Count
loop
968 Source
.Reference
:= DR
;
978 (Source
: Unbounded_String
;
980 Going
: Strings
.Direction
:= Strings
.Forward
;
981 Mapping
: Maps
.Character_Mapping
:= Maps
.Identity
) return Natural
983 SR
: constant Shared_String_Access
:= Source
.Reference
;
985 return Search
.Index
(SR
.Data
(1 .. SR
.Last
), Pattern
, Going
, Mapping
);
989 (Source
: Unbounded_String
;
991 Going
: Direction
:= Forward
;
992 Mapping
: Maps
.Character_Mapping_Function
) return Natural
994 SR
: constant Shared_String_Access
:= Source
.Reference
;
996 return Search
.Index
(SR
.Data
(1 .. SR
.Last
), Pattern
, Going
, Mapping
);
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
;
1007 return Search
.Index
(SR
.Data
(1 .. SR
.Last
), Set
, Test
, Going
);
1011 (Source
: Unbounded_String
;
1014 Going
: Direction
:= Forward
;
1015 Mapping
: Maps
.Character_Mapping
:= Maps
.Identity
) return Natural
1017 SR
: constant Shared_String_Access
:= Source
.Reference
;
1020 (SR
.Data
(1 .. SR
.Last
), Pattern
, From
, Going
, Mapping
);
1024 (Source
: Unbounded_String
;
1027 Going
: Direction
:= Forward
;
1028 Mapping
: Maps
.Character_Mapping_Function
) return Natural
1030 SR
: constant Shared_String_Access
:= Source
.Reference
;
1033 (SR
.Data
(1 .. SR
.Last
), Pattern
, From
, Going
, Mapping
);
1037 (Source
: Unbounded_String
;
1038 Set
: Maps
.Character_Set
;
1040 Test
: Membership
:= Inside
;
1041 Going
: Direction
:= Forward
) return Natural
1043 SR
: constant Shared_String_Access
:= Source
.Reference
;
1045 return Search
.Index
(SR
.Data
(1 .. SR
.Last
), Set
, From
, Test
, Going
);
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
;
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
;
1064 Going
: Direction
:= Forward
) return Natural
1066 SR
: constant Shared_String_Access
:= Source
.Reference
;
1068 return Search
.Index_Non_Blank
(SR
.Data
(1 .. SR
.Last
), From
, Going
);
1069 end Index_Non_Blank
;
1075 procedure Initialize
(Object
: in out Unbounded_String
) is
1077 Reference
(Object
.Reference
);
1085 (Source
: Unbounded_String
;
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
;
1094 -- Check index first
1096 if Before
> SR
.Last
+ 1 then
1100 -- Result is empty, reuse empty shared string
1103 DR
:= Empty_Shared_String
'Access;
1105 -- Inserted string is empty, reuse source shared string
1107 elsif New_Item
'Length = 0 then
1111 -- Otherwise, allocate new shared string and fill it
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
);
1122 return (AF
.Controlled
with Reference
=> DR
);
1126 (Source
: in out Unbounded_String
;
1130 SR
: constant Shared_String_Access
:= Source
.Reference
;
1131 DL
: constant Natural := SR
.Last
+ New_Item
'Length;
1132 DR
: Shared_String_Access
;
1137 if Before
> SR
.Last
+ 1 then
1141 -- Result is empty string, reuse empty shared string
1144 Source
.Reference
:= Empty_Shared_String
'Access;
1147 -- Inserted string is empty, nothing to do
1149 elsif New_Item
'Length = 0 then
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
;
1160 -- Otherwise, allocate new shared string and fill it
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
);
1169 Source
.Reference
:= DR
;
1178 function Length
(Source
: Unbounded_String
) return Natural is
1180 return Source
.Reference
.Last
;
1187 function Mul
(Left
, Right
: Natural) return Natural is
1188 pragma Unsuppress
(Overflow_Check
);
1190 return Left
* Right
;
1198 (Source
: Unbounded_String
;
1199 Position
: Positive;
1200 New_Item
: String) return Unbounded_String
1202 SR
: constant Shared_String_Access
:= Source
.Reference
;
1204 DR
: Shared_String_Access
;
1209 if Position
> SR
.Last
+ 1 then
1213 DL
:= Integer'Max (SR
.Last
, Sum
(Position
- 1, New_Item
'Length));
1215 -- Result is empty string, reuse empty shared string
1218 DR
:= Empty_Shared_String
'Access;
1220 -- Result is same as source string, reuse source shared string
1222 elsif New_Item
'Length = 0 then
1226 -- Otherwise, allocate new shared string and fill it
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
);
1237 return (AF
.Controlled
with Reference
=> DR
);
1241 (Source
: in out Unbounded_String
;
1242 Position
: Positive;
1245 SR
: constant Shared_String_Access
:= Source
.Reference
;
1247 DR
: Shared_String_Access
;
1252 if Position
> SR
.Last
+ 1 then
1256 DL
:= Integer'Max (SR
.Last
, Position
+ New_Item
'Length - 1);
1258 -- Result is empty string, reuse empty shared string
1261 Source
.Reference
:= Empty_Shared_String
'Access;
1264 -- String unchanged, nothing to do
1266 elsif New_Item
'Length = 0 then
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
;
1275 -- Otherwise allocate new shared string and fill it
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
);
1284 Source
.Reference
:= DR
;
1294 (S
: in out Ada
.Strings
.Text_Buffers
.Root_Buffer_Type
'Class;
1295 V
: Unbounded_String
) is
1297 String'Put_Image (S
, To_String
(V
));
1304 procedure Reference
(Item
: not null Shared_String_Access
) is
1306 if Item
= Empty_Shared_String
'Access then
1310 System
.Atomic_Counters
.Increment
(Item
.Counter
);
1313 ---------------------
1314 -- Replace_Element --
1315 ---------------------
1317 procedure Replace_Element
1318 (Source
: in out Unbounded_String
;
1322 SR
: constant Shared_String_Access
:= Source
.Reference
;
1323 DR
: Shared_String_Access
;
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
1338 DR
:= Allocate
(SR
.Last
);
1339 DR
.Data
(1 .. SR
.Last
) := SR
.Data
(1 .. SR
.Last
);
1340 DR
.Data
(Index
) := By
;
1342 Source
.Reference
:= DR
;
1349 end Replace_Element
;
1355 function Replace_Slice
1356 (Source
: Unbounded_String
;
1359 By
: String) return Unbounded_String
1361 SR
: constant Shared_String_Access
:= Source
.Reference
;
1363 DR
: Shared_String_Access
;
1368 if Low
> SR
.Last
+ 1 then
1372 -- Do replace operation when removed slice is not empty
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
1383 DR
:= Empty_Shared_String
'Access;
1385 -- Otherwise allocate new shared string and fill it
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
);
1395 return (AF
.Controlled
with Reference
=> DR
);
1397 -- Otherwise just insert string
1400 return Insert
(Source
, Low
, By
);
1404 procedure Replace_Slice
1405 (Source
: in out Unbounded_String
;
1410 SR
: constant Shared_String_Access
:= Source
.Reference
;
1412 DR
: Shared_String_Access
;
1417 if Low
> SR
.Last
+ 1 then
1421 -- Do replace operation only when replaced slice is not empty
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
1431 Source
.Reference
:= Empty_Shared_String
'Access;
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
;
1441 -- Otherwise allocate new shared string and fill it
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
);
1449 Source
.Reference
:= DR
;
1453 -- Otherwise just insert item
1456 Insert
(Source
, Low
, By
);
1460 --------------------------
1461 -- Set_Unbounded_String --
1462 --------------------------
1464 procedure Set_Unbounded_String
1465 (Target
: out Unbounded_String
;
1468 TR
: constant Shared_String_Access
:= Target
.Reference
;
1469 DR
: Shared_String_Access
;
1472 -- In case of empty string, reuse empty shared string
1474 if Source
'Length = 0 then
1475 Target
.Reference
:= Empty_Shared_String
'Access;
1478 -- Try to reuse existing shared string
1480 if Can_Be_Reused
(TR
, Source
'Length) then
1484 -- Otherwise allocate new shared string
1487 DR
:= Allocate
(Source
'Length);
1488 Target
.Reference
:= DR
;
1491 DR
.Data
(1 .. Source
'Length) := Source
;
1492 DR
.Last
:= Source
'Length;
1496 end Set_Unbounded_String
;
1503 (Source
: Unbounded_String
;
1505 High
: Natural) return String
1507 SR
: constant Shared_String_Access
:= Source
.Reference
;
1510 -- Note: test of High > Length is in accordance with AI95-00128
1512 if Low
> SR
.Last
+ 1 or else High
> SR
.Last
then
1516 return SR
.Data
(Low
.. High
);
1524 function Sum
(Left
: Natural; Right
: Integer) return Natural is
1525 pragma Unsuppress
(Overflow_Check
);
1527 return Left
+ Right
;
1535 (Source
: Unbounded_String
;
1537 Pad
: Character := Space
) return Unbounded_String
1539 SR
: constant Shared_String_Access
:= Source
.Reference
;
1540 DR
: Shared_String_Access
;
1543 -- For empty result reuse empty shared string
1546 DR
:= Empty_Shared_String
'Access;
1548 -- Result is whole source string, reuse source shared string
1550 elsif Count
= SR
.Last
then
1554 -- Otherwise allocate new shared string and fill it
1557 DR
:= Allocate
(Count
);
1559 if Count
< SR
.Last
then
1560 DR
.Data
(1 .. Count
) := SR
.Data
(SR
.Last
- Count
+ 1 .. SR
.Last
);
1563 for J
in 1 .. Count
- SR
.Last
loop
1567 DR
.Data
(Count
- SR
.Last
+ 1 .. Count
) := SR
.Data
(1 .. SR
.Last
);
1573 return (AF
.Controlled
with Reference
=> DR
);
1577 (Source
: in out Unbounded_String
;
1579 Pad
: Character := Space
)
1581 SR
: constant Shared_String_Access
:= Source
.Reference
;
1582 DR
: Shared_String_Access
;
1585 (SR
: Shared_String_Access
;
1586 DR
: Shared_String_Access
;
1588 -- Common code of tail computation. SR/DR can point to the same object
1595 (SR
: Shared_String_Access
;
1596 DR
: Shared_String_Access
;
1599 if Count
< SR
.Last
then
1600 DR
.Data
(1 .. Count
) := SR
.Data
(SR
.Last
- Count
+ 1 .. SR
.Last
);
1603 DR
.Data
(Count
- SR
.Last
+ 1 .. Count
) := SR
.Data
(1 .. SR
.Last
);
1605 for J
in 1 .. Count
- SR
.Last
loop
1614 -- Result is empty string, reuse empty shared string
1617 Source
.Reference
:= Empty_Shared_String
'Access;
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
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
1634 DR
:= Allocate
(Count
);
1635 Common
(SR
, DR
, Count
);
1636 Source
.Reference
:= DR
;
1645 function To_String
(Source
: Unbounded_String
) return String is
1647 return Source
.Reference
.Data
(1 .. Source
.Reference
.Last
);
1650 -------------------------
1651 -- To_Unbounded_String --
1652 -------------------------
1654 function To_Unbounded_String
(Source
: String) return Unbounded_String
is
1655 DR
: Shared_String_Access
;
1658 if Source
'Length = 0 then
1659 DR
:= Empty_Shared_String
'Access;
1662 DR
:= Allocate
(Source
'Length);
1663 DR
.Data
(1 .. Source
'Length) := Source
;
1664 DR
.Last
:= Source
'Length;
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
;
1675 DR
:= Empty_Shared_String
'Access;
1678 DR
:= Allocate
(Length
);
1682 return (AF
.Controlled
with Reference
=> DR
);
1683 end To_Unbounded_String
;
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
;
1697 -- Nothing to translate, reuse empty shared string
1700 DR
:= Empty_Shared_String
'Access;
1702 -- Otherwise, allocate new shared string and fill it
1705 DR
:= Allocate
(SR
.Last
);
1707 for J
in 1 .. SR
.Last
loop
1708 DR
.Data
(J
) := Value
(Mapping
, SR
.Data
(J
));
1714 return (AF
.Controlled
with Reference
=> DR
);
1718 (Source
: in out Unbounded_String
;
1719 Mapping
: Maps
.Character_Mapping
)
1721 SR
: constant Shared_String_Access
:= Source
.Reference
;
1722 DR
: Shared_String_Access
;
1725 -- Nothing to translate
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
));
1737 -- Otherwise, allocate new shared string
1740 DR
:= Allocate
(SR
.Last
);
1742 for J
in 1 .. SR
.Last
loop
1743 DR
.Data
(J
) := Value
(Mapping
, SR
.Data
(J
));
1747 Source
.Reference
:= DR
;
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
;
1760 -- Nothing to translate, reuse empty shared string
1763 DR
:= Empty_Shared_String
'Access;
1765 -- Otherwise, allocate new shared string and fill it
1768 DR
:= Allocate
(SR
.Last
);
1770 for J
in 1 .. SR
.Last
loop
1771 DR
.Data
(J
) := Mapping
.all (SR
.Data
(J
));
1777 return (AF
.Controlled
with Reference
=> DR
);
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
;
1794 -- Nothing to translate
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
));
1806 -- Otherwise allocate new shared string and fill it
1809 DR
:= Allocate
(SR
.Last
);
1811 for J
in 1 .. SR
.Last
loop
1812 DR
.Data
(J
) := Mapping
.all (SR
.Data
(J
));
1816 Source
.Reference
:= DR
;
1834 (Source
: Unbounded_String
;
1835 Side
: Trim_End
) return Unbounded_String
1837 SR
: constant Shared_String_Access
:= Source
.Reference
;
1839 DR
: Shared_String_Access
;
1844 Low
:= Index_Non_Blank
(Source
, Forward
);
1846 -- All blanks, reuse empty shared string
1849 DR
:= Empty_Shared_String
'Access;
1855 DL
:= SR
.Last
- Low
+ 1;
1859 High
:= Index_Non_Blank
(Source
, Backward
);
1863 High
:= Index_Non_Blank
(Source
, Backward
);
1864 DL
:= High
- Low
+ 1;
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
1874 -- Otherwise, allocate new shared string
1877 DR
:= Allocate
(DL
);
1878 DR
.Data
(1 .. DL
) := SR
.Data
(Low
.. High
);
1883 return (AF
.Controlled
with Reference
=> DR
);
1887 (Source
: in out Unbounded_String
;
1890 SR
: constant Shared_String_Access
:= Source
.Reference
;
1892 DR
: Shared_String_Access
;
1897 Low
:= Index_Non_Blank
(Source
, Forward
);
1899 -- All blanks, reuse empty shared string
1902 Source
.Reference
:= Empty_Shared_String
'Access;
1909 DL
:= SR
.Last
- Low
+ 1;
1913 High
:= Index_Non_Blank
(Source
, Backward
);
1917 High
:= Index_Non_Blank
(Source
, Backward
);
1918 DL
:= High
- Low
+ 1;
1921 -- Length of the result is the same as length of the source string,
1924 if DL
= SR
.Last
then
1927 -- Try to reuse existing shared string
1929 elsif Can_Be_Reused
(SR
, DL
) then
1930 SR
.Data
(1 .. DL
) := SR
.Data
(Low
.. High
);
1933 -- Otherwise, allocate new shared string
1936 DR
:= Allocate
(DL
);
1937 DR
.Data
(1 .. DL
) := SR
.Data
(Low
.. High
);
1939 Source
.Reference
:= DR
;
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
;
1952 DR
: Shared_String_Access
;
1957 Low
:= Index
(Source
, Left
, Outside
, Forward
);
1959 -- Source includes only characters from Left set, reuse empty shared
1963 DR
:= Empty_Shared_String
'Access;
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
1978 DR
:= Allocate
(DL
);
1979 DR
.Data
(1 .. DL
) := SR
.Data
(Low
.. High
);
1984 return (AF
.Controlled
with Reference
=> DR
);
1988 (Source
: in out Unbounded_String
;
1989 Left
: Maps
.Character_Set
;
1990 Right
: Maps
.Character_Set
)
1992 SR
: constant Shared_String_Access
:= Source
.Reference
;
1994 DR
: Shared_String_Access
;
1999 Low
:= Index
(Source
, Left
, Outside
, Forward
);
2001 -- Source includes only characters from Left set, reuse empty shared
2005 Source
.Reference
:= Empty_Shared_String
'Access;
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;
2019 -- Try to reuse existing shared string
2021 elsif Can_Be_Reused
(SR
, DL
) then
2022 SR
.Data
(1 .. DL
) := SR
.Data
(Low
.. High
);
2025 -- Otherwise, allocate new shared string and fill it
2028 DR
:= Allocate
(DL
);
2029 DR
.Data
(1 .. DL
) := SR
.Data
(Low
.. High
);
2031 Source
.Reference
:= DR
;
2037 ---------------------
2038 -- Unbounded_Slice --
2039 ---------------------
2041 function Unbounded_Slice
2042 (Source
: Unbounded_String
;
2044 High
: Natural) return Unbounded_String
2046 SR
: constant Shared_String_Access
:= Source
.Reference
;
2048 DR
: Shared_String_Access
;
2053 if Low
- 1 > SR
.Last
or else High
> SR
.Last
then
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
2064 DL
:= High
- Low
+ 1;
2065 DR
:= Allocate
(DL
);
2066 DR
.Data
(1 .. DL
) := SR
.Data
(Low
.. High
);
2070 return (AF
.Controlled
with Reference
=> DR
);
2071 end Unbounded_Slice
;
2073 procedure Unbounded_Slice
2074 (Source
: Unbounded_String
;
2075 Target
: out Unbounded_String
;
2079 SR
: constant Shared_String_Access
:= Source
.Reference
;
2080 TR
: constant Shared_String_Access
:= Target
.Reference
;
2082 DR
: Shared_String_Access
;
2087 if Low
- 1 > SR
.Last
or else High
> SR
.Last
then
2090 -- Result is empty slice, reuse empty shared string
2092 elsif Low
> High
then
2093 Target
.Reference
:= Empty_Shared_String
'Access;
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
);
2105 -- Otherwise, allocate new shared string and fill it
2108 DR
:= Allocate
(DL
);
2109 DR
.Data
(1 .. DL
) := SR
.Data
(Low
.. High
);
2111 Target
.Reference
:= DR
;
2115 end Unbounded_Slice
;
2121 procedure Unreference
(Item
: not null Shared_String_Access
) is
2124 new Ada
.Unchecked_Deallocation
(Shared_String
, Shared_String_Access
);
2126 Aux
: Shared_String_Access
:= Item
;
2129 if Aux
= Empty_Shared_String
'Access then
2133 if System
.Atomic_Counters
.Decrement
(Aux
.Counter
) then
2138 end Ada
.Strings
.Unbounded
;