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-2019, 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 (Max_Length : Natural) return Natural;
54 -- Returns recommended length of the shared string which is greater or
55 -- equal to specified length. Calculation take in sense alignment of the
56 -- allocated memory segments to use memory effectively by Append/Insert/etc
64 (Left : Unbounded_String;
65 Right : Unbounded_String) return Unbounded_String
67 LR : constant Shared_String_Access := Left.Reference;
68 RR : constant Shared_String_Access := Right.Reference;
69 DL : constant Natural := LR.Last + RR.Last;
70 DR : Shared_String_Access;
73 -- Result is an empty string, reuse shared empty string
76 Reference (Empty_Shared_String'Access);
77 DR := Empty_Shared_String'Access;
79 -- Left string is empty, return Right string
81 elsif LR.Last = 0 then
85 -- Right string is empty, return Left string
87 elsif RR.Last = 0 then
91 -- Otherwise, allocate new shared string and fill data
95 DR.Data (1 .. LR.Last) := LR.Data (1 .. LR.Last);
96 DR.Data (LR.Last + 1 .. DL) := RR.Data (1 .. RR.Last);
100 return (AF.Controlled with Reference => DR);
104 (Left : Unbounded_String;
105 Right : String) return Unbounded_String
107 LR : constant Shared_String_Access := Left.Reference;
108 DL : constant Natural := LR.Last + Right'Length;
109 DR : Shared_String_Access;
112 -- Result is an empty string, reuse shared empty string
115 Reference (Empty_Shared_String'Access);
116 DR := Empty_Shared_String'Access;
118 -- Right is an empty string, return Left string
120 elsif Right'Length = 0 then
124 -- Otherwise, allocate new shared string and fill it
128 DR.Data (1 .. LR.Last) := LR.Data (1 .. LR.Last);
129 DR.Data (LR.Last + 1 .. DL) := Right;
133 return (AF.Controlled with Reference => DR);
138 Right : Unbounded_String) return Unbounded_String
140 RR : constant Shared_String_Access := Right.Reference;
141 DL : constant Natural := Left'Length + RR.Last;
142 DR : Shared_String_Access;
145 -- Result is an empty string, reuse shared one
148 Reference (Empty_Shared_String'Access);
149 DR := Empty_Shared_String'Access;
151 -- Left is empty string, return Right string
153 elsif Left'Length = 0 then
157 -- Otherwise, allocate new shared string and fill it
161 DR.Data (1 .. Left'Length) := Left;
162 DR.Data (Left'Length + 1 .. DL) := RR.Data (1 .. RR.Last);
166 return (AF.Controlled with Reference => DR);
170 (Left : Unbounded_String;
171 Right : Character) return Unbounded_String
173 LR : constant Shared_String_Access := Left.Reference;
174 DL : constant Natural := LR.Last + 1;
175 DR : Shared_String_Access;
179 DR.Data (1 .. LR.Last) := LR.Data (1 .. LR.Last);
180 DR.Data (DL) := Right;
183 return (AF.Controlled with Reference => DR);
188 Right : Unbounded_String) return Unbounded_String
190 RR : constant Shared_String_Access := Right.Reference;
191 DL : constant Natural := 1 + RR.Last;
192 DR : Shared_String_Access;
197 DR.Data (2 .. DL) := RR.Data (1 .. RR.Last);
200 return (AF.Controlled with Reference => DR);
209 Right : Character) return Unbounded_String
211 DR : Shared_String_Access;
214 -- Result is an empty string, reuse shared empty string
217 Reference (Empty_Shared_String'Access);
218 DR := Empty_Shared_String'Access;
220 -- Otherwise, allocate new shared string and fill it
223 DR := Allocate (Left);
225 for J in 1 .. Left loop
226 DR.Data (J) := Right;
232 return (AF.Controlled with Reference => DR);
237 Right : String) return Unbounded_String
239 DL : constant Natural := Left * Right'Length;
240 DR : Shared_String_Access;
244 -- Result is an empty string, reuse shared empty string
247 Reference (Empty_Shared_String'Access);
248 DR := Empty_Shared_String'Access;
250 -- Otherwise, allocate new shared string and fill it
256 for J in 1 .. Left loop
257 DR.Data (K .. K + Right'Length - 1) := Right;
258 K := K + Right'Length;
264 return (AF.Controlled with Reference => DR);
269 Right : Unbounded_String) return Unbounded_String
271 RR : constant Shared_String_Access := Right.Reference;
272 DL : constant Natural := Left * RR.Last;
273 DR : Shared_String_Access;
277 -- Result is an empty string, reuse shared empty string
280 Reference (Empty_Shared_String'Access);
281 DR := Empty_Shared_String'Access;
283 -- Coefficient is one, just return string itself
289 -- Otherwise, allocate new shared string and fill it
295 for J in 1 .. Left loop
296 DR.Data (K .. K + RR.Last - 1) := RR.Data (1 .. RR.Last);
303 return (AF.Controlled with Reference => DR);
311 (Left : Unbounded_String;
312 Right : Unbounded_String) return Boolean
314 LR : constant Shared_String_Access := Left.Reference;
315 RR : constant Shared_String_Access := Right.Reference;
317 return LR.Data (1 .. LR.Last) < RR.Data (1 .. RR.Last);
321 (Left : Unbounded_String;
322 Right : String) return Boolean
324 LR : constant Shared_String_Access := Left.Reference;
326 return LR.Data (1 .. LR.Last) < Right;
331 Right : Unbounded_String) return Boolean
333 RR : constant Shared_String_Access := Right.Reference;
335 return Left < RR.Data (1 .. RR.Last);
343 (Left : Unbounded_String;
344 Right : Unbounded_String) return Boolean
346 LR : constant Shared_String_Access := Left.Reference;
347 RR : constant Shared_String_Access := Right.Reference;
350 -- LR = RR means two strings shares shared string, thus they are equal
352 return LR = RR or else LR.Data (1 .. LR.Last) <= RR.Data (1 .. RR.Last);
356 (Left : Unbounded_String;
357 Right : String) return Boolean
359 LR : constant Shared_String_Access := Left.Reference;
361 return LR.Data (1 .. LR.Last) <= Right;
366 Right : Unbounded_String) return Boolean
368 RR : constant Shared_String_Access := Right.Reference;
370 return Left <= RR.Data (1 .. RR.Last);
378 (Left : Unbounded_String;
379 Right : Unbounded_String) return Boolean
381 LR : constant Shared_String_Access := Left.Reference;
382 RR : constant Shared_String_Access := Right.Reference;
385 return LR = RR or else LR.Data (1 .. LR.Last) = RR.Data (1 .. RR.Last);
386 -- LR = RR means two strings shares shared string, thus they are equal
390 (Left : Unbounded_String;
391 Right : String) return Boolean
393 LR : constant Shared_String_Access := Left.Reference;
395 return LR.Data (1 .. LR.Last) = Right;
400 Right : Unbounded_String) return Boolean
402 RR : constant Shared_String_Access := Right.Reference;
404 return Left = RR.Data (1 .. RR.Last);
412 (Left : Unbounded_String;
413 Right : Unbounded_String) return Boolean
415 LR : constant Shared_String_Access := Left.Reference;
416 RR : constant Shared_String_Access := Right.Reference;
418 return LR.Data (1 .. LR.Last) > RR.Data (1 .. RR.Last);
422 (Left : Unbounded_String;
423 Right : String) return Boolean
425 LR : constant Shared_String_Access := Left.Reference;
427 return LR.Data (1 .. LR.Last) > Right;
432 Right : Unbounded_String) return Boolean
434 RR : constant Shared_String_Access := Right.Reference;
436 return Left > RR.Data (1 .. RR.Last);
444 (Left : Unbounded_String;
445 Right : Unbounded_String) return Boolean
447 LR : constant Shared_String_Access := Left.Reference;
448 RR : constant Shared_String_Access := Right.Reference;
451 -- LR = RR means two strings shares shared string, thus they are equal
453 return LR = RR or else LR.Data (1 .. LR.Last) >= RR.Data (1 .. RR.Last);
457 (Left : Unbounded_String;
458 Right : String) return Boolean
460 LR : constant Shared_String_Access := Left.Reference;
462 return LR.Data (1 .. LR.Last) >= Right;
467 Right : Unbounded_String) return Boolean
469 RR : constant Shared_String_Access := Right.Reference;
471 return Left >= RR.Data (1 .. RR.Last);
478 procedure Adjust (Object : in out Unbounded_String) is
480 Reference (Object.Reference);
483 ------------------------
484 -- Aligned_Max_Length --
485 ------------------------
487 function Aligned_Max_Length (Max_Length : Natural) return Natural is
488 Static_Size : constant Natural :=
489 Empty_Shared_String'Size / Standard'Storage_Unit;
490 -- Total size of all static components
494 ((Static_Size + Max_Length - 1) / Min_Mul_Alloc + 2) * Min_Mul_Alloc
496 end Aligned_Max_Length;
503 (Max_Length : Natural) return not null Shared_String_Access
506 -- Empty string requested, return shared empty string
508 if Max_Length = 0 then
509 Reference (Empty_Shared_String'Access);
510 return Empty_Shared_String'Access;
512 -- Otherwise, allocate requested space (and probably some more room)
515 return new Shared_String (Aligned_Max_Length (Max_Length));
524 (Source : in out Unbounded_String;
525 New_Item : Unbounded_String)
527 SR : constant Shared_String_Access := Source.Reference;
528 NR : constant Shared_String_Access := New_Item.Reference;
529 DL : constant Natural := SR.Last + NR.Last;
530 DR : Shared_String_Access;
533 -- Source is an empty string, reuse New_Item data
537 Source.Reference := NR;
540 -- New_Item is empty string, nothing to do
542 elsif NR.Last = 0 then
545 -- Try to reuse existing shared string
547 elsif Can_Be_Reused (SR, DL) then
548 SR.Data (SR.Last + 1 .. DL) := NR.Data (1 .. NR.Last);
551 -- Otherwise, allocate new one and fill it
554 DR := Allocate (DL + DL / Growth_Factor);
555 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
556 DR.Data (SR.Last + 1 .. DL) := NR.Data (1 .. NR.Last);
558 Source.Reference := DR;
564 (Source : in out Unbounded_String;
567 SR : constant Shared_String_Access := Source.Reference;
568 DL : constant Natural := SR.Last + New_Item'Length;
569 DR : Shared_String_Access;
572 -- New_Item is an empty string, nothing to do
574 if New_Item'Length = 0 then
577 -- Try to reuse existing shared string
579 elsif Can_Be_Reused (SR, DL) then
580 SR.Data (SR.Last + 1 .. DL) := New_Item;
583 -- Otherwise, allocate new one and fill it
586 DR := Allocate (DL + DL / Growth_Factor);
587 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
588 DR.Data (SR.Last + 1 .. DL) := New_Item;
590 Source.Reference := DR;
596 (Source : in out Unbounded_String;
597 New_Item : Character)
599 SR : constant Shared_String_Access := Source.Reference;
600 DL : constant Natural := SR.Last + 1;
601 DR : Shared_String_Access;
604 -- Try to reuse existing shared string
606 if Can_Be_Reused (SR, SR.Last + 1) then
607 SR.Data (SR.Last + 1) := New_Item;
608 SR.Last := SR.Last + 1;
610 -- Otherwise, allocate new one and fill it
613 DR := Allocate (DL + DL / Growth_Factor);
614 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
615 DR.Data (DL) := New_Item;
617 Source.Reference := DR;
626 function Can_Be_Reused
627 (Item : not null Shared_String_Access;
628 Length : Natural) return Boolean
632 System.Atomic_Counters.Is_One (Item.Counter)
633 and then Item.Max_Length >= Length
634 and then Item.Max_Length <=
635 Aligned_Max_Length (Length + Length / Growth_Factor);
643 (Source : Unbounded_String;
645 Mapping : Maps.Character_Mapping := Maps.Identity) return Natural
647 SR : constant Shared_String_Access := Source.Reference;
649 return Search.Count (SR.Data (1 .. SR.Last), Pattern, Mapping);
653 (Source : Unbounded_String;
655 Mapping : Maps.Character_Mapping_Function) return Natural
657 SR : constant Shared_String_Access := Source.Reference;
659 return Search.Count (SR.Data (1 .. SR.Last), Pattern, Mapping);
663 (Source : Unbounded_String;
664 Set : Maps.Character_Set) return Natural
666 SR : constant Shared_String_Access := Source.Reference;
668 return Search.Count (SR.Data (1 .. SR.Last), Set);
676 (Source : Unbounded_String;
678 Through : Natural) return Unbounded_String
680 SR : constant Shared_String_Access := Source.Reference;
682 DR : Shared_String_Access;
685 -- Empty slice is deleted, use the same shared string
687 if From > Through then
691 -- Index is out of range
693 elsif Through > SR.Last then
696 -- Compute size of the result
699 DL := SR.Last - (Through - From + 1);
701 -- Result is an empty string, reuse shared empty string
704 Reference (Empty_Shared_String'Access);
705 DR := Empty_Shared_String'Access;
707 -- Otherwise, allocate new shared string and fill it
711 DR.Data (1 .. From - 1) := SR.Data (1 .. From - 1);
712 DR.Data (From .. DL) := SR.Data (Through + 1 .. SR.Last);
717 return (AF.Controlled with Reference => DR);
721 (Source : in out Unbounded_String;
725 SR : constant Shared_String_Access := Source.Reference;
727 DR : Shared_String_Access;
730 -- Nothing changed, return
732 if From > Through then
735 -- Through is outside of the range
737 elsif Through > SR.Last then
741 DL := SR.Last - (Through - From + 1);
743 -- Result is empty, reuse shared empty string
746 Reference (Empty_Shared_String'Access);
747 Source.Reference := Empty_Shared_String'Access;
750 -- Try to reuse existing shared string
752 elsif Can_Be_Reused (SR, DL) then
753 SR.Data (From .. DL) := SR.Data (Through + 1 .. SR.Last);
756 -- Otherwise, allocate new shared string
760 DR.Data (1 .. From - 1) := SR.Data (1 .. From - 1);
761 DR.Data (From .. DL) := SR.Data (Through + 1 .. SR.Last);
763 Source.Reference := DR;
774 (Source : Unbounded_String;
775 Index : Positive) return Character
777 SR : constant Shared_String_Access := Source.Reference;
779 if Index <= SR.Last then
780 return SR.Data (Index);
790 procedure Finalize (Object : in out Unbounded_String) is
791 SR : constant not null Shared_String_Access := Object.Reference;
793 if SR /= Null_Unbounded_String.Reference then
795 -- The same controlled object can be finalized several times for
796 -- some reason. As per 7.6.1(24) this should have no ill effect,
797 -- so we need to add a guard for the case of finalizing the same
800 -- We set the Object to the empty string so there will be no ill
801 -- effects if a program references an already-finalized object.
803 Object.Reference := Null_Unbounded_String.Reference;
804 Reference (Object.Reference);
814 (Source : Unbounded_String;
815 Set : Maps.Character_Set;
817 Test : Strings.Membership;
818 First : out Positive;
821 SR : constant Shared_String_Access := Source.Reference;
823 Search.Find_Token (SR.Data (From .. SR.Last), Set, Test, First, Last);
827 (Source : Unbounded_String;
828 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 (1 .. SR.Last), Set, Test, First, Last);
842 procedure Free (X : in out String_Access) is
843 procedure Deallocate is
844 new Ada.Unchecked_Deallocation (String, String_Access);
854 (Source : Unbounded_String;
856 Pad : Character := Space) return Unbounded_String
858 SR : constant Shared_String_Access := Source.Reference;
859 DR : Shared_String_Access;
862 -- Result is empty, reuse shared empty string
865 Reference (Empty_Shared_String'Access);
866 DR := Empty_Shared_String'Access;
868 -- Length of the string is the same as requested, reuse source shared
871 elsif Count = SR.Last then
875 -- Otherwise, allocate new shared string and fill it
878 DR := Allocate (Count);
880 -- Length of the source string is more than requested, copy
881 -- corresponding slice.
883 if Count < SR.Last then
884 DR.Data (1 .. Count) := SR.Data (1 .. Count);
886 -- Length of the source string is less than requested, copy all
887 -- contents and fill others by Pad character.
890 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
892 for J in SR.Last + 1 .. Count loop
900 return (AF.Controlled with Reference => DR);
904 (Source : in out Unbounded_String;
906 Pad : Character := Space)
908 SR : constant Shared_String_Access := Source.Reference;
909 DR : Shared_String_Access;
912 -- Result is empty, reuse empty shared string
915 Reference (Empty_Shared_String'Access);
916 Source.Reference := Empty_Shared_String'Access;
919 -- Result is same as source string, reuse source shared string
921 elsif Count = SR.Last then
924 -- Try to reuse existing shared string
926 elsif Can_Be_Reused (SR, Count) then
927 if Count > SR.Last then
928 for J in SR.Last + 1 .. Count loop
935 -- Otherwise, allocate new shared string and fill it
938 DR := Allocate (Count);
940 -- Length of the source string is greater than requested, copy
941 -- corresponding slice.
943 if Count < SR.Last then
944 DR.Data (1 .. Count) := SR.Data (1 .. Count);
946 -- Length of the source string is less than requested, copy all
947 -- existing data and fill remaining positions with Pad characters.
950 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
952 for J in SR.Last + 1 .. Count loop
958 Source.Reference := DR;
968 (Source : Unbounded_String;
970 Going : Strings.Direction := Strings.Forward;
971 Mapping : Maps.Character_Mapping := Maps.Identity) return Natural
973 SR : constant Shared_String_Access := Source.Reference;
975 return Search.Index (SR.Data (1 .. SR.Last), Pattern, Going, Mapping);
979 (Source : Unbounded_String;
981 Going : Direction := Forward;
982 Mapping : Maps.Character_Mapping_Function) return Natural
984 SR : constant Shared_String_Access := Source.Reference;
986 return Search.Index (SR.Data (1 .. SR.Last), Pattern, Going, Mapping);
990 (Source : Unbounded_String;
991 Set : Maps.Character_Set;
992 Test : Strings.Membership := Strings.Inside;
993 Going : Strings.Direction := Strings.Forward) return Natural
995 SR : constant Shared_String_Access := Source.Reference;
997 return Search.Index (SR.Data (1 .. SR.Last), Set, Test, Going);
1001 (Source : Unbounded_String;
1004 Going : Direction := Forward;
1005 Mapping : Maps.Character_Mapping := Maps.Identity) return Natural
1007 SR : constant Shared_String_Access := Source.Reference;
1010 (SR.Data (1 .. SR.Last), Pattern, From, Going, Mapping);
1014 (Source : Unbounded_String;
1017 Going : Direction := Forward;
1018 Mapping : Maps.Character_Mapping_Function) return Natural
1020 SR : constant Shared_String_Access := Source.Reference;
1023 (SR.Data (1 .. SR.Last), Pattern, From, Going, Mapping);
1027 (Source : Unbounded_String;
1028 Set : Maps.Character_Set;
1030 Test : Membership := Inside;
1031 Going : Direction := Forward) return Natural
1033 SR : constant Shared_String_Access := Source.Reference;
1035 return Search.Index (SR.Data (1 .. SR.Last), Set, From, Test, Going);
1038 ---------------------
1039 -- Index_Non_Blank --
1040 ---------------------
1042 function Index_Non_Blank
1043 (Source : Unbounded_String;
1044 Going : Strings.Direction := Strings.Forward) return Natural
1046 SR : constant Shared_String_Access := Source.Reference;
1048 return Search.Index_Non_Blank (SR.Data (1 .. SR.Last), Going);
1049 end Index_Non_Blank;
1051 function Index_Non_Blank
1052 (Source : Unbounded_String;
1054 Going : Direction := Forward) return Natural
1056 SR : constant Shared_String_Access := Source.Reference;
1058 return Search.Index_Non_Blank (SR.Data (1 .. SR.Last), From, Going);
1059 end Index_Non_Blank;
1065 procedure Initialize (Object : in out Unbounded_String) is
1067 Reference (Object.Reference);
1075 (Source : Unbounded_String;
1077 New_Item : String) return Unbounded_String
1079 SR : constant Shared_String_Access := Source.Reference;
1080 DL : constant Natural := SR.Last + New_Item'Length;
1081 DR : Shared_String_Access;
1084 -- Check index first
1086 if Before > SR.Last + 1 then
1090 -- Result is empty, reuse empty shared string
1093 Reference (Empty_Shared_String'Access);
1094 DR := Empty_Shared_String'Access;
1096 -- Inserted string is empty, reuse source shared string
1098 elsif New_Item'Length = 0 then
1102 -- Otherwise, allocate new shared string and fill it
1105 DR := Allocate (DL + DL / Growth_Factor);
1106 DR.Data (1 .. Before - 1) := SR.Data (1 .. Before - 1);
1107 DR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1108 DR.Data (Before + New_Item'Length .. DL) :=
1109 SR.Data (Before .. SR.Last);
1113 return (AF.Controlled with Reference => DR);
1117 (Source : in out Unbounded_String;
1121 SR : constant Shared_String_Access := Source.Reference;
1122 DL : constant Natural := SR.Last + New_Item'Length;
1123 DR : Shared_String_Access;
1128 if Before > SR.Last + 1 then
1132 -- Result is empty string, reuse empty shared string
1135 Reference (Empty_Shared_String'Access);
1136 Source.Reference := Empty_Shared_String'Access;
1139 -- Inserted string is empty, nothing to do
1141 elsif New_Item'Length = 0 then
1144 -- Try to reuse existing shared string first
1146 elsif Can_Be_Reused (SR, DL) then
1147 SR.Data (Before + New_Item'Length .. DL) :=
1148 SR.Data (Before .. SR.Last);
1149 SR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1152 -- Otherwise, allocate new shared string and fill it
1155 DR := Allocate (DL + DL / Growth_Factor);
1156 DR.Data (1 .. Before - 1) := SR.Data (1 .. Before - 1);
1157 DR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1158 DR.Data (Before + New_Item'Length .. DL) :=
1159 SR.Data (Before .. SR.Last);
1161 Source.Reference := DR;
1170 function Length (Source : Unbounded_String) return Natural is
1172 return Source.Reference.Last;
1180 (Source : Unbounded_String;
1181 Position : Positive;
1182 New_Item : String) return Unbounded_String
1184 SR : constant Shared_String_Access := Source.Reference;
1186 DR : Shared_String_Access;
1191 if Position > SR.Last + 1 then
1195 DL := Integer'Max (SR.Last, Position + New_Item'Length - 1);
1197 -- Result is empty string, reuse empty shared string
1200 Reference (Empty_Shared_String'Access);
1201 DR := Empty_Shared_String'Access;
1203 -- Result is same as source string, reuse source shared string
1205 elsif New_Item'Length = 0 then
1209 -- Otherwise, allocate new shared string and fill it
1212 DR := Allocate (DL);
1213 DR.Data (1 .. Position - 1) := SR.Data (1 .. Position - 1);
1214 DR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1215 DR.Data (Position + New_Item'Length .. DL) :=
1216 SR.Data (Position + New_Item'Length .. SR.Last);
1220 return (AF.Controlled with Reference => DR);
1224 (Source : in out Unbounded_String;
1225 Position : Positive;
1228 SR : constant Shared_String_Access := Source.Reference;
1230 DR : Shared_String_Access;
1235 if Position > SR.Last + 1 then
1239 DL := Integer'Max (SR.Last, Position + New_Item'Length - 1);
1241 -- Result is empty string, reuse empty shared string
1244 Reference (Empty_Shared_String'Access);
1245 Source.Reference := Empty_Shared_String'Access;
1248 -- String unchanged, nothing to do
1250 elsif New_Item'Length = 0 then
1253 -- Try to reuse existing shared string
1255 elsif Can_Be_Reused (SR, DL) then
1256 SR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1259 -- Otherwise allocate new shared string and fill it
1262 DR := Allocate (DL);
1263 DR.Data (1 .. Position - 1) := SR.Data (1 .. Position - 1);
1264 DR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1265 DR.Data (Position + New_Item'Length .. DL) :=
1266 SR.Data (Position + New_Item'Length .. SR.Last);
1268 Source.Reference := DR;
1277 procedure Reference (Item : not null Shared_String_Access) is
1279 System.Atomic_Counters.Increment (Item.Counter);
1282 ---------------------
1283 -- Replace_Element --
1284 ---------------------
1286 procedure Replace_Element
1287 (Source : in out Unbounded_String;
1291 SR : constant Shared_String_Access := Source.Reference;
1292 DR : Shared_String_Access;
1297 if Index <= SR.Last then
1299 -- Try to reuse existing shared string
1301 if Can_Be_Reused (SR, SR.Last) then
1302 SR.Data (Index) := By;
1304 -- Otherwise allocate new shared string and fill it
1307 DR := Allocate (SR.Last);
1308 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
1309 DR.Data (Index) := By;
1311 Source.Reference := DR;
1318 end Replace_Element;
1324 function Replace_Slice
1325 (Source : Unbounded_String;
1328 By : String) return Unbounded_String
1330 SR : constant Shared_String_Access := Source.Reference;
1332 DR : Shared_String_Access;
1337 if Low > SR.Last + 1 then
1341 -- Do replace operation when removed slice is not empty
1344 DL := By'Length + SR.Last + Low - Integer'Min (High, SR.Last) - 1;
1345 -- This is the number of characters remaining in the string after
1346 -- replacing the slice.
1348 -- Result is empty string, reuse empty shared string
1351 Reference (Empty_Shared_String'Access);
1352 DR := Empty_Shared_String'Access;
1354 -- Otherwise allocate new shared string and fill it
1357 DR := Allocate (DL);
1358 DR.Data (1 .. Low - 1) := SR.Data (1 .. Low - 1);
1359 DR.Data (Low .. Low + By'Length - 1) := By;
1360 DR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1364 return (AF.Controlled with Reference => DR);
1366 -- Otherwise just insert string
1369 return Insert (Source, Low, By);
1373 procedure Replace_Slice
1374 (Source : in out Unbounded_String;
1379 SR : constant Shared_String_Access := Source.Reference;
1381 DR : Shared_String_Access;
1386 if Low > SR.Last + 1 then
1390 -- Do replace operation only when replaced slice is not empty
1393 DL := By'Length + SR.Last + Low - Integer'Min (High, SR.Last) - 1;
1394 -- This is the number of characters remaining in the string after
1395 -- replacing the slice.
1397 -- Result is empty string, reuse empty shared string
1400 Reference (Empty_Shared_String'Access);
1401 Source.Reference := Empty_Shared_String'Access;
1404 -- Try to reuse existing shared string
1406 elsif Can_Be_Reused (SR, DL) then
1407 SR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1408 SR.Data (Low .. Low + By'Length - 1) := By;
1411 -- Otherwise allocate new shared string and fill it
1414 DR := Allocate (DL);
1415 DR.Data (1 .. Low - 1) := SR.Data (1 .. Low - 1);
1416 DR.Data (Low .. Low + By'Length - 1) := By;
1417 DR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1419 Source.Reference := DR;
1423 -- Otherwise just insert item
1426 Insert (Source, Low, By);
1430 --------------------------
1431 -- Set_Unbounded_String --
1432 --------------------------
1434 procedure Set_Unbounded_String
1435 (Target : out Unbounded_String;
1438 TR : constant Shared_String_Access := Target.Reference;
1439 DR : Shared_String_Access;
1442 -- In case of empty string, reuse empty shared string
1444 if Source'Length = 0 then
1445 Reference (Empty_Shared_String'Access);
1446 Target.Reference := Empty_Shared_String'Access;
1449 -- Try to reuse existing shared string
1451 if Can_Be_Reused (TR, Source'Length) then
1455 -- Otherwise allocate new shared string
1458 DR := Allocate (Source'Length);
1459 Target.Reference := DR;
1462 DR.Data (1 .. Source'Length) := Source;
1463 DR.Last := Source'Length;
1467 end Set_Unbounded_String;
1474 (Source : Unbounded_String;
1476 High : Natural) return String
1478 SR : constant Shared_String_Access := Source.Reference;
1481 -- Note: test of High > Length is in accordance with AI95-00128
1483 if Low > SR.Last + 1 or else High > SR.Last then
1487 return SR.Data (Low .. High);
1496 (Source : Unbounded_String;
1498 Pad : Character := Space) return Unbounded_String
1500 SR : constant Shared_String_Access := Source.Reference;
1501 DR : Shared_String_Access;
1504 -- For empty result reuse empty shared string
1507 Reference (Empty_Shared_String'Access);
1508 DR := Empty_Shared_String'Access;
1510 -- Result is whole source string, reuse source shared string
1512 elsif Count = SR.Last then
1516 -- Otherwise allocate new shared string and fill it
1519 DR := Allocate (Count);
1521 if Count < SR.Last then
1522 DR.Data (1 .. Count) := SR.Data (SR.Last - Count + 1 .. SR.Last);
1525 for J in 1 .. Count - SR.Last loop
1529 DR.Data (Count - SR.Last + 1 .. Count) := SR.Data (1 .. SR.Last);
1535 return (AF.Controlled with Reference => DR);
1539 (Source : in out Unbounded_String;
1541 Pad : Character := Space)
1543 SR : constant Shared_String_Access := Source.Reference;
1544 DR : Shared_String_Access;
1547 (SR : Shared_String_Access;
1548 DR : Shared_String_Access;
1550 -- Common code of tail computation. SR/DR can point to the same object
1557 (SR : Shared_String_Access;
1558 DR : Shared_String_Access;
1561 if Count < SR.Last then
1562 DR.Data (1 .. Count) := SR.Data (SR.Last - Count + 1 .. SR.Last);
1565 DR.Data (Count - SR.Last + 1 .. Count) := SR.Data (1 .. SR.Last);
1567 for J in 1 .. Count - SR.Last loop
1576 -- Result is empty string, reuse empty shared string
1579 Reference (Empty_Shared_String'Access);
1580 Source.Reference := Empty_Shared_String'Access;
1583 -- Length of the result is the same as length of the source string,
1584 -- reuse source shared string.
1586 elsif Count = SR.Last then
1589 -- Try to reuse existing shared string
1591 elsif Can_Be_Reused (SR, Count) then
1592 Common (SR, SR, Count);
1594 -- Otherwise allocate new shared string and fill it
1597 DR := Allocate (Count);
1598 Common (SR, DR, Count);
1599 Source.Reference := DR;
1608 function To_String (Source : Unbounded_String) return String is
1610 return Source.Reference.Data (1 .. Source.Reference.Last);
1613 -------------------------
1614 -- To_Unbounded_String --
1615 -------------------------
1617 function To_Unbounded_String (Source : String) return Unbounded_String is
1618 DR : Shared_String_Access;
1621 if Source'Length = 0 then
1622 Reference (Empty_Shared_String'Access);
1623 DR := Empty_Shared_String'Access;
1626 DR := Allocate (Source'Length);
1627 DR.Data (1 .. Source'Length) := Source;
1628 DR.Last := Source'Length;
1631 return (AF.Controlled with Reference => DR);
1632 end To_Unbounded_String;
1634 function To_Unbounded_String (Length : Natural) return Unbounded_String is
1635 DR : Shared_String_Access;
1639 Reference (Empty_Shared_String'Access);
1640 DR := Empty_Shared_String'Access;
1643 DR := Allocate (Length);
1647 return (AF.Controlled with Reference => DR);
1648 end To_Unbounded_String;
1655 (Source : Unbounded_String;
1656 Mapping : Maps.Character_Mapping) return Unbounded_String
1658 SR : constant Shared_String_Access := Source.Reference;
1659 DR : Shared_String_Access;
1662 -- Nothing to translate, reuse empty shared string
1665 Reference (Empty_Shared_String'Access);
1666 DR := Empty_Shared_String'Access;
1668 -- Otherwise, allocate new shared string and fill it
1671 DR := Allocate (SR.Last);
1673 for J in 1 .. SR.Last loop
1674 DR.Data (J) := Value (Mapping, SR.Data (J));
1680 return (AF.Controlled with Reference => DR);
1684 (Source : in out Unbounded_String;
1685 Mapping : Maps.Character_Mapping)
1687 SR : constant Shared_String_Access := Source.Reference;
1688 DR : Shared_String_Access;
1691 -- Nothing to translate
1696 -- Try to reuse shared string
1698 elsif Can_Be_Reused (SR, SR.Last) then
1699 for J in 1 .. SR.Last loop
1700 SR.Data (J) := Value (Mapping, SR.Data (J));
1703 -- Otherwise, allocate new shared string
1706 DR := Allocate (SR.Last);
1708 for J in 1 .. SR.Last loop
1709 DR.Data (J) := Value (Mapping, SR.Data (J));
1713 Source.Reference := DR;
1719 (Source : Unbounded_String;
1720 Mapping : Maps.Character_Mapping_Function) return Unbounded_String
1722 SR : constant Shared_String_Access := Source.Reference;
1723 DR : Shared_String_Access;
1726 -- Nothing to translate, reuse empty shared string
1729 Reference (Empty_Shared_String'Access);
1730 DR := Empty_Shared_String'Access;
1732 -- Otherwise, allocate new shared string and fill it
1735 DR := Allocate (SR.Last);
1737 for J in 1 .. SR.Last loop
1738 DR.Data (J) := Mapping.all (SR.Data (J));
1744 return (AF.Controlled with Reference => DR);
1754 (Source : in out Unbounded_String;
1755 Mapping : Maps.Character_Mapping_Function)
1757 SR : constant Shared_String_Access := Source.Reference;
1758 DR : Shared_String_Access;
1761 -- Nothing to translate
1766 -- Try to reuse shared string
1768 elsif Can_Be_Reused (SR, SR.Last) then
1769 for J in 1 .. SR.Last loop
1770 SR.Data (J) := Mapping.all (SR.Data (J));
1773 -- Otherwise allocate new shared string and fill it
1776 DR := Allocate (SR.Last);
1778 for J in 1 .. SR.Last loop
1779 DR.Data (J) := Mapping.all (SR.Data (J));
1783 Source.Reference := DR;
1801 (Source : Unbounded_String;
1802 Side : Trim_End) return Unbounded_String
1804 SR : constant Shared_String_Access := Source.Reference;
1806 DR : Shared_String_Access;
1811 Low := Index_Non_Blank (Source, Forward);
1813 -- All blanks, reuse empty shared string
1816 Reference (Empty_Shared_String'Access);
1817 DR := Empty_Shared_String'Access;
1823 DL := SR.Last - Low + 1;
1827 High := Index_Non_Blank (Source, Backward);
1831 High := Index_Non_Blank (Source, Backward);
1832 DL := High - Low + 1;
1835 -- Length of the result is the same as length of the source string,
1836 -- reuse source shared string.
1838 if DL = SR.Last then
1842 -- Otherwise, allocate new shared string
1845 DR := Allocate (DL);
1846 DR.Data (1 .. DL) := SR.Data (Low .. High);
1851 return (AF.Controlled with Reference => DR);
1855 (Source : in out Unbounded_String;
1858 SR : constant Shared_String_Access := Source.Reference;
1860 DR : Shared_String_Access;
1865 Low := Index_Non_Blank (Source, Forward);
1867 -- All blanks, reuse empty shared string
1870 Reference (Empty_Shared_String'Access);
1871 Source.Reference := Empty_Shared_String'Access;
1878 DL := SR.Last - Low + 1;
1882 High := Index_Non_Blank (Source, Backward);
1886 High := Index_Non_Blank (Source, Backward);
1887 DL := High - Low + 1;
1890 -- Length of the result is the same as length of the source string,
1893 if DL = SR.Last then
1896 -- Try to reuse existing shared string
1898 elsif Can_Be_Reused (SR, DL) then
1899 SR.Data (1 .. DL) := SR.Data (Low .. High);
1902 -- Otherwise, allocate new shared string
1905 DR := Allocate (DL);
1906 DR.Data (1 .. DL) := SR.Data (Low .. High);
1908 Source.Reference := DR;
1915 (Source : Unbounded_String;
1916 Left : Maps.Character_Set;
1917 Right : Maps.Character_Set) return Unbounded_String
1919 SR : constant Shared_String_Access := Source.Reference;
1921 DR : Shared_String_Access;
1926 Low := Index (Source, Left, Outside, Forward);
1928 -- Source includes only characters from Left set, reuse empty shared
1932 Reference (Empty_Shared_String'Access);
1933 DR := Empty_Shared_String'Access;
1936 High := Index (Source, Right, Outside, Backward);
1937 DL := Integer'Max (0, High - Low + 1);
1939 -- Source includes only characters from Right set or result string
1940 -- is empty, reuse empty shared string.
1942 if High = 0 or else DL = 0 then
1943 Reference (Empty_Shared_String'Access);
1944 DR := Empty_Shared_String'Access;
1946 -- Otherwise, allocate new shared string and fill it
1949 DR := Allocate (DL);
1950 DR.Data (1 .. DL) := SR.Data (Low .. High);
1955 return (AF.Controlled with Reference => DR);
1959 (Source : in out Unbounded_String;
1960 Left : Maps.Character_Set;
1961 Right : Maps.Character_Set)
1963 SR : constant Shared_String_Access := Source.Reference;
1965 DR : Shared_String_Access;
1970 Low := Index (Source, Left, Outside, Forward);
1972 -- Source includes only characters from Left set, reuse empty shared
1976 Reference (Empty_Shared_String'Access);
1977 Source.Reference := Empty_Shared_String'Access;
1981 High := Index (Source, Right, Outside, Backward);
1982 DL := Integer'Max (0, High - Low + 1);
1984 -- Source includes only characters from Right set or result string
1985 -- is empty, reuse empty shared string.
1987 if High = 0 or else DL = 0 then
1988 Reference (Empty_Shared_String'Access);
1989 Source.Reference := Empty_Shared_String'Access;
1992 -- Try to reuse existing shared string
1994 elsif Can_Be_Reused (SR, DL) then
1995 SR.Data (1 .. DL) := SR.Data (Low .. High);
1998 -- Otherwise, allocate new shared string and fill it
2001 DR := Allocate (DL);
2002 DR.Data (1 .. DL) := SR.Data (Low .. High);
2004 Source.Reference := DR;
2010 ---------------------
2011 -- Unbounded_Slice --
2012 ---------------------
2014 function Unbounded_Slice
2015 (Source : Unbounded_String;
2017 High : Natural) return Unbounded_String
2019 SR : constant Shared_String_Access := Source.Reference;
2021 DR : Shared_String_Access;
2026 if Low > SR.Last + 1 or else High > SR.Last then
2029 -- Result is empty slice, reuse empty shared string
2031 elsif Low > High then
2032 Reference (Empty_Shared_String'Access);
2033 DR := Empty_Shared_String'Access;
2035 -- Otherwise, allocate new shared string and fill it
2038 DL := High - Low + 1;
2039 DR := Allocate (DL);
2040 DR.Data (1 .. DL) := SR.Data (Low .. High);
2044 return (AF.Controlled with Reference => DR);
2045 end Unbounded_Slice;
2047 procedure Unbounded_Slice
2048 (Source : Unbounded_String;
2049 Target : out Unbounded_String;
2053 SR : constant Shared_String_Access := Source.Reference;
2054 TR : constant Shared_String_Access := Target.Reference;
2056 DR : Shared_String_Access;
2061 if Low > SR.Last + 1 or else High > SR.Last then
2064 -- Result is empty slice, reuse empty shared string
2066 elsif Low > High then
2067 Reference (Empty_Shared_String'Access);
2068 Target.Reference := Empty_Shared_String'Access;
2072 DL := High - Low + 1;
2074 -- Try to reuse existing shared string
2076 if Can_Be_Reused (TR, DL) then
2077 TR.Data (1 .. DL) := SR.Data (Low .. High);
2080 -- Otherwise, allocate new shared string and fill it
2083 DR := Allocate (DL);
2084 DR.Data (1 .. DL) := SR.Data (Low .. High);
2086 Target.Reference := DR;
2090 end Unbounded_Slice;
2096 procedure Unreference (Item : not null Shared_String_Access) is
2099 new Ada.Unchecked_Deallocation (Shared_String, Shared_String_Access);
2101 Aux : Shared_String_Access := Item;
2104 if System.Atomic_Counters.Decrement (Aux.Counter) then
2106 -- Reference counter of Empty_Shared_String should never reach
2107 -- zero. We check here in case it wraps around.
2109 if Aux /= Empty_Shared_String'Access then
2115 end Ada.Strings.Unbounded;