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-2010, 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 := 32;
40 -- The growth factor controls how much extra space is allocated when
41 -- we have to increase the size of an allocated unbounded string. By
42 -- allocating extra space, we avoid the need to reallocate on every
43 -- append, particularly important when a string is built up by repeated
44 -- append operations of small pieces. This is expressed as a factor so
45 -- 32 means add 1/32 of the length of the string as growth space.
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 procedure Sync_Add_And_Fetch
54 (Ptr : access Interfaces.Unsigned_32;
55 Value : Interfaces.Unsigned_32);
56 pragma Import (Intrinsic, Sync_Add_And_Fetch, "__sync_add_and_fetch_4");
58 function Sync_Sub_And_Fetch
59 (Ptr : access Interfaces.Unsigned_32;
60 Value : Interfaces.Unsigned_32) return Interfaces.Unsigned_32;
61 pragma Import (Intrinsic, Sync_Sub_And_Fetch, "__sync_sub_and_fetch_4");
63 function Aligned_Max_Length (Max_Length : Natural) return Natural;
64 -- Returns recommended length of the shared string which is greater or
65 -- equal to specified length. Calculation take in sense alignment of the
66 -- allocated memory segments to use memory effectively by Append/Insert/etc
74 (Left : Unbounded_String;
75 Right : Unbounded_String) return Unbounded_String
77 LR : constant Shared_String_Access := Left.Reference;
78 RR : constant Shared_String_Access := Right.Reference;
79 DL : constant Natural := LR.Last + RR.Last;
80 DR : Shared_String_Access;
83 -- Result is an empty string, reuse shared empty string
86 Reference (Empty_Shared_String'Access);
87 DR := Empty_Shared_String'Access;
89 -- Left string is empty, return Right string
91 elsif LR.Last = 0 then
95 -- Right string is empty, return Left string
97 elsif RR.Last = 0 then
101 -- Otherwise, allocate new shared string and fill data
104 DR := Allocate (LR.Last + RR.Last);
105 DR.Data (1 .. LR.Last) := LR.Data (1 .. LR.Last);
106 DR.Data (LR.Last + 1 .. DL) := RR.Data (1 .. RR.Last);
110 return (AF.Controlled with Reference => DR);
114 (Left : Unbounded_String;
115 Right : String) return Unbounded_String
117 LR : constant Shared_String_Access := Left.Reference;
118 DL : constant Natural := LR.Last + Right'Length;
119 DR : Shared_String_Access;
122 -- Result is an empty string, reuse shared empty string
125 Reference (Empty_Shared_String'Access);
126 DR := Empty_Shared_String'Access;
128 -- Right is an empty string, return Left string
130 elsif Right'Length = 0 then
134 -- Otherwise, allocate new shared string and fill it
138 DR.Data (1 .. LR.Last) := LR.Data (1 .. LR.Last);
139 DR.Data (LR.Last + 1 .. DL) := Right;
143 return (AF.Controlled with Reference => DR);
148 Right : Unbounded_String) return Unbounded_String
150 RR : constant Shared_String_Access := Right.Reference;
151 DL : constant Natural := Left'Length + RR.Last;
152 DR : Shared_String_Access;
155 -- Result is an empty string, reuse shared one
158 Reference (Empty_Shared_String'Access);
159 DR := Empty_Shared_String'Access;
161 -- Left is empty string, return Right string
163 elsif Left'Length = 0 then
167 -- Otherwise, allocate new shared string and fill it
171 DR.Data (1 .. Left'Length) := Left;
172 DR.Data (Left'Length + 1 .. DL) := RR.Data (1 .. RR.Last);
176 return (AF.Controlled with Reference => DR);
180 (Left : Unbounded_String;
181 Right : Character) return Unbounded_String
183 LR : constant Shared_String_Access := Left.Reference;
184 DL : constant Natural := LR.Last + 1;
185 DR : Shared_String_Access;
189 DR.Data (1 .. LR.Last) := LR.Data (1 .. LR.Last);
190 DR.Data (DL) := Right;
193 return (AF.Controlled with Reference => DR);
198 Right : Unbounded_String) return Unbounded_String
200 RR : constant Shared_String_Access := Right.Reference;
201 DL : constant Natural := 1 + RR.Last;
202 DR : Shared_String_Access;
207 DR.Data (2 .. DL) := RR.Data (1 .. RR.Last);
210 return (AF.Controlled with Reference => DR);
219 Right : Character) return Unbounded_String
221 DR : Shared_String_Access;
224 -- Result is an empty string, reuse shared empty string
227 Reference (Empty_Shared_String'Access);
228 DR := Empty_Shared_String'Access;
230 -- Otherwise, allocate new shared string and fill it
233 DR := Allocate (Left);
235 for J in 1 .. Left loop
236 DR.Data (J) := Right;
242 return (AF.Controlled with Reference => DR);
247 Right : String) return Unbounded_String
249 DL : constant Natural := Left * Right'Length;
250 DR : Shared_String_Access;
254 -- Result is an empty string, reuse shared empty string
257 Reference (Empty_Shared_String'Access);
258 DR := Empty_Shared_String'Access;
260 -- Otherwise, allocate new shared string and fill it
266 for J in 1 .. Left loop
267 DR.Data (K .. K + Right'Length - 1) := Right;
268 K := K + Right'Length;
274 return (AF.Controlled with Reference => DR);
279 Right : Unbounded_String) return Unbounded_String
281 RR : constant Shared_String_Access := Right.Reference;
282 DL : constant Natural := Left * RR.Last;
283 DR : Shared_String_Access;
287 -- Result is an empty string, reuse shared empty string
290 Reference (Empty_Shared_String'Access);
291 DR := Empty_Shared_String'Access;
293 -- Coefficient is one, just return string itself
299 -- Otherwise, allocate new shared string and fill it
305 for J in 1 .. Left loop
306 DR.Data (K .. K + RR.Last - 1) := RR.Data (1 .. RR.Last);
313 return (AF.Controlled with Reference => DR);
321 (Left : Unbounded_String;
322 Right : Unbounded_String) return Boolean
324 LR : constant Shared_String_Access := Left.Reference;
325 RR : constant Shared_String_Access := Right.Reference;
327 return LR.Data (1 .. LR.Last) < RR.Data (1 .. RR.Last);
331 (Left : Unbounded_String;
332 Right : String) return Boolean
334 LR : constant Shared_String_Access := Left.Reference;
336 return LR.Data (1 .. LR.Last) < Right;
341 Right : Unbounded_String) return Boolean
343 RR : constant Shared_String_Access := Right.Reference;
345 return Left < RR.Data (1 .. RR.Last);
353 (Left : Unbounded_String;
354 Right : Unbounded_String) return Boolean
356 LR : constant Shared_String_Access := Left.Reference;
357 RR : constant Shared_String_Access := Right.Reference;
360 -- LR = RR means two strings shares shared string, thus they are equal
362 return LR = RR or else LR.Data (1 .. LR.Last) <= RR.Data (1 .. RR.Last);
366 (Left : Unbounded_String;
367 Right : String) return Boolean
369 LR : constant Shared_String_Access := Left.Reference;
371 return LR.Data (1 .. LR.Last) <= Right;
376 Right : Unbounded_String) return Boolean
378 RR : constant Shared_String_Access := Right.Reference;
380 return Left <= RR.Data (1 .. RR.Last);
388 (Left : Unbounded_String;
389 Right : Unbounded_String) return Boolean
391 LR : constant Shared_String_Access := Left.Reference;
392 RR : constant Shared_String_Access := Right.Reference;
395 return LR = RR or else LR.Data (1 .. LR.Last) = RR.Data (1 .. RR.Last);
396 -- LR = RR means two strings shares shared string, thus they are equal
400 (Left : Unbounded_String;
401 Right : String) return Boolean
403 LR : constant Shared_String_Access := Left.Reference;
405 return LR.Data (1 .. LR.Last) = Right;
410 Right : Unbounded_String) return Boolean
412 RR : constant Shared_String_Access := Right.Reference;
414 return Left = RR.Data (1 .. RR.Last);
422 (Left : Unbounded_String;
423 Right : Unbounded_String) return Boolean
425 LR : constant Shared_String_Access := Left.Reference;
426 RR : constant Shared_String_Access := Right.Reference;
428 return LR.Data (1 .. LR.Last) > RR.Data (1 .. RR.Last);
432 (Left : Unbounded_String;
433 Right : String) return Boolean
435 LR : constant Shared_String_Access := Left.Reference;
437 return LR.Data (1 .. LR.Last) > Right;
442 Right : Unbounded_String) return Boolean
444 RR : constant Shared_String_Access := Right.Reference;
446 return Left > RR.Data (1 .. RR.Last);
454 (Left : Unbounded_String;
455 Right : Unbounded_String) return Boolean
457 LR : constant Shared_String_Access := Left.Reference;
458 RR : constant Shared_String_Access := Right.Reference;
461 -- LR = RR means two strings shares shared string, thus they are equal
463 return LR = RR or else LR.Data (1 .. LR.Last) >= RR.Data (1 .. RR.Last);
467 (Left : Unbounded_String;
468 Right : String) return Boolean
470 LR : constant Shared_String_Access := Left.Reference;
472 return LR.Data (1 .. LR.Last) >= Right;
477 Right : Unbounded_String) return Boolean
479 RR : constant Shared_String_Access := Right.Reference;
481 return Left >= RR.Data (1 .. RR.Last);
488 procedure Adjust (Object : in out Unbounded_String) is
490 Reference (Object.Reference);
493 ------------------------
494 -- Aligned_Max_Length --
495 ------------------------
497 function Aligned_Max_Length (Max_Length : Natural) return Natural is
498 Static_Size : constant Natural :=
499 Empty_Shared_String'Size / Standard'Storage_Unit;
500 -- Total size of all static components
504 ((Static_Size + Max_Length - 1) / Min_Mul_Alloc + 2) * Min_Mul_Alloc
506 end Aligned_Max_Length;
512 function Allocate (Max_Length : Natural) return Shared_String_Access is
514 -- Empty string requested, return shared empty string
516 if Max_Length = 0 then
517 Reference (Empty_Shared_String'Access);
518 return Empty_Shared_String'Access;
520 -- Otherwise, allocate requested space (and probably some more room)
523 return new Shared_String (Aligned_Max_Length (Max_Length));
532 (Source : in out Unbounded_String;
533 New_Item : Unbounded_String)
535 SR : constant Shared_String_Access := Source.Reference;
536 NR : constant Shared_String_Access := New_Item.Reference;
537 DL : constant Natural := SR.Last + NR.Last;
538 DR : Shared_String_Access;
541 -- Source is an empty string, reuse New_Item data
545 Source.Reference := NR;
548 -- New_Item is empty string, nothing to do
550 elsif NR.Last = 0 then
553 -- Try to reuse existing shared string
555 elsif Can_Be_Reused (SR, DL) then
556 SR.Data (SR.Last + 1 .. DL) := NR.Data (1 .. NR.Last);
559 -- Otherwise, allocate new one and fill it
562 DR := Allocate (DL + DL / Growth_Factor);
563 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
564 DR.Data (SR.Last + 1 .. DL) := NR.Data (1 .. NR.Last);
566 Source.Reference := DR;
572 (Source : in out Unbounded_String;
575 SR : constant Shared_String_Access := Source.Reference;
576 DL : constant Natural := SR.Last + New_Item'Length;
577 DR : Shared_String_Access;
580 -- New_Item is an empty string, nothing to do
582 if New_Item'Length = 0 then
585 -- Try to reuse existing shared string
587 elsif Can_Be_Reused (SR, DL) then
588 SR.Data (SR.Last + 1 .. DL) := New_Item;
591 -- Otherwise, allocate new one and fill it
594 DR := Allocate (DL + DL / Growth_Factor);
595 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
596 DR.Data (SR.Last + 1 .. DL) := New_Item;
598 Source.Reference := DR;
604 (Source : in out Unbounded_String;
605 New_Item : Character)
607 SR : constant Shared_String_Access := Source.Reference;
608 DL : constant Natural := SR.Last + 1;
609 DR : Shared_String_Access;
612 -- Try to reuse existing shared string
614 if Can_Be_Reused (SR, SR.Last + 1) then
615 SR.Data (SR.Last + 1) := New_Item;
616 SR.Last := SR.Last + 1;
618 -- Otherwise, allocate new one and fill it
621 DR := Allocate (DL + DL / Growth_Factor);
622 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
623 DR.Data (DL) := New_Item;
625 Source.Reference := DR;
634 function Can_Be_Reused
635 (Item : Shared_String_Access;
636 Length : Natural) return Boolean
642 and then Item.Max_Length >= Length
643 and then Item.Max_Length <=
644 Aligned_Max_Length (Length + Length / Growth_Factor);
652 (Source : Unbounded_String;
654 Mapping : Maps.Character_Mapping := Maps.Identity) return Natural
656 SR : constant Shared_String_Access := Source.Reference;
658 return Search.Count (SR.Data (1 .. SR.Last), Pattern, Mapping);
662 (Source : Unbounded_String;
664 Mapping : Maps.Character_Mapping_Function) return Natural
666 SR : constant Shared_String_Access := Source.Reference;
668 return Search.Count (SR.Data (1 .. SR.Last), Pattern, Mapping);
672 (Source : Unbounded_String;
673 Set : Maps.Character_Set) return Natural
675 SR : constant Shared_String_Access := Source.Reference;
677 return Search.Count (SR.Data (1 .. SR.Last), Set);
685 (Source : Unbounded_String;
687 Through : Natural) return Unbounded_String
689 SR : constant Shared_String_Access := Source.Reference;
691 DR : Shared_String_Access;
694 -- Empty slice is deleted, use the same shared string
696 if From > Through then
700 -- Index is out of range
702 elsif Through > SR.Last then
705 -- Compute size of the result
708 DL := SR.Last - (Through - From + 1);
710 -- Result is an empty string, reuse shared empty string
713 Reference (Empty_Shared_String'Access);
714 DR := Empty_Shared_String'Access;
716 -- Otherwise, allocate new shared string and fill it
720 DR.Data (1 .. From - 1) := SR.Data (1 .. From - 1);
721 DR.Data (From .. DL) := SR.Data (Through + 1 .. SR.Last);
726 return (AF.Controlled with Reference => DR);
730 (Source : in out Unbounded_String;
734 SR : constant Shared_String_Access := Source.Reference;
736 DR : Shared_String_Access;
739 -- Nothing changed, return
741 if From > Through then
744 -- Through is outside of the range
746 elsif Through > SR.Last then
750 DL := SR.Last - (Through - From + 1);
752 -- Result is empty, reuse shared empty string
755 Reference (Empty_Shared_String'Access);
756 Source.Reference := Empty_Shared_String'Access;
759 -- Try to reuse existing shared string
761 elsif Can_Be_Reused (SR, DL) then
762 SR.Data (From .. DL) := SR.Data (Through + 1 .. SR.Last);
765 -- Otherwise, allocate new shared string
769 DR.Data (1 .. From - 1) := SR.Data (1 .. From - 1);
770 DR.Data (From .. DL) := SR.Data (Through + 1 .. SR.Last);
772 Source.Reference := DR;
783 (Source : Unbounded_String;
784 Index : Positive) return Character
786 SR : constant Shared_String_Access := Source.Reference;
788 if Index <= SR.Last then
789 return SR.Data (Index);
799 procedure Finalize (Object : in out Unbounded_String) is
800 SR : constant Shared_String_Access := Object.Reference;
805 -- The same controlled object can be finalized several times for
806 -- some reason. As per 7.6.1(24) this should have no ill effect,
807 -- so we need to add a guard for the case of finalizing the same
810 Object.Reference := null;
820 (Source : Unbounded_String;
821 Set : Maps.Character_Set;
823 Test : Strings.Membership;
824 First : out Positive;
827 SR : constant Shared_String_Access := Source.Reference;
829 Search.Find_Token (SR.Data (From .. SR.Last), Set, Test, First, Last);
833 (Source : Unbounded_String;
834 Set : Maps.Character_Set;
835 Test : Strings.Membership;
836 First : out Positive;
839 SR : constant Shared_String_Access := Source.Reference;
841 Search.Find_Token (SR.Data (1 .. SR.Last), Set, Test, First, Last);
848 procedure Free (X : in out String_Access) is
849 procedure Deallocate is
850 new Ada.Unchecked_Deallocation (String, String_Access);
860 (Source : Unbounded_String;
862 Pad : Character := Space) return Unbounded_String
864 SR : constant Shared_String_Access := Source.Reference;
865 DR : Shared_String_Access;
868 -- Result is empty, reuse shared empty string
871 Reference (Empty_Shared_String'Access);
872 DR := Empty_Shared_String'Access;
874 -- Length of the string is the same as requested, reuse source shared
877 elsif Count = SR.Last then
881 -- Otherwise, allocate new shared string and fill it
884 DR := Allocate (Count);
886 -- Length of the source string is more than requested, copy
887 -- corresponding slice.
889 if Count < SR.Last then
890 DR.Data (1 .. Count) := SR.Data (1 .. Count);
892 -- Length of the source string is less then requested, copy all
893 -- contents and fill others by Pad character.
896 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
898 for J in SR.Last + 1 .. Count loop
906 return (AF.Controlled with Reference => DR);
910 (Source : in out Unbounded_String;
912 Pad : Character := Space)
914 SR : constant Shared_String_Access := Source.Reference;
915 DR : Shared_String_Access;
918 -- Result is empty, reuse empty shared string
921 Reference (Empty_Shared_String'Access);
922 Source.Reference := Empty_Shared_String'Access;
925 -- Result is same as source string, reuse source shared string
927 elsif Count = SR.Last then
930 -- Try to reuse existing shared string
932 elsif Can_Be_Reused (SR, Count) then
933 if Count > SR.Last then
934 for J in SR.Last + 1 .. Count loop
941 -- Otherwise, allocate new shared string and fill it
944 DR := Allocate (Count);
946 -- Length of the source string is greater then requested, copy
947 -- corresponding slice.
949 if Count < SR.Last then
950 DR.Data (1 .. Count) := SR.Data (1 .. Count);
952 -- Length of the source string is less the requested, copy all
953 -- existing data and fill remaining positions with Pad characters.
956 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
958 for J in SR.Last + 1 .. Count loop
964 Source.Reference := DR;
974 (Source : Unbounded_String;
976 Going : Strings.Direction := Strings.Forward;
977 Mapping : Maps.Character_Mapping := Maps.Identity) return Natural
979 SR : constant Shared_String_Access := Source.Reference;
981 return Search.Index (SR.Data (1 .. SR.Last), Pattern, Going, Mapping);
985 (Source : Unbounded_String;
987 Going : Direction := Forward;
988 Mapping : Maps.Character_Mapping_Function) return Natural
990 SR : constant Shared_String_Access := Source.Reference;
992 return Search.Index (SR.Data (1 .. SR.Last), Pattern, Going, Mapping);
996 (Source : Unbounded_String;
997 Set : Maps.Character_Set;
998 Test : Strings.Membership := Strings.Inside;
999 Going : Strings.Direction := Strings.Forward) return Natural
1001 SR : constant Shared_String_Access := Source.Reference;
1003 return Search.Index (SR.Data (1 .. SR.Last), Set, Test, Going);
1007 (Source : Unbounded_String;
1010 Going : Direction := Forward;
1011 Mapping : Maps.Character_Mapping := Maps.Identity) return Natural
1013 SR : constant Shared_String_Access := Source.Reference;
1016 (SR.Data (1 .. SR.Last), Pattern, From, Going, Mapping);
1020 (Source : Unbounded_String;
1023 Going : Direction := Forward;
1024 Mapping : Maps.Character_Mapping_Function) return Natural
1026 SR : constant Shared_String_Access := Source.Reference;
1029 (SR.Data (1 .. SR.Last), Pattern, From, Going, Mapping);
1033 (Source : Unbounded_String;
1034 Set : Maps.Character_Set;
1036 Test : Membership := Inside;
1037 Going : Direction := Forward) return Natural
1039 SR : constant Shared_String_Access := Source.Reference;
1041 return Search.Index (SR.Data (1 .. SR.Last), Set, From, Test, Going);
1044 ---------------------
1045 -- Index_Non_Blank --
1046 ---------------------
1048 function Index_Non_Blank
1049 (Source : Unbounded_String;
1050 Going : Strings.Direction := Strings.Forward) return Natural
1052 SR : constant Shared_String_Access := Source.Reference;
1054 return Search.Index_Non_Blank (SR.Data (1 .. SR.Last), Going);
1055 end Index_Non_Blank;
1057 function Index_Non_Blank
1058 (Source : Unbounded_String;
1060 Going : Direction := Forward) return Natural
1062 SR : constant Shared_String_Access := Source.Reference;
1064 return Search.Index_Non_Blank (SR.Data (1 .. SR.Last), From, Going);
1065 end Index_Non_Blank;
1071 procedure Initialize (Object : in out Unbounded_String) is
1073 Reference (Object.Reference);
1081 (Source : Unbounded_String;
1083 New_Item : String) return Unbounded_String
1085 SR : constant Shared_String_Access := Source.Reference;
1086 DL : constant Natural := SR.Last + New_Item'Length;
1087 DR : Shared_String_Access;
1090 -- Check index first
1092 if Before > SR.Last + 1 then
1096 -- Result is empty, reuse empty shared string
1099 Reference (Empty_Shared_String'Access);
1100 DR := Empty_Shared_String'Access;
1102 -- Inserted string is empty, reuse source shared string
1104 elsif New_Item'Length = 0 then
1108 -- Otherwise, allocate new shared string and fill it
1111 DR := Allocate (DL + DL /Growth_Factor);
1112 DR.Data (1 .. Before - 1) := SR.Data (1 .. Before - 1);
1113 DR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1114 DR.Data (Before + New_Item'Length .. DL) :=
1115 SR.Data (Before .. SR.Last);
1119 return (AF.Controlled with Reference => DR);
1123 (Source : in out Unbounded_String;
1127 SR : constant Shared_String_Access := Source.Reference;
1128 DL : constant Natural := SR.Last + New_Item'Length;
1129 DR : Shared_String_Access;
1134 if Before > SR.Last + 1 then
1138 -- Result is empty string, reuse empty shared string
1141 Reference (Empty_Shared_String'Access);
1142 Source.Reference := Empty_Shared_String'Access;
1145 -- Inserted string is empty, nothing to do
1147 elsif New_Item'Length = 0 then
1150 -- Try to reuse existing shared string first
1152 elsif Can_Be_Reused (SR, DL) then
1153 SR.Data (Before + New_Item'Length .. DL) :=
1154 SR.Data (Before .. SR.Last);
1155 SR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1158 -- Otherwise, allocate new shared string and fill it
1161 DR := Allocate (DL + DL / Growth_Factor);
1162 DR.Data (1 .. Before - 1) := SR.Data (1 .. Before - 1);
1163 DR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1164 DR.Data (Before + New_Item'Length .. DL) :=
1165 SR.Data (Before .. SR.Last);
1167 Source.Reference := DR;
1176 function Length (Source : Unbounded_String) return Natural is
1178 return Source.Reference.Last;
1186 (Source : Unbounded_String;
1187 Position : Positive;
1188 New_Item : String) return Unbounded_String
1190 SR : constant Shared_String_Access := Source.Reference;
1192 DR : Shared_String_Access;
1197 if Position > SR.Last + 1 then
1201 DL := Integer'Max (SR.Last, Position + New_Item'Length - 1);
1203 -- Result is empty string, reuse empty shared string
1206 Reference (Empty_Shared_String'Access);
1207 DR := Empty_Shared_String'Access;
1209 -- Result is same as source string, reuse source shared string
1211 elsif New_Item'Length = 0 then
1215 -- Otherwise, allocate new shared string and fill it
1218 DR := Allocate (DL);
1219 DR.Data (1 .. Position - 1) := SR.Data (1 .. Position - 1);
1220 DR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1221 DR.Data (Position + New_Item'Length .. DL) :=
1222 SR.Data (Position + New_Item'Length .. SR.Last);
1226 return (AF.Controlled with Reference => DR);
1230 (Source : in out Unbounded_String;
1231 Position : Positive;
1234 SR : constant Shared_String_Access := Source.Reference;
1236 DR : Shared_String_Access;
1241 if Position > SR.Last + 1 then
1245 DL := Integer'Max (SR.Last, Position + New_Item'Length - 1);
1247 -- Result is empty string, reuse empty shared string
1250 Reference (Empty_Shared_String'Access);
1251 Source.Reference := Empty_Shared_String'Access;
1254 -- String unchanged, nothing to do
1256 elsif New_Item'Length = 0 then
1259 -- Try to reuse existing shared string
1261 elsif Can_Be_Reused (SR, DL) then
1262 SR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1265 -- Otherwise allocate new shared string and fill it
1268 DR := Allocate (DL);
1269 DR.Data (1 .. Position - 1) := SR.Data (1 .. Position - 1);
1270 DR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1271 DR.Data (Position + New_Item'Length .. DL) :=
1272 SR.Data (Position + New_Item'Length .. SR.Last);
1274 Source.Reference := DR;
1283 procedure Reference (Item : not null Shared_String_Access) is
1285 Sync_Add_And_Fetch (Item.Counter'Access, 1);
1288 ---------------------
1289 -- Replace_Element --
1290 ---------------------
1292 procedure Replace_Element
1293 (Source : in out Unbounded_String;
1297 SR : constant Shared_String_Access := Source.Reference;
1298 DR : Shared_String_Access;
1303 if Index <= SR.Last then
1305 -- Try to reuse existing shared string
1307 if Can_Be_Reused (SR, SR.Last) then
1308 SR.Data (Index) := By;
1310 -- Otherwise allocate new shared string and fill it
1313 DR := Allocate (SR.Last);
1314 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
1315 DR.Data (Index) := By;
1317 Source.Reference := DR;
1324 end Replace_Element;
1330 function Replace_Slice
1331 (Source : Unbounded_String;
1334 By : String) return Unbounded_String
1336 SR : constant Shared_String_Access := Source.Reference;
1338 DR : Shared_String_Access;
1343 if Low > SR.Last + 1 then
1347 -- Do replace operation when removed slice is not empty
1350 DL := By'Length + SR.Last + Low - Integer'Min (High, SR.Last) - 1;
1351 -- This is the number of characters remaining in the string after
1352 -- replacing the slice.
1354 -- Result is empty string, reuse empty shared string
1357 Reference (Empty_Shared_String'Access);
1358 DR := Empty_Shared_String'Access;
1360 -- Otherwise allocate new shared string and fill it
1363 DR := Allocate (DL);
1364 DR.Data (1 .. Low - 1) := SR.Data (1 .. Low - 1);
1365 DR.Data (Low .. Low + By'Length - 1) := By;
1366 DR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1370 return (AF.Controlled with Reference => DR);
1372 -- Otherwise just insert string
1375 return Insert (Source, Low, By);
1379 procedure Replace_Slice
1380 (Source : in out Unbounded_String;
1385 SR : constant Shared_String_Access := Source.Reference;
1387 DR : Shared_String_Access;
1392 if Low > SR.Last + 1 then
1396 -- Do replace operation only when replaced slice is not empty
1399 DL := By'Length + SR.Last + Low - Integer'Min (High, SR.Last) - 1;
1400 -- This is the number of characters remaining in the string after
1401 -- replacing the slice.
1403 -- Result is empty string, reuse empty shared string
1406 Reference (Empty_Shared_String'Access);
1407 Source.Reference := Empty_Shared_String'Access;
1410 -- Try to reuse existing shared string
1412 elsif Can_Be_Reused (SR, DL) then
1413 SR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1414 SR.Data (Low .. Low + By'Length - 1) := By;
1417 -- Otherwise allocate new shared string and fill it
1420 DR := Allocate (DL);
1421 DR.Data (1 .. Low - 1) := SR.Data (1 .. Low - 1);
1422 DR.Data (Low .. Low + By'Length - 1) := By;
1423 DR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1425 Source.Reference := DR;
1429 -- Otherwise just insert item
1432 Insert (Source, Low, By);
1436 --------------------------
1437 -- Set_Unbounded_String --
1438 --------------------------
1440 procedure Set_Unbounded_String
1441 (Target : out Unbounded_String;
1444 TR : constant Shared_String_Access := Target.Reference;
1445 DR : Shared_String_Access;
1448 -- In case of empty string, reuse empty shared string
1450 if Source'Length = 0 then
1451 Reference (Empty_Shared_String'Access);
1452 Target.Reference := Empty_Shared_String'Access;
1455 -- Try to reuse existing shared string
1457 if Can_Be_Reused (TR, Source'Length) then
1461 -- Otherwise allocate new shared string
1464 DR := Allocate (Source'Length);
1465 Target.Reference := DR;
1468 DR.Data (1 .. Source'Length) := Source;
1469 DR.Last := Source'Length;
1473 end Set_Unbounded_String;
1480 (Source : Unbounded_String;
1482 High : Natural) return String
1484 SR : constant Shared_String_Access := Source.Reference;
1487 -- Note: test of High > Length is in accordance with AI95-00128
1489 if Low > SR.Last + 1 or else High > SR.Last then
1493 return SR.Data (Low .. High);
1502 (Source : Unbounded_String;
1504 Pad : Character := Space) return Unbounded_String
1506 SR : constant Shared_String_Access := Source.Reference;
1507 DR : Shared_String_Access;
1510 -- For empty result reuse empty shared string
1513 Reference (Empty_Shared_String'Access);
1514 DR := Empty_Shared_String'Access;
1516 -- Result is whole source string, reuse source shared string
1518 elsif Count = SR.Last then
1522 -- Otherwise allocate new shared string and fill it
1525 DR := Allocate (Count);
1527 if Count < SR.Last then
1528 DR.Data (1 .. Count) := SR.Data (SR.Last - Count + 1 .. SR.Last);
1531 for J in 1 .. Count - SR.Last loop
1535 DR.Data (Count - SR.Last + 1 .. Count) := SR.Data (1 .. SR.Last);
1541 return (AF.Controlled with Reference => DR);
1545 (Source : in out Unbounded_String;
1547 Pad : Character := Space)
1549 SR : constant Shared_String_Access := Source.Reference;
1550 DR : Shared_String_Access;
1553 (SR : Shared_String_Access;
1554 DR : Shared_String_Access;
1556 -- Common code of tail computation. SR/DR can point to the same object
1563 (SR : Shared_String_Access;
1564 DR : Shared_String_Access;
1567 if Count < SR.Last then
1568 DR.Data (1 .. Count) := SR.Data (SR.Last - Count + 1 .. SR.Last);
1571 DR.Data (Count - SR.Last + 1 .. Count) := SR.Data (1 .. SR.Last);
1573 for J in 1 .. Count - SR.Last loop
1582 -- Result is empty string, reuse empty shared string
1585 Reference (Empty_Shared_String'Access);
1586 Source.Reference := Empty_Shared_String'Access;
1589 -- Length of the result is the same as length of the source string,
1590 -- reuse source shared string.
1592 elsif Count = SR.Last then
1595 -- Try to reuse existing shared string
1597 elsif Can_Be_Reused (SR, Count) then
1598 Common (SR, SR, Count);
1600 -- Otherwise allocate new shared string and fill it
1603 DR := Allocate (Count);
1604 Common (SR, DR, Count);
1605 Source.Reference := DR;
1614 function To_String (Source : Unbounded_String) return String is
1616 return Source.Reference.Data (1 .. Source.Reference.Last);
1619 -------------------------
1620 -- To_Unbounded_String --
1621 -------------------------
1623 function To_Unbounded_String (Source : String) return Unbounded_String is
1624 DR : constant Shared_String_Access := Allocate (Source'Length);
1626 DR.Data (1 .. Source'Length) := Source;
1627 DR.Last := Source'Length;
1628 return (AF.Controlled with Reference => DR);
1629 end To_Unbounded_String;
1631 function To_Unbounded_String (Length : Natural) return Unbounded_String is
1632 DR : constant Shared_String_Access := Allocate (Length);
1635 return (AF.Controlled with Reference => DR);
1636 end To_Unbounded_String;
1643 (Source : Unbounded_String;
1644 Mapping : Maps.Character_Mapping) return Unbounded_String
1646 SR : constant Shared_String_Access := Source.Reference;
1647 DR : Shared_String_Access;
1650 -- Nothing to translate, reuse empty shared string
1653 Reference (Empty_Shared_String'Access);
1654 DR := Empty_Shared_String'Access;
1656 -- Otherwise, allocate new shared string and fill it
1659 DR := Allocate (SR.Last);
1661 for J in 1 .. SR.Last loop
1662 DR.Data (J) := Value (Mapping, SR.Data (J));
1668 return (AF.Controlled with Reference => DR);
1672 (Source : in out Unbounded_String;
1673 Mapping : Maps.Character_Mapping)
1675 SR : constant Shared_String_Access := Source.Reference;
1676 DR : Shared_String_Access;
1679 -- Nothing to translate
1684 -- Try to reuse shared string
1686 elsif Can_Be_Reused (SR, SR.Last) then
1687 for J in 1 .. SR.Last loop
1688 SR.Data (J) := Value (Mapping, SR.Data (J));
1691 -- Otherwise, allocate new shared string
1694 DR := Allocate (SR.Last);
1696 for J in 1 .. SR.Last loop
1697 DR.Data (J) := Value (Mapping, SR.Data (J));
1701 Source.Reference := DR;
1707 (Source : Unbounded_String;
1708 Mapping : Maps.Character_Mapping_Function) return Unbounded_String
1710 SR : constant Shared_String_Access := Source.Reference;
1711 DR : Shared_String_Access;
1714 -- Nothing to translate, reuse empty shared string
1717 Reference (Empty_Shared_String'Access);
1718 DR := Empty_Shared_String'Access;
1720 -- Otherwise, allocate new shared string and fill it
1723 DR := Allocate (SR.Last);
1725 for J in 1 .. SR.Last loop
1726 DR.Data (J) := Mapping.all (SR.Data (J));
1732 return (AF.Controlled with Reference => DR);
1742 (Source : in out Unbounded_String;
1743 Mapping : Maps.Character_Mapping_Function)
1745 SR : constant Shared_String_Access := Source.Reference;
1746 DR : Shared_String_Access;
1749 -- Nothing to translate
1754 -- Try to reuse shared string
1756 elsif Can_Be_Reused (SR, SR.Last) then
1757 for J in 1 .. SR.Last loop
1758 SR.Data (J) := Mapping.all (SR.Data (J));
1761 -- Otherwise allocate new shared string and fill it
1764 DR := Allocate (SR.Last);
1766 for J in 1 .. SR.Last loop
1767 DR.Data (J) := Mapping.all (SR.Data (J));
1771 Source.Reference := DR;
1789 (Source : Unbounded_String;
1790 Side : Trim_End) return Unbounded_String
1792 SR : constant Shared_String_Access := Source.Reference;
1794 DR : Shared_String_Access;
1799 Low := Index_Non_Blank (Source, Forward);
1801 -- All blanks, reuse empty shared string
1804 Reference (Empty_Shared_String'Access);
1805 DR := Empty_Shared_String'Access;
1811 DL := SR.Last - Low + 1;
1815 High := Index_Non_Blank (Source, Backward);
1819 High := Index_Non_Blank (Source, Backward);
1820 DL := High - Low + 1;
1823 -- Length of the result is the same as length of the source string,
1824 -- reuse source shared string.
1826 if DL = SR.Last then
1830 -- Otherwise, allocate new shared string
1833 DR := Allocate (DL);
1834 DR.Data (1 .. DL) := SR.Data (Low .. High);
1839 return (AF.Controlled with Reference => DR);
1843 (Source : in out Unbounded_String;
1846 SR : constant Shared_String_Access := Source.Reference;
1848 DR : Shared_String_Access;
1853 Low := Index_Non_Blank (Source, Forward);
1855 -- All blanks, reuse empty shared string
1858 Reference (Empty_Shared_String'Access);
1859 Source.Reference := Empty_Shared_String'Access;
1866 DL := SR.Last - Low + 1;
1870 High := Index_Non_Blank (Source, Backward);
1874 High := Index_Non_Blank (Source, Backward);
1875 DL := High - Low + 1;
1878 -- Length of the result is the same as length of the source string,
1881 if DL = SR.Last then
1884 -- Try to reuse existing shared string
1886 elsif Can_Be_Reused (SR, DL) then
1887 SR.Data (1 .. DL) := SR.Data (Low .. High);
1890 -- Otherwise, allocate new shared string
1893 DR := Allocate (DL);
1894 DR.Data (1 .. DL) := SR.Data (Low .. High);
1896 Source.Reference := DR;
1903 (Source : Unbounded_String;
1904 Left : Maps.Character_Set;
1905 Right : Maps.Character_Set) return Unbounded_String
1907 SR : constant Shared_String_Access := Source.Reference;
1909 DR : Shared_String_Access;
1914 Low := Index (Source, Left, Outside, Forward);
1916 -- Source includes only characters from Left set, reuse empty shared
1920 Reference (Empty_Shared_String'Access);
1921 DR := Empty_Shared_String'Access;
1924 High := Index (Source, Right, Outside, Backward);
1925 DL := Integer'Max (0, High - Low + 1);
1927 -- Source includes only characters from Right set or result string
1928 -- is empty, reuse empty shared string.
1930 if High = 0 or else DL = 0 then
1931 Reference (Empty_Shared_String'Access);
1932 DR := Empty_Shared_String'Access;
1934 -- Otherwise, allocate new shared string and fill it
1937 DR := Allocate (DL);
1938 DR.Data (1 .. DL) := SR.Data (Low .. High);
1943 return (AF.Controlled with Reference => DR);
1947 (Source : in out Unbounded_String;
1948 Left : Maps.Character_Set;
1949 Right : Maps.Character_Set)
1951 SR : constant Shared_String_Access := Source.Reference;
1953 DR : Shared_String_Access;
1958 Low := Index (Source, Left, Outside, Forward);
1960 -- Source includes only characters from Left set, reuse empty shared
1964 Reference (Empty_Shared_String'Access);
1965 Source.Reference := Empty_Shared_String'Access;
1969 High := Index (Source, Right, Outside, Backward);
1970 DL := Integer'Max (0, High - Low + 1);
1972 -- Source includes only characters from Right set or result string
1973 -- is empty, reuse empty shared string.
1975 if High = 0 or else DL = 0 then
1976 Reference (Empty_Shared_String'Access);
1977 Source.Reference := Empty_Shared_String'Access;
1980 -- Try to reuse existing shared string
1982 elsif Can_Be_Reused (SR, DL) then
1983 SR.Data (1 .. DL) := SR.Data (Low .. High);
1986 -- Otherwise, allocate new shared string and fill it
1989 DR := Allocate (DL);
1990 DR.Data (1 .. DL) := SR.Data (Low .. High);
1992 Source.Reference := DR;
1998 ---------------------
1999 -- Unbounded_Slice --
2000 ---------------------
2002 function Unbounded_Slice
2003 (Source : Unbounded_String;
2005 High : Natural) return Unbounded_String
2007 SR : constant Shared_String_Access := Source.Reference;
2009 DR : Shared_String_Access;
2014 if Low > SR.Last + 1 or else High > SR.Last then
2017 -- Result is empty slice, reuse empty shared string
2019 elsif Low > High then
2020 Reference (Empty_Shared_String'Access);
2021 DR := Empty_Shared_String'Access;
2023 -- Otherwise, allocate new shared string and fill it
2026 DL := High - Low + 1;
2027 DR := Allocate (DL);
2028 DR.Data (1 .. DL) := SR.Data (Low .. High);
2032 return (AF.Controlled with Reference => DR);
2033 end Unbounded_Slice;
2035 procedure Unbounded_Slice
2036 (Source : Unbounded_String;
2037 Target : out Unbounded_String;
2041 SR : constant Shared_String_Access := Source.Reference;
2042 TR : constant Shared_String_Access := Target.Reference;
2044 DR : Shared_String_Access;
2049 if Low > SR.Last + 1 or else High > SR.Last then
2052 -- Result is empty slice, reuse empty shared string
2054 elsif Low > High then
2055 Reference (Empty_Shared_String'Access);
2056 Target.Reference := Empty_Shared_String'Access;
2060 DL := High - Low + 1;
2062 -- Try to reuse existing shared string
2064 if Can_Be_Reused (TR, DL) then
2065 TR.Data (1 .. DL) := SR.Data (Low .. High);
2068 -- Otherwise, allocate new shared string and fill it
2071 DR := Allocate (DL);
2072 DR.Data (1 .. DL) := SR.Data (Low .. High);
2074 Target.Reference := DR;
2078 end Unbounded_Slice;
2084 procedure Unreference (Item : not null Shared_String_Access) is
2088 new Ada.Unchecked_Deallocation (Shared_String, Shared_String_Access);
2090 Aux : Shared_String_Access := Item;
2093 if Sync_Sub_And_Fetch (Aux.Counter'Access, 1) = 0 then
2095 -- Reference counter of Empty_Shared_String must never reach zero
2097 pragma Assert (Aux /= Empty_Shared_String'Access);
2103 end Ada.Strings.Unbounded;