Merge from mainline (167278:168000).
[official-gcc/graphite-test-results.git] / gcc / ada / a-stzunb-shared.adb
blob75799dad2f224e13e06bfc671f69002503c5e6b8
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 From : Positive;
831 Test : Strings.Membership;
832 First : out Positive;
833 Last : out Natural)
835 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
836 begin
837 Wide_Wide_Search.Find_Token
838 (SR.Data (From .. SR.Last), Set, Test, First, Last);
839 end Find_Token;
841 procedure Find_Token
842 (Source : Unbounded_Wide_Wide_String;
843 Set : Wide_Wide_Maps.Wide_Wide_Character_Set;
844 Test : Strings.Membership;
845 First : out Positive;
846 Last : out Natural)
848 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
849 begin
850 Wide_Wide_Search.Find_Token
851 (SR.Data (1 .. SR.Last), Set, Test, First, Last);
852 end Find_Token;
854 ----------
855 -- Free --
856 ----------
858 procedure Free (X : in out Wide_Wide_String_Access) is
859 procedure Deallocate is
860 new Ada.Unchecked_Deallocation
861 (Wide_Wide_String, Wide_Wide_String_Access);
862 begin
863 Deallocate (X);
864 end Free;
866 ----------
867 -- Head --
868 ----------
870 function Head
871 (Source : Unbounded_Wide_Wide_String;
872 Count : Natural;
873 Pad : Wide_Wide_Character := Wide_Wide_Space)
874 return Unbounded_Wide_Wide_String
876 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
877 DR : Shared_Wide_Wide_String_Access;
879 begin
880 -- Result is empty, reuse shared empty string
882 if Count = 0 then
883 Reference (Empty_Shared_Wide_Wide_String'Access);
884 DR := Empty_Shared_Wide_Wide_String'Access;
886 -- Length of the string is the same as requested, reuse source shared
887 -- string.
889 elsif Count = SR.Last then
890 Reference (SR);
891 DR := SR;
893 -- Otherwise, allocate new shared string and fill it
895 else
896 DR := Allocate (Count);
898 -- Length of the source string is more than requested, copy
899 -- corresponding slice.
901 if Count < SR.Last then
902 DR.Data (1 .. Count) := SR.Data (1 .. Count);
904 -- Length of the source string is less then requested, copy all
905 -- contents and fill others by Pad character.
907 else
908 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
910 for J in SR.Last + 1 .. Count loop
911 DR.Data (J) := Pad;
912 end loop;
913 end if;
915 DR.Last := Count;
916 end if;
918 return (AF.Controlled with Reference => DR);
919 end Head;
921 procedure Head
922 (Source : in out Unbounded_Wide_Wide_String;
923 Count : Natural;
924 Pad : Wide_Wide_Character := Wide_Wide_Space)
926 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
927 DR : Shared_Wide_Wide_String_Access;
929 begin
930 -- Result is empty, reuse empty shared string
932 if Count = 0 then
933 Reference (Empty_Shared_Wide_Wide_String'Access);
934 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
935 Unreference (SR);
937 -- Result is same with source string, reuse source shared string
939 elsif Count = SR.Last then
940 null;
942 -- Try to reuse existent shared string
944 elsif Can_Be_Reused (SR, Count) then
945 if Count > SR.Last then
946 for J in SR.Last + 1 .. Count loop
947 SR.Data (J) := Pad;
948 end loop;
949 end if;
951 SR.Last := Count;
953 -- Otherwise, allocate new shared string and fill it
955 else
956 DR := Allocate (Count);
958 -- Length of the source string is greater then requested, copy
959 -- corresponding slice.
961 if Count < SR.Last then
962 DR.Data (1 .. Count) := SR.Data (1 .. Count);
964 -- Length of the source string is less the requested, copy all
965 -- exists data and fill others by Pad character.
967 else
968 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
970 for J in SR.Last + 1 .. Count loop
971 DR.Data (J) := Pad;
972 end loop;
973 end if;
975 DR.Last := Count;
976 Source.Reference := DR;
977 Unreference (SR);
978 end if;
979 end Head;
981 -----------
982 -- Index --
983 -----------
985 function Index
986 (Source : Unbounded_Wide_Wide_String;
987 Pattern : Wide_Wide_String;
988 Going : Strings.Direction := Strings.Forward;
989 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping :=
990 Wide_Wide_Maps.Identity)
991 return Natural
993 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
994 begin
995 return Wide_Wide_Search.Index
996 (SR.Data (1 .. SR.Last), Pattern, Going, Mapping);
997 end Index;
999 function Index
1000 (Source : Unbounded_Wide_Wide_String;
1001 Pattern : Wide_Wide_String;
1002 Going : Direction := Forward;
1003 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
1004 return Natural
1006 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1007 begin
1008 return Wide_Wide_Search.Index
1009 (SR.Data (1 .. SR.Last), Pattern, Going, Mapping);
1010 end Index;
1012 function Index
1013 (Source : Unbounded_Wide_Wide_String;
1014 Set : Wide_Wide_Maps.Wide_Wide_Character_Set;
1015 Test : Strings.Membership := Strings.Inside;
1016 Going : Strings.Direction := Strings.Forward) return Natural
1018 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1019 begin
1020 return Wide_Wide_Search.Index (SR.Data (1 .. SR.Last), Set, Test, Going);
1021 end Index;
1023 function Index
1024 (Source : Unbounded_Wide_Wide_String;
1025 Pattern : Wide_Wide_String;
1026 From : Positive;
1027 Going : Direction := Forward;
1028 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping :=
1029 Wide_Wide_Maps.Identity)
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 Pattern : Wide_Wide_String;
1041 From : Positive;
1042 Going : Direction := Forward;
1043 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
1044 return Natural
1046 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1047 begin
1048 return Wide_Wide_Search.Index
1049 (SR.Data (1 .. SR.Last), Pattern, From, Going, Mapping);
1050 end Index;
1052 function Index
1053 (Source : Unbounded_Wide_Wide_String;
1054 Set : Wide_Wide_Maps.Wide_Wide_Character_Set;
1055 From : Positive;
1056 Test : Membership := Inside;
1057 Going : Direction := Forward) return Natural
1059 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1060 begin
1061 return Wide_Wide_Search.Index
1062 (SR.Data (1 .. SR.Last), Set, From, Test, Going);
1063 end Index;
1065 ---------------------
1066 -- Index_Non_Blank --
1067 ---------------------
1069 function Index_Non_Blank
1070 (Source : Unbounded_Wide_Wide_String;
1071 Going : Strings.Direction := Strings.Forward) return Natural
1073 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1074 begin
1075 return Wide_Wide_Search.Index_Non_Blank (SR.Data (1 .. SR.Last), Going);
1076 end Index_Non_Blank;
1078 function Index_Non_Blank
1079 (Source : Unbounded_Wide_Wide_String;
1080 From : Positive;
1081 Going : Direction := Forward) return Natural
1083 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1084 begin
1085 return Wide_Wide_Search.Index_Non_Blank
1086 (SR.Data (1 .. SR.Last), From, Going);
1087 end Index_Non_Blank;
1089 ----------------
1090 -- Initialize --
1091 ----------------
1093 procedure Initialize (Object : in out Unbounded_Wide_Wide_String) is
1094 begin
1095 Reference (Object.Reference);
1096 end Initialize;
1098 ------------
1099 -- Insert --
1100 ------------
1102 function Insert
1103 (Source : Unbounded_Wide_Wide_String;
1104 Before : Positive;
1105 New_Item : Wide_Wide_String) return Unbounded_Wide_Wide_String
1107 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1108 DL : constant Natural := SR.Last + New_Item'Length;
1109 DR : Shared_Wide_Wide_String_Access;
1111 begin
1112 -- Check index first
1114 if Before > SR.Last + 1 then
1115 raise Index_Error;
1116 end if;
1118 -- Result is empty, reuse empty shared string
1120 if DL = 0 then
1121 Reference (Empty_Shared_Wide_Wide_String'Access);
1122 DR := Empty_Shared_Wide_Wide_String'Access;
1124 -- Inserted string is empty, reuse source shared string
1126 elsif New_Item'Length = 0 then
1127 Reference (SR);
1128 DR := SR;
1130 -- Otherwise, allocate new shared string and fill it
1132 else
1133 DR := Allocate (DL + DL / Growth_Factor);
1134 DR.Data (1 .. Before - 1) := SR.Data (1 .. Before - 1);
1135 DR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1136 DR.Data (Before + New_Item'Length .. DL) :=
1137 SR.Data (Before .. SR.Last);
1138 DR.Last := DL;
1139 end if;
1141 return (AF.Controlled with Reference => DR);
1142 end Insert;
1144 procedure Insert
1145 (Source : in out Unbounded_Wide_Wide_String;
1146 Before : Positive;
1147 New_Item : Wide_Wide_String)
1149 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1150 DL : constant Natural := SR.Last + New_Item'Length;
1151 DR : Shared_Wide_Wide_String_Access;
1153 begin
1154 -- Check bounds
1156 if Before > SR.Last + 1 then
1157 raise Index_Error;
1158 end if;
1160 -- Result is empty string, reuse empty shared string
1162 if DL = 0 then
1163 Reference (Empty_Shared_Wide_Wide_String'Access);
1164 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1165 Unreference (SR);
1167 -- Inserted string is empty, nothing to do
1169 elsif New_Item'Length = 0 then
1170 null;
1172 -- Try to reuse existent shared string first
1174 elsif Can_Be_Reused (SR, DL) then
1175 SR.Data (Before + New_Item'Length .. DL) :=
1176 SR.Data (Before .. SR.Last);
1177 SR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1178 SR.Last := DL;
1180 -- Otherwise, allocate new shared string and fill it
1182 else
1183 DR := Allocate (DL + DL / Growth_Factor);
1184 DR.Data (1 .. Before - 1) := SR.Data (1 .. Before - 1);
1185 DR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1186 DR.Data (Before + New_Item'Length .. DL) :=
1187 SR.Data (Before .. SR.Last);
1188 DR.Last := DL;
1189 Source.Reference := DR;
1190 Unreference (SR);
1191 end if;
1192 end Insert;
1194 ------------
1195 -- Length --
1196 ------------
1198 function Length (Source : Unbounded_Wide_Wide_String) return Natural is
1199 begin
1200 return Source.Reference.Last;
1201 end Length;
1203 ---------------
1204 -- Overwrite --
1205 ---------------
1207 function Overwrite
1208 (Source : Unbounded_Wide_Wide_String;
1209 Position : Positive;
1210 New_Item : Wide_Wide_String) return Unbounded_Wide_Wide_String
1212 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1213 DL : Natural;
1214 DR : Shared_Wide_Wide_String_Access;
1216 begin
1217 -- Check bounds
1219 if Position > SR.Last + 1 then
1220 raise Index_Error;
1221 end if;
1223 DL := Integer'Max (SR.Last, Position + New_Item'Length - 1);
1225 -- Result is empty string, reuse empty shared string
1227 if DL = 0 then
1228 Reference (Empty_Shared_Wide_Wide_String'Access);
1229 DR := Empty_Shared_Wide_Wide_String'Access;
1231 -- Result is same with source string, reuse source shared string
1233 elsif New_Item'Length = 0 then
1234 Reference (SR);
1235 DR := SR;
1237 -- Otherwise, allocate new shared string and fill it
1239 else
1240 DR := Allocate (DL);
1241 DR.Data (1 .. Position - 1) := SR.Data (1 .. Position - 1);
1242 DR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1243 DR.Data (Position + New_Item'Length .. DL) :=
1244 SR.Data (Position + New_Item'Length .. SR.Last);
1245 DR.Last := DL;
1246 end if;
1248 return (AF.Controlled with Reference => DR);
1249 end Overwrite;
1251 procedure Overwrite
1252 (Source : in out Unbounded_Wide_Wide_String;
1253 Position : Positive;
1254 New_Item : Wide_Wide_String)
1256 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1257 DL : Natural;
1258 DR : Shared_Wide_Wide_String_Access;
1260 begin
1261 -- Bounds check
1263 if Position > SR.Last + 1 then
1264 raise Index_Error;
1265 end if;
1267 DL := Integer'Max (SR.Last, Position + New_Item'Length - 1);
1269 -- Result is empty string, reuse empty shared string
1271 if DL = 0 then
1272 Reference (Empty_Shared_Wide_Wide_String'Access);
1273 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1274 Unreference (SR);
1276 -- String unchanged, nothing to do
1278 elsif New_Item'Length = 0 then
1279 null;
1281 -- Try to reuse existent shared string
1283 elsif Can_Be_Reused (SR, DL) then
1284 SR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1285 SR.Last := DL;
1287 -- Otherwise allocate new shared string and fill it
1289 else
1290 DR := Allocate (DL);
1291 DR.Data (1 .. Position - 1) := SR.Data (1 .. Position - 1);
1292 DR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1293 DR.Data (Position + New_Item'Length .. DL) :=
1294 SR.Data (Position + New_Item'Length .. SR.Last);
1295 DR.Last := DL;
1296 Source.Reference := DR;
1297 Unreference (SR);
1298 end if;
1299 end Overwrite;
1301 ---------------
1302 -- Reference --
1303 ---------------
1305 procedure Reference (Item : not null Shared_Wide_Wide_String_Access) is
1306 begin
1307 Sync_Add_And_Fetch (Item.Counter'Access, 1);
1308 end Reference;
1310 ---------------------
1311 -- Replace_Element --
1312 ---------------------
1314 procedure Replace_Element
1315 (Source : in out Unbounded_Wide_Wide_String;
1316 Index : Positive;
1317 By : Wide_Wide_Character)
1319 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1320 DR : Shared_Wide_Wide_String_Access;
1322 begin
1323 -- Bounds check.
1325 if Index <= SR.Last then
1327 -- Try to reuse existent shared string
1329 if Can_Be_Reused (SR, SR.Last) then
1330 SR.Data (Index) := By;
1332 -- Otherwise allocate new shared string and fill it
1334 else
1335 DR := Allocate (SR.Last);
1336 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
1337 DR.Data (Index) := By;
1338 DR.Last := SR.Last;
1339 Source.Reference := DR;
1340 Unreference (SR);
1341 end if;
1343 else
1344 raise Index_Error;
1345 end if;
1346 end Replace_Element;
1348 -------------------
1349 -- Replace_Slice --
1350 -------------------
1352 function Replace_Slice
1353 (Source : Unbounded_Wide_Wide_String;
1354 Low : Positive;
1355 High : Natural;
1356 By : Wide_Wide_String) return Unbounded_Wide_Wide_String
1358 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1359 DL : Natural;
1360 DR : Shared_Wide_Wide_String_Access;
1362 begin
1363 -- Check bounds
1365 if Low > SR.Last + 1 then
1366 raise Index_Error;
1367 end if;
1369 -- Do replace operation when removed slice is not empty
1371 if High >= Low then
1372 DL := By'Length + SR.Last + Low - High - 1;
1374 -- Result is empty string, reuse empty shared string
1376 if DL = 0 then
1377 Reference (Empty_Shared_Wide_Wide_String'Access);
1378 DR := Empty_Shared_Wide_Wide_String'Access;
1380 -- Otherwise allocate new shared string and fill it
1382 else
1383 DR := Allocate (DL);
1384 DR.Data (1 .. Low - 1) := SR.Data (1 .. Low - 1);
1385 DR.Data (Low .. Low + By'Length - 1) := By;
1386 DR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1387 DR.Last := DL;
1388 end if;
1390 return (AF.Controlled with Reference => DR);
1392 -- Otherwise just insert string
1394 else
1395 return Insert (Source, Low, By);
1396 end if;
1397 end Replace_Slice;
1399 procedure Replace_Slice
1400 (Source : in out Unbounded_Wide_Wide_String;
1401 Low : Positive;
1402 High : Natural;
1403 By : Wide_Wide_String)
1405 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1406 DL : Natural;
1407 DR : Shared_Wide_Wide_String_Access;
1409 begin
1410 -- Bounds check
1412 if Low > SR.Last + 1 then
1413 raise Index_Error;
1414 end if;
1416 -- Do replace operation only when replaced slice is not empty
1418 if High >= Low then
1419 DL := By'Length + SR.Last + Low - High - 1;
1421 -- Result is empty string, reuse empty shared string
1423 if DL = 0 then
1424 Reference (Empty_Shared_Wide_Wide_String'Access);
1425 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1426 Unreference (SR);
1428 -- Try to reuse existent shared string
1430 elsif Can_Be_Reused (SR, DL) then
1431 SR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1432 SR.Data (Low .. Low + By'Length - 1) := By;
1433 SR.Last := DL;
1435 -- Otherwise allocate new shared string and fill it
1437 else
1438 DR := Allocate (DL);
1439 DR.Data (1 .. Low - 1) := SR.Data (1 .. Low - 1);
1440 DR.Data (Low .. Low + By'Length - 1) := By;
1441 DR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1442 DR.Last := DL;
1443 Source.Reference := DR;
1444 Unreference (SR);
1445 end if;
1447 -- Otherwise just insert item
1449 else
1450 Insert (Source, Low, By);
1451 end if;
1452 end Replace_Slice;
1454 -------------------------------
1455 -- Set_Unbounded_Wide_Wide_String --
1456 -------------------------------
1458 procedure Set_Unbounded_Wide_Wide_String
1459 (Target : out Unbounded_Wide_Wide_String;
1460 Source : Wide_Wide_String)
1462 TR : constant Shared_Wide_Wide_String_Access := Target.Reference;
1463 DR : Shared_Wide_Wide_String_Access;
1465 begin
1466 -- In case of empty string, reuse empty shared string
1468 if Source'Length = 0 then
1469 Reference (Empty_Shared_Wide_Wide_String'Access);
1470 Target.Reference := Empty_Shared_Wide_Wide_String'Access;
1472 else
1473 -- Try to reuse existent shared string
1475 if Can_Be_Reused (TR, Source'Length) then
1476 Reference (TR);
1477 DR := TR;
1479 -- Otherwise allocate new shared string
1481 else
1482 DR := Allocate (Source'Length);
1483 Target.Reference := DR;
1484 end if;
1486 DR.Data (1 .. Source'Length) := Source;
1487 DR.Last := Source'Length;
1488 end if;
1490 Unreference (TR);
1491 end Set_Unbounded_Wide_Wide_String;
1493 -----------
1494 -- Slice --
1495 -----------
1497 function Slice
1498 (Source : Unbounded_Wide_Wide_String;
1499 Low : Positive;
1500 High : Natural) return Wide_Wide_String
1502 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1504 begin
1505 -- Note: test of High > Length is in accordance with AI95-00128
1507 if Low > SR.Last + 1 or else High > SR.Last then
1508 raise Index_Error;
1510 else
1511 return SR.Data (Low .. High);
1512 end if;
1513 end Slice;
1515 ----------
1516 -- Tail --
1517 ----------
1519 function Tail
1520 (Source : Unbounded_Wide_Wide_String;
1521 Count : Natural;
1522 Pad : Wide_Wide_Character := Wide_Wide_Space)
1523 return Unbounded_Wide_Wide_String
1525 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1526 DR : Shared_Wide_Wide_String_Access;
1528 begin
1529 -- For empty result reuse empty shared string
1531 if Count = 0 then
1532 Reference (Empty_Shared_Wide_Wide_String'Access);
1533 DR := Empty_Shared_Wide_Wide_String'Access;
1535 -- Result is hole source string, reuse source shared string
1537 elsif Count = SR.Last then
1538 Reference (SR);
1539 DR := SR;
1541 -- Otherwise allocate new shared string and fill it
1543 else
1544 DR := Allocate (Count);
1546 if Count < SR.Last then
1547 DR.Data (1 .. Count) := SR.Data (SR.Last - Count + 1 .. SR.Last);
1549 else
1550 for J in 1 .. Count - SR.Last loop
1551 DR.Data (J) := Pad;
1552 end loop;
1554 DR.Data (Count - SR.Last + 1 .. Count) := SR.Data (1 .. SR.Last);
1555 end if;
1557 DR.Last := Count;
1558 end if;
1560 return (AF.Controlled with Reference => DR);
1561 end Tail;
1563 procedure Tail
1564 (Source : in out Unbounded_Wide_Wide_String;
1565 Count : Natural;
1566 Pad : Wide_Wide_Character := Wide_Wide_Space)
1568 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1569 DR : Shared_Wide_Wide_String_Access;
1571 procedure Common
1572 (SR : Shared_Wide_Wide_String_Access;
1573 DR : Shared_Wide_Wide_String_Access;
1574 Count : Natural);
1575 -- Common code of tail computation. SR/DR can point to the same object
1577 ------------
1578 -- Common --
1579 ------------
1581 procedure Common
1582 (SR : Shared_Wide_Wide_String_Access;
1583 DR : Shared_Wide_Wide_String_Access;
1584 Count : Natural) is
1585 begin
1586 if Count < SR.Last then
1587 DR.Data (1 .. Count) := SR.Data (SR.Last - Count + 1 .. SR.Last);
1589 else
1590 DR.Data (Count - SR.Last + 1 .. Count) := SR.Data (1 .. SR.Last);
1592 for J in 1 .. Count - SR.Last loop
1593 DR.Data (J) := Pad;
1594 end loop;
1595 end if;
1597 DR.Last := Count;
1598 end Common;
1600 begin
1601 -- Result is empty string, reuse empty shared string
1603 if Count = 0 then
1604 Reference (Empty_Shared_Wide_Wide_String'Access);
1605 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1606 Unreference (SR);
1608 -- Length of the result is the same with length of the source string,
1609 -- reuse source shared string.
1611 elsif Count = SR.Last then
1612 null;
1614 -- Try to reuse existent shared string
1616 elsif Can_Be_Reused (SR, Count) then
1617 Common (SR, SR, Count);
1619 -- Otherwise allocate new shared string and fill it
1621 else
1622 DR := Allocate (Count);
1623 Common (SR, DR, Count);
1624 Source.Reference := DR;
1625 Unreference (SR);
1626 end if;
1627 end Tail;
1629 --------------------
1630 -- To_Wide_Wide_String --
1631 --------------------
1633 function To_Wide_Wide_String
1634 (Source : Unbounded_Wide_Wide_String) return Wide_Wide_String is
1635 begin
1636 return Source.Reference.Data (1 .. Source.Reference.Last);
1637 end To_Wide_Wide_String;
1639 ------------------------------
1640 -- To_Unbounded_Wide_Wide_String --
1641 ------------------------------
1643 function To_Unbounded_Wide_Wide_String
1644 (Source : Wide_Wide_String) return Unbounded_Wide_Wide_String
1646 DR : constant Shared_Wide_Wide_String_Access := Allocate (Source'Length);
1647 begin
1648 DR.Data (1 .. Source'Length) := Source;
1649 DR.Last := Source'Length;
1650 return (AF.Controlled with Reference => DR);
1651 end To_Unbounded_Wide_Wide_String;
1653 function To_Unbounded_Wide_Wide_String
1654 (Length : Natural) return Unbounded_Wide_Wide_String
1656 DR : constant Shared_Wide_Wide_String_Access := Allocate (Length);
1657 begin
1658 DR.Last := Length;
1659 return (AF.Controlled with Reference => DR);
1660 end To_Unbounded_Wide_Wide_String;
1662 ---------------
1663 -- Translate --
1664 ---------------
1666 function Translate
1667 (Source : Unbounded_Wide_Wide_String;
1668 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping)
1669 return Unbounded_Wide_Wide_String
1671 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1672 DR : Shared_Wide_Wide_String_Access;
1674 begin
1675 -- Nothing to translate, reuse empty shared string
1677 if SR.Last = 0 then
1678 Reference (Empty_Shared_Wide_Wide_String'Access);
1679 DR := Empty_Shared_Wide_Wide_String'Access;
1681 -- Otherwise, allocate new shared string and fill it
1683 else
1684 DR := Allocate (SR.Last);
1686 for J in 1 .. SR.Last loop
1687 DR.Data (J) := Value (Mapping, SR.Data (J));
1688 end loop;
1690 DR.Last := SR.Last;
1691 end if;
1693 return (AF.Controlled with Reference => DR);
1694 end Translate;
1696 procedure Translate
1697 (Source : in out Unbounded_Wide_Wide_String;
1698 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping)
1700 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1701 DR : Shared_Wide_Wide_String_Access;
1703 begin
1704 -- Nothing to translate
1706 if SR.Last = 0 then
1707 null;
1709 -- Try to reuse shared string
1711 elsif Can_Be_Reused (SR, SR.Last) then
1712 for J in 1 .. SR.Last loop
1713 SR.Data (J) := Value (Mapping, SR.Data (J));
1714 end loop;
1716 -- Otherwise, allocate new shared string
1718 else
1719 DR := Allocate (SR.Last);
1721 for J in 1 .. SR.Last loop
1722 DR.Data (J) := Value (Mapping, SR.Data (J));
1723 end loop;
1725 DR.Last := SR.Last;
1726 Source.Reference := DR;
1727 Unreference (SR);
1728 end if;
1729 end Translate;
1731 function Translate
1732 (Source : Unbounded_Wide_Wide_String;
1733 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
1734 return Unbounded_Wide_Wide_String
1736 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1737 DR : Shared_Wide_Wide_String_Access;
1739 begin
1740 -- Nothing to translate, reuse empty shared string
1742 if SR.Last = 0 then
1743 Reference (Empty_Shared_Wide_Wide_String'Access);
1744 DR := Empty_Shared_Wide_Wide_String'Access;
1746 -- Otherwise, allocate new shared string and fill it
1748 else
1749 DR := Allocate (SR.Last);
1751 for J in 1 .. SR.Last loop
1752 DR.Data (J) := Mapping.all (SR.Data (J));
1753 end loop;
1755 DR.Last := SR.Last;
1756 end if;
1758 return (AF.Controlled with Reference => DR);
1760 exception
1761 when others =>
1762 Unreference (DR);
1764 raise;
1765 end Translate;
1767 procedure Translate
1768 (Source : in out Unbounded_Wide_Wide_String;
1769 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
1771 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1772 DR : Shared_Wide_Wide_String_Access;
1774 begin
1775 -- Nothing to translate
1777 if SR.Last = 0 then
1778 null;
1780 -- Try to reuse shared string
1782 elsif Can_Be_Reused (SR, SR.Last) then
1783 for J in 1 .. SR.Last loop
1784 SR.Data (J) := Mapping.all (SR.Data (J));
1785 end loop;
1787 -- Otherwise allocate new shared string and fill it
1789 else
1790 DR := Allocate (SR.Last);
1792 for J in 1 .. SR.Last loop
1793 DR.Data (J) := Mapping.all (SR.Data (J));
1794 end loop;
1796 DR.Last := SR.Last;
1797 Source.Reference := DR;
1798 Unreference (SR);
1799 end if;
1801 exception
1802 when others =>
1803 if DR /= null then
1804 Unreference (DR);
1805 end if;
1807 raise;
1808 end Translate;
1810 ----------
1811 -- Trim --
1812 ----------
1814 function Trim
1815 (Source : Unbounded_Wide_Wide_String;
1816 Side : Trim_End) return Unbounded_Wide_Wide_String
1818 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1819 DL : Natural;
1820 DR : Shared_Wide_Wide_String_Access;
1821 Low : Natural;
1822 High : Natural;
1824 begin
1825 Low := Index_Non_Blank (Source, Forward);
1827 -- All blanks, reuse empty shared string
1829 if Low = 0 then
1830 Reference (Empty_Shared_Wide_Wide_String'Access);
1831 DR := Empty_Shared_Wide_Wide_String'Access;
1833 else
1834 case Side is
1835 when Left =>
1836 High := SR.Last;
1837 DL := SR.Last - Low + 1;
1839 when Right =>
1840 Low := 1;
1841 High := Index_Non_Blank (Source, Backward);
1842 DL := High;
1844 when Both =>
1845 High := Index_Non_Blank (Source, Backward);
1846 DL := High - Low + 1;
1847 end case;
1849 -- Length of the result is the same as length of the source string,
1850 -- reuse source shared string.
1852 if DL = SR.Last then
1853 Reference (SR);
1854 DR := SR;
1856 -- Otherwise, allocate new shared string
1858 else
1859 DR := Allocate (DL);
1860 DR.Data (1 .. DL) := SR.Data (Low .. High);
1861 DR.Last := DL;
1862 end if;
1863 end if;
1865 return (AF.Controlled with Reference => DR);
1866 end Trim;
1868 procedure Trim
1869 (Source : in out Unbounded_Wide_Wide_String;
1870 Side : Trim_End)
1872 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1873 DL : Natural;
1874 DR : Shared_Wide_Wide_String_Access;
1875 Low : Natural;
1876 High : Natural;
1878 begin
1879 Low := Index_Non_Blank (Source, Forward);
1881 -- All blanks, reuse empty shared string
1883 if Low = 0 then
1884 Reference (Empty_Shared_Wide_Wide_String'Access);
1885 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1886 Unreference (SR);
1888 else
1889 case Side is
1890 when Left =>
1891 High := SR.Last;
1892 DL := SR.Last - Low + 1;
1894 when Right =>
1895 Low := 1;
1896 High := Index_Non_Blank (Source, Backward);
1897 DL := High;
1899 when Both =>
1900 High := Index_Non_Blank (Source, Backward);
1901 DL := High - Low + 1;
1902 end case;
1904 -- Length of the result is the same as length of the source string,
1905 -- nothing to do.
1907 if DL = SR.Last then
1908 null;
1910 -- Try to reuse existent shared string
1912 elsif Can_Be_Reused (SR, DL) then
1913 SR.Data (1 .. DL) := SR.Data (Low .. High);
1914 SR.Last := DL;
1916 -- Otherwise, allocate new shared string
1918 else
1919 DR := Allocate (DL);
1920 DR.Data (1 .. DL) := SR.Data (Low .. High);
1921 DR.Last := DL;
1922 Source.Reference := DR;
1923 Unreference (SR);
1924 end if;
1925 end if;
1926 end Trim;
1928 function Trim
1929 (Source : Unbounded_Wide_Wide_String;
1930 Left : Wide_Wide_Maps.Wide_Wide_Character_Set;
1931 Right : Wide_Wide_Maps.Wide_Wide_Character_Set)
1932 return Unbounded_Wide_Wide_String
1934 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1935 DL : Natural;
1936 DR : Shared_Wide_Wide_String_Access;
1937 Low : Natural;
1938 High : Natural;
1940 begin
1941 Low := Index (Source, Left, Outside, Forward);
1943 -- Source includes only characters from Left set, reuse empty shared
1944 -- string.
1946 if Low = 0 then
1947 Reference (Empty_Shared_Wide_Wide_String'Access);
1948 DR := Empty_Shared_Wide_Wide_String'Access;
1950 else
1951 High := Index (Source, Right, Outside, Backward);
1952 DL := Integer'Max (0, High - Low + 1);
1954 -- Source includes only characters from Right set or result string
1955 -- is empty, reuse empty shared string.
1957 if High = 0 or else DL = 0 then
1958 Reference (Empty_Shared_Wide_Wide_String'Access);
1959 DR := Empty_Shared_Wide_Wide_String'Access;
1961 -- Otherwise, allocate new shared string and fill it
1963 else
1964 DR := Allocate (DL);
1965 DR.Data (1 .. DL) := SR.Data (Low .. High);
1966 DR.Last := DL;
1967 end if;
1968 end if;
1970 return (AF.Controlled with Reference => DR);
1971 end Trim;
1973 procedure Trim
1974 (Source : in out Unbounded_Wide_Wide_String;
1975 Left : Wide_Wide_Maps.Wide_Wide_Character_Set;
1976 Right : Wide_Wide_Maps.Wide_Wide_Character_Set)
1978 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1979 DL : Natural;
1980 DR : Shared_Wide_Wide_String_Access;
1981 Low : Natural;
1982 High : Natural;
1984 begin
1985 Low := Index (Source, Left, Outside, Forward);
1987 -- Source includes only characters from Left set, reuse empty shared
1988 -- string.
1990 if Low = 0 then
1991 Reference (Empty_Shared_Wide_Wide_String'Access);
1992 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1993 Unreference (SR);
1995 else
1996 High := Index (Source, Right, Outside, Backward);
1997 DL := Integer'Max (0, High - Low + 1);
1999 -- Source includes only characters from Right set or result string
2000 -- is empty, reuse empty shared string.
2002 if High = 0 or else DL = 0 then
2003 Reference (Empty_Shared_Wide_Wide_String'Access);
2004 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
2005 Unreference (SR);
2007 -- Try to reuse existent shared string
2009 elsif Can_Be_Reused (SR, DL) then
2010 SR.Data (1 .. DL) := SR.Data (Low .. High);
2011 SR.Last := DL;
2013 -- Otherwise, allocate new shared string and fill it
2015 else
2016 DR := Allocate (DL);
2017 DR.Data (1 .. DL) := SR.Data (Low .. High);
2018 DR.Last := DL;
2019 Source.Reference := DR;
2020 Unreference (SR);
2021 end if;
2022 end if;
2023 end Trim;
2025 ---------------------
2026 -- Unbounded_Slice --
2027 ---------------------
2029 function Unbounded_Slice
2030 (Source : Unbounded_Wide_Wide_String;
2031 Low : Positive;
2032 High : Natural) return Unbounded_Wide_Wide_String
2034 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
2035 DL : Natural;
2036 DR : Shared_Wide_Wide_String_Access;
2038 begin
2039 -- Check bounds
2041 if Low > SR.Last + 1 or else High > SR.Last then
2042 raise Index_Error;
2044 -- Result is empty slice, reuse empty shared string
2046 elsif Low > High then
2047 Reference (Empty_Shared_Wide_Wide_String'Access);
2048 DR := Empty_Shared_Wide_Wide_String'Access;
2050 -- Otherwise, allocate new shared string and fill it
2052 else
2053 DL := High - Low + 1;
2054 DR := Allocate (DL);
2055 DR.Data (1 .. DL) := SR.Data (Low .. High);
2056 DR.Last := DL;
2057 end if;
2059 return (AF.Controlled with Reference => DR);
2060 end Unbounded_Slice;
2062 procedure Unbounded_Slice
2063 (Source : Unbounded_Wide_Wide_String;
2064 Target : out Unbounded_Wide_Wide_String;
2065 Low : Positive;
2066 High : Natural)
2068 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
2069 TR : constant Shared_Wide_Wide_String_Access := Target.Reference;
2070 DL : Natural;
2071 DR : Shared_Wide_Wide_String_Access;
2073 begin
2074 -- Check bounds
2076 if Low > SR.Last + 1 or else High > SR.Last then
2077 raise Index_Error;
2079 -- Result is empty slice, reuse empty shared string
2081 elsif Low > High then
2082 Reference (Empty_Shared_Wide_Wide_String'Access);
2083 Target.Reference := Empty_Shared_Wide_Wide_String'Access;
2084 Unreference (TR);
2086 else
2087 DL := High - Low + 1;
2089 -- Try to reuse existent shared string
2091 if Can_Be_Reused (TR, DL) then
2092 TR.Data (1 .. DL) := SR.Data (Low .. High);
2093 TR.Last := DL;
2095 -- Otherwise, allocate new shared string and fill it
2097 else
2098 DR := Allocate (DL);
2099 DR.Data (1 .. DL) := SR.Data (Low .. High);
2100 DR.Last := DL;
2101 Target.Reference := DR;
2102 Unreference (TR);
2103 end if;
2104 end if;
2105 end Unbounded_Slice;
2107 -----------------
2108 -- Unreference --
2109 -----------------
2111 procedure Unreference (Item : not null Shared_Wide_Wide_String_Access) is
2112 use Interfaces;
2114 procedure Free is
2115 new Ada.Unchecked_Deallocation
2116 (Shared_Wide_Wide_String, Shared_Wide_Wide_String_Access);
2118 Aux : Shared_Wide_Wide_String_Access := Item;
2120 begin
2121 if Sync_Sub_And_Fetch (Aux.Counter'Access, 1) = 0 then
2123 -- Reference counter of Empty_Shared_Wide_Wide_String must never
2124 -- reach zero.
2126 pragma Assert (Aux /= Empty_Shared_Wide_Wide_String'Access);
2128 Free (Aux);
2129 end if;
2130 end Unreference;
2132 end Ada.Strings.Wide_Wide_Unbounded;