PR testsuite/44195
[official-gcc.git] / gcc / ada / a-stzunb-shared.adb
blobe20cd98e8a098574124fd892097562ba55be126b
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUN-TIME COMPONENTS --
4 -- --
5 -- A D A . S T R I N G S . W I D E _ W I D E _ U N B O U N D E D --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1992-2010, Free Software Foundation, Inc. --
10 -- --
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. --
17 -- --
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. --
21 -- --
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/>. --
26 -- --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
29 -- --
30 ------------------------------------------------------------------------------
32 with Ada.Strings.Wide_Wide_Search;
33 with Ada.Unchecked_Deallocation;
35 package body Ada.Strings.Wide_Wide_Unbounded is
37 use Ada.Strings.Wide_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.
69 ---------
70 -- "&" --
71 ---------
73 function "&"
74 (Left : Unbounded_Wide_Wide_String;
75 Right : Unbounded_Wide_Wide_String) return Unbounded_Wide_Wide_String
77 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
78 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
79 DL : constant Natural := LR.Last + RR.Last;
80 DR : Shared_Wide_Wide_String_Access;
82 begin
83 -- Result is an empty string, reuse shared empty string.
85 if DL = 0 then
86 Reference (Empty_Shared_Wide_Wide_String'Access);
87 DR := Empty_Shared_Wide_Wide_String'Access;
89 -- Left string is empty, return Rigth string.
91 elsif LR.Last = 0 then
92 Reference (RR);
93 DR := RR;
95 -- Right string is empty, return Left string.
97 elsif RR.Last = 0 then
98 Reference (LR);
99 DR := LR;
101 -- Overwise, allocate new shared string and fill data.
103 else
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);
107 DR.Last := DL;
108 end if;
110 return (AF.Controlled with Reference => DR);
111 end "&";
113 function "&"
114 (Left : Unbounded_Wide_Wide_String;
115 Right : Wide_Wide_String) return Unbounded_Wide_Wide_String
117 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
118 DL : constant Natural := LR.Last + Right'Length;
119 DR : Shared_Wide_Wide_String_Access;
121 begin
122 -- Result is an empty string, reuse shared empty string.
124 if DL = 0 then
125 Reference (Empty_Shared_Wide_Wide_String'Access);
126 DR := Empty_Shared_Wide_Wide_String'Access;
128 -- Right is an empty string, return Left string.
130 elsif Right'Length = 0 then
131 Reference (LR);
132 DR := LR;
134 -- Otherwise, allocate new shared string and fill it.
136 else
137 DR := Allocate (DL);
138 DR.Data (1 .. LR.Last) := LR.Data (1 .. LR.Last);
139 DR.Data (LR.Last + 1 .. DL) := Right;
140 DR.Last := DL;
141 end if;
143 return (AF.Controlled with Reference => DR);
144 end "&";
146 function "&"
147 (Left : Wide_Wide_String;
148 Right : Unbounded_Wide_Wide_String) return Unbounded_Wide_Wide_String
150 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
151 DL : constant Natural := Left'Length + RR.Last;
152 DR : Shared_Wide_Wide_String_Access;
154 begin
155 -- Result is an empty string, reuse shared one.
157 if DL = 0 then
158 Reference (Empty_Shared_Wide_Wide_String'Access);
159 DR := Empty_Shared_Wide_Wide_String'Access;
161 -- Left is empty string, return Right string.
163 elsif Left'Length = 0 then
164 Reference (RR);
165 DR := RR;
167 -- Otherwise, allocate new shared string and fill it.
169 else
170 DR := Allocate (DL);
171 DR.Data (1 .. Left'Length) := Left;
172 DR.Data (Left'Length + 1 .. DL) := RR.Data (1 .. RR.Last);
173 DR.Last := DL;
174 end if;
176 return (AF.Controlled with Reference => DR);
177 end "&";
179 function "&"
180 (Left : Unbounded_Wide_Wide_String;
181 Right : Wide_Wide_Character) return Unbounded_Wide_Wide_String
183 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
184 DL : constant Natural := LR.Last + 1;
185 DR : Shared_Wide_Wide_String_Access;
187 begin
188 DR := Allocate (DL);
189 DR.Data (1 .. LR.Last) := LR.Data (1 .. LR.Last);
190 DR.Data (DL) := Right;
191 DR.Last := DL;
193 return (AF.Controlled with Reference => DR);
194 end "&";
196 function "&"
197 (Left : Wide_Wide_Character;
198 Right : Unbounded_Wide_Wide_String) return Unbounded_Wide_Wide_String
200 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
201 DL : constant Natural := 1 + RR.Last;
202 DR : Shared_Wide_Wide_String_Access;
204 begin
205 DR := Allocate (DL);
206 DR.Data (1) := Left;
207 DR.Data (2 .. DL) := RR.Data (1 .. RR.Last);
208 DR.Last := DL;
210 return (AF.Controlled with Reference => DR);
211 end "&";
213 ---------
214 -- "*" --
215 ---------
217 function "*"
218 (Left : Natural;
219 Right : Wide_Wide_Character) return Unbounded_Wide_Wide_String
221 DR : Shared_Wide_Wide_String_Access;
223 begin
224 -- Result is an empty string, reuse shared empty string.
226 if Left = 0 then
227 Reference (Empty_Shared_Wide_Wide_String'Access);
228 DR := Empty_Shared_Wide_Wide_String'Access;
230 -- Otherwise, allocate new shared string and fill it.
232 else
233 DR := Allocate (Left);
235 for J in 1 .. Left loop
236 DR.Data (J) := Right;
237 end loop;
239 DR.Last := Left;
240 end if;
242 return (AF.Controlled with Reference => DR);
243 end "*";
245 function "*"
246 (Left : Natural;
247 Right : Wide_Wide_String) return Unbounded_Wide_Wide_String
249 DL : constant Natural := Left * Right'Length;
250 DR : Shared_Wide_Wide_String_Access;
251 K : Positive;
253 begin
254 -- Result is an empty string, reuse shared empty string.
256 if DL = 0 then
257 Reference (Empty_Shared_Wide_Wide_String'Access);
258 DR := Empty_Shared_Wide_Wide_String'Access;
260 -- Otherwise, allocate new shared string and fill it.
262 else
263 DR := Allocate (DL);
264 K := 1;
266 for J in 1 .. Left loop
267 DR.Data (K .. K + Right'Length - 1) := Right;
268 K := K + Right'Length;
269 end loop;
271 DR.Last := DL;
272 end if;
274 return (AF.Controlled with Reference => DR);
275 end "*";
277 function "*"
278 (Left : Natural;
279 Right : Unbounded_Wide_Wide_String) return Unbounded_Wide_Wide_String
281 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
282 DL : constant Natural := Left * RR.Last;
283 DR : Shared_Wide_Wide_String_Access;
284 K : Positive;
286 begin
287 -- Result is an empty string, reuse shared empty string.
289 if DL = 0 then
290 Reference (Empty_Shared_Wide_Wide_String'Access);
291 DR := Empty_Shared_Wide_Wide_String'Access;
293 -- Coefficient is one, just return string itself.
295 elsif Left = 1 then
296 Reference (RR);
297 DR := RR;
299 -- Otherwise, allocate new shared string and fill it.
301 else
302 DR := Allocate (DL);
303 K := 1;
305 for J in 1 .. Left loop
306 DR.Data (K .. K + RR.Last - 1) := RR.Data (1 .. RR.Last);
307 K := K + RR.Last;
308 end loop;
310 DR.Last := DL;
311 end if;
313 return (AF.Controlled with Reference => DR);
314 end "*";
316 ---------
317 -- "<" --
318 ---------
320 function "<"
321 (Left : Unbounded_Wide_Wide_String;
322 Right : Unbounded_Wide_Wide_String) return Boolean
324 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
325 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
326 begin
327 return LR.Data (1 .. LR.Last) < RR.Data (1 .. RR.Last);
328 end "<";
330 function "<"
331 (Left : Unbounded_Wide_Wide_String;
332 Right : Wide_Wide_String) return Boolean
334 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
335 begin
336 return LR.Data (1 .. LR.Last) < Right;
337 end "<";
339 function "<"
340 (Left : Wide_Wide_String;
341 Right : Unbounded_Wide_Wide_String) return Boolean
343 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
344 begin
345 return Left < RR.Data (1 .. RR.Last);
346 end "<";
348 ----------
349 -- "<=" --
350 ----------
352 function "<="
353 (Left : Unbounded_Wide_Wide_String;
354 Right : Unbounded_Wide_Wide_String) return Boolean
356 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
357 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
359 begin
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);
363 end "<=";
365 function "<="
366 (Left : Unbounded_Wide_Wide_String;
367 Right : Wide_Wide_String) return Boolean
369 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
370 begin
371 return LR.Data (1 .. LR.Last) <= Right;
372 end "<=";
374 function "<="
375 (Left : Wide_Wide_String;
376 Right : Unbounded_Wide_Wide_String) return Boolean
378 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
379 begin
380 return Left <= RR.Data (1 .. RR.Last);
381 end "<=";
383 ---------
384 -- "=" --
385 ---------
387 function "="
388 (Left : Unbounded_Wide_Wide_String;
389 Right : Unbounded_Wide_Wide_String) return Boolean
391 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
392 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
394 begin
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.
397 end "=";
399 function "="
400 (Left : Unbounded_Wide_Wide_String;
401 Right : Wide_Wide_String) return Boolean
403 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
404 begin
405 return LR.Data (1 .. LR.Last) = Right;
406 end "=";
408 function "="
409 (Left : Wide_Wide_String;
410 Right : Unbounded_Wide_Wide_String) return Boolean
412 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
413 begin
414 return Left = RR.Data (1 .. RR.Last);
415 end "=";
417 ---------
418 -- ">" --
419 ---------
421 function ">"
422 (Left : Unbounded_Wide_Wide_String;
423 Right : Unbounded_Wide_Wide_String) return Boolean
425 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
426 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
427 begin
428 return LR.Data (1 .. LR.Last) > RR.Data (1 .. RR.Last);
429 end ">";
431 function ">"
432 (Left : Unbounded_Wide_Wide_String;
433 Right : Wide_Wide_String) return Boolean
435 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
436 begin
437 return LR.Data (1 .. LR.Last) > Right;
438 end ">";
440 function ">"
441 (Left : Wide_Wide_String;
442 Right : Unbounded_Wide_Wide_String) return Boolean
444 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
445 begin
446 return Left > RR.Data (1 .. RR.Last);
447 end ">";
449 ----------
450 -- ">=" --
451 ----------
453 function ">="
454 (Left : Unbounded_Wide_Wide_String;
455 Right : Unbounded_Wide_Wide_String) return Boolean
457 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
458 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
460 begin
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);
464 end ">=";
466 function ">="
467 (Left : Unbounded_Wide_Wide_String;
468 Right : Wide_Wide_String) return Boolean
470 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
471 begin
472 return LR.Data (1 .. LR.Last) >= Right;
473 end ">=";
475 function ">="
476 (Left : Wide_Wide_String;
477 Right : Unbounded_Wide_Wide_String) return Boolean
479 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
480 begin
481 return Left >= RR.Data (1 .. RR.Last);
482 end ">=";
484 ------------
485 -- Adjust --
486 ------------
488 procedure Adjust (Object : in out Unbounded_Wide_Wide_String) is
489 begin
490 Reference (Object.Reference);
491 end Adjust;
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_Wide_String'Size
500 / Standard'Storage_Unit;
501 -- Total size of all static components
503 Element_Size : constant Natural :=
504 Wide_Wide_Character'Size / Standard'Storage_Unit;
506 begin
507 return
508 (((Static_Size + Max_Length * Element_Size - 1) / Min_Mul_Alloc + 2)
509 * Min_Mul_Alloc - Static_Size) / Element_Size;
510 end Aligned_Max_Length;
512 --------------
513 -- Allocate --
514 --------------
516 function Allocate
517 (Max_Length : Natural) return Shared_Wide_Wide_String_Access is
518 begin
519 -- Empty string requested, return shared empty string
521 if Max_Length = 0 then
522 Reference (Empty_Shared_Wide_Wide_String'Access);
523 return Empty_Shared_Wide_Wide_String'Access;
525 -- Otherwise, allocate requested space (and probably some more room)
527 else
528 return new Shared_Wide_Wide_String (Aligned_Max_Length (Max_Length));
529 end if;
530 end Allocate;
532 ------------
533 -- Append --
534 ------------
536 procedure Append
537 (Source : in out Unbounded_Wide_Wide_String;
538 New_Item : Unbounded_Wide_Wide_String)
540 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
541 NR : constant Shared_Wide_Wide_String_Access := New_Item.Reference;
542 DL : constant Natural := SR.Last + NR.Last;
543 DR : Shared_Wide_Wide_String_Access;
545 begin
546 -- Source is an empty string, reuse New_Item data
548 if SR.Last = 0 then
549 Reference (NR);
550 Source.Reference := NR;
551 Unreference (SR);
553 -- New_Item is empty string, nothing to do
555 elsif NR.Last = 0 then
556 null;
558 -- Try to reuse existent shared string
560 elsif Can_Be_Reused (SR, DL) then
561 SR.Data (SR.Last + 1 .. DL) := NR.Data (1 .. NR.Last);
562 SR.Last := DL;
564 -- Otherwise, allocate new one and fill it
566 else
567 DR := Allocate (DL + DL / Growth_Factor);
568 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
569 DR.Data (SR.Last + 1 .. DL) := NR.Data (1 .. NR.Last);
570 DR.Last := DL;
571 Source.Reference := DR;
572 Unreference (SR);
573 end if;
574 end Append;
576 procedure Append
577 (Source : in out Unbounded_Wide_Wide_String;
578 New_Item : Wide_Wide_String)
580 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
581 DL : constant Natural := SR.Last + New_Item'Length;
582 DR : Shared_Wide_Wide_String_Access;
584 begin
585 -- New_Item is an empty string, nothing to do
587 if New_Item'Length = 0 then
588 null;
590 -- Try to reuse existing shared string
592 elsif Can_Be_Reused (SR, DL) then
593 SR.Data (SR.Last + 1 .. DL) := New_Item;
594 SR.Last := DL;
596 -- Otherwise, allocate new one and fill it
598 else
599 DR := Allocate (DL + DL / Growth_Factor);
600 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
601 DR.Data (SR.Last + 1 .. DL) := New_Item;
602 DR.Last := DL;
603 Source.Reference := DR;
604 Unreference (SR);
605 end if;
606 end Append;
608 procedure Append
609 (Source : in out Unbounded_Wide_Wide_String;
610 New_Item : Wide_Wide_Character)
612 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
613 DL : constant Natural := SR.Last + 1;
614 DR : Shared_Wide_Wide_String_Access;
616 begin
617 -- Try to reuse existing shared string
619 if Can_Be_Reused (SR, SR.Last + 1) then
620 SR.Data (SR.Last + 1) := New_Item;
621 SR.Last := SR.Last + 1;
623 -- Otherwise, allocate new one and fill it
625 else
626 DR := Allocate (DL + DL / Growth_Factor);
627 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
628 DR.Data (DL) := New_Item;
629 DR.Last := DL;
630 Source.Reference := DR;
631 Unreference (SR);
632 end if;
633 end Append;
635 -------------------
636 -- Can_Be_Reused --
637 -------------------
639 function Can_Be_Reused
640 (Item : Shared_Wide_Wide_String_Access;
641 Length : Natural) return Boolean
643 use Interfaces;
644 begin
645 return
646 Item.Counter = 1
647 and then Item.Max_Length >= Length
648 and then Item.Max_Length <=
649 Aligned_Max_Length (Length + Length / Growth_Factor);
650 end Can_Be_Reused;
652 -----------
653 -- Count --
654 -----------
656 function Count
657 (Source : Unbounded_Wide_Wide_String;
658 Pattern : Wide_Wide_String;
659 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping :=
660 Wide_Wide_Maps.Identity)
661 return Natural
663 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
664 begin
665 return Wide_Wide_Search.Count (SR.Data (1 .. SR.Last), Pattern, Mapping);
666 end Count;
668 function Count
669 (Source : Unbounded_Wide_Wide_String;
670 Pattern : Wide_Wide_String;
671 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
672 return Natural
674 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
675 begin
676 return Wide_Wide_Search.Count (SR.Data (1 .. SR.Last), Pattern, Mapping);
677 end Count;
679 function Count
680 (Source : Unbounded_Wide_Wide_String;
681 Set : Wide_Wide_Maps.Wide_Wide_Character_Set) return Natural
683 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
684 begin
685 return Wide_Wide_Search.Count (SR.Data (1 .. SR.Last), Set);
686 end Count;
688 ------------
689 -- Delete --
690 ------------
692 function Delete
693 (Source : Unbounded_Wide_Wide_String;
694 From : Positive;
695 Through : Natural) return Unbounded_Wide_Wide_String
697 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
698 DL : Natural;
699 DR : Shared_Wide_Wide_String_Access;
701 begin
702 -- Empty slice is deleted, use the same shared string
704 if From > Through then
705 Reference (SR);
706 DR := SR;
708 -- Index is out of range
710 elsif Through > SR.Last then
711 raise Index_Error;
713 -- Compute size of the result
715 else
716 DL := SR.Last - (Through - From + 1);
718 -- Result is an empty string, reuse shared empty string
720 if DL = 0 then
721 Reference (Empty_Shared_Wide_Wide_String'Access);
722 DR := Empty_Shared_Wide_Wide_String'Access;
724 -- Otherwise, allocate new shared string and fill it
726 else
727 DR := Allocate (DL);
728 DR.Data (1 .. From - 1) := SR.Data (1 .. From - 1);
729 DR.Data (From .. DL) := SR.Data (Through + 1 .. SR.Last);
730 DR.Last := DL;
731 end if;
732 end if;
734 return (AF.Controlled with Reference => DR);
735 end Delete;
737 procedure Delete
738 (Source : in out Unbounded_Wide_Wide_String;
739 From : Positive;
740 Through : Natural)
742 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
743 DL : Natural;
744 DR : Shared_Wide_Wide_String_Access;
746 begin
747 -- Nothing changed, return
749 if From > Through then
750 null;
752 -- Through is outside of the range
754 elsif Through > SR.Last then
755 raise Index_Error;
757 else
758 DL := SR.Last - (Through - From + 1);
760 -- Result is empty, reuse shared empty string
762 if DL = 0 then
763 Reference (Empty_Shared_Wide_Wide_String'Access);
764 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
765 Unreference (SR);
767 -- Try to reuse existent shared string
769 elsif Can_Be_Reused (SR, DL) then
770 SR.Data (From .. DL) := SR.Data (Through + 1 .. SR.Last);
771 SR.Last := DL;
773 -- Otherwise, allocate new shared string
775 else
776 DR := Allocate (DL);
777 DR.Data (1 .. From - 1) := SR.Data (1 .. From - 1);
778 DR.Data (From .. DL) := SR.Data (Through + 1 .. SR.Last);
779 DR.Last := DL;
780 Source.Reference := DR;
781 Unreference (SR);
782 end if;
783 end if;
784 end Delete;
786 -------------
787 -- Element --
788 -------------
790 function Element
791 (Source : Unbounded_Wide_Wide_String;
792 Index : Positive) return Wide_Wide_Character
794 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
795 begin
796 if Index <= SR.Last then
797 return SR.Data (Index);
798 else
799 raise Index_Error;
800 end if;
801 end Element;
803 --------------
804 -- Finalize --
805 --------------
807 procedure Finalize (Object : in out Unbounded_Wide_Wide_String) is
808 SR : constant Shared_Wide_Wide_String_Access := Object.Reference;
810 begin
811 if SR /= null then
813 -- The same controlled object can be finalized several times for
814 -- some reason. As per 7.6.1(24) this should have no ill effect,
815 -- so we need to add a guard for the case of finalizing the same
816 -- object twice.
818 Object.Reference := null;
819 Unreference (SR);
820 end if;
821 end Finalize;
823 ----------------
824 -- Find_Token --
825 ----------------
827 procedure Find_Token
828 (Source : Unbounded_Wide_Wide_String;
829 Set : Wide_Wide_Maps.Wide_Wide_Character_Set;
830 Test : Strings.Membership;
831 First : out Positive;
832 Last : out Natural)
834 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
835 begin
836 Wide_Wide_Search.Find_Token
837 (SR.Data (1 .. SR.Last), Set, Test, First, Last);
838 end Find_Token;
840 ----------
841 -- Free --
842 ----------
844 procedure Free (X : in out Wide_Wide_String_Access) is
845 procedure Deallocate is
846 new Ada.Unchecked_Deallocation
847 (Wide_Wide_String, Wide_Wide_String_Access);
848 begin
849 Deallocate (X);
850 end Free;
852 ----------
853 -- Head --
854 ----------
856 function Head
857 (Source : Unbounded_Wide_Wide_String;
858 Count : Natural;
859 Pad : Wide_Wide_Character := Wide_Wide_Space)
860 return Unbounded_Wide_Wide_String
862 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
863 DR : Shared_Wide_Wide_String_Access;
865 begin
866 -- Result is empty, reuse shared empty string
868 if Count = 0 then
869 Reference (Empty_Shared_Wide_Wide_String'Access);
870 DR := Empty_Shared_Wide_Wide_String'Access;
872 -- Length of the string is the same as requested, reuse source shared
873 -- string.
875 elsif Count = SR.Last then
876 Reference (SR);
877 DR := SR;
879 -- Otherwise, allocate new shared string and fill it
881 else
882 DR := Allocate (Count);
884 -- Length of the source string is more than requested, copy
885 -- corresponding slice.
887 if Count < SR.Last then
888 DR.Data (1 .. Count) := SR.Data (1 .. Count);
890 -- Length of the source string is less then requested, copy all
891 -- contents and fill others by Pad character.
893 else
894 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
896 for J in SR.Last + 1 .. Count loop
897 DR.Data (J) := Pad;
898 end loop;
899 end if;
901 DR.Last := Count;
902 end if;
904 return (AF.Controlled with Reference => DR);
905 end Head;
907 procedure Head
908 (Source : in out Unbounded_Wide_Wide_String;
909 Count : Natural;
910 Pad : Wide_Wide_Character := Wide_Wide_Space)
912 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
913 DR : Shared_Wide_Wide_String_Access;
915 begin
916 -- Result is empty, reuse empty shared string
918 if Count = 0 then
919 Reference (Empty_Shared_Wide_Wide_String'Access);
920 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
921 Unreference (SR);
923 -- Result is same with source string, reuse source shared string
925 elsif Count = SR.Last then
926 null;
928 -- Try to reuse existent shared string
930 elsif Can_Be_Reused (SR, Count) then
931 if Count > SR.Last then
932 for J in SR.Last + 1 .. Count loop
933 SR.Data (J) := Pad;
934 end loop;
935 end if;
937 SR.Last := Count;
939 -- Otherwise, allocate new shared string and fill it
941 else
942 DR := Allocate (Count);
944 -- Length of the source string is greater then requested, copy
945 -- corresponding slice.
947 if Count < SR.Last then
948 DR.Data (1 .. Count) := SR.Data (1 .. Count);
950 -- Length of the source string is less the requested, copy all
951 -- exists data and fill others by Pad character.
953 else
954 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
956 for J in SR.Last + 1 .. Count loop
957 DR.Data (J) := Pad;
958 end loop;
959 end if;
961 DR.Last := Count;
962 Source.Reference := DR;
963 Unreference (SR);
964 end if;
965 end Head;
967 -----------
968 -- Index --
969 -----------
971 function Index
972 (Source : Unbounded_Wide_Wide_String;
973 Pattern : Wide_Wide_String;
974 Going : Strings.Direction := Strings.Forward;
975 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping :=
976 Wide_Wide_Maps.Identity)
977 return Natural
979 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
980 begin
981 return Wide_Wide_Search.Index
982 (SR.Data (1 .. SR.Last), Pattern, Going, Mapping);
983 end Index;
985 function Index
986 (Source : Unbounded_Wide_Wide_String;
987 Pattern : Wide_Wide_String;
988 Going : Direction := Forward;
989 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
990 return Natural
992 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
993 begin
994 return Wide_Wide_Search.Index
995 (SR.Data (1 .. SR.Last), Pattern, Going, Mapping);
996 end Index;
998 function Index
999 (Source : Unbounded_Wide_Wide_String;
1000 Set : Wide_Wide_Maps.Wide_Wide_Character_Set;
1001 Test : Strings.Membership := Strings.Inside;
1002 Going : Strings.Direction := Strings.Forward) return Natural
1004 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1005 begin
1006 return Wide_Wide_Search.Index (SR.Data (1 .. SR.Last), Set, Test, Going);
1007 end Index;
1009 function Index
1010 (Source : Unbounded_Wide_Wide_String;
1011 Pattern : Wide_Wide_String;
1012 From : Positive;
1013 Going : Direction := Forward;
1014 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping :=
1015 Wide_Wide_Maps.Identity)
1016 return Natural
1018 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1019 begin
1020 return Wide_Wide_Search.Index
1021 (SR.Data (1 .. SR.Last), Pattern, From, Going, Mapping);
1022 end Index;
1024 function Index
1025 (Source : Unbounded_Wide_Wide_String;
1026 Pattern : Wide_Wide_String;
1027 From : Positive;
1028 Going : Direction := Forward;
1029 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
1030 return Natural
1032 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1033 begin
1034 return Wide_Wide_Search.Index
1035 (SR.Data (1 .. SR.Last), Pattern, From, Going, Mapping);
1036 end Index;
1038 function Index
1039 (Source : Unbounded_Wide_Wide_String;
1040 Set : Wide_Wide_Maps.Wide_Wide_Character_Set;
1041 From : Positive;
1042 Test : Membership := Inside;
1043 Going : Direction := Forward) return Natural
1045 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1046 begin
1047 return Wide_Wide_Search.Index
1048 (SR.Data (1 .. SR.Last), Set, From, Test, Going);
1049 end Index;
1051 ---------------------
1052 -- Index_Non_Blank --
1053 ---------------------
1055 function Index_Non_Blank
1056 (Source : Unbounded_Wide_Wide_String;
1057 Going : Strings.Direction := Strings.Forward) return Natural
1059 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1060 begin
1061 return Wide_Wide_Search.Index_Non_Blank (SR.Data (1 .. SR.Last), Going);
1062 end Index_Non_Blank;
1064 function Index_Non_Blank
1065 (Source : Unbounded_Wide_Wide_String;
1066 From : Positive;
1067 Going : Direction := Forward) return Natural
1069 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1070 begin
1071 return Wide_Wide_Search.Index_Non_Blank
1072 (SR.Data (1 .. SR.Last), From, Going);
1073 end Index_Non_Blank;
1075 ----------------
1076 -- Initialize --
1077 ----------------
1079 procedure Initialize (Object : in out Unbounded_Wide_Wide_String) is
1080 begin
1081 Reference (Object.Reference);
1082 end Initialize;
1084 ------------
1085 -- Insert --
1086 ------------
1088 function Insert
1089 (Source : Unbounded_Wide_Wide_String;
1090 Before : Positive;
1091 New_Item : Wide_Wide_String) return Unbounded_Wide_Wide_String
1093 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1094 DL : constant Natural := SR.Last + New_Item'Length;
1095 DR : Shared_Wide_Wide_String_Access;
1097 begin
1098 -- Check index first
1100 if Before > SR.Last + 1 then
1101 raise Index_Error;
1102 end if;
1104 -- Result is empty, reuse empty shared string
1106 if DL = 0 then
1107 Reference (Empty_Shared_Wide_Wide_String'Access);
1108 DR := Empty_Shared_Wide_Wide_String'Access;
1110 -- Inserted string is empty, reuse source shared string
1112 elsif New_Item'Length = 0 then
1113 Reference (SR);
1114 DR := SR;
1116 -- Otherwise, allocate new shared string and fill it
1118 else
1119 DR := Allocate (DL + DL / Growth_Factor);
1120 DR.Data (1 .. Before - 1) := SR.Data (1 .. Before - 1);
1121 DR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1122 DR.Data (Before + New_Item'Length .. DL) :=
1123 SR.Data (Before .. SR.Last);
1124 DR.Last := DL;
1125 end if;
1127 return (AF.Controlled with Reference => DR);
1128 end Insert;
1130 procedure Insert
1131 (Source : in out Unbounded_Wide_Wide_String;
1132 Before : Positive;
1133 New_Item : Wide_Wide_String)
1135 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1136 DL : constant Natural := SR.Last + New_Item'Length;
1137 DR : Shared_Wide_Wide_String_Access;
1139 begin
1140 -- Check bounds
1142 if Before > SR.Last + 1 then
1143 raise Index_Error;
1144 end if;
1146 -- Result is empty string, reuse empty shared string
1148 if DL = 0 then
1149 Reference (Empty_Shared_Wide_Wide_String'Access);
1150 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1151 Unreference (SR);
1153 -- Inserted string is empty, nothing to do
1155 elsif New_Item'Length = 0 then
1156 null;
1158 -- Try to reuse existent shared string first
1160 elsif Can_Be_Reused (SR, DL) then
1161 SR.Data (Before + New_Item'Length .. DL) :=
1162 SR.Data (Before .. SR.Last);
1163 SR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1164 SR.Last := DL;
1166 -- Otherwise, allocate new shared string and fill it
1168 else
1169 DR := Allocate (DL + DL / Growth_Factor);
1170 DR.Data (1 .. Before - 1) := SR.Data (1 .. Before - 1);
1171 DR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1172 DR.Data (Before + New_Item'Length .. DL) :=
1173 SR.Data (Before .. SR.Last);
1174 DR.Last := DL;
1175 Source.Reference := DR;
1176 Unreference (SR);
1177 end if;
1178 end Insert;
1180 ------------
1181 -- Length --
1182 ------------
1184 function Length (Source : Unbounded_Wide_Wide_String) return Natural is
1185 begin
1186 return Source.Reference.Last;
1187 end Length;
1189 ---------------
1190 -- Overwrite --
1191 ---------------
1193 function Overwrite
1194 (Source : Unbounded_Wide_Wide_String;
1195 Position : Positive;
1196 New_Item : Wide_Wide_String) return Unbounded_Wide_Wide_String
1198 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1199 DL : Natural;
1200 DR : Shared_Wide_Wide_String_Access;
1202 begin
1203 -- Check bounds
1205 if Position > SR.Last + 1 then
1206 raise Index_Error;
1207 end if;
1209 DL := Integer'Max (SR.Last, Position + New_Item'Length - 1);
1211 -- Result is empty string, reuse empty shared string
1213 if DL = 0 then
1214 Reference (Empty_Shared_Wide_Wide_String'Access);
1215 DR := Empty_Shared_Wide_Wide_String'Access;
1217 -- Result is same with source string, reuse source shared string
1219 elsif New_Item'Length = 0 then
1220 Reference (SR);
1221 DR := SR;
1223 -- Otherwise, allocate new shared string and fill it
1225 else
1226 DR := Allocate (DL);
1227 DR.Data (1 .. Position - 1) := SR.Data (1 .. Position - 1);
1228 DR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1229 DR.Data (Position + New_Item'Length .. DL) :=
1230 SR.Data (Position + New_Item'Length .. SR.Last);
1231 DR.Last := DL;
1232 end if;
1234 return (AF.Controlled with Reference => DR);
1235 end Overwrite;
1237 procedure Overwrite
1238 (Source : in out Unbounded_Wide_Wide_String;
1239 Position : Positive;
1240 New_Item : Wide_Wide_String)
1242 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1243 DL : Natural;
1244 DR : Shared_Wide_Wide_String_Access;
1246 begin
1247 -- Bounds check
1249 if Position > SR.Last + 1 then
1250 raise Index_Error;
1251 end if;
1253 DL := Integer'Max (SR.Last, Position + New_Item'Length - 1);
1255 -- Result is empty string, reuse empty shared string
1257 if DL = 0 then
1258 Reference (Empty_Shared_Wide_Wide_String'Access);
1259 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1260 Unreference (SR);
1262 -- String unchanged, nothing to do
1264 elsif New_Item'Length = 0 then
1265 null;
1267 -- Try to reuse existent shared string
1269 elsif Can_Be_Reused (SR, DL) then
1270 SR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1271 SR.Last := DL;
1273 -- Otherwise allocate new shared string and fill it
1275 else
1276 DR := Allocate (DL);
1277 DR.Data (1 .. Position - 1) := SR.Data (1 .. Position - 1);
1278 DR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1279 DR.Data (Position + New_Item'Length .. DL) :=
1280 SR.Data (Position + New_Item'Length .. SR.Last);
1281 DR.Last := DL;
1282 Source.Reference := DR;
1283 Unreference (SR);
1284 end if;
1285 end Overwrite;
1287 ---------------
1288 -- Reference --
1289 ---------------
1291 procedure Reference (Item : not null Shared_Wide_Wide_String_Access) is
1292 begin
1293 Sync_Add_And_Fetch (Item.Counter'Access, 1);
1294 end Reference;
1296 ---------------------
1297 -- Replace_Element --
1298 ---------------------
1300 procedure Replace_Element
1301 (Source : in out Unbounded_Wide_Wide_String;
1302 Index : Positive;
1303 By : Wide_Wide_Character)
1305 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1306 DR : Shared_Wide_Wide_String_Access;
1308 begin
1309 -- Bounds check.
1311 if Index <= SR.Last then
1313 -- Try to reuse existent shared string
1315 if Can_Be_Reused (SR, SR.Last) then
1316 SR.Data (Index) := By;
1318 -- Otherwise allocate new shared string and fill it
1320 else
1321 DR := Allocate (SR.Last);
1322 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
1323 DR.Data (Index) := By;
1324 DR.Last := SR.Last;
1325 Source.Reference := DR;
1326 Unreference (SR);
1327 end if;
1329 else
1330 raise Index_Error;
1331 end if;
1332 end Replace_Element;
1334 -------------------
1335 -- Replace_Slice --
1336 -------------------
1338 function Replace_Slice
1339 (Source : Unbounded_Wide_Wide_String;
1340 Low : Positive;
1341 High : Natural;
1342 By : Wide_Wide_String) return Unbounded_Wide_Wide_String
1344 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1345 DL : Natural;
1346 DR : Shared_Wide_Wide_String_Access;
1348 begin
1349 -- Check bounds
1351 if Low > SR.Last + 1 then
1352 raise Index_Error;
1353 end if;
1355 -- Do replace operation when removed slice is not empty
1357 if High >= Low then
1358 DL := By'Length + SR.Last + Low - High - 1;
1360 -- Result is empty string, reuse empty shared string
1362 if DL = 0 then
1363 Reference (Empty_Shared_Wide_Wide_String'Access);
1364 DR := Empty_Shared_Wide_Wide_String'Access;
1366 -- Otherwise allocate new shared string and fill it
1368 else
1369 DR := Allocate (DL);
1370 DR.Data (1 .. Low - 1) := SR.Data (1 .. Low - 1);
1371 DR.Data (Low .. Low + By'Length - 1) := By;
1372 DR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1373 DR.Last := DL;
1374 end if;
1376 return (AF.Controlled with Reference => DR);
1378 -- Otherwise just insert string
1380 else
1381 return Insert (Source, Low, By);
1382 end if;
1383 end Replace_Slice;
1385 procedure Replace_Slice
1386 (Source : in out Unbounded_Wide_Wide_String;
1387 Low : Positive;
1388 High : Natural;
1389 By : Wide_Wide_String)
1391 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1392 DL : Natural;
1393 DR : Shared_Wide_Wide_String_Access;
1395 begin
1396 -- Bounds check
1398 if Low > SR.Last + 1 then
1399 raise Index_Error;
1400 end if;
1402 -- Do replace operation only when replaced slice is not empty
1404 if High >= Low then
1405 DL := By'Length + SR.Last + Low - High - 1;
1407 -- Result is empty string, reuse empty shared string
1409 if DL = 0 then
1410 Reference (Empty_Shared_Wide_Wide_String'Access);
1411 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1412 Unreference (SR);
1414 -- Try to reuse existent shared string
1416 elsif Can_Be_Reused (SR, DL) then
1417 SR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1418 SR.Data (Low .. Low + By'Length - 1) := By;
1419 SR.Last := DL;
1421 -- Otherwise allocate new shared string and fill it
1423 else
1424 DR := Allocate (DL);
1425 DR.Data (1 .. Low - 1) := SR.Data (1 .. Low - 1);
1426 DR.Data (Low .. Low + By'Length - 1) := By;
1427 DR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1428 DR.Last := DL;
1429 Source.Reference := DR;
1430 Unreference (SR);
1431 end if;
1433 -- Otherwise just insert item
1435 else
1436 Insert (Source, Low, By);
1437 end if;
1438 end Replace_Slice;
1440 -------------------------------
1441 -- Set_Unbounded_Wide_Wide_String --
1442 -------------------------------
1444 procedure Set_Unbounded_Wide_Wide_String
1445 (Target : out Unbounded_Wide_Wide_String;
1446 Source : Wide_Wide_String)
1448 TR : constant Shared_Wide_Wide_String_Access := Target.Reference;
1449 DR : Shared_Wide_Wide_String_Access;
1451 begin
1452 -- In case of empty string, reuse empty shared string
1454 if Source'Length = 0 then
1455 Reference (Empty_Shared_Wide_Wide_String'Access);
1456 Target.Reference := Empty_Shared_Wide_Wide_String'Access;
1458 else
1459 -- Try to reuse existent shared string
1461 if Can_Be_Reused (TR, Source'Length) then
1462 Reference (TR);
1463 DR := TR;
1465 -- Otherwise allocate new shared string
1467 else
1468 DR := Allocate (Source'Length);
1469 Target.Reference := DR;
1470 end if;
1472 DR.Data (1 .. Source'Length) := Source;
1473 DR.Last := Source'Length;
1474 end if;
1476 Unreference (TR);
1477 end Set_Unbounded_Wide_Wide_String;
1479 -----------
1480 -- Slice --
1481 -----------
1483 function Slice
1484 (Source : Unbounded_Wide_Wide_String;
1485 Low : Positive;
1486 High : Natural) return Wide_Wide_String
1488 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1490 begin
1491 -- Note: test of High > Length is in accordance with AI95-00128
1493 if Low > SR.Last + 1 or else High > SR.Last then
1494 raise Index_Error;
1496 else
1497 return SR.Data (Low .. High);
1498 end if;
1499 end Slice;
1501 ----------
1502 -- Tail --
1503 ----------
1505 function Tail
1506 (Source : Unbounded_Wide_Wide_String;
1507 Count : Natural;
1508 Pad : Wide_Wide_Character := Wide_Wide_Space)
1509 return Unbounded_Wide_Wide_String
1511 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1512 DR : Shared_Wide_Wide_String_Access;
1514 begin
1515 -- For empty result reuse empty shared string
1517 if Count = 0 then
1518 Reference (Empty_Shared_Wide_Wide_String'Access);
1519 DR := Empty_Shared_Wide_Wide_String'Access;
1521 -- Result is hole source string, reuse source shared string
1523 elsif Count = SR.Last then
1524 Reference (SR);
1525 DR := SR;
1527 -- Otherwise allocate new shared string and fill it
1529 else
1530 DR := Allocate (Count);
1532 if Count < SR.Last then
1533 DR.Data (1 .. Count) := SR.Data (SR.Last - Count + 1 .. SR.Last);
1535 else
1536 for J in 1 .. Count - SR.Last loop
1537 DR.Data (J) := Pad;
1538 end loop;
1540 DR.Data (Count - SR.Last + 1 .. Count) := SR.Data (1 .. SR.Last);
1541 end if;
1543 DR.Last := Count;
1544 end if;
1546 return (AF.Controlled with Reference => DR);
1547 end Tail;
1549 procedure Tail
1550 (Source : in out Unbounded_Wide_Wide_String;
1551 Count : Natural;
1552 Pad : Wide_Wide_Character := Wide_Wide_Space)
1554 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1555 DR : Shared_Wide_Wide_String_Access;
1557 procedure Common
1558 (SR : Shared_Wide_Wide_String_Access;
1559 DR : Shared_Wide_Wide_String_Access;
1560 Count : Natural);
1561 -- Common code of tail computation. SR/DR can point to the same object
1563 ------------
1564 -- Common --
1565 ------------
1567 procedure Common
1568 (SR : Shared_Wide_Wide_String_Access;
1569 DR : Shared_Wide_Wide_String_Access;
1570 Count : Natural) is
1571 begin
1572 if Count < SR.Last then
1573 DR.Data (1 .. Count) := SR.Data (SR.Last - Count + 1 .. SR.Last);
1575 else
1576 DR.Data (Count - SR.Last + 1 .. Count) := SR.Data (1 .. SR.Last);
1578 for J in 1 .. Count - SR.Last loop
1579 DR.Data (J) := Pad;
1580 end loop;
1581 end if;
1583 DR.Last := Count;
1584 end Common;
1586 begin
1587 -- Result is empty string, reuse empty shared string
1589 if Count = 0 then
1590 Reference (Empty_Shared_Wide_Wide_String'Access);
1591 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1592 Unreference (SR);
1594 -- Length of the result is the same with length of the source string,
1595 -- reuse source shared string.
1597 elsif Count = SR.Last then
1598 null;
1600 -- Try to reuse existent shared string
1602 elsif Can_Be_Reused (SR, Count) then
1603 Common (SR, SR, Count);
1605 -- Otherwise allocate new shared string and fill it
1607 else
1608 DR := Allocate (Count);
1609 Common (SR, DR, Count);
1610 Source.Reference := DR;
1611 Unreference (SR);
1612 end if;
1613 end Tail;
1615 --------------------
1616 -- To_Wide_Wide_String --
1617 --------------------
1619 function To_Wide_Wide_String
1620 (Source : Unbounded_Wide_Wide_String) return Wide_Wide_String is
1621 begin
1622 return Source.Reference.Data (1 .. Source.Reference.Last);
1623 end To_Wide_Wide_String;
1625 ------------------------------
1626 -- To_Unbounded_Wide_Wide_String --
1627 ------------------------------
1629 function To_Unbounded_Wide_Wide_String
1630 (Source : Wide_Wide_String) return Unbounded_Wide_Wide_String
1632 DR : constant Shared_Wide_Wide_String_Access := Allocate (Source'Length);
1633 begin
1634 DR.Data (1 .. Source'Length) := Source;
1635 DR.Last := Source'Length;
1636 return (AF.Controlled with Reference => DR);
1637 end To_Unbounded_Wide_Wide_String;
1639 function To_Unbounded_Wide_Wide_String
1640 (Length : Natural) return Unbounded_Wide_Wide_String
1642 DR : constant Shared_Wide_Wide_String_Access := Allocate (Length);
1643 begin
1644 DR.Last := Length;
1645 return (AF.Controlled with Reference => DR);
1646 end To_Unbounded_Wide_Wide_String;
1648 ---------------
1649 -- Translate --
1650 ---------------
1652 function Translate
1653 (Source : Unbounded_Wide_Wide_String;
1654 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping)
1655 return Unbounded_Wide_Wide_String
1657 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1658 DR : Shared_Wide_Wide_String_Access;
1660 begin
1661 -- Nothing to translate, reuse empty shared string
1663 if SR.Last = 0 then
1664 Reference (Empty_Shared_Wide_Wide_String'Access);
1665 DR := Empty_Shared_Wide_Wide_String'Access;
1667 -- Otherwise, allocate new shared string and fill it
1669 else
1670 DR := Allocate (SR.Last);
1672 for J in 1 .. SR.Last loop
1673 DR.Data (J) := Value (Mapping, SR.Data (J));
1674 end loop;
1676 DR.Last := SR.Last;
1677 end if;
1679 return (AF.Controlled with Reference => DR);
1680 end Translate;
1682 procedure Translate
1683 (Source : in out Unbounded_Wide_Wide_String;
1684 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping)
1686 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1687 DR : Shared_Wide_Wide_String_Access;
1689 begin
1690 -- Nothing to translate
1692 if SR.Last = 0 then
1693 null;
1695 -- Try to reuse shared string
1697 elsif Can_Be_Reused (SR, SR.Last) then
1698 for J in 1 .. SR.Last loop
1699 SR.Data (J) := Value (Mapping, SR.Data (J));
1700 end loop;
1702 -- Otherwise, allocate new shared string
1704 else
1705 DR := Allocate (SR.Last);
1707 for J in 1 .. SR.Last loop
1708 DR.Data (J) := Value (Mapping, SR.Data (J));
1709 end loop;
1711 DR.Last := SR.Last;
1712 Source.Reference := DR;
1713 Unreference (SR);
1714 end if;
1715 end Translate;
1717 function Translate
1718 (Source : Unbounded_Wide_Wide_String;
1719 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
1720 return Unbounded_Wide_Wide_String
1722 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1723 DR : Shared_Wide_Wide_String_Access;
1725 begin
1726 -- Nothing to translate, reuse empty shared string
1728 if SR.Last = 0 then
1729 Reference (Empty_Shared_Wide_Wide_String'Access);
1730 DR := Empty_Shared_Wide_Wide_String'Access;
1732 -- Otherwise, allocate new shared string and fill it
1734 else
1735 DR := Allocate (SR.Last);
1737 for J in 1 .. SR.Last loop
1738 DR.Data (J) := Mapping.all (SR.Data (J));
1739 end loop;
1741 DR.Last := SR.Last;
1742 end if;
1744 return (AF.Controlled with Reference => DR);
1746 exception
1747 when others =>
1748 Unreference (DR);
1750 raise;
1751 end Translate;
1753 procedure Translate
1754 (Source : in out Unbounded_Wide_Wide_String;
1755 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
1757 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1758 DR : Shared_Wide_Wide_String_Access;
1760 begin
1761 -- Nothing to translate
1763 if SR.Last = 0 then
1764 null;
1766 -- Try to reuse shared string
1768 elsif Can_Be_Reused (SR, SR.Last) then
1769 for J in 1 .. SR.Last loop
1770 SR.Data (J) := Mapping.all (SR.Data (J));
1771 end loop;
1773 -- Otherwise allocate new shared string and fill it
1775 else
1776 DR := Allocate (SR.Last);
1778 for J in 1 .. SR.Last loop
1779 DR.Data (J) := Mapping.all (SR.Data (J));
1780 end loop;
1782 DR.Last := SR.Last;
1783 Source.Reference := DR;
1784 Unreference (SR);
1785 end if;
1787 exception
1788 when others =>
1789 if DR /= null then
1790 Unreference (DR);
1791 end if;
1793 raise;
1794 end Translate;
1796 ----------
1797 -- Trim --
1798 ----------
1800 function Trim
1801 (Source : Unbounded_Wide_Wide_String;
1802 Side : Trim_End) return Unbounded_Wide_Wide_String
1804 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1805 DL : Natural;
1806 DR : Shared_Wide_Wide_String_Access;
1807 Low : Natural;
1808 High : Natural;
1810 begin
1811 Low := Index_Non_Blank (Source, Forward);
1813 -- All blanks, reuse empty shared string
1815 if Low = 0 then
1816 Reference (Empty_Shared_Wide_Wide_String'Access);
1817 DR := Empty_Shared_Wide_Wide_String'Access;
1819 else
1820 case Side is
1821 when Left =>
1822 High := SR.Last;
1823 DL := SR.Last - Low + 1;
1825 when Right =>
1826 Low := 1;
1827 High := Index_Non_Blank (Source, Backward);
1828 DL := High;
1830 when Both =>
1831 High := Index_Non_Blank (Source, Backward);
1832 DL := High - Low + 1;
1833 end case;
1835 -- Length of the result is the same as length of the source string,
1836 -- reuse source shared string.
1838 if DL = SR.Last then
1839 Reference (SR);
1840 DR := SR;
1842 -- Otherwise, allocate new shared string
1844 else
1845 DR := Allocate (DL);
1846 DR.Data (1 .. DL) := SR.Data (Low .. High);
1847 DR.Last := DL;
1848 end if;
1849 end if;
1851 return (AF.Controlled with Reference => DR);
1852 end Trim;
1854 procedure Trim
1855 (Source : in out Unbounded_Wide_Wide_String;
1856 Side : Trim_End)
1858 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1859 DL : Natural;
1860 DR : Shared_Wide_Wide_String_Access;
1861 Low : Natural;
1862 High : Natural;
1864 begin
1865 Low := Index_Non_Blank (Source, Forward);
1867 -- All blanks, reuse empty shared string
1869 if Low = 0 then
1870 Reference (Empty_Shared_Wide_Wide_String'Access);
1871 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1872 Unreference (SR);
1874 else
1875 case Side is
1876 when Left =>
1877 High := SR.Last;
1878 DL := SR.Last - Low + 1;
1880 when Right =>
1881 Low := 1;
1882 High := Index_Non_Blank (Source, Backward);
1883 DL := High;
1885 when Both =>
1886 High := Index_Non_Blank (Source, Backward);
1887 DL := High - Low + 1;
1888 end case;
1890 -- Length of the result is the same as length of the source string,
1891 -- nothing to do.
1893 if DL = SR.Last then
1894 null;
1896 -- Try to reuse existent shared string
1898 elsif Can_Be_Reused (SR, DL) then
1899 SR.Data (1 .. DL) := SR.Data (Low .. High);
1900 SR.Last := DL;
1902 -- Otherwise, allocate new shared string
1904 else
1905 DR := Allocate (DL);
1906 DR.Data (1 .. DL) := SR.Data (Low .. High);
1907 DR.Last := DL;
1908 Source.Reference := DR;
1909 Unreference (SR);
1910 end if;
1911 end if;
1912 end Trim;
1914 function Trim
1915 (Source : Unbounded_Wide_Wide_String;
1916 Left : Wide_Wide_Maps.Wide_Wide_Character_Set;
1917 Right : Wide_Wide_Maps.Wide_Wide_Character_Set)
1918 return Unbounded_Wide_Wide_String
1920 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1921 DL : Natural;
1922 DR : Shared_Wide_Wide_String_Access;
1923 Low : Natural;
1924 High : Natural;
1926 begin
1927 Low := Index (Source, Left, Outside, Forward);
1929 -- Source includes only characters from Left set, reuse empty shared
1930 -- string.
1932 if Low = 0 then
1933 Reference (Empty_Shared_Wide_Wide_String'Access);
1934 DR := Empty_Shared_Wide_Wide_String'Access;
1936 else
1937 High := Index (Source, Right, Outside, Backward);
1938 DL := Integer'Max (0, High - Low + 1);
1940 -- Source includes only characters from Right set or result string
1941 -- is empty, reuse empty shared string.
1943 if High = 0 or else DL = 0 then
1944 Reference (Empty_Shared_Wide_Wide_String'Access);
1945 DR := Empty_Shared_Wide_Wide_String'Access;
1947 -- Otherwise, allocate new shared string and fill it
1949 else
1950 DR := Allocate (DL);
1951 DR.Data (1 .. DL) := SR.Data (Low .. High);
1952 DR.Last := DL;
1953 end if;
1954 end if;
1956 return (AF.Controlled with Reference => DR);
1957 end Trim;
1959 procedure Trim
1960 (Source : in out Unbounded_Wide_Wide_String;
1961 Left : Wide_Wide_Maps.Wide_Wide_Character_Set;
1962 Right : Wide_Wide_Maps.Wide_Wide_Character_Set)
1964 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1965 DL : Natural;
1966 DR : Shared_Wide_Wide_String_Access;
1967 Low : Natural;
1968 High : Natural;
1970 begin
1971 Low := Index (Source, Left, Outside, Forward);
1973 -- Source includes only characters from Left set, reuse empty shared
1974 -- string.
1976 if Low = 0 then
1977 Reference (Empty_Shared_Wide_Wide_String'Access);
1978 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1979 Unreference (SR);
1981 else
1982 High := Index (Source, Right, Outside, Backward);
1983 DL := Integer'Max (0, High - Low + 1);
1985 -- Source includes only characters from Right set or result string
1986 -- is empty, reuse empty shared string.
1988 if High = 0 or else DL = 0 then
1989 Reference (Empty_Shared_Wide_Wide_String'Access);
1990 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1991 Unreference (SR);
1993 -- Try to reuse existent shared string
1995 elsif Can_Be_Reused (SR, DL) then
1996 SR.Data (1 .. DL) := SR.Data (Low .. High);
1997 SR.Last := DL;
1999 -- Otherwise, allocate new shared string and fill it
2001 else
2002 DR := Allocate (DL);
2003 DR.Data (1 .. DL) := SR.Data (Low .. High);
2004 DR.Last := DL;
2005 Source.Reference := DR;
2006 Unreference (SR);
2007 end if;
2008 end if;
2009 end Trim;
2011 ---------------------
2012 -- Unbounded_Slice --
2013 ---------------------
2015 function Unbounded_Slice
2016 (Source : Unbounded_Wide_Wide_String;
2017 Low : Positive;
2018 High : Natural) return Unbounded_Wide_Wide_String
2020 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
2021 DL : Natural;
2022 DR : Shared_Wide_Wide_String_Access;
2024 begin
2025 -- Check bounds
2027 if Low > SR.Last + 1 or else High > SR.Last then
2028 raise Index_Error;
2030 -- Result is empty slice, reuse empty shared string
2032 elsif Low > High then
2033 Reference (Empty_Shared_Wide_Wide_String'Access);
2034 DR := Empty_Shared_Wide_Wide_String'Access;
2036 -- Otherwise, allocate new shared string and fill it
2038 else
2039 DL := High - Low + 1;
2040 DR := Allocate (DL);
2041 DR.Data (1 .. DL) := SR.Data (Low .. High);
2042 DR.Last := DL;
2043 end if;
2045 return (AF.Controlled with Reference => DR);
2046 end Unbounded_Slice;
2048 procedure Unbounded_Slice
2049 (Source : Unbounded_Wide_Wide_String;
2050 Target : out Unbounded_Wide_Wide_String;
2051 Low : Positive;
2052 High : Natural)
2054 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
2055 TR : constant Shared_Wide_Wide_String_Access := Target.Reference;
2056 DL : Natural;
2057 DR : Shared_Wide_Wide_String_Access;
2059 begin
2060 -- Check bounds
2062 if Low > SR.Last + 1 or else High > SR.Last then
2063 raise Index_Error;
2065 -- Result is empty slice, reuse empty shared string
2067 elsif Low > High then
2068 Reference (Empty_Shared_Wide_Wide_String'Access);
2069 Target.Reference := Empty_Shared_Wide_Wide_String'Access;
2070 Unreference (TR);
2072 else
2073 DL := High - Low + 1;
2075 -- Try to reuse existent shared string
2077 if Can_Be_Reused (TR, DL) then
2078 TR.Data (1 .. DL) := SR.Data (Low .. High);
2079 TR.Last := DL;
2081 -- Otherwise, allocate new shared string and fill it
2083 else
2084 DR := Allocate (DL);
2085 DR.Data (1 .. DL) := SR.Data (Low .. High);
2086 DR.Last := DL;
2087 Target.Reference := DR;
2088 Unreference (TR);
2089 end if;
2090 end if;
2091 end Unbounded_Slice;
2093 -----------------
2094 -- Unreference --
2095 -----------------
2097 procedure Unreference (Item : not null Shared_Wide_Wide_String_Access) is
2098 use Interfaces;
2100 procedure Free is
2101 new Ada.Unchecked_Deallocation
2102 (Shared_Wide_Wide_String, Shared_Wide_Wide_String_Access);
2104 Aux : Shared_Wide_Wide_String_Access := Item;
2106 begin
2107 if Sync_Sub_And_Fetch (Aux.Counter'Access, 1) = 0 then
2109 -- Reference counter of Empty_Shared_Wide_Wide_String must never
2110 -- reach zero.
2112 pragma Assert (Aux /= Empty_Shared_Wide_Wide_String'Access);
2114 Free (Aux);
2115 end if;
2116 end Unreference;
2118 end Ada.Strings.Wide_Wide_Unbounded;