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-2005, 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 2, 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. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
20 -- Boston, MA 02110-1301, USA. --
22 -- As a special exception, if other files instantiate generics from this --
23 -- unit, or you link this unit with other files to produce an executable, --
24 -- this unit does not by itself cause the resulting executable to be --
25 -- covered by the GNU General Public License. This exception does not --
26 -- however invalidate any other reasons why the executable file might be --
27 -- covered by the GNU Public License. --
29 -- GNAT was originally developed by the GNAT team at New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc. --
32 ------------------------------------------------------------------------------
34 with Ada
.Strings
.Fixed
;
35 with Ada
.Strings
.Search
;
36 with Ada
.Unchecked_Deallocation
;
38 package body Ada
.Strings
.Unbounded
is
47 (Left
: Unbounded_String
;
48 Right
: Unbounded_String
) return Unbounded_String
50 L_Length
: constant Natural := Left
.Last
;
51 R_Length
: constant Natural := Right
.Last
;
52 Result
: Unbounded_String
;
55 Result
.Last
:= L_Length
+ R_Length
;
57 Result
.Reference
:= new String (1 .. Result
.Last
);
59 Result
.Reference
(1 .. L_Length
) :=
60 Left
.Reference
(1 .. Left
.Last
);
61 Result
.Reference
(L_Length
+ 1 .. Result
.Last
) :=
62 Right
.Reference
(1 .. Right
.Last
);
68 (Left
: Unbounded_String
;
69 Right
: String) return Unbounded_String
71 L_Length
: constant Natural := Left
.Last
;
72 Result
: Unbounded_String
;
75 Result
.Last
:= L_Length
+ Right
'Length;
77 Result
.Reference
:= new String (1 .. Result
.Last
);
79 Result
.Reference
(1 .. L_Length
) := Left
.Reference
(1 .. Left
.Last
);
80 Result
.Reference
(L_Length
+ 1 .. Result
.Last
) := Right
;
87 Right
: Unbounded_String
) return Unbounded_String
89 R_Length
: constant Natural := Right
.Last
;
90 Result
: Unbounded_String
;
93 Result
.Last
:= Left
'Length + R_Length
;
95 Result
.Reference
:= new String (1 .. Result
.Last
);
97 Result
.Reference
(1 .. Left
'Length) := Left
;
98 Result
.Reference
(Left
'Length + 1 .. Result
.Last
) :=
99 Right
.Reference
(1 .. Right
.Last
);
105 (Left
: Unbounded_String
;
106 Right
: Character) return Unbounded_String
108 Result
: Unbounded_String
;
111 Result
.Last
:= Left
.Last
+ 1;
113 Result
.Reference
:= new String (1 .. Result
.Last
);
115 Result
.Reference
(1 .. Result
.Last
- 1) :=
116 Left
.Reference
(1 .. Left
.Last
);
117 Result
.Reference
(Result
.Last
) := Right
;
124 Right
: Unbounded_String
) return Unbounded_String
126 Result
: Unbounded_String
;
129 Result
.Last
:= Right
.Last
+ 1;
131 Result
.Reference
:= new String (1 .. Result
.Last
);
132 Result
.Reference
(1) := Left
;
133 Result
.Reference
(2 .. Result
.Last
) :=
134 Right
.Reference
(1 .. Right
.Last
);
144 Right
: Character) return Unbounded_String
146 Result
: Unbounded_String
;
151 Result
.Reference
:= new String (1 .. Left
);
152 for J
in Result
.Reference
'Range loop
153 Result
.Reference
(J
) := Right
;
161 Right
: String) return Unbounded_String
163 Len
: constant Natural := Right
'Length;
165 Result
: Unbounded_String
;
168 Result
.Last
:= Left
* Len
;
170 Result
.Reference
:= new String (1 .. Result
.Last
);
173 for J
in 1 .. Left
loop
174 Result
.Reference
(K
.. K
+ Len
- 1) := Right
;
183 Right
: Unbounded_String
) return Unbounded_String
185 Len
: constant Natural := Right
.Last
;
187 Result
: Unbounded_String
;
190 Result
.Last
:= Left
* Len
;
192 Result
.Reference
:= new String (1 .. Result
.Last
);
195 for J
in 1 .. Left
loop
196 Result
.Reference
(K
.. K
+ Len
- 1) :=
197 Right
.Reference
(1 .. Right
.Last
);
209 (Left
: Unbounded_String
;
210 Right
: Unbounded_String
) return Boolean
214 Left
.Reference
(1 .. Left
.Last
) < Right
.Reference
(1 .. Right
.Last
);
218 (Left
: Unbounded_String
;
219 Right
: String) return Boolean
222 return Left
.Reference
(1 .. Left
.Last
) < Right
;
227 Right
: Unbounded_String
) return Boolean
230 return Left
< Right
.Reference
(1 .. Right
.Last
);
238 (Left
: Unbounded_String
;
239 Right
: Unbounded_String
) return Boolean
243 Left
.Reference
(1 .. Left
.Last
) <= Right
.Reference
(1 .. Right
.Last
);
247 (Left
: Unbounded_String
;
248 Right
: String) return Boolean
251 return Left
.Reference
(1 .. Left
.Last
) <= Right
;
256 Right
: Unbounded_String
) return Boolean
259 return Left
<= Right
.Reference
(1 .. Right
.Last
);
267 (Left
: Unbounded_String
;
268 Right
: Unbounded_String
) return Boolean
272 Left
.Reference
(1 .. Left
.Last
) = Right
.Reference
(1 .. Right
.Last
);
276 (Left
: Unbounded_String
;
277 Right
: String) return Boolean
280 return Left
.Reference
(1 .. Left
.Last
) = Right
;
285 Right
: Unbounded_String
) return Boolean
288 return Left
= Right
.Reference
(1 .. Right
.Last
);
296 (Left
: Unbounded_String
;
297 Right
: Unbounded_String
) return Boolean
301 Left
.Reference
(1 .. Left
.Last
) > Right
.Reference
(1 .. Right
.Last
);
305 (Left
: Unbounded_String
;
306 Right
: String) return Boolean
309 return Left
.Reference
(1 .. Left
.Last
) > Right
;
314 Right
: Unbounded_String
) return Boolean
317 return Left
> Right
.Reference
(1 .. Right
.Last
);
325 (Left
: Unbounded_String
;
326 Right
: Unbounded_String
) return Boolean
330 Left
.Reference
(1 .. Left
.Last
) >= Right
.Reference
(1 .. Right
.Last
);
334 (Left
: Unbounded_String
;
335 Right
: String) return Boolean
338 return Left
.Reference
(1 .. Left
.Last
) >= Right
;
343 Right
: Unbounded_String
) return Boolean
346 return Left
>= Right
.Reference
(1 .. Right
.Last
);
353 procedure Adjust
(Object
: in out Unbounded_String
) is
355 -- Copy string, except we do not copy the statically allocated null
356 -- string since it can never be deallocated. Note that we do not copy
357 -- extra string room here to avoid dragging unused allocated memory.
359 if Object
.Reference
/= Null_String
'Access then
360 Object
.Reference
:= new String'(Object.Reference (1 .. Object.Last));
369 (Source : in out Unbounded_String;
370 New_Item : Unbounded_String)
373 Realloc_For_Chunk (Source, New_Item.Last);
374 Source.Reference (Source.Last + 1 .. Source.Last + New_Item.Last) :=
375 New_Item.Reference (1 .. New_Item.Last);
376 Source.Last := Source.Last + New_Item.Last;
380 (Source : in out Unbounded_String;
384 Realloc_For_Chunk (Source, New_Item'Length);
385 Source.Reference (Source.Last + 1 .. Source.Last + New_Item'Length) :=
387 Source.Last := Source.Last + New_Item'Length;
391 (Source : in out Unbounded_String;
392 New_Item : Character)
395 Realloc_For_Chunk (Source, 1);
396 Source.Reference (Source.Last + 1) := New_Item;
397 Source.Last := Source.Last + 1;
405 (Source : Unbounded_String;
407 Mapping : Maps.Character_Mapping := Maps.Identity) return Natural
411 Search.Count (Source.Reference (1 .. Source.Last), Pattern, Mapping);
415 (Source : Unbounded_String;
417 Mapping : Maps.Character_Mapping_Function) return Natural
421 Search.Count (Source.Reference (1 .. Source.Last), Pattern, Mapping);
425 (Source : Unbounded_String;
426 Set : Maps.Character_Set) return Natural
429 return Search.Count (Source.Reference (1 .. Source.Last), Set);
437 (Source : Unbounded_String;
439 Through : Natural) return Unbounded_String
444 (Fixed.Delete (Source.Reference (1 .. Source.Last), From, Through));
448 (Source : in out Unbounded_String;
453 if From > Through then
456 elsif From < Source.Reference'First or else Through > Source.Last then
461 Len : constant Natural := Through - From + 1;
464 Source.Reference (From .. Source.Last - Len) :=
465 Source.Reference (Through + 1 .. Source.Last);
466 Source.Last := Source.Last - Len;
476 (Source : Unbounded_String;
477 Index : Positive) return Character
480 if Index <= Source.Last then
481 return Source.Reference (Index);
483 raise Strings.Index_Error;
491 procedure Finalize (Object : in out Unbounded_String) is
492 procedure Deallocate is
493 new Ada.Unchecked_Deallocation (String, String_Access);
496 -- Note: Don't try to free statically allocated null string
498 if Object.Reference /= Null_String'Access then
499 Deallocate (Object.Reference);
500 Object.Reference := Null_Unbounded_String.Reference;
510 (Source : Unbounded_String;
511 Set : Maps.Character_Set;
512 Test : Strings.Membership;
513 First : out Positive;
518 (Source.Reference (1 .. Source.Last), Set, Test, First, Last);
525 procedure Free (X : in out String_Access) is
526 procedure Deallocate is
527 new Ada.Unchecked_Deallocation (String, String_Access);
530 -- Note: Do not try to free statically allocated null string
532 if X /= Null_Unbounded_String.Reference then
542 (Source : Unbounded_String;
544 Pad : Character := Space) return Unbounded_String
547 return To_Unbounded_String
548 (Fixed.Head (Source.Reference (1 .. Source.Last), Count, Pad));
552 (Source : in out Unbounded_String;
554 Pad : Character := Space)
556 Old : String_Access := Source.Reference;
559 new String'(Fixed
.Head
(Source
.Reference
(1 .. Source
.Last
),
561 Source
.Last
:= Source
.Reference
'Length;
570 (Source
: Unbounded_String
;
572 Going
: Strings
.Direction
:= Strings
.Forward
;
573 Mapping
: Maps
.Character_Mapping
:= Maps
.Identity
) return Natural
577 (Source
.Reference
(1 .. Source
.Last
), Pattern
, Going
, Mapping
);
581 (Source
: Unbounded_String
;
583 Going
: Direction
:= Forward
;
584 Mapping
: Maps
.Character_Mapping_Function
) return Natural
588 (Source
.Reference
(1 .. Source
.Last
), Pattern
, Going
, Mapping
);
592 (Source
: Unbounded_String
;
593 Set
: Maps
.Character_Set
;
594 Test
: Strings
.Membership
:= Strings
.Inside
;
595 Going
: Strings
.Direction
:= Strings
.Forward
) return Natural
599 (Source
.Reference
(1 .. Source
.Last
), Set
, Test
, Going
);
603 (Source
: Unbounded_String
;
606 Going
: Direction
:= Forward
;
607 Mapping
: Maps
.Character_Mapping
:= Maps
.Identity
) return Natural
611 (Source
.Reference
(1 .. Source
.Last
), Pattern
, From
, Going
, Mapping
);
615 (Source
: Unbounded_String
;
618 Going
: Direction
:= Forward
;
619 Mapping
: Maps
.Character_Mapping_Function
) return Natural
623 (Source
.Reference
(1 .. Source
.Last
), Pattern
, From
, Going
, Mapping
);
627 (Source
: Unbounded_String
;
628 Set
: Maps
.Character_Set
;
630 Test
: Membership
:= Inside
;
631 Going
: Direction
:= Forward
) return Natural
635 (Source
.Reference
(1 .. Source
.Last
), Set
, From
, Test
, Going
);
638 function Index_Non_Blank
639 (Source
: Unbounded_String
;
640 Going
: Strings
.Direction
:= Strings
.Forward
) return Natural
644 Search
.Index_Non_Blank
645 (Source
.Reference
(1 .. Source
.Last
), Going
);
648 function Index_Non_Blank
649 (Source
: Unbounded_String
;
651 Going
: Direction
:= Forward
) return Natural
655 Search
.Index_Non_Blank
656 (Source
.Reference
(1 .. Source
.Last
), From
, Going
);
663 procedure Initialize
(Object
: in out Unbounded_String
) is
665 Object
.Reference
:= Null_Unbounded_String
.Reference
;
674 (Source
: Unbounded_String
;
676 New_Item
: String) return Unbounded_String
679 return To_Unbounded_String
680 (Fixed
.Insert
(Source
.Reference
(1 .. Source
.Last
), Before
, New_Item
));
684 (Source
: in out Unbounded_String
;
689 if Before
not in Source
.Reference
'First .. Source
.Last
+ 1 then
693 Realloc_For_Chunk
(Source
, New_Item
'Size);
696 (Before
+ New_Item
'Length .. Source
.Last
+ New_Item
'Length) :=
697 Source
.Reference
(Before
.. Source
.Last
);
699 Source
.Reference
(Before
.. Before
+ New_Item
'Length - 1) := New_Item
;
700 Source
.Last
:= Source
.Last
+ New_Item
'Length;
707 function Length
(Source
: Unbounded_String
) return Natural is
717 (Source
: Unbounded_String
;
719 New_Item
: String) return Unbounded_String
722 return To_Unbounded_String
724 (Source
.Reference
(1 .. Source
.Last
), Position
, New_Item
));
728 (Source
: in out Unbounded_String
;
732 NL
: constant Natural := New_Item
'Length;
734 if Position
<= Source
.Last
- NL
+ 1 then
735 Source
.Reference
(Position
.. Position
+ NL
- 1) := New_Item
;
738 Old
: String_Access
:= Source
.Reference
;
740 Source
.Reference
:= new String'
742 (Source.Reference (1 .. Source.Last), Position, New_Item));
743 Source.Last := Source.Reference'Length;
749 -----------------------
750 -- Realloc_For_Chunk --
751 -----------------------
753 procedure Realloc_For_Chunk
754 (Source : in out Unbounded_String;
755 Chunk_Size : Natural)
757 Growth_Factor : constant := 32;
758 -- The growth factor controls how much extra space is allocated when
759 -- we have to increase the size of an allocated unbounded string. By
760 -- allocating extra space, we avoid the need to reallocate on every
761 -- append, particularly important when a string is built up by repeated
762 -- append operations of small pieces. This is expressed as a factor so
763 -- 32 means add 1/32 of the length of the string as growth space.
765 Min_Mul_Alloc : constant := Standard'Maximum_Alignment;
766 -- Allocation will be done by a multiple of Min_Mul_Alloc This causes
767 -- no memory loss as most (all?) malloc implementations are obliged to
768 -- align the returned memory on the maximum alignment as malloc does not
769 -- know the target alignment.
771 S_Length : constant Natural := Source.Reference'Length;
774 if Chunk_Size > S_Length - Source.Last then
776 New_Size : constant Positive :=
777 S_Length + Chunk_Size + (S_Length / Growth_Factor);
779 New_Rounded_Up_Size : constant Positive :=
780 ((New_Size - 1) / Min_Mul_Alloc + 1) *
783 Tmp : constant String_Access :=
784 new String (1 .. New_Rounded_Up_Size);
787 Tmp (1 .. Source.Last) := Source.Reference (1 .. Source.Last);
788 Free (Source.Reference);
789 Source.Reference := Tmp;
792 end Realloc_For_Chunk;
794 ---------------------
795 -- Replace_Element --
796 ---------------------
798 procedure Replace_Element
799 (Source : in out Unbounded_String;
804 if Index <= Source.Last then
805 Source.Reference (Index) := By;
807 raise Strings.Index_Error;
815 function Replace_Slice
816 (Source : Unbounded_String;
819 By : String) return Unbounded_String
822 return To_Unbounded_String
824 (Source.Reference (1 .. Source.Last), Low, High, By));
827 procedure Replace_Slice
828 (Source : in out Unbounded_String;
833 Old : String_Access := Source.Reference;
835 Source.Reference := new String'
837 (Source
.Reference
(1 .. Source
.Last
), Low
, High
, By
));
838 Source
.Last
:= Source
.Reference
'Length;
842 --------------------------
843 -- Set_Unbounded_String --
844 --------------------------
846 procedure Set_Unbounded_String
847 (Target
: out Unbounded_String
;
851 Target
.Last
:= Source
'Length;
852 Target
.Reference
:= new String (1 .. Source
'Length);
853 Target
.Reference
.all := Source
;
854 end Set_Unbounded_String
;
861 (Source
: Unbounded_String
;
863 High
: Natural) return String
866 -- Note: test of High > Length is in accordance with AI95-00128
868 if Low
> Source
.Last
+ 1 or else High
> Source
.Last
then
871 return Source
.Reference
(Low
.. High
);
880 (Source
: Unbounded_String
;
882 Pad
: Character := Space
) return Unbounded_String
is
884 return To_Unbounded_String
885 (Fixed
.Tail
(Source
.Reference
(1 .. Source
.Last
), Count
, Pad
));
889 (Source
: in out Unbounded_String
;
891 Pad
: Character := Space
)
893 Old
: String_Access
:= Source
.Reference
;
895 Source
.Reference
:= new String'
896 (Fixed.Tail (Source.Reference (1 .. Source.Last), Count, Pad));
897 Source.Last := Source.Reference'Length;
905 function To_String (Source : Unbounded_String) return String is
907 return Source.Reference (1 .. Source.Last);
910 -------------------------
911 -- To_Unbounded_String --
912 -------------------------
914 function To_Unbounded_String (Source : String) return Unbounded_String is
915 Result : Unbounded_String;
917 Result.Last := Source'Length;
918 Result.Reference := new String (1 .. Source'Length);
919 Result.Reference.all := Source;
921 end To_Unbounded_String;
923 function To_Unbounded_String
924 (Length : Natural) return Unbounded_String
926 Result : Unbounded_String;
928 Result.Last := Length;
929 Result.Reference := new String (1 .. Length);
931 end To_Unbounded_String;
938 (Source : Unbounded_String;
939 Mapping : Maps.Character_Mapping) return Unbounded_String
942 return To_Unbounded_String
943 (Fixed.Translate (Source.Reference (1 .. Source.Last), Mapping));
947 (Source : in out Unbounded_String;
948 Mapping : Maps.Character_Mapping)
951 Fixed.Translate (Source.Reference (1 .. Source.Last), Mapping);
955 (Source : Unbounded_String;
956 Mapping : Maps.Character_Mapping_Function) return Unbounded_String
959 return To_Unbounded_String
960 (Fixed.Translate (Source.Reference (1 .. Source.Last), Mapping));
964 (Source : in out Unbounded_String;
965 Mapping : Maps.Character_Mapping_Function)
968 Fixed.Translate (Source.Reference (1 .. Source.Last), Mapping);
976 (Source : Unbounded_String;
977 Side : Trim_End) return Unbounded_String
980 return To_Unbounded_String
981 (Fixed.Trim (Source.Reference (1 .. Source.Last), Side));
985 (Source : in out Unbounded_String;
988 Old : String_Access := Source.Reference;
990 Source.Reference := new String'
991 (Fixed
.Trim
(Source
.Reference
(1 .. Source
.Last
), Side
));
992 Source
.Last
:= Source
.Reference
'Length;
997 (Source
: Unbounded_String
;
998 Left
: Maps
.Character_Set
;
999 Right
: Maps
.Character_Set
) return Unbounded_String
1002 return To_Unbounded_String
1003 (Fixed
.Trim
(Source
.Reference
(1 .. Source
.Last
), Left
, Right
));
1007 (Source
: in out Unbounded_String
;
1008 Left
: Maps
.Character_Set
;
1009 Right
: Maps
.Character_Set
)
1011 Old
: String_Access
:= Source
.Reference
;
1013 Source
.Reference
:= new String'
1014 (Fixed.Trim (Source.Reference (1 .. Source.Last), Left, Right));
1015 Source.Last := Source.Reference'Length;
1019 ---------------------
1020 -- Unbounded_Slice --
1021 ---------------------
1023 function Unbounded_Slice
1024 (Source : Unbounded_String;
1026 High : Natural) return Unbounded_String
1029 if Low > Source.Last + 1 or else High > Source.Last then
1032 return To_Unbounded_String (Source.Reference.all (Low .. High));
1034 end Unbounded_Slice;
1036 procedure Unbounded_Slice
1037 (Source : Unbounded_String;
1038 Target : out Unbounded_String;
1043 if Low > Source.Last + 1 or else High > Source.Last then
1046 Target := To_Unbounded_String (Source.Reference.all (Low .. High));
1048 end Unbounded_Slice;
1050 end Ada.Strings.Unbounded;