1 ------------------------------------------------------------------------------
3 -- GNAT RUN-TIME COMPONENTS --
5 -- A D A . S T R I N G S . W I D E _ 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.Wide_Search;
33 with Ada.Unchecked_Deallocation;
35 package body Ada.Strings.Wide_Unbounded is
37 use Ada.Strings.Wide_Maps;
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
66 -- the allocated memory segments to use memory effectively by
67 -- Append/Insert/etc operations.
74 (Left : Unbounded_Wide_String;
75 Right : Unbounded_Wide_String) return Unbounded_Wide_String
77 LR : constant Shared_Wide_String_Access := Left.Reference;
78 RR : constant Shared_Wide_String_Access := Right.Reference;
79 DL : constant Natural := LR.Last + RR.Last;
80 DR : Shared_Wide_String_Access;
83 -- Result is an empty string, reuse shared empty string.
86 Reference (Empty_Shared_Wide_String'Access);
87 DR := Empty_Shared_Wide_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_Wide_String;
115 Right : Wide_String) return Unbounded_Wide_String
117 LR : constant Shared_Wide_String_Access := Left.Reference;
118 DL : constant Natural := LR.Last + Right'Length;
119 DR : Shared_Wide_String_Access;
122 -- Result is an empty string, reuse shared empty string.
125 Reference (Empty_Shared_Wide_String'Access);
126 DR := Empty_Shared_Wide_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_Wide_String) return Unbounded_Wide_String
150 RR : constant Shared_Wide_String_Access := Right.Reference;
151 DL : constant Natural := Left'Length + RR.Last;
152 DR : Shared_Wide_String_Access;
155 -- Result is an empty string, reuse shared one.
158 Reference (Empty_Shared_Wide_String'Access);
159 DR := Empty_Shared_Wide_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_Wide_String;
181 Right : Wide_Character) return Unbounded_Wide_String
183 LR : constant Shared_Wide_String_Access := Left.Reference;
184 DL : constant Natural := LR.Last + 1;
185 DR : Shared_Wide_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);
197 (Left : Wide_Character;
198 Right : Unbounded_Wide_String) return Unbounded_Wide_String
200 RR : constant Shared_Wide_String_Access := Right.Reference;
201 DL : constant Natural := 1 + RR.Last;
202 DR : Shared_Wide_String_Access;
207 DR.Data (2 .. DL) := RR.Data (1 .. RR.Last);
210 return (AF.Controlled with Reference => DR);
219 Right : Wide_Character) return Unbounded_Wide_String
221 DR : Shared_Wide_String_Access;
224 -- Result is an empty string, reuse shared empty string.
227 Reference (Empty_Shared_Wide_String'Access);
228 DR := Empty_Shared_Wide_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 : Wide_String) return Unbounded_Wide_String
249 DL : constant Natural := Left * Right'Length;
250 DR : Shared_Wide_String_Access;
254 -- Result is an empty string, reuse shared empty string.
257 Reference (Empty_Shared_Wide_String'Access);
258 DR := Empty_Shared_Wide_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_Wide_String) return Unbounded_Wide_String
281 RR : constant Shared_Wide_String_Access := Right.Reference;
282 DL : constant Natural := Left * RR.Last;
283 DR : Shared_Wide_String_Access;
287 -- Result is an empty string, reuse shared empty string.
290 Reference (Empty_Shared_Wide_String'Access);
291 DR := Empty_Shared_Wide_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_Wide_String;
322 Right : Unbounded_Wide_String) return Boolean
324 LR : constant Shared_Wide_String_Access := Left.Reference;
325 RR : constant Shared_Wide_String_Access := Right.Reference;
327 return LR.Data (1 .. LR.Last) < RR.Data (1 .. RR.Last);
331 (Left : Unbounded_Wide_String;
332 Right : Wide_String) return Boolean
334 LR : constant Shared_Wide_String_Access := Left.Reference;
336 return LR.Data (1 .. LR.Last) < Right;
341 Right : Unbounded_Wide_String) return Boolean
343 RR : constant Shared_Wide_String_Access := Right.Reference;
345 return Left < RR.Data (1 .. RR.Last);
353 (Left : Unbounded_Wide_String;
354 Right : Unbounded_Wide_String) return Boolean
356 LR : constant Shared_Wide_String_Access := Left.Reference;
357 RR : constant Shared_Wide_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_Wide_String;
367 Right : Wide_String) return Boolean
369 LR : constant Shared_Wide_String_Access := Left.Reference;
371 return LR.Data (1 .. LR.Last) <= Right;
376 Right : Unbounded_Wide_String) return Boolean
378 RR : constant Shared_Wide_String_Access := Right.Reference;
380 return Left <= RR.Data (1 .. RR.Last);
388 (Left : Unbounded_Wide_String;
389 Right : Unbounded_Wide_String) return Boolean
391 LR : constant Shared_Wide_String_Access := Left.Reference;
392 RR : constant Shared_Wide_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_Wide_String;
401 Right : Wide_String) return Boolean
403 LR : constant Shared_Wide_String_Access := Left.Reference;
405 return LR.Data (1 .. LR.Last) = Right;
410 Right : Unbounded_Wide_String) return Boolean
412 RR : constant Shared_Wide_String_Access := Right.Reference;
414 return Left = RR.Data (1 .. RR.Last);
422 (Left : Unbounded_Wide_String;
423 Right : Unbounded_Wide_String) return Boolean
425 LR : constant Shared_Wide_String_Access := Left.Reference;
426 RR : constant Shared_Wide_String_Access := Right.Reference;
428 return LR.Data (1 .. LR.Last) > RR.Data (1 .. RR.Last);
432 (Left : Unbounded_Wide_String;
433 Right : Wide_String) return Boolean
435 LR : constant Shared_Wide_String_Access := Left.Reference;
437 return LR.Data (1 .. LR.Last) > Right;
442 Right : Unbounded_Wide_String) return Boolean
444 RR : constant Shared_Wide_String_Access := Right.Reference;
446 return Left > RR.Data (1 .. RR.Last);
454 (Left : Unbounded_Wide_String;
455 Right : Unbounded_Wide_String) return Boolean
457 LR : constant Shared_Wide_String_Access := Left.Reference;
458 RR : constant Shared_Wide_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_Wide_String;
468 Right : Wide_String) return Boolean
470 LR : constant Shared_Wide_String_Access := Left.Reference;
472 return LR.Data (1 .. LR.Last) >= Right;
477 Right : Unbounded_Wide_String) return Boolean
479 RR : constant Shared_Wide_String_Access := Right.Reference;
481 return Left >= RR.Data (1 .. RR.Last);
488 procedure Adjust (Object : in out Unbounded_Wide_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_Wide_String'Size / Standard'Storage_Unit;
500 -- Total size of all static components
502 Element_Size : constant Natural :=
503 Wide_Character'Size / Standard'Storage_Unit;
507 (((Static_Size + Max_Length * Element_Size - 1) / Min_Mul_Alloc + 2)
508 * Min_Mul_Alloc - Static_Size) / Element_Size;
509 end Aligned_Max_Length;
515 function Allocate (Max_Length : Natural) return Shared_Wide_String_Access is
517 -- Empty string requested, return shared empty string
519 if Max_Length = 0 then
520 Reference (Empty_Shared_Wide_String'Access);
521 return Empty_Shared_Wide_String'Access;
523 -- Otherwise, allocate requested space (and probably some more room)
526 return new Shared_Wide_String (Aligned_Max_Length (Max_Length));
535 (Source : in out Unbounded_Wide_String;
536 New_Item : Unbounded_Wide_String)
538 SR : constant Shared_Wide_String_Access := Source.Reference;
539 NR : constant Shared_Wide_String_Access := New_Item.Reference;
540 DL : constant Natural := SR.Last + NR.Last;
541 DR : Shared_Wide_String_Access;
544 -- Source is an empty string, reuse New_Item data
548 Source.Reference := NR;
551 -- New_Item is empty string, nothing to do
553 elsif NR.Last = 0 then
556 -- Try to reuse existent shared string
558 elsif Can_Be_Reused (SR, DL) then
559 SR.Data (SR.Last + 1 .. DL) := NR.Data (1 .. NR.Last);
562 -- Otherwise, allocate new one and fill it
565 DR := Allocate (DL + DL / Growth_Factor);
566 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
567 DR.Data (SR.Last + 1 .. DL) := NR.Data (1 .. NR.Last);
569 Source.Reference := DR;
575 (Source : in out Unbounded_Wide_String;
576 New_Item : Wide_String)
578 SR : constant Shared_Wide_String_Access := Source.Reference;
579 DL : constant Natural := SR.Last + New_Item'Length;
580 DR : Shared_Wide_String_Access;
583 -- New_Item is an empty string, nothing to do
585 if New_Item'Length = 0 then
588 -- Try to reuse existing shared string
590 elsif Can_Be_Reused (SR, DL) then
591 SR.Data (SR.Last + 1 .. DL) := New_Item;
594 -- Otherwise, allocate new one and fill it
597 DR := Allocate (DL + DL / Growth_Factor);
598 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
599 DR.Data (SR.Last + 1 .. DL) := New_Item;
601 Source.Reference := DR;
607 (Source : in out Unbounded_Wide_String;
608 New_Item : Wide_Character)
610 SR : constant Shared_Wide_String_Access := Source.Reference;
611 DL : constant Natural := SR.Last + 1;
612 DR : Shared_Wide_String_Access;
615 -- Try to reuse existing shared string
617 if Can_Be_Reused (SR, SR.Last + 1) then
618 SR.Data (SR.Last + 1) := New_Item;
619 SR.Last := SR.Last + 1;
621 -- Otherwise, allocate new one and fill it
624 DR := Allocate (DL + DL / Growth_Factor);
625 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
626 DR.Data (DL) := New_Item;
628 Source.Reference := DR;
637 function Can_Be_Reused
638 (Item : Shared_Wide_String_Access;
639 Length : Natural) return Boolean
645 and then Item.Max_Length >= Length
646 and then Item.Max_Length <=
647 Aligned_Max_Length (Length + Length / Growth_Factor);
655 (Source : Unbounded_Wide_String;
656 Pattern : Wide_String;
657 Mapping : Wide_Maps.Wide_Character_Mapping := Wide_Maps.Identity)
660 SR : constant Shared_Wide_String_Access := Source.Reference;
662 return Wide_Search.Count (SR.Data (1 .. SR.Last), Pattern, Mapping);
666 (Source : Unbounded_Wide_String;
667 Pattern : Wide_String;
668 Mapping : Wide_Maps.Wide_Character_Mapping_Function) return Natural
670 SR : constant Shared_Wide_String_Access := Source.Reference;
672 return Wide_Search.Count (SR.Data (1 .. SR.Last), Pattern, Mapping);
676 (Source : Unbounded_Wide_String;
677 Set : Wide_Maps.Wide_Character_Set) return Natural
679 SR : constant Shared_Wide_String_Access := Source.Reference;
681 return Wide_Search.Count (SR.Data (1 .. SR.Last), Set);
689 (Source : Unbounded_Wide_String;
691 Through : Natural) return Unbounded_Wide_String
693 SR : constant Shared_Wide_String_Access := Source.Reference;
695 DR : Shared_Wide_String_Access;
698 -- Empty slice is deleted, use the same shared string
700 if From > Through then
704 -- Index is out of range
706 elsif Through > SR.Last then
709 -- Compute size of the result
712 DL := SR.Last - (Through - From + 1);
714 -- Result is an empty string, reuse shared empty string
717 Reference (Empty_Shared_Wide_String'Access);
718 DR := Empty_Shared_Wide_String'Access;
720 -- Otherwise, allocate new shared string and fill it
724 DR.Data (1 .. From - 1) := SR.Data (1 .. From - 1);
725 DR.Data (From .. DL) := SR.Data (Through + 1 .. SR.Last);
730 return (AF.Controlled with Reference => DR);
734 (Source : in out Unbounded_Wide_String;
738 SR : constant Shared_Wide_String_Access := Source.Reference;
740 DR : Shared_Wide_String_Access;
743 -- Nothing changed, return
745 if From > Through then
748 -- Through is outside of the range
750 elsif Through > SR.Last then
754 DL := SR.Last - (Through - From + 1);
756 -- Result is empty, reuse shared empty string
759 Reference (Empty_Shared_Wide_String'Access);
760 Source.Reference := Empty_Shared_Wide_String'Access;
763 -- Try to reuse existent 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_Wide_String;
788 Index : Positive) return Wide_Character
790 SR : constant Shared_Wide_String_Access := Source.Reference;
792 if Index <= SR.Last then
793 return SR.Data (Index);
803 procedure Finalize (Object : in out Unbounded_Wide_String) is
804 SR : constant Shared_Wide_String_Access := Object.Reference;
809 -- The same controlled object can be finalized several times for
810 -- some reason. As per 7.6.1(24) this should have no ill effect,
811 -- so we need to add a guard for the case of finalizing the same
814 Object.Reference := null;
824 (Source : Unbounded_Wide_String;
825 Set : Wide_Maps.Wide_Character_Set;
827 Test : Strings.Membership;
828 First : out Positive;
831 SR : constant Shared_Wide_String_Access := Source.Reference;
833 Wide_Search.Find_Token
834 (SR.Data (From .. SR.Last), Set, Test, First, Last);
838 (Source : Unbounded_Wide_String;
839 Set : Wide_Maps.Wide_Character_Set;
840 Test : Strings.Membership;
841 First : out Positive;
844 SR : constant Shared_Wide_String_Access := Source.Reference;
846 Wide_Search.Find_Token
847 (SR.Data (1 .. SR.Last), Set, Test, First, Last);
854 procedure Free (X : in out Wide_String_Access) is
855 procedure Deallocate is
856 new Ada.Unchecked_Deallocation (Wide_String, Wide_String_Access);
866 (Source : Unbounded_Wide_String;
868 Pad : Wide_Character := Wide_Space) return Unbounded_Wide_String
870 SR : constant Shared_Wide_String_Access := Source.Reference;
871 DR : Shared_Wide_String_Access;
874 -- Result is empty, reuse shared empty string
877 Reference (Empty_Shared_Wide_String'Access);
878 DR := Empty_Shared_Wide_String'Access;
880 -- Length of the string is the same as requested, reuse source shared
883 elsif Count = SR.Last then
887 -- Otherwise, allocate new shared string and fill it
890 DR := Allocate (Count);
892 -- Length of the source string is more than requested, copy
893 -- corresponding slice.
895 if Count < SR.Last then
896 DR.Data (1 .. Count) := SR.Data (1 .. Count);
898 -- Length of the source string is less then requested, copy all
899 -- contents and fill others by Pad character.
902 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
904 for J in SR.Last + 1 .. Count loop
912 return (AF.Controlled with Reference => DR);
916 (Source : in out Unbounded_Wide_String;
918 Pad : Wide_Character := Wide_Space)
920 SR : constant Shared_Wide_String_Access := Source.Reference;
921 DR : Shared_Wide_String_Access;
924 -- Result is empty, reuse empty shared string
927 Reference (Empty_Shared_Wide_String'Access);
928 Source.Reference := Empty_Shared_Wide_String'Access;
931 -- Result is same with source string, reuse source shared string
933 elsif Count = SR.Last then
936 -- Try to reuse existent shared string
938 elsif Can_Be_Reused (SR, Count) then
939 if Count > SR.Last then
940 for J in SR.Last + 1 .. Count loop
947 -- Otherwise, allocate new shared string and fill it
950 DR := Allocate (Count);
952 -- Length of the source string is greater then requested, copy
953 -- corresponding slice.
955 if Count < SR.Last then
956 DR.Data (1 .. Count) := SR.Data (1 .. Count);
958 -- Length of the source string is less the requested, copy all
959 -- exists data and fill others by Pad character.
962 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
964 for J in SR.Last + 1 .. Count loop
970 Source.Reference := DR;
980 (Source : Unbounded_Wide_String;
981 Pattern : Wide_String;
982 Going : Strings.Direction := Strings.Forward;
983 Mapping : Wide_Maps.Wide_Character_Mapping := Wide_Maps.Identity)
986 SR : constant Shared_Wide_String_Access := Source.Reference;
988 return Wide_Search.Index
989 (SR.Data (1 .. SR.Last), Pattern, Going, Mapping);
993 (Source : Unbounded_Wide_String;
994 Pattern : Wide_String;
995 Going : Direction := Forward;
996 Mapping : Wide_Maps.Wide_Character_Mapping_Function) return Natural
998 SR : constant Shared_Wide_String_Access := Source.Reference;
1000 return Wide_Search.Index
1001 (SR.Data (1 .. SR.Last), Pattern, Going, Mapping);
1005 (Source : Unbounded_Wide_String;
1006 Set : Wide_Maps.Wide_Character_Set;
1007 Test : Strings.Membership := Strings.Inside;
1008 Going : Strings.Direction := Strings.Forward) return Natural
1010 SR : constant Shared_Wide_String_Access := Source.Reference;
1012 return Wide_Search.Index (SR.Data (1 .. SR.Last), Set, Test, Going);
1016 (Source : Unbounded_Wide_String;
1017 Pattern : Wide_String;
1019 Going : Direction := Forward;
1020 Mapping : Wide_Maps.Wide_Character_Mapping := Wide_Maps.Identity)
1023 SR : constant Shared_Wide_String_Access := Source.Reference;
1025 return Wide_Search.Index
1026 (SR.Data (1 .. SR.Last), Pattern, From, Going, Mapping);
1030 (Source : Unbounded_Wide_String;
1031 Pattern : Wide_String;
1033 Going : Direction := Forward;
1034 Mapping : Wide_Maps.Wide_Character_Mapping_Function) return Natural
1036 SR : constant Shared_Wide_String_Access := Source.Reference;
1038 return Wide_Search.Index
1039 (SR.Data (1 .. SR.Last), Pattern, From, Going, Mapping);
1043 (Source : Unbounded_Wide_String;
1044 Set : Wide_Maps.Wide_Character_Set;
1046 Test : Membership := Inside;
1047 Going : Direction := Forward) return Natural
1049 SR : constant Shared_Wide_String_Access := Source.Reference;
1051 return Wide_Search.Index
1052 (SR.Data (1 .. SR.Last), Set, From, Test, Going);
1055 ---------------------
1056 -- Index_Non_Blank --
1057 ---------------------
1059 function Index_Non_Blank
1060 (Source : Unbounded_Wide_String;
1061 Going : Strings.Direction := Strings.Forward) return Natural
1063 SR : constant Shared_Wide_String_Access := Source.Reference;
1065 return Wide_Search.Index_Non_Blank (SR.Data (1 .. SR.Last), Going);
1066 end Index_Non_Blank;
1068 function Index_Non_Blank
1069 (Source : Unbounded_Wide_String;
1071 Going : Direction := Forward) return Natural
1073 SR : constant Shared_Wide_String_Access := Source.Reference;
1075 return Wide_Search.Index_Non_Blank
1076 (SR.Data (1 .. SR.Last), From, Going);
1077 end Index_Non_Blank;
1083 procedure Initialize (Object : in out Unbounded_Wide_String) is
1085 Reference (Object.Reference);
1093 (Source : Unbounded_Wide_String;
1095 New_Item : Wide_String) return Unbounded_Wide_String
1097 SR : constant Shared_Wide_String_Access := Source.Reference;
1098 DL : constant Natural := SR.Last + New_Item'Length;
1099 DR : Shared_Wide_String_Access;
1102 -- Check index first
1104 if Before > SR.Last + 1 then
1108 -- Result is empty, reuse empty shared string
1111 Reference (Empty_Shared_Wide_String'Access);
1112 DR := Empty_Shared_Wide_String'Access;
1114 -- Inserted string is empty, reuse source shared string
1116 elsif New_Item'Length = 0 then
1120 -- Otherwise, allocate new shared string and fill it
1123 DR := Allocate (DL + DL / Growth_Factor);
1124 DR.Data (1 .. Before - 1) := SR.Data (1 .. Before - 1);
1125 DR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1126 DR.Data (Before + New_Item'Length .. DL) :=
1127 SR.Data (Before .. SR.Last);
1131 return (AF.Controlled with Reference => DR);
1135 (Source : in out Unbounded_Wide_String;
1137 New_Item : Wide_String)
1139 SR : constant Shared_Wide_String_Access := Source.Reference;
1140 DL : constant Natural := SR.Last + New_Item'Length;
1141 DR : Shared_Wide_String_Access;
1146 if Before > SR.Last + 1 then
1150 -- Result is empty string, reuse empty shared string
1153 Reference (Empty_Shared_Wide_String'Access);
1154 Source.Reference := Empty_Shared_Wide_String'Access;
1157 -- Inserted string is empty, nothing to do
1159 elsif New_Item'Length = 0 then
1162 -- Try to reuse existent shared string first
1164 elsif Can_Be_Reused (SR, DL) then
1165 SR.Data (Before + New_Item'Length .. DL) :=
1166 SR.Data (Before .. SR.Last);
1167 SR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1170 -- Otherwise, allocate new shared string and fill it
1173 DR := Allocate (DL + DL / Growth_Factor);
1174 DR.Data (1 .. Before - 1) := SR.Data (1 .. Before - 1);
1175 DR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1176 DR.Data (Before + New_Item'Length .. DL) :=
1177 SR.Data (Before .. SR.Last);
1179 Source.Reference := DR;
1188 function Length (Source : Unbounded_Wide_String) return Natural is
1190 return Source.Reference.Last;
1198 (Source : Unbounded_Wide_String;
1199 Position : Positive;
1200 New_Item : Wide_String) return Unbounded_Wide_String
1202 SR : constant Shared_Wide_String_Access := Source.Reference;
1204 DR : Shared_Wide_String_Access;
1209 if Position > SR.Last + 1 then
1213 DL := Integer'Max (SR.Last, Position + New_Item'Length - 1);
1215 -- Result is empty string, reuse empty shared string
1218 Reference (Empty_Shared_Wide_String'Access);
1219 DR := Empty_Shared_Wide_String'Access;
1221 -- Result is same with source string, reuse source shared string
1223 elsif New_Item'Length = 0 then
1227 -- Otherwise, allocate new shared string and fill it
1230 DR := Allocate (DL);
1231 DR.Data (1 .. Position - 1) := SR.Data (1 .. Position - 1);
1232 DR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1233 DR.Data (Position + New_Item'Length .. DL) :=
1234 SR.Data (Position + New_Item'Length .. SR.Last);
1238 return (AF.Controlled with Reference => DR);
1242 (Source : in out Unbounded_Wide_String;
1243 Position : Positive;
1244 New_Item : Wide_String)
1246 SR : constant Shared_Wide_String_Access := Source.Reference;
1248 DR : Shared_Wide_String_Access;
1253 if Position > SR.Last + 1 then
1257 DL := Integer'Max (SR.Last, Position + New_Item'Length - 1);
1259 -- Result is empty string, reuse empty shared string
1262 Reference (Empty_Shared_Wide_String'Access);
1263 Source.Reference := Empty_Shared_Wide_String'Access;
1266 -- String unchanged, nothing to do
1268 elsif New_Item'Length = 0 then
1271 -- Try to reuse existent shared string
1273 elsif Can_Be_Reused (SR, DL) then
1274 SR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1277 -- Otherwise allocate new shared string and fill it
1280 DR := Allocate (DL);
1281 DR.Data (1 .. Position - 1) := SR.Data (1 .. Position - 1);
1282 DR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1283 DR.Data (Position + New_Item'Length .. DL) :=
1284 SR.Data (Position + New_Item'Length .. SR.Last);
1286 Source.Reference := DR;
1295 procedure Reference (Item : not null Shared_Wide_String_Access) is
1297 Sync_Add_And_Fetch (Item.Counter'Access, 1);
1300 ---------------------
1301 -- Replace_Element --
1302 ---------------------
1304 procedure Replace_Element
1305 (Source : in out Unbounded_Wide_String;
1307 By : Wide_Character)
1309 SR : constant Shared_Wide_String_Access := Source.Reference;
1310 DR : Shared_Wide_String_Access;
1315 if Index <= SR.Last then
1317 -- Try to reuse existent shared string
1319 if Can_Be_Reused (SR, SR.Last) then
1320 SR.Data (Index) := By;
1322 -- Otherwise allocate new shared string and fill it
1325 DR := Allocate (SR.Last);
1326 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
1327 DR.Data (Index) := By;
1329 Source.Reference := DR;
1336 end Replace_Element;
1342 function Replace_Slice
1343 (Source : Unbounded_Wide_String;
1346 By : Wide_String) return Unbounded_Wide_String
1348 SR : constant Shared_Wide_String_Access := Source.Reference;
1350 DR : Shared_Wide_String_Access;
1355 if Low > SR.Last + 1 then
1359 -- Do replace operation when removed slice is not empty
1362 DL := By'Length + SR.Last + Low - High - 1;
1364 -- Result is empty string, reuse empty shared string
1367 Reference (Empty_Shared_Wide_String'Access);
1368 DR := Empty_Shared_Wide_String'Access;
1370 -- Otherwise allocate new shared string and fill it
1373 DR := Allocate (DL);
1374 DR.Data (1 .. Low - 1) := SR.Data (1 .. Low - 1);
1375 DR.Data (Low .. Low + By'Length - 1) := By;
1376 DR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1380 return (AF.Controlled with Reference => DR);
1382 -- Otherwise just insert string
1385 return Insert (Source, Low, By);
1389 procedure Replace_Slice
1390 (Source : in out Unbounded_Wide_String;
1395 SR : constant Shared_Wide_String_Access := Source.Reference;
1397 DR : Shared_Wide_String_Access;
1402 if Low > SR.Last + 1 then
1406 -- Do replace operation only when replaced slice is not empty
1409 DL := By'Length + SR.Last + Low - High - 1;
1411 -- Result is empty string, reuse empty shared string
1414 Reference (Empty_Shared_Wide_String'Access);
1415 Source.Reference := Empty_Shared_Wide_String'Access;
1418 -- Try to reuse existent shared string
1420 elsif Can_Be_Reused (SR, DL) then
1421 SR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1422 SR.Data (Low .. Low + By'Length - 1) := By;
1425 -- Otherwise allocate new shared string and fill it
1428 DR := Allocate (DL);
1429 DR.Data (1 .. Low - 1) := SR.Data (1 .. Low - 1);
1430 DR.Data (Low .. Low + By'Length - 1) := By;
1431 DR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1433 Source.Reference := DR;
1437 -- Otherwise just insert item
1440 Insert (Source, Low, By);
1444 -------------------------------
1445 -- Set_Unbounded_Wide_String --
1446 -------------------------------
1448 procedure Set_Unbounded_Wide_String
1449 (Target : out Unbounded_Wide_String;
1450 Source : Wide_String)
1452 TR : constant Shared_Wide_String_Access := Target.Reference;
1453 DR : Shared_Wide_String_Access;
1456 -- In case of empty string, reuse empty shared string
1458 if Source'Length = 0 then
1459 Reference (Empty_Shared_Wide_String'Access);
1460 Target.Reference := Empty_Shared_Wide_String'Access;
1463 -- Try to reuse existent shared string
1465 if Can_Be_Reused (TR, Source'Length) then
1469 -- Otherwise allocate new shared string
1472 DR := Allocate (Source'Length);
1473 Target.Reference := DR;
1476 DR.Data (1 .. Source'Length) := Source;
1477 DR.Last := Source'Length;
1481 end Set_Unbounded_Wide_String;
1488 (Source : Unbounded_Wide_String;
1490 High : Natural) return Wide_String
1492 SR : constant Shared_Wide_String_Access := Source.Reference;
1495 -- Note: test of High > Length is in accordance with AI95-00128
1497 if Low > SR.Last + 1 or else High > SR.Last then
1501 return SR.Data (Low .. High);
1510 (Source : Unbounded_Wide_String;
1512 Pad : Wide_Character := Wide_Space) return Unbounded_Wide_String
1514 SR : constant Shared_Wide_String_Access := Source.Reference;
1515 DR : Shared_Wide_String_Access;
1518 -- For empty result reuse empty shared string
1521 Reference (Empty_Shared_Wide_String'Access);
1522 DR := Empty_Shared_Wide_String'Access;
1524 -- Result is hole source string, reuse source shared string
1526 elsif Count = SR.Last then
1530 -- Otherwise allocate new shared string and fill it
1533 DR := Allocate (Count);
1535 if Count < SR.Last then
1536 DR.Data (1 .. Count) := SR.Data (SR.Last - Count + 1 .. SR.Last);
1539 for J in 1 .. Count - SR.Last loop
1543 DR.Data (Count - SR.Last + 1 .. Count) := SR.Data (1 .. SR.Last);
1549 return (AF.Controlled with Reference => DR);
1553 (Source : in out Unbounded_Wide_String;
1555 Pad : Wide_Character := Wide_Space)
1557 SR : constant Shared_Wide_String_Access := Source.Reference;
1558 DR : Shared_Wide_String_Access;
1561 (SR : Shared_Wide_String_Access;
1562 DR : Shared_Wide_String_Access;
1564 -- Common code of tail computation. SR/DR can point to the same object
1571 (SR : Shared_Wide_String_Access;
1572 DR : Shared_Wide_String_Access;
1575 if Count < SR.Last then
1576 DR.Data (1 .. Count) := SR.Data (SR.Last - Count + 1 .. SR.Last);
1579 DR.Data (Count - SR.Last + 1 .. Count) := SR.Data (1 .. SR.Last);
1581 for J in 1 .. Count - SR.Last loop
1590 -- Result is empty string, reuse empty shared string
1593 Reference (Empty_Shared_Wide_String'Access);
1594 Source.Reference := Empty_Shared_Wide_String'Access;
1597 -- Length of the result is the same with length of the source string,
1598 -- reuse source shared string.
1600 elsif Count = SR.Last then
1603 -- Try to reuse existent shared string
1605 elsif Can_Be_Reused (SR, Count) then
1606 Common (SR, SR, Count);
1608 -- Otherwise allocate new shared string and fill it
1611 DR := Allocate (Count);
1612 Common (SR, DR, Count);
1613 Source.Reference := DR;
1618 --------------------
1619 -- To_Wide_String --
1620 --------------------
1622 function To_Wide_String
1623 (Source : Unbounded_Wide_String) return Wide_String is
1625 return Source.Reference.Data (1 .. Source.Reference.Last);
1628 ------------------------------
1629 -- To_Unbounded_Wide_String --
1630 ------------------------------
1632 function To_Unbounded_Wide_String
1633 (Source : Wide_String) return Unbounded_Wide_String
1635 DR : constant Shared_Wide_String_Access := Allocate (Source'Length);
1637 DR.Data (1 .. Source'Length) := Source;
1638 DR.Last := Source'Length;
1639 return (AF.Controlled with Reference => DR);
1640 end To_Unbounded_Wide_String;
1642 function To_Unbounded_Wide_String
1643 (Length : Natural) return Unbounded_Wide_String
1645 DR : constant Shared_Wide_String_Access := Allocate (Length);
1648 return (AF.Controlled with Reference => DR);
1649 end To_Unbounded_Wide_String;
1656 (Source : Unbounded_Wide_String;
1657 Mapping : Wide_Maps.Wide_Character_Mapping) return Unbounded_Wide_String
1659 SR : constant Shared_Wide_String_Access := Source.Reference;
1660 DR : Shared_Wide_String_Access;
1663 -- Nothing to translate, reuse empty shared string
1666 Reference (Empty_Shared_Wide_String'Access);
1667 DR := Empty_Shared_Wide_String'Access;
1669 -- Otherwise, allocate new shared string and fill it
1672 DR := Allocate (SR.Last);
1674 for J in 1 .. SR.Last loop
1675 DR.Data (J) := Value (Mapping, SR.Data (J));
1681 return (AF.Controlled with Reference => DR);
1685 (Source : in out Unbounded_Wide_String;
1686 Mapping : Wide_Maps.Wide_Character_Mapping)
1688 SR : constant Shared_Wide_String_Access := Source.Reference;
1689 DR : Shared_Wide_String_Access;
1692 -- Nothing to translate
1697 -- Try to reuse shared string
1699 elsif Can_Be_Reused (SR, SR.Last) then
1700 for J in 1 .. SR.Last loop
1701 SR.Data (J) := Value (Mapping, SR.Data (J));
1704 -- Otherwise, allocate new shared string
1707 DR := Allocate (SR.Last);
1709 for J in 1 .. SR.Last loop
1710 DR.Data (J) := Value (Mapping, SR.Data (J));
1714 Source.Reference := DR;
1720 (Source : Unbounded_Wide_String;
1721 Mapping : Wide_Maps.Wide_Character_Mapping_Function)
1722 return Unbounded_Wide_String
1724 SR : constant Shared_Wide_String_Access := Source.Reference;
1725 DR : Shared_Wide_String_Access;
1728 -- Nothing to translate, reuse empty shared string
1731 Reference (Empty_Shared_Wide_String'Access);
1732 DR := Empty_Shared_Wide_String'Access;
1734 -- Otherwise, allocate new shared string and fill it
1737 DR := Allocate (SR.Last);
1739 for J in 1 .. SR.Last loop
1740 DR.Data (J) := Mapping.all (SR.Data (J));
1746 return (AF.Controlled with Reference => DR);
1756 (Source : in out Unbounded_Wide_String;
1757 Mapping : Wide_Maps.Wide_Character_Mapping_Function)
1759 SR : constant Shared_Wide_String_Access := Source.Reference;
1760 DR : Shared_Wide_String_Access;
1763 -- Nothing to translate
1768 -- Try to reuse shared string
1770 elsif Can_Be_Reused (SR, SR.Last) then
1771 for J in 1 .. SR.Last loop
1772 SR.Data (J) := Mapping.all (SR.Data (J));
1775 -- Otherwise allocate new shared string and fill it
1778 DR := Allocate (SR.Last);
1780 for J in 1 .. SR.Last loop
1781 DR.Data (J) := Mapping.all (SR.Data (J));
1785 Source.Reference := DR;
1803 (Source : Unbounded_Wide_String;
1804 Side : Trim_End) return Unbounded_Wide_String
1806 SR : constant Shared_Wide_String_Access := Source.Reference;
1808 DR : Shared_Wide_String_Access;
1813 Low := Index_Non_Blank (Source, Forward);
1815 -- All blanks, reuse empty shared string
1818 Reference (Empty_Shared_Wide_String'Access);
1819 DR := Empty_Shared_Wide_String'Access;
1825 DL := SR.Last - Low + 1;
1829 High := Index_Non_Blank (Source, Backward);
1833 High := Index_Non_Blank (Source, Backward);
1834 DL := High - Low + 1;
1837 -- Length of the result is the same as length of the source string,
1838 -- reuse source shared string.
1840 if DL = SR.Last then
1844 -- Otherwise, allocate new shared string
1847 DR := Allocate (DL);
1848 DR.Data (1 .. DL) := SR.Data (Low .. High);
1853 return (AF.Controlled with Reference => DR);
1857 (Source : in out Unbounded_Wide_String;
1860 SR : constant Shared_Wide_String_Access := Source.Reference;
1862 DR : Shared_Wide_String_Access;
1867 Low := Index_Non_Blank (Source, Forward);
1869 -- All blanks, reuse empty shared string
1872 Reference (Empty_Shared_Wide_String'Access);
1873 Source.Reference := Empty_Shared_Wide_String'Access;
1880 DL := SR.Last - Low + 1;
1884 High := Index_Non_Blank (Source, Backward);
1888 High := Index_Non_Blank (Source, Backward);
1889 DL := High - Low + 1;
1892 -- Length of the result is the same as length of the source string,
1895 if DL = SR.Last then
1898 -- Try to reuse existent shared string
1900 elsif Can_Be_Reused (SR, DL) then
1901 SR.Data (1 .. DL) := SR.Data (Low .. High);
1904 -- Otherwise, allocate new shared string
1907 DR := Allocate (DL);
1908 DR.Data (1 .. DL) := SR.Data (Low .. High);
1910 Source.Reference := DR;
1917 (Source : Unbounded_Wide_String;
1918 Left : Wide_Maps.Wide_Character_Set;
1919 Right : Wide_Maps.Wide_Character_Set) return Unbounded_Wide_String
1921 SR : constant Shared_Wide_String_Access := Source.Reference;
1923 DR : Shared_Wide_String_Access;
1928 Low := Index (Source, Left, Outside, Forward);
1930 -- Source includes only characters from Left set, reuse empty shared
1934 Reference (Empty_Shared_Wide_String'Access);
1935 DR := Empty_Shared_Wide_String'Access;
1938 High := Index (Source, Right, Outside, Backward);
1939 DL := Integer'Max (0, High - Low + 1);
1941 -- Source includes only characters from Right set or result string
1942 -- is empty, reuse empty shared string.
1944 if High = 0 or else DL = 0 then
1945 Reference (Empty_Shared_Wide_String'Access);
1946 DR := Empty_Shared_Wide_String'Access;
1948 -- Otherwise, allocate new shared string and fill it
1951 DR := Allocate (DL);
1952 DR.Data (1 .. DL) := SR.Data (Low .. High);
1957 return (AF.Controlled with Reference => DR);
1961 (Source : in out Unbounded_Wide_String;
1962 Left : Wide_Maps.Wide_Character_Set;
1963 Right : Wide_Maps.Wide_Character_Set)
1965 SR : constant Shared_Wide_String_Access := Source.Reference;
1967 DR : Shared_Wide_String_Access;
1972 Low := Index (Source, Left, Outside, Forward);
1974 -- Source includes only characters from Left set, reuse empty shared
1978 Reference (Empty_Shared_Wide_String'Access);
1979 Source.Reference := Empty_Shared_Wide_String'Access;
1983 High := Index (Source, Right, Outside, Backward);
1984 DL := Integer'Max (0, High - Low + 1);
1986 -- Source includes only characters from Right set or result string
1987 -- is empty, reuse empty shared string.
1989 if High = 0 or else DL = 0 then
1990 Reference (Empty_Shared_Wide_String'Access);
1991 Source.Reference := Empty_Shared_Wide_String'Access;
1994 -- Try to reuse existent shared string
1996 elsif Can_Be_Reused (SR, DL) then
1997 SR.Data (1 .. DL) := SR.Data (Low .. High);
2000 -- Otherwise, allocate new shared string and fill it
2003 DR := Allocate (DL);
2004 DR.Data (1 .. DL) := SR.Data (Low .. High);
2006 Source.Reference := DR;
2012 ---------------------
2013 -- Unbounded_Slice --
2014 ---------------------
2016 function Unbounded_Slice
2017 (Source : Unbounded_Wide_String;
2019 High : Natural) return Unbounded_Wide_String
2021 SR : constant Shared_Wide_String_Access := Source.Reference;
2023 DR : Shared_Wide_String_Access;
2028 if Low > SR.Last + 1 or else High > SR.Last then
2031 -- Result is empty slice, reuse empty shared string
2033 elsif Low > High then
2034 Reference (Empty_Shared_Wide_String'Access);
2035 DR := Empty_Shared_Wide_String'Access;
2037 -- Otherwise, allocate new shared string and fill it
2040 DL := High - Low + 1;
2041 DR := Allocate (DL);
2042 DR.Data (1 .. DL) := SR.Data (Low .. High);
2046 return (AF.Controlled with Reference => DR);
2047 end Unbounded_Slice;
2049 procedure Unbounded_Slice
2050 (Source : Unbounded_Wide_String;
2051 Target : out Unbounded_Wide_String;
2055 SR : constant Shared_Wide_String_Access := Source.Reference;
2056 TR : constant Shared_Wide_String_Access := Target.Reference;
2058 DR : Shared_Wide_String_Access;
2063 if Low > SR.Last + 1 or else High > SR.Last then
2066 -- Result is empty slice, reuse empty shared string
2068 elsif Low > High then
2069 Reference (Empty_Shared_Wide_String'Access);
2070 Target.Reference := Empty_Shared_Wide_String'Access;
2074 DL := High - Low + 1;
2076 -- Try to reuse existent shared string
2078 if Can_Be_Reused (TR, DL) then
2079 TR.Data (1 .. DL) := SR.Data (Low .. High);
2082 -- Otherwise, allocate new shared string and fill it
2085 DR := Allocate (DL);
2086 DR.Data (1 .. DL) := SR.Data (Low .. High);
2088 Target.Reference := DR;
2092 end Unbounded_Slice;
2098 procedure Unreference (Item : not null Shared_Wide_String_Access) is
2102 new Ada.Unchecked_Deallocation
2103 (Shared_Wide_String, Shared_Wide_String_Access);
2105 Aux : Shared_Wide_String_Access := Item;
2108 if Sync_Sub_And_Fetch (Aux.Counter'Access, 1) = 0 then
2110 -- Reference counter of Empty_Shared_Wide_String must never reach
2113 pragma Assert (Aux /= Empty_Shared_Wide_String'Access);
2119 end Ada.Strings.Wide_Unbounded;