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-2017, 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
.Fixed
;
33 with Ada
.Strings
.Search
;
34 with Ada
.Unchecked_Deallocation
;
36 package body Ada
.Strings
.Unbounded
is
43 (Left
: Unbounded_String
;
44 Right
: Unbounded_String
) return Unbounded_String
46 L_Length
: constant Natural := Left
.Last
;
47 R_Length
: constant Natural := Right
.Last
;
48 Result
: Unbounded_String
;
51 Result
.Last
:= L_Length
+ R_Length
;
53 Result
.Reference
:= new String (1 .. Result
.Last
);
55 Result
.Reference
(1 .. L_Length
) :=
56 Left
.Reference
(1 .. Left
.Last
);
57 Result
.Reference
(L_Length
+ 1 .. Result
.Last
) :=
58 Right
.Reference
(1 .. Right
.Last
);
64 (Left
: Unbounded_String
;
65 Right
: String) return Unbounded_String
67 L_Length
: constant Natural := Left
.Last
;
68 Result
: Unbounded_String
;
71 Result
.Last
:= L_Length
+ Right
'Length;
73 Result
.Reference
:= new String (1 .. Result
.Last
);
75 Result
.Reference
(1 .. L_Length
) := Left
.Reference
(1 .. Left
.Last
);
76 Result
.Reference
(L_Length
+ 1 .. Result
.Last
) := Right
;
83 Right
: Unbounded_String
) return Unbounded_String
85 R_Length
: constant Natural := Right
.Last
;
86 Result
: Unbounded_String
;
89 Result
.Last
:= Left
'Length + R_Length
;
91 Result
.Reference
:= new String (1 .. Result
.Last
);
93 Result
.Reference
(1 .. Left
'Length) := Left
;
94 Result
.Reference
(Left
'Length + 1 .. Result
.Last
) :=
95 Right
.Reference
(1 .. Right
.Last
);
101 (Left
: Unbounded_String
;
102 Right
: Character) return Unbounded_String
104 Result
: Unbounded_String
;
107 Result
.Last
:= Left
.Last
+ 1;
109 Result
.Reference
:= new String (1 .. Result
.Last
);
111 Result
.Reference
(1 .. Result
.Last
- 1) :=
112 Left
.Reference
(1 .. Left
.Last
);
113 Result
.Reference
(Result
.Last
) := Right
;
120 Right
: Unbounded_String
) return Unbounded_String
122 Result
: Unbounded_String
;
125 Result
.Last
:= Right
.Last
+ 1;
127 Result
.Reference
:= new String (1 .. Result
.Last
);
128 Result
.Reference
(1) := Left
;
129 Result
.Reference
(2 .. Result
.Last
) :=
130 Right
.Reference
(1 .. Right
.Last
);
140 Right
: Character) return Unbounded_String
142 Result
: Unbounded_String
;
147 Result
.Reference
:= new String (1 .. Left
);
148 for J
in Result
.Reference
'Range loop
149 Result
.Reference
(J
) := Right
;
157 Right
: String) return Unbounded_String
159 Len
: constant Natural := Right
'Length;
161 Result
: Unbounded_String
;
164 Result
.Last
:= Left
* Len
;
166 Result
.Reference
:= new String (1 .. Result
.Last
);
169 for J
in 1 .. Left
loop
170 Result
.Reference
(K
.. K
+ Len
- 1) := Right
;
179 Right
: Unbounded_String
) return Unbounded_String
181 Len
: constant Natural := Right
.Last
;
183 Result
: Unbounded_String
;
186 Result
.Last
:= Left
* Len
;
188 Result
.Reference
:= new String (1 .. Result
.Last
);
191 for J
in 1 .. Left
loop
192 Result
.Reference
(K
.. K
+ Len
- 1) :=
193 Right
.Reference
(1 .. Right
.Last
);
205 (Left
: Unbounded_String
;
206 Right
: Unbounded_String
) return Boolean
210 Left
.Reference
(1 .. Left
.Last
) < Right
.Reference
(1 .. Right
.Last
);
214 (Left
: Unbounded_String
;
215 Right
: String) return Boolean
218 return Left
.Reference
(1 .. Left
.Last
) < Right
;
223 Right
: Unbounded_String
) return Boolean
226 return Left
< Right
.Reference
(1 .. Right
.Last
);
234 (Left
: Unbounded_String
;
235 Right
: Unbounded_String
) return Boolean
239 Left
.Reference
(1 .. Left
.Last
) <= Right
.Reference
(1 .. Right
.Last
);
243 (Left
: Unbounded_String
;
244 Right
: String) return Boolean
247 return Left
.Reference
(1 .. Left
.Last
) <= Right
;
252 Right
: Unbounded_String
) return Boolean
255 return Left
<= Right
.Reference
(1 .. Right
.Last
);
263 (Left
: Unbounded_String
;
264 Right
: Unbounded_String
) return Boolean
268 Left
.Reference
(1 .. Left
.Last
) = Right
.Reference
(1 .. Right
.Last
);
272 (Left
: Unbounded_String
;
273 Right
: String) return Boolean
276 return Left
.Reference
(1 .. Left
.Last
) = Right
;
281 Right
: Unbounded_String
) return Boolean
284 return Left
= Right
.Reference
(1 .. Right
.Last
);
292 (Left
: Unbounded_String
;
293 Right
: Unbounded_String
) return Boolean
297 Left
.Reference
(1 .. Left
.Last
) > Right
.Reference
(1 .. Right
.Last
);
301 (Left
: Unbounded_String
;
302 Right
: String) return Boolean
305 return Left
.Reference
(1 .. Left
.Last
) > Right
;
310 Right
: Unbounded_String
) return Boolean
313 return Left
> Right
.Reference
(1 .. Right
.Last
);
321 (Left
: Unbounded_String
;
322 Right
: Unbounded_String
) return Boolean
326 Left
.Reference
(1 .. Left
.Last
) >= Right
.Reference
(1 .. Right
.Last
);
330 (Left
: Unbounded_String
;
331 Right
: String) return Boolean
334 return Left
.Reference
(1 .. Left
.Last
) >= Right
;
339 Right
: Unbounded_String
) return Boolean
342 return Left
>= Right
.Reference
(1 .. Right
.Last
);
349 procedure Adjust
(Object
: in out Unbounded_String
) is
351 -- Copy string, except we do not copy the statically allocated null
352 -- string since it can never be deallocated. Note that we do not copy
353 -- extra string room here to avoid dragging unused allocated memory.
355 if Object
.Reference
/= Null_String
'Access then
356 Object
.Reference
:= new String'(Object.Reference (1 .. Object.Last));
365 (Source : in out Unbounded_String;
366 New_Item : Unbounded_String)
369 Realloc_For_Chunk (Source, New_Item.Last);
370 Source.Reference (Source.Last + 1 .. Source.Last + New_Item.Last) :=
371 New_Item.Reference (1 .. New_Item.Last);
372 Source.Last := Source.Last + New_Item.Last;
376 (Source : in out Unbounded_String;
380 Realloc_For_Chunk (Source, New_Item'Length);
381 Source.Reference (Source.Last + 1 .. Source.Last + New_Item'Length) :=
383 Source.Last := Source.Last + New_Item'Length;
387 (Source : in out Unbounded_String;
388 New_Item : Character)
391 Realloc_For_Chunk (Source, 1);
392 Source.Reference (Source.Last + 1) := New_Item;
393 Source.Last := Source.Last + 1;
401 (Source : Unbounded_String;
403 Mapping : Maps.Character_Mapping := Maps.Identity) return Natural
407 Search.Count (Source.Reference (1 .. Source.Last), Pattern, Mapping);
411 (Source : Unbounded_String;
413 Mapping : Maps.Character_Mapping_Function) return Natural
417 Search.Count (Source.Reference (1 .. Source.Last), Pattern, Mapping);
421 (Source : Unbounded_String;
422 Set : Maps.Character_Set) return Natural
425 return Search.Count (Source.Reference (1 .. Source.Last), Set);
433 (Source : Unbounded_String;
435 Through : Natural) return Unbounded_String
440 (Fixed.Delete (Source.Reference (1 .. Source.Last), From, Through));
444 (Source : in out Unbounded_String;
449 if From > Through then
452 elsif From < Source.Reference'First or else Through > Source.Last then
457 Len : constant Natural := Through - From + 1;
460 Source.Reference (From .. Source.Last - Len) :=
461 Source.Reference (Through + 1 .. Source.Last);
462 Source.Last := Source.Last - Len;
472 (Source : Unbounded_String;
473 Index : Positive) return Character
476 if Index <= Source.Last then
477 return Source.Reference (Index);
479 raise Strings.Index_Error;
487 procedure Finalize (Object : in out Unbounded_String) is
488 procedure Deallocate is
489 new Ada.Unchecked_Deallocation (String, String_Access);
492 -- Note: Don't try to free statically allocated null string
494 if Object.Reference /= Null_String'Access then
495 Deallocate (Object.Reference);
496 Object.Reference := Null_Unbounded_String.Reference;
506 (Source : Unbounded_String;
507 Set : Maps.Character_Set;
509 Test : Strings.Membership;
510 First : out Positive;
515 (Source.Reference (From .. Source.Last), Set, Test, First, Last);
519 (Source : Unbounded_String;
520 Set : Maps.Character_Set;
521 Test : Strings.Membership;
522 First : out Positive;
527 (Source.Reference (1 .. Source.Last), Set, Test, First, Last);
534 procedure Free (X : in out String_Access) is
535 procedure Deallocate is
536 new Ada.Unchecked_Deallocation (String, String_Access);
539 -- Note: Do not try to free statically allocated null string
541 if X /= Null_Unbounded_String.Reference then
551 (Source : Unbounded_String;
553 Pad : Character := Space) return Unbounded_String
556 return To_Unbounded_String
557 (Fixed.Head (Source.Reference (1 .. Source.Last), Count, Pad));
561 (Source : in out Unbounded_String;
563 Pad : Character := Space)
565 Old : String_Access := Source.Reference;
568 new String'(Fixed
.Head
(Source
.Reference
(1 .. Source
.Last
),
570 Source
.Last
:= Source
.Reference
'Length;
579 (Source
: Unbounded_String
;
581 Going
: Strings
.Direction
:= Strings
.Forward
;
582 Mapping
: Maps
.Character_Mapping
:= Maps
.Identity
) return Natural
586 (Source
.Reference
(1 .. Source
.Last
), Pattern
, Going
, Mapping
);
590 (Source
: Unbounded_String
;
592 Going
: Direction
:= Forward
;
593 Mapping
: Maps
.Character_Mapping_Function
) return Natural
597 (Source
.Reference
(1 .. Source
.Last
), Pattern
, Going
, Mapping
);
601 (Source
: Unbounded_String
;
602 Set
: Maps
.Character_Set
;
603 Test
: Strings
.Membership
:= Strings
.Inside
;
604 Going
: Strings
.Direction
:= Strings
.Forward
) return Natural
608 (Source
.Reference
(1 .. Source
.Last
), Set
, Test
, Going
);
612 (Source
: Unbounded_String
;
615 Going
: Direction
:= Forward
;
616 Mapping
: Maps
.Character_Mapping
:= Maps
.Identity
) return Natural
620 (Source
.Reference
(1 .. Source
.Last
), Pattern
, From
, Going
, Mapping
);
624 (Source
: Unbounded_String
;
627 Going
: Direction
:= Forward
;
628 Mapping
: Maps
.Character_Mapping_Function
) return Natural
632 (Source
.Reference
(1 .. Source
.Last
), Pattern
, From
, Going
, Mapping
);
636 (Source
: Unbounded_String
;
637 Set
: Maps
.Character_Set
;
639 Test
: Membership
:= Inside
;
640 Going
: Direction
:= Forward
) return Natural
644 (Source
.Reference
(1 .. Source
.Last
), Set
, From
, Test
, Going
);
647 function Index_Non_Blank
648 (Source
: Unbounded_String
;
649 Going
: Strings
.Direction
:= Strings
.Forward
) return Natural
653 Search
.Index_Non_Blank
654 (Source
.Reference
(1 .. Source
.Last
), Going
);
657 function Index_Non_Blank
658 (Source
: Unbounded_String
;
660 Going
: Direction
:= Forward
) return Natural
664 Search
.Index_Non_Blank
665 (Source
.Reference
(1 .. Source
.Last
), From
, Going
);
672 procedure Initialize
(Object
: in out Unbounded_String
) is
674 Object
.Reference
:= Null_Unbounded_String
.Reference
;
683 (Source
: Unbounded_String
;
685 New_Item
: String) return Unbounded_String
688 return To_Unbounded_String
689 (Fixed
.Insert
(Source
.Reference
(1 .. Source
.Last
), Before
, New_Item
));
693 (Source
: in out Unbounded_String
;
698 if Before
not in Source
.Reference
'First .. Source
.Last
+ 1 then
702 Realloc_For_Chunk
(Source
, New_Item
'Length);
705 (Before
+ New_Item
'Length .. Source
.Last
+ New_Item
'Length) :=
706 Source
.Reference
(Before
.. Source
.Last
);
708 Source
.Reference
(Before
.. Before
+ New_Item
'Length - 1) := New_Item
;
709 Source
.Last
:= Source
.Last
+ New_Item
'Length;
716 function Length
(Source
: Unbounded_String
) return Natural is
726 (Source
: Unbounded_String
;
728 New_Item
: String) return Unbounded_String
731 return To_Unbounded_String
733 (Source
.Reference
(1 .. Source
.Last
), Position
, New_Item
));
737 (Source
: in out Unbounded_String
;
741 NL
: constant Natural := New_Item
'Length;
743 if Position
<= Source
.Last
- NL
+ 1 then
744 Source
.Reference
(Position
.. Position
+ NL
- 1) := New_Item
;
747 Old
: String_Access
:= Source
.Reference
;
749 Source
.Reference
:= new String'
751 (Source.Reference (1 .. Source.Last), Position, New_Item));
752 Source.Last := Source.Reference'Length;
758 -----------------------
759 -- Realloc_For_Chunk --
760 -----------------------
762 procedure Realloc_For_Chunk
763 (Source : in out Unbounded_String;
764 Chunk_Size : Natural)
766 Growth_Factor : constant := 32;
767 -- The growth factor controls how much extra space is allocated when
768 -- we have to increase the size of an allocated unbounded string. By
769 -- allocating extra space, we avoid the need to reallocate on every
770 -- append, particularly important when a string is built up by repeated
771 -- append operations of small pieces. This is expressed as a factor so
772 -- 32 means add 1/32 of the length of the string as growth space.
774 Min_Mul_Alloc : constant := Standard'Maximum_Alignment;
775 -- Allocation will be done by a multiple of Min_Mul_Alloc This causes
776 -- no memory loss as most (all?) malloc implementations are obliged to
777 -- align the returned memory on the maximum alignment as malloc does not
778 -- know the target alignment.
780 S_Length : constant Natural := Source.Reference'Length;
783 if Chunk_Size > S_Length - Source.Last then
785 New_Size : constant Positive :=
786 S_Length + Chunk_Size + (S_Length / Growth_Factor);
788 New_Rounded_Up_Size : constant Positive :=
789 ((New_Size - 1) / Min_Mul_Alloc + 1) * Min_Mul_Alloc;
791 Tmp : constant String_Access :=
792 new String (1 .. New_Rounded_Up_Size);
795 Tmp (1 .. Source.Last) := Source.Reference (1 .. Source.Last);
796 Free (Source.Reference);
797 Source.Reference := Tmp;
800 end Realloc_For_Chunk;
802 ---------------------
803 -- Replace_Element --
804 ---------------------
806 procedure Replace_Element
807 (Source : in out Unbounded_String;
812 if Index <= Source.Last then
813 Source.Reference (Index) := By;
815 raise Strings.Index_Error;
823 function Replace_Slice
824 (Source : Unbounded_String;
827 By : String) return Unbounded_String
830 return To_Unbounded_String
832 (Source.Reference (1 .. Source.Last), Low, High, By));
835 procedure Replace_Slice
836 (Source : in out Unbounded_String;
841 Old : String_Access := Source.Reference;
843 Source.Reference := new String'
845 (Source
.Reference
(1 .. Source
.Last
), Low
, High
, By
));
846 Source
.Last
:= Source
.Reference
'Length;
850 --------------------------
851 -- Set_Unbounded_String --
852 --------------------------
854 procedure Set_Unbounded_String
855 (Target
: out Unbounded_String
;
858 Old
: String_Access
:= Target
.Reference
;
860 Target
.Last
:= Source
'Length;
861 Target
.Reference
:= new String (1 .. Source
'Length);
862 Target
.Reference
.all := Source
;
864 end Set_Unbounded_String
;
871 (Source
: Unbounded_String
;
873 High
: Natural) return String
876 -- Note: test of High > Length is in accordance with AI95-00128
878 if Low
> Source
.Last
+ 1 or else High
> Source
.Last
then
881 return Source
.Reference
(Low
.. High
);
890 (Source
: Unbounded_String
;
892 Pad
: Character := Space
) return Unbounded_String
is
894 return To_Unbounded_String
895 (Fixed
.Tail
(Source
.Reference
(1 .. Source
.Last
), Count
, Pad
));
899 (Source
: in out Unbounded_String
;
901 Pad
: Character := Space
)
903 Old
: String_Access
:= Source
.Reference
;
905 Source
.Reference
:= new String'
906 (Fixed.Tail (Source.Reference (1 .. Source.Last), Count, Pad));
907 Source.Last := Source.Reference'Length;
915 function To_String (Source : Unbounded_String) return String is
917 return Source.Reference (1 .. Source.Last);
920 -------------------------
921 -- To_Unbounded_String --
922 -------------------------
924 function To_Unbounded_String (Source : String) return Unbounded_String is
925 Result : Unbounded_String;
927 -- Do not allocate an empty string: keep the default
929 if Source'Length > 0 then
930 Result.Last := Source'Length;
931 Result.Reference := new String (1 .. Source'Length);
932 Result.Reference.all := Source;
936 end To_Unbounded_String;
938 function To_Unbounded_String
939 (Length : Natural) return Unbounded_String
941 Result : Unbounded_String;
944 -- Do not allocate an empty string: keep the default
947 Result.Last := Length;
948 Result.Reference := new String (1 .. Length);
952 end To_Unbounded_String;
959 (Source : Unbounded_String;
960 Mapping : Maps.Character_Mapping) return Unbounded_String
963 return To_Unbounded_String
964 (Fixed.Translate (Source.Reference (1 .. Source.Last), Mapping));
968 (Source : in out Unbounded_String;
969 Mapping : Maps.Character_Mapping)
972 Fixed.Translate (Source.Reference (1 .. Source.Last), Mapping);
976 (Source : Unbounded_String;
977 Mapping : Maps.Character_Mapping_Function) return Unbounded_String
980 return To_Unbounded_String
981 (Fixed.Translate (Source.Reference (1 .. Source.Last), Mapping));
985 (Source : in out Unbounded_String;
986 Mapping : Maps.Character_Mapping_Function)
989 Fixed.Translate (Source.Reference (1 .. Source.Last), Mapping);
997 (Source : Unbounded_String;
998 Side : Trim_End) return Unbounded_String
1001 return To_Unbounded_String
1002 (Fixed.Trim (Source.Reference (1 .. Source.Last), Side));
1006 (Source : in out Unbounded_String;
1009 Old : String_Access := Source.Reference;
1011 Source.Reference := new String'
1012 (Fixed
.Trim
(Source
.Reference
(1 .. Source
.Last
), Side
));
1013 Source
.Last
:= Source
.Reference
'Length;
1018 (Source
: Unbounded_String
;
1019 Left
: Maps
.Character_Set
;
1020 Right
: Maps
.Character_Set
) return Unbounded_String
1023 return To_Unbounded_String
1024 (Fixed
.Trim
(Source
.Reference
(1 .. Source
.Last
), Left
, Right
));
1028 (Source
: in out Unbounded_String
;
1029 Left
: Maps
.Character_Set
;
1030 Right
: Maps
.Character_Set
)
1032 Old
: String_Access
:= Source
.Reference
;
1034 Source
.Reference
:= new String'
1035 (Fixed.Trim (Source.Reference (1 .. Source.Last), Left, Right));
1036 Source.Last := Source.Reference'Length;
1040 ---------------------
1041 -- Unbounded_Slice --
1042 ---------------------
1044 function Unbounded_Slice
1045 (Source : Unbounded_String;
1047 High : Natural) return Unbounded_String
1050 if Low > Source.Last + 1 or else High > Source.Last then
1053 return To_Unbounded_String (Source.Reference.all (Low .. High));
1055 end Unbounded_Slice;
1057 procedure Unbounded_Slice
1058 (Source : Unbounded_String;
1059 Target : out Unbounded_String;
1064 if Low > Source.Last + 1 or else High > Source.Last then
1067 Target := To_Unbounded_String (Source.Reference.all (Low .. High));
1069 end Unbounded_Slice;
1071 end Ada.Strings.Unbounded;