2013-11-13 Jan-Benedict Glaw <jbglaw@lug-owl.de>
[official-gcc.git] / gcc / ada / a-stzunb-shared.adb
blob37ab295369ea6dd495641b43391f3dc6e4d0989c
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-2012, 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 function Aligned_Max_Length (Max_Length : Natural) return Natural;
54 -- Returns recommended length of the shared string which is greater or
55 -- equal to specified length. Calculation take in sense alignment of
56 -- the allocated memory segments to use memory effectively by
57 -- Append/Insert/etc operations.
59 ---------
60 -- "&" --
61 ---------
63 function "&"
64 (Left : Unbounded_Wide_Wide_String;
65 Right : Unbounded_Wide_Wide_String) return Unbounded_Wide_Wide_String
67 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
68 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
69 DL : constant Natural := LR.Last + RR.Last;
70 DR : Shared_Wide_Wide_String_Access;
72 begin
73 -- Result is an empty string, reuse shared empty string
75 if DL = 0 then
76 Reference (Empty_Shared_Wide_Wide_String'Access);
77 DR := Empty_Shared_Wide_Wide_String'Access;
79 -- Left string is empty, return Rigth string
81 elsif LR.Last = 0 then
82 Reference (RR);
83 DR := RR;
85 -- Right string is empty, return Left string
87 elsif RR.Last = 0 then
88 Reference (LR);
89 DR := LR;
91 -- Overwise, allocate new shared string and fill data
93 else
94 DR := Allocate (LR.Last + RR.Last);
95 DR.Data (1 .. LR.Last) := LR.Data (1 .. LR.Last);
96 DR.Data (LR.Last + 1 .. DL) := RR.Data (1 .. RR.Last);
97 DR.Last := DL;
98 end if;
100 return (AF.Controlled with Reference => DR);
101 end "&";
103 function "&"
104 (Left : Unbounded_Wide_Wide_String;
105 Right : Wide_Wide_String) return Unbounded_Wide_Wide_String
107 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
108 DL : constant Natural := LR.Last + Right'Length;
109 DR : Shared_Wide_Wide_String_Access;
111 begin
112 -- Result is an empty string, reuse shared empty string
114 if DL = 0 then
115 Reference (Empty_Shared_Wide_Wide_String'Access);
116 DR := Empty_Shared_Wide_Wide_String'Access;
118 -- Right is an empty string, return Left string
120 elsif Right'Length = 0 then
121 Reference (LR);
122 DR := LR;
124 -- Otherwise, allocate new shared string and fill it
126 else
127 DR := Allocate (DL);
128 DR.Data (1 .. LR.Last) := LR.Data (1 .. LR.Last);
129 DR.Data (LR.Last + 1 .. DL) := Right;
130 DR.Last := DL;
131 end if;
133 return (AF.Controlled with Reference => DR);
134 end "&";
136 function "&"
137 (Left : Wide_Wide_String;
138 Right : Unbounded_Wide_Wide_String) return Unbounded_Wide_Wide_String
140 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
141 DL : constant Natural := Left'Length + RR.Last;
142 DR : Shared_Wide_Wide_String_Access;
144 begin
145 -- Result is an empty string, reuse shared one
147 if DL = 0 then
148 Reference (Empty_Shared_Wide_Wide_String'Access);
149 DR := Empty_Shared_Wide_Wide_String'Access;
151 -- Left is empty string, return Right string
153 elsif Left'Length = 0 then
154 Reference (RR);
155 DR := RR;
157 -- Otherwise, allocate new shared string and fill it
159 else
160 DR := Allocate (DL);
161 DR.Data (1 .. Left'Length) := Left;
162 DR.Data (Left'Length + 1 .. DL) := RR.Data (1 .. RR.Last);
163 DR.Last := DL;
164 end if;
166 return (AF.Controlled with Reference => DR);
167 end "&";
169 function "&"
170 (Left : Unbounded_Wide_Wide_String;
171 Right : Wide_Wide_Character) return Unbounded_Wide_Wide_String
173 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
174 DL : constant Natural := LR.Last + 1;
175 DR : Shared_Wide_Wide_String_Access;
177 begin
178 DR := Allocate (DL);
179 DR.Data (1 .. LR.Last) := LR.Data (1 .. LR.Last);
180 DR.Data (DL) := Right;
181 DR.Last := DL;
183 return (AF.Controlled with Reference => DR);
184 end "&";
186 function "&"
187 (Left : Wide_Wide_Character;
188 Right : Unbounded_Wide_Wide_String) return Unbounded_Wide_Wide_String
190 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
191 DL : constant Natural := 1 + RR.Last;
192 DR : Shared_Wide_Wide_String_Access;
194 begin
195 DR := Allocate (DL);
196 DR.Data (1) := Left;
197 DR.Data (2 .. DL) := RR.Data (1 .. RR.Last);
198 DR.Last := DL;
200 return (AF.Controlled with Reference => DR);
201 end "&";
203 ---------
204 -- "*" --
205 ---------
207 function "*"
208 (Left : Natural;
209 Right : Wide_Wide_Character) return Unbounded_Wide_Wide_String
211 DR : Shared_Wide_Wide_String_Access;
213 begin
214 -- Result is an empty string, reuse shared empty string
216 if Left = 0 then
217 Reference (Empty_Shared_Wide_Wide_String'Access);
218 DR := Empty_Shared_Wide_Wide_String'Access;
220 -- Otherwise, allocate new shared string and fill it
222 else
223 DR := Allocate (Left);
225 for J in 1 .. Left loop
226 DR.Data (J) := Right;
227 end loop;
229 DR.Last := Left;
230 end if;
232 return (AF.Controlled with Reference => DR);
233 end "*";
235 function "*"
236 (Left : Natural;
237 Right : Wide_Wide_String) return Unbounded_Wide_Wide_String
239 DL : constant Natural := Left * Right'Length;
240 DR : Shared_Wide_Wide_String_Access;
241 K : Positive;
243 begin
244 -- Result is an empty string, reuse shared empty string
246 if DL = 0 then
247 Reference (Empty_Shared_Wide_Wide_String'Access);
248 DR := Empty_Shared_Wide_Wide_String'Access;
250 -- Otherwise, allocate new shared string and fill it
252 else
253 DR := Allocate (DL);
254 K := 1;
256 for J in 1 .. Left loop
257 DR.Data (K .. K + Right'Length - 1) := Right;
258 K := K + Right'Length;
259 end loop;
261 DR.Last := DL;
262 end if;
264 return (AF.Controlled with Reference => DR);
265 end "*";
267 function "*"
268 (Left : Natural;
269 Right : Unbounded_Wide_Wide_String) return Unbounded_Wide_Wide_String
271 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
272 DL : constant Natural := Left * RR.Last;
273 DR : Shared_Wide_Wide_String_Access;
274 K : Positive;
276 begin
277 -- Result is an empty string, reuse shared empty string
279 if DL = 0 then
280 Reference (Empty_Shared_Wide_Wide_String'Access);
281 DR := Empty_Shared_Wide_Wide_String'Access;
283 -- Coefficient is one, just return string itself
285 elsif Left = 1 then
286 Reference (RR);
287 DR := RR;
289 -- Otherwise, allocate new shared string and fill it
291 else
292 DR := Allocate (DL);
293 K := 1;
295 for J in 1 .. Left loop
296 DR.Data (K .. K + RR.Last - 1) := RR.Data (1 .. RR.Last);
297 K := K + RR.Last;
298 end loop;
300 DR.Last := DL;
301 end if;
303 return (AF.Controlled with Reference => DR);
304 end "*";
306 ---------
307 -- "<" --
308 ---------
310 function "<"
311 (Left : Unbounded_Wide_Wide_String;
312 Right : Unbounded_Wide_Wide_String) return Boolean
314 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
315 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
316 begin
317 return LR.Data (1 .. LR.Last) < RR.Data (1 .. RR.Last);
318 end "<";
320 function "<"
321 (Left : Unbounded_Wide_Wide_String;
322 Right : Wide_Wide_String) return Boolean
324 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
325 begin
326 return LR.Data (1 .. LR.Last) < Right;
327 end "<";
329 function "<"
330 (Left : Wide_Wide_String;
331 Right : Unbounded_Wide_Wide_String) return Boolean
333 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
334 begin
335 return Left < RR.Data (1 .. RR.Last);
336 end "<";
338 ----------
339 -- "<=" --
340 ----------
342 function "<="
343 (Left : Unbounded_Wide_Wide_String;
344 Right : Unbounded_Wide_Wide_String) return Boolean
346 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
347 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
349 begin
350 -- LR = RR means two strings shares shared string, thus they are equal
352 return LR = RR or else LR.Data (1 .. LR.Last) <= RR.Data (1 .. RR.Last);
353 end "<=";
355 function "<="
356 (Left : Unbounded_Wide_Wide_String;
357 Right : Wide_Wide_String) return Boolean
359 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
360 begin
361 return LR.Data (1 .. LR.Last) <= Right;
362 end "<=";
364 function "<="
365 (Left : Wide_Wide_String;
366 Right : Unbounded_Wide_Wide_String) return Boolean
368 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
369 begin
370 return Left <= RR.Data (1 .. RR.Last);
371 end "<=";
373 ---------
374 -- "=" --
375 ---------
377 function "="
378 (Left : Unbounded_Wide_Wide_String;
379 Right : Unbounded_Wide_Wide_String) return Boolean
381 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
382 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
384 begin
385 return LR = RR or else LR.Data (1 .. LR.Last) = RR.Data (1 .. RR.Last);
386 -- LR = RR means two strings shares shared string, thus they are equal
387 end "=";
389 function "="
390 (Left : Unbounded_Wide_Wide_String;
391 Right : Wide_Wide_String) return Boolean
393 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
394 begin
395 return LR.Data (1 .. LR.Last) = Right;
396 end "=";
398 function "="
399 (Left : Wide_Wide_String;
400 Right : Unbounded_Wide_Wide_String) return Boolean
402 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
403 begin
404 return Left = RR.Data (1 .. RR.Last);
405 end "=";
407 ---------
408 -- ">" --
409 ---------
411 function ">"
412 (Left : Unbounded_Wide_Wide_String;
413 Right : Unbounded_Wide_Wide_String) return Boolean
415 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
416 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
417 begin
418 return LR.Data (1 .. LR.Last) > RR.Data (1 .. RR.Last);
419 end ">";
421 function ">"
422 (Left : Unbounded_Wide_Wide_String;
423 Right : Wide_Wide_String) return Boolean
425 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
426 begin
427 return LR.Data (1 .. LR.Last) > Right;
428 end ">";
430 function ">"
431 (Left : Wide_Wide_String;
432 Right : Unbounded_Wide_Wide_String) return Boolean
434 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
435 begin
436 return Left > RR.Data (1 .. RR.Last);
437 end ">";
439 ----------
440 -- ">=" --
441 ----------
443 function ">="
444 (Left : Unbounded_Wide_Wide_String;
445 Right : Unbounded_Wide_Wide_String) return Boolean
447 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
448 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
450 begin
451 -- LR = RR means two strings shares shared string, thus they are equal
453 return LR = RR or else LR.Data (1 .. LR.Last) >= RR.Data (1 .. RR.Last);
454 end ">=";
456 function ">="
457 (Left : Unbounded_Wide_Wide_String;
458 Right : Wide_Wide_String) return Boolean
460 LR : constant Shared_Wide_Wide_String_Access := Left.Reference;
461 begin
462 return LR.Data (1 .. LR.Last) >= Right;
463 end ">=";
465 function ">="
466 (Left : Wide_Wide_String;
467 Right : Unbounded_Wide_Wide_String) return Boolean
469 RR : constant Shared_Wide_Wide_String_Access := Right.Reference;
470 begin
471 return Left >= RR.Data (1 .. RR.Last);
472 end ">=";
474 ------------
475 -- Adjust --
476 ------------
478 procedure Adjust (Object : in out Unbounded_Wide_Wide_String) is
479 begin
480 Reference (Object.Reference);
481 end Adjust;
483 ------------------------
484 -- Aligned_Max_Length --
485 ------------------------
487 function Aligned_Max_Length (Max_Length : Natural) return Natural is
488 Static_Size : constant Natural :=
489 Empty_Shared_Wide_Wide_String'Size / Standard'Storage_Unit;
490 -- Total size of all static components
492 Element_Size : constant Natural :=
493 Wide_Wide_Character'Size / Standard'Storage_Unit;
495 begin
496 return
497 (((Static_Size + Max_Length * Element_Size - 1) / Min_Mul_Alloc + 2)
498 * Min_Mul_Alloc - Static_Size) / Element_Size;
499 end Aligned_Max_Length;
501 --------------
502 -- Allocate --
503 --------------
505 function Allocate
506 (Max_Length : Natural) return Shared_Wide_Wide_String_Access is
507 begin
508 -- Empty string requested, return shared empty string
510 if Max_Length = 0 then
511 Reference (Empty_Shared_Wide_Wide_String'Access);
512 return Empty_Shared_Wide_Wide_String'Access;
514 -- Otherwise, allocate requested space (and probably some more room)
516 else
517 return new Shared_Wide_Wide_String (Aligned_Max_Length (Max_Length));
518 end if;
519 end Allocate;
521 ------------
522 -- Append --
523 ------------
525 procedure Append
526 (Source : in out Unbounded_Wide_Wide_String;
527 New_Item : Unbounded_Wide_Wide_String)
529 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
530 NR : constant Shared_Wide_Wide_String_Access := New_Item.Reference;
531 DL : constant Natural := SR.Last + NR.Last;
532 DR : Shared_Wide_Wide_String_Access;
534 begin
535 -- Source is an empty string, reuse New_Item data
537 if SR.Last = 0 then
538 Reference (NR);
539 Source.Reference := NR;
540 Unreference (SR);
542 -- New_Item is empty string, nothing to do
544 elsif NR.Last = 0 then
545 null;
547 -- Try to reuse existent shared string
549 elsif Can_Be_Reused (SR, DL) then
550 SR.Data (SR.Last + 1 .. DL) := NR.Data (1 .. NR.Last);
551 SR.Last := DL;
553 -- Otherwise, allocate new one and fill it
555 else
556 DR := Allocate (DL + DL / Growth_Factor);
557 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
558 DR.Data (SR.Last + 1 .. DL) := NR.Data (1 .. NR.Last);
559 DR.Last := DL;
560 Source.Reference := DR;
561 Unreference (SR);
562 end if;
563 end Append;
565 procedure Append
566 (Source : in out Unbounded_Wide_Wide_String;
567 New_Item : Wide_Wide_String)
569 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
570 DL : constant Natural := SR.Last + New_Item'Length;
571 DR : Shared_Wide_Wide_String_Access;
573 begin
574 -- New_Item is an empty string, nothing to do
576 if New_Item'Length = 0 then
577 null;
579 -- Try to reuse existing shared string
581 elsif Can_Be_Reused (SR, DL) then
582 SR.Data (SR.Last + 1 .. DL) := New_Item;
583 SR.Last := DL;
585 -- Otherwise, allocate new one and fill it
587 else
588 DR := Allocate (DL + DL / Growth_Factor);
589 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
590 DR.Data (SR.Last + 1 .. DL) := New_Item;
591 DR.Last := DL;
592 Source.Reference := DR;
593 Unreference (SR);
594 end if;
595 end Append;
597 procedure Append
598 (Source : in out Unbounded_Wide_Wide_String;
599 New_Item : Wide_Wide_Character)
601 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
602 DL : constant Natural := SR.Last + 1;
603 DR : Shared_Wide_Wide_String_Access;
605 begin
606 -- Try to reuse existing shared string
608 if Can_Be_Reused (SR, SR.Last + 1) then
609 SR.Data (SR.Last + 1) := New_Item;
610 SR.Last := SR.Last + 1;
612 -- Otherwise, allocate new one and fill it
614 else
615 DR := Allocate (DL + DL / Growth_Factor);
616 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
617 DR.Data (DL) := New_Item;
618 DR.Last := DL;
619 Source.Reference := DR;
620 Unreference (SR);
621 end if;
622 end Append;
624 -------------------
625 -- Can_Be_Reused --
626 -------------------
628 function Can_Be_Reused
629 (Item : Shared_Wide_Wide_String_Access;
630 Length : Natural) return Boolean is
631 begin
632 return
633 System.Atomic_Counters.Is_One (Item.Counter)
634 and then Item.Max_Length >= Length
635 and then Item.Max_Length <=
636 Aligned_Max_Length (Length + Length / Growth_Factor);
637 end Can_Be_Reused;
639 -----------
640 -- Count --
641 -----------
643 function Count
644 (Source : Unbounded_Wide_Wide_String;
645 Pattern : Wide_Wide_String;
646 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping :=
647 Wide_Wide_Maps.Identity) return Natural
649 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
650 begin
651 return Wide_Wide_Search.Count (SR.Data (1 .. SR.Last), Pattern, Mapping);
652 end Count;
654 function Count
655 (Source : Unbounded_Wide_Wide_String;
656 Pattern : Wide_Wide_String;
657 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
658 return Natural
660 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
661 begin
662 return Wide_Wide_Search.Count (SR.Data (1 .. SR.Last), Pattern, Mapping);
663 end Count;
665 function Count
666 (Source : Unbounded_Wide_Wide_String;
667 Set : Wide_Wide_Maps.Wide_Wide_Character_Set) return Natural
669 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
670 begin
671 return Wide_Wide_Search.Count (SR.Data (1 .. SR.Last), Set);
672 end Count;
674 ------------
675 -- Delete --
676 ------------
678 function Delete
679 (Source : Unbounded_Wide_Wide_String;
680 From : Positive;
681 Through : Natural) return Unbounded_Wide_Wide_String
683 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
684 DL : Natural;
685 DR : Shared_Wide_Wide_String_Access;
687 begin
688 -- Empty slice is deleted, use the same shared string
690 if From > Through then
691 Reference (SR);
692 DR := SR;
694 -- Index is out of range
696 elsif Through > SR.Last then
697 raise Index_Error;
699 -- Compute size of the result
701 else
702 DL := SR.Last - (Through - From + 1);
704 -- Result is an empty string, reuse shared empty string
706 if DL = 0 then
707 Reference (Empty_Shared_Wide_Wide_String'Access);
708 DR := Empty_Shared_Wide_Wide_String'Access;
710 -- Otherwise, allocate new shared string and fill it
712 else
713 DR := Allocate (DL);
714 DR.Data (1 .. From - 1) := SR.Data (1 .. From - 1);
715 DR.Data (From .. DL) := SR.Data (Through + 1 .. SR.Last);
716 DR.Last := DL;
717 end if;
718 end if;
720 return (AF.Controlled with Reference => DR);
721 end Delete;
723 procedure Delete
724 (Source : in out Unbounded_Wide_Wide_String;
725 From : Positive;
726 Through : Natural)
728 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
729 DL : Natural;
730 DR : Shared_Wide_Wide_String_Access;
732 begin
733 -- Nothing changed, return
735 if From > Through then
736 null;
738 -- Through is outside of the range
740 elsif Through > SR.Last then
741 raise Index_Error;
743 else
744 DL := SR.Last - (Through - From + 1);
746 -- Result is empty, reuse shared empty string
748 if DL = 0 then
749 Reference (Empty_Shared_Wide_Wide_String'Access);
750 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
751 Unreference (SR);
753 -- Try to reuse existent shared string
755 elsif Can_Be_Reused (SR, DL) then
756 SR.Data (From .. DL) := SR.Data (Through + 1 .. SR.Last);
757 SR.Last := DL;
759 -- Otherwise, allocate new shared string
761 else
762 DR := Allocate (DL);
763 DR.Data (1 .. From - 1) := SR.Data (1 .. From - 1);
764 DR.Data (From .. DL) := SR.Data (Through + 1 .. SR.Last);
765 DR.Last := DL;
766 Source.Reference := DR;
767 Unreference (SR);
768 end if;
769 end if;
770 end Delete;
772 -------------
773 -- Element --
774 -------------
776 function Element
777 (Source : Unbounded_Wide_Wide_String;
778 Index : Positive) return Wide_Wide_Character
780 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
781 begin
782 if Index <= SR.Last then
783 return SR.Data (Index);
784 else
785 raise Index_Error;
786 end if;
787 end Element;
789 --------------
790 -- Finalize --
791 --------------
793 procedure Finalize (Object : in out Unbounded_Wide_Wide_String) is
794 SR : constant Shared_Wide_Wide_String_Access := Object.Reference;
796 begin
797 if SR /= null then
799 -- The same controlled object can be finalized several times for
800 -- some reason. As per 7.6.1(24) this should have no ill effect,
801 -- so we need to add a guard for the case of finalizing the same
802 -- object twice.
804 Object.Reference := null;
805 Unreference (SR);
806 end if;
807 end Finalize;
809 ----------------
810 -- Find_Token --
811 ----------------
813 procedure Find_Token
814 (Source : Unbounded_Wide_Wide_String;
815 Set : Wide_Wide_Maps.Wide_Wide_Character_Set;
816 From : Positive;
817 Test : Strings.Membership;
818 First : out Positive;
819 Last : out Natural)
821 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
822 begin
823 Wide_Wide_Search.Find_Token
824 (SR.Data (From .. SR.Last), Set, Test, First, Last);
825 end Find_Token;
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 than 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 than 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 than 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) return Natural
978 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
979 begin
980 return Wide_Wide_Search.Index
981 (SR.Data (1 .. SR.Last), Pattern, Going, Mapping);
982 end Index;
984 function Index
985 (Source : Unbounded_Wide_Wide_String;
986 Pattern : Wide_Wide_String;
987 Going : Direction := Forward;
988 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
989 return Natural
991 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
992 begin
993 return Wide_Wide_Search.Index
994 (SR.Data (1 .. SR.Last), Pattern, Going, Mapping);
995 end Index;
997 function Index
998 (Source : Unbounded_Wide_Wide_String;
999 Set : Wide_Wide_Maps.Wide_Wide_Character_Set;
1000 Test : Strings.Membership := Strings.Inside;
1001 Going : Strings.Direction := Strings.Forward) return Natural
1003 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1004 begin
1005 return Wide_Wide_Search.Index (SR.Data (1 .. SR.Last), Set, Test, Going);
1006 end Index;
1008 function Index
1009 (Source : Unbounded_Wide_Wide_String;
1010 Pattern : Wide_Wide_String;
1011 From : Positive;
1012 Going : Direction := Forward;
1013 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping :=
1014 Wide_Wide_Maps.Identity) return Natural
1016 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1017 begin
1018 return Wide_Wide_Search.Index
1019 (SR.Data (1 .. SR.Last), Pattern, From, Going, Mapping);
1020 end Index;
1022 function Index
1023 (Source : Unbounded_Wide_Wide_String;
1024 Pattern : Wide_Wide_String;
1025 From : Positive;
1026 Going : Direction := Forward;
1027 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
1028 return Natural
1030 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1031 begin
1032 return Wide_Wide_Search.Index
1033 (SR.Data (1 .. SR.Last), Pattern, From, Going, Mapping);
1034 end Index;
1036 function Index
1037 (Source : Unbounded_Wide_Wide_String;
1038 Set : Wide_Wide_Maps.Wide_Wide_Character_Set;
1039 From : Positive;
1040 Test : Membership := Inside;
1041 Going : Direction := Forward) return Natural
1043 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1044 begin
1045 return Wide_Wide_Search.Index
1046 (SR.Data (1 .. SR.Last), Set, From, Test, Going);
1047 end Index;
1049 ---------------------
1050 -- Index_Non_Blank --
1051 ---------------------
1053 function Index_Non_Blank
1054 (Source : Unbounded_Wide_Wide_String;
1055 Going : Strings.Direction := Strings.Forward) return Natural
1057 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1058 begin
1059 return Wide_Wide_Search.Index_Non_Blank (SR.Data (1 .. SR.Last), Going);
1060 end Index_Non_Blank;
1062 function Index_Non_Blank
1063 (Source : Unbounded_Wide_Wide_String;
1064 From : Positive;
1065 Going : Direction := Forward) return Natural
1067 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1068 begin
1069 return Wide_Wide_Search.Index_Non_Blank
1070 (SR.Data (1 .. SR.Last), From, Going);
1071 end Index_Non_Blank;
1073 ----------------
1074 -- Initialize --
1075 ----------------
1077 procedure Initialize (Object : in out Unbounded_Wide_Wide_String) is
1078 begin
1079 Reference (Object.Reference);
1080 end Initialize;
1082 ------------
1083 -- Insert --
1084 ------------
1086 function Insert
1087 (Source : Unbounded_Wide_Wide_String;
1088 Before : Positive;
1089 New_Item : Wide_Wide_String) return Unbounded_Wide_Wide_String
1091 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1092 DL : constant Natural := SR.Last + New_Item'Length;
1093 DR : Shared_Wide_Wide_String_Access;
1095 begin
1096 -- Check index first
1098 if Before > SR.Last + 1 then
1099 raise Index_Error;
1100 end if;
1102 -- Result is empty, reuse empty shared string
1104 if DL = 0 then
1105 Reference (Empty_Shared_Wide_Wide_String'Access);
1106 DR := Empty_Shared_Wide_Wide_String'Access;
1108 -- Inserted string is empty, reuse source shared string
1110 elsif New_Item'Length = 0 then
1111 Reference (SR);
1112 DR := SR;
1114 -- Otherwise, allocate new shared string and fill it
1116 else
1117 DR := Allocate (DL + DL / Growth_Factor);
1118 DR.Data (1 .. Before - 1) := SR.Data (1 .. Before - 1);
1119 DR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1120 DR.Data (Before + New_Item'Length .. DL) :=
1121 SR.Data (Before .. SR.Last);
1122 DR.Last := DL;
1123 end if;
1125 return (AF.Controlled with Reference => DR);
1126 end Insert;
1128 procedure Insert
1129 (Source : in out Unbounded_Wide_Wide_String;
1130 Before : Positive;
1131 New_Item : Wide_Wide_String)
1133 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1134 DL : constant Natural := SR.Last + New_Item'Length;
1135 DR : Shared_Wide_Wide_String_Access;
1137 begin
1138 -- Check bounds
1140 if Before > SR.Last + 1 then
1141 raise Index_Error;
1142 end if;
1144 -- Result is empty string, reuse empty shared string
1146 if DL = 0 then
1147 Reference (Empty_Shared_Wide_Wide_String'Access);
1148 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1149 Unreference (SR);
1151 -- Inserted string is empty, nothing to do
1153 elsif New_Item'Length = 0 then
1154 null;
1156 -- Try to reuse existent shared string first
1158 elsif Can_Be_Reused (SR, DL) then
1159 SR.Data (Before + New_Item'Length .. DL) :=
1160 SR.Data (Before .. SR.Last);
1161 SR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1162 SR.Last := DL;
1164 -- Otherwise, allocate new shared string and fill it
1166 else
1167 DR := Allocate (DL + DL / Growth_Factor);
1168 DR.Data (1 .. Before - 1) := SR.Data (1 .. Before - 1);
1169 DR.Data (Before .. Before + New_Item'Length - 1) := New_Item;
1170 DR.Data (Before + New_Item'Length .. DL) :=
1171 SR.Data (Before .. SR.Last);
1172 DR.Last := DL;
1173 Source.Reference := DR;
1174 Unreference (SR);
1175 end if;
1176 end Insert;
1178 ------------
1179 -- Length --
1180 ------------
1182 function Length (Source : Unbounded_Wide_Wide_String) return Natural is
1183 begin
1184 return Source.Reference.Last;
1185 end Length;
1187 ---------------
1188 -- Overwrite --
1189 ---------------
1191 function Overwrite
1192 (Source : Unbounded_Wide_Wide_String;
1193 Position : Positive;
1194 New_Item : Wide_Wide_String) return Unbounded_Wide_Wide_String
1196 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1197 DL : Natural;
1198 DR : Shared_Wide_Wide_String_Access;
1200 begin
1201 -- Check bounds
1203 if Position > SR.Last + 1 then
1204 raise Index_Error;
1205 end if;
1207 DL := Integer'Max (SR.Last, Position + New_Item'Length - 1);
1209 -- Result is empty string, reuse empty shared string
1211 if DL = 0 then
1212 Reference (Empty_Shared_Wide_Wide_String'Access);
1213 DR := Empty_Shared_Wide_Wide_String'Access;
1215 -- Result is same with source string, reuse source shared string
1217 elsif New_Item'Length = 0 then
1218 Reference (SR);
1219 DR := SR;
1221 -- Otherwise, allocate new shared string and fill it
1223 else
1224 DR := Allocate (DL);
1225 DR.Data (1 .. Position - 1) := SR.Data (1 .. Position - 1);
1226 DR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1227 DR.Data (Position + New_Item'Length .. DL) :=
1228 SR.Data (Position + New_Item'Length .. SR.Last);
1229 DR.Last := DL;
1230 end if;
1232 return (AF.Controlled with Reference => DR);
1233 end Overwrite;
1235 procedure Overwrite
1236 (Source : in out Unbounded_Wide_Wide_String;
1237 Position : Positive;
1238 New_Item : Wide_Wide_String)
1240 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1241 DL : Natural;
1242 DR : Shared_Wide_Wide_String_Access;
1244 begin
1245 -- Bounds check
1247 if Position > SR.Last + 1 then
1248 raise Index_Error;
1249 end if;
1251 DL := Integer'Max (SR.Last, Position + New_Item'Length - 1);
1253 -- Result is empty string, reuse empty shared string
1255 if DL = 0 then
1256 Reference (Empty_Shared_Wide_Wide_String'Access);
1257 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1258 Unreference (SR);
1260 -- String unchanged, nothing to do
1262 elsif New_Item'Length = 0 then
1263 null;
1265 -- Try to reuse existent shared string
1267 elsif Can_Be_Reused (SR, DL) then
1268 SR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1269 SR.Last := DL;
1271 -- Otherwise allocate new shared string and fill it
1273 else
1274 DR := Allocate (DL);
1275 DR.Data (1 .. Position - 1) := SR.Data (1 .. Position - 1);
1276 DR.Data (Position .. Position + New_Item'Length - 1) := New_Item;
1277 DR.Data (Position + New_Item'Length .. DL) :=
1278 SR.Data (Position + New_Item'Length .. SR.Last);
1279 DR.Last := DL;
1280 Source.Reference := DR;
1281 Unreference (SR);
1282 end if;
1283 end Overwrite;
1285 ---------------
1286 -- Reference --
1287 ---------------
1289 procedure Reference (Item : not null Shared_Wide_Wide_String_Access) is
1290 begin
1291 System.Atomic_Counters.Increment (Item.Counter);
1292 end Reference;
1294 ---------------------
1295 -- Replace_Element --
1296 ---------------------
1298 procedure Replace_Element
1299 (Source : in out Unbounded_Wide_Wide_String;
1300 Index : Positive;
1301 By : Wide_Wide_Character)
1303 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1304 DR : Shared_Wide_Wide_String_Access;
1306 begin
1307 -- Bounds check
1309 if Index <= SR.Last then
1311 -- Try to reuse existent shared string
1313 if Can_Be_Reused (SR, SR.Last) then
1314 SR.Data (Index) := By;
1316 -- Otherwise allocate new shared string and fill it
1318 else
1319 DR := Allocate (SR.Last);
1320 DR.Data (1 .. SR.Last) := SR.Data (1 .. SR.Last);
1321 DR.Data (Index) := By;
1322 DR.Last := SR.Last;
1323 Source.Reference := DR;
1324 Unreference (SR);
1325 end if;
1327 else
1328 raise Index_Error;
1329 end if;
1330 end Replace_Element;
1332 -------------------
1333 -- Replace_Slice --
1334 -------------------
1336 function Replace_Slice
1337 (Source : Unbounded_Wide_Wide_String;
1338 Low : Positive;
1339 High : Natural;
1340 By : Wide_Wide_String) return Unbounded_Wide_Wide_String
1342 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1343 DL : Natural;
1344 DR : Shared_Wide_Wide_String_Access;
1346 begin
1347 -- Check bounds
1349 if Low > SR.Last + 1 then
1350 raise Index_Error;
1351 end if;
1353 -- Do replace operation when removed slice is not empty
1355 if High >= Low then
1356 DL := By'Length + SR.Last + Low - Integer'Min (High, SR.Last) - 1;
1357 -- This is the number of characters remaining in the string after
1358 -- replacing the slice.
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 - Integer'Min (High, SR.Last) - 1;
1406 -- This is the number of characters remaining in the string after
1407 -- replacing the slice.
1409 -- Result is empty string, reuse empty shared string
1411 if DL = 0 then
1412 Reference (Empty_Shared_Wide_Wide_String'Access);
1413 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1414 Unreference (SR);
1416 -- Try to reuse existent shared string
1418 elsif Can_Be_Reused (SR, DL) then
1419 SR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1420 SR.Data (Low .. Low + By'Length - 1) := By;
1421 SR.Last := DL;
1423 -- Otherwise allocate new shared string and fill it
1425 else
1426 DR := Allocate (DL);
1427 DR.Data (1 .. Low - 1) := SR.Data (1 .. Low - 1);
1428 DR.Data (Low .. Low + By'Length - 1) := By;
1429 DR.Data (Low + By'Length .. DL) := SR.Data (High + 1 .. SR.Last);
1430 DR.Last := DL;
1431 Source.Reference := DR;
1432 Unreference (SR);
1433 end if;
1435 -- Otherwise just insert item
1437 else
1438 Insert (Source, Low, By);
1439 end if;
1440 end Replace_Slice;
1442 -------------------------------
1443 -- Set_Unbounded_Wide_Wide_String --
1444 -------------------------------
1446 procedure Set_Unbounded_Wide_Wide_String
1447 (Target : out Unbounded_Wide_Wide_String;
1448 Source : Wide_Wide_String)
1450 TR : constant Shared_Wide_Wide_String_Access := Target.Reference;
1451 DR : Shared_Wide_Wide_String_Access;
1453 begin
1454 -- In case of empty string, reuse empty shared string
1456 if Source'Length = 0 then
1457 Reference (Empty_Shared_Wide_Wide_String'Access);
1458 Target.Reference := Empty_Shared_Wide_Wide_String'Access;
1460 else
1461 -- Try to reuse existent shared string
1463 if Can_Be_Reused (TR, Source'Length) then
1464 Reference (TR);
1465 DR := TR;
1467 -- Otherwise allocate new shared string
1469 else
1470 DR := Allocate (Source'Length);
1471 Target.Reference := DR;
1472 end if;
1474 DR.Data (1 .. Source'Length) := Source;
1475 DR.Last := Source'Length;
1476 end if;
1478 Unreference (TR);
1479 end Set_Unbounded_Wide_Wide_String;
1481 -----------
1482 -- Slice --
1483 -----------
1485 function Slice
1486 (Source : Unbounded_Wide_Wide_String;
1487 Low : Positive;
1488 High : Natural) return Wide_Wide_String
1490 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1492 begin
1493 -- Note: test of High > Length is in accordance with AI95-00128
1495 if Low > SR.Last + 1 or else High > SR.Last then
1496 raise Index_Error;
1498 else
1499 return SR.Data (Low .. High);
1500 end if;
1501 end Slice;
1503 ----------
1504 -- Tail --
1505 ----------
1507 function Tail
1508 (Source : Unbounded_Wide_Wide_String;
1509 Count : Natural;
1510 Pad : Wide_Wide_Character := Wide_Wide_Space)
1511 return Unbounded_Wide_Wide_String
1513 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1514 DR : Shared_Wide_Wide_String_Access;
1516 begin
1517 -- For empty result reuse empty shared string
1519 if Count = 0 then
1520 Reference (Empty_Shared_Wide_Wide_String'Access);
1521 DR := Empty_Shared_Wide_Wide_String'Access;
1523 -- Result is hole source string, reuse source shared string
1525 elsif Count = SR.Last then
1526 Reference (SR);
1527 DR := SR;
1529 -- Otherwise allocate new shared string and fill it
1531 else
1532 DR := Allocate (Count);
1534 if Count < SR.Last then
1535 DR.Data (1 .. Count) := SR.Data (SR.Last - Count + 1 .. SR.Last);
1537 else
1538 for J in 1 .. Count - SR.Last loop
1539 DR.Data (J) := Pad;
1540 end loop;
1542 DR.Data (Count - SR.Last + 1 .. Count) := SR.Data (1 .. SR.Last);
1543 end if;
1545 DR.Last := Count;
1546 end if;
1548 return (AF.Controlled with Reference => DR);
1549 end Tail;
1551 procedure Tail
1552 (Source : in out Unbounded_Wide_Wide_String;
1553 Count : Natural;
1554 Pad : Wide_Wide_Character := Wide_Wide_Space)
1556 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1557 DR : Shared_Wide_Wide_String_Access;
1559 procedure Common
1560 (SR : Shared_Wide_Wide_String_Access;
1561 DR : Shared_Wide_Wide_String_Access;
1562 Count : Natural);
1563 -- Common code of tail computation. SR/DR can point to the same object
1565 ------------
1566 -- Common --
1567 ------------
1569 procedure Common
1570 (SR : Shared_Wide_Wide_String_Access;
1571 DR : Shared_Wide_Wide_String_Access;
1572 Count : Natural) is
1573 begin
1574 if Count < SR.Last then
1575 DR.Data (1 .. Count) := SR.Data (SR.Last - Count + 1 .. SR.Last);
1577 else
1578 DR.Data (Count - SR.Last + 1 .. Count) := SR.Data (1 .. SR.Last);
1580 for J in 1 .. Count - SR.Last loop
1581 DR.Data (J) := Pad;
1582 end loop;
1583 end if;
1585 DR.Last := Count;
1586 end Common;
1588 begin
1589 -- Result is empty string, reuse empty shared string
1591 if Count = 0 then
1592 Reference (Empty_Shared_Wide_Wide_String'Access);
1593 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1594 Unreference (SR);
1596 -- Length of the result is the same with length of the source string,
1597 -- reuse source shared string.
1599 elsif Count = SR.Last then
1600 null;
1602 -- Try to reuse existent shared string
1604 elsif Can_Be_Reused (SR, Count) then
1605 Common (SR, SR, Count);
1607 -- Otherwise allocate new shared string and fill it
1609 else
1610 DR := Allocate (Count);
1611 Common (SR, DR, Count);
1612 Source.Reference := DR;
1613 Unreference (SR);
1614 end if;
1615 end Tail;
1617 --------------------
1618 -- To_Wide_Wide_String --
1619 --------------------
1621 function To_Wide_Wide_String
1622 (Source : Unbounded_Wide_Wide_String) return Wide_Wide_String is
1623 begin
1624 return Source.Reference.Data (1 .. Source.Reference.Last);
1625 end To_Wide_Wide_String;
1627 ------------------------------
1628 -- To_Unbounded_Wide_Wide_String --
1629 ------------------------------
1631 function To_Unbounded_Wide_Wide_String
1632 (Source : Wide_Wide_String) return Unbounded_Wide_Wide_String
1634 DR : constant Shared_Wide_Wide_String_Access := Allocate (Source'Length);
1635 begin
1636 DR.Data (1 .. Source'Length) := Source;
1637 DR.Last := Source'Length;
1638 return (AF.Controlled with Reference => DR);
1639 end To_Unbounded_Wide_Wide_String;
1641 function To_Unbounded_Wide_Wide_String
1642 (Length : Natural) return Unbounded_Wide_Wide_String
1644 DR : constant Shared_Wide_Wide_String_Access := Allocate (Length);
1645 begin
1646 DR.Last := Length;
1647 return (AF.Controlled with Reference => DR);
1648 end To_Unbounded_Wide_Wide_String;
1650 ---------------
1651 -- Translate --
1652 ---------------
1654 function Translate
1655 (Source : Unbounded_Wide_Wide_String;
1656 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping)
1657 return Unbounded_Wide_Wide_String
1659 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1660 DR : Shared_Wide_Wide_String_Access;
1662 begin
1663 -- Nothing to translate, reuse empty shared string
1665 if SR.Last = 0 then
1666 Reference (Empty_Shared_Wide_Wide_String'Access);
1667 DR := Empty_Shared_Wide_Wide_String'Access;
1669 -- Otherwise, allocate new shared string and fill it
1671 else
1672 DR := Allocate (SR.Last);
1674 for J in 1 .. SR.Last loop
1675 DR.Data (J) := Value (Mapping, SR.Data (J));
1676 end loop;
1678 DR.Last := SR.Last;
1679 end if;
1681 return (AF.Controlled with Reference => DR);
1682 end Translate;
1684 procedure Translate
1685 (Source : in out Unbounded_Wide_Wide_String;
1686 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping)
1688 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1689 DR : Shared_Wide_Wide_String_Access;
1691 begin
1692 -- Nothing to translate
1694 if SR.Last = 0 then
1695 null;
1697 -- Try to reuse shared string
1699 elsif Can_Be_Reused (SR, SR.Last) then
1700 for J in 1 .. SR.Last loop
1701 SR.Data (J) := Value (Mapping, SR.Data (J));
1702 end loop;
1704 -- Otherwise, allocate new shared string
1706 else
1707 DR := Allocate (SR.Last);
1709 for J in 1 .. SR.Last loop
1710 DR.Data (J) := Value (Mapping, SR.Data (J));
1711 end loop;
1713 DR.Last := SR.Last;
1714 Source.Reference := DR;
1715 Unreference (SR);
1716 end if;
1717 end Translate;
1719 function Translate
1720 (Source : Unbounded_Wide_Wide_String;
1721 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
1722 return Unbounded_Wide_Wide_String
1724 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1725 DR : Shared_Wide_Wide_String_Access;
1727 begin
1728 -- Nothing to translate, reuse empty shared string
1730 if SR.Last = 0 then
1731 Reference (Empty_Shared_Wide_Wide_String'Access);
1732 DR := Empty_Shared_Wide_Wide_String'Access;
1734 -- Otherwise, allocate new shared string and fill it
1736 else
1737 DR := Allocate (SR.Last);
1739 for J in 1 .. SR.Last loop
1740 DR.Data (J) := Mapping.all (SR.Data (J));
1741 end loop;
1743 DR.Last := SR.Last;
1744 end if;
1746 return (AF.Controlled with Reference => DR);
1748 exception
1749 when others =>
1750 Unreference (DR);
1752 raise;
1753 end Translate;
1755 procedure Translate
1756 (Source : in out Unbounded_Wide_Wide_String;
1757 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
1759 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1760 DR : Shared_Wide_Wide_String_Access;
1762 begin
1763 -- Nothing to translate
1765 if SR.Last = 0 then
1766 null;
1768 -- Try to reuse shared string
1770 elsif Can_Be_Reused (SR, SR.Last) then
1771 for J in 1 .. SR.Last loop
1772 SR.Data (J) := Mapping.all (SR.Data (J));
1773 end loop;
1775 -- Otherwise allocate new shared string and fill it
1777 else
1778 DR := Allocate (SR.Last);
1780 for J in 1 .. SR.Last loop
1781 DR.Data (J) := Mapping.all (SR.Data (J));
1782 end loop;
1784 DR.Last := SR.Last;
1785 Source.Reference := DR;
1786 Unreference (SR);
1787 end if;
1789 exception
1790 when others =>
1791 if DR /= null then
1792 Unreference (DR);
1793 end if;
1795 raise;
1796 end Translate;
1798 ----------
1799 -- Trim --
1800 ----------
1802 function Trim
1803 (Source : Unbounded_Wide_Wide_String;
1804 Side : Trim_End) return Unbounded_Wide_Wide_String
1806 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1807 DL : Natural;
1808 DR : Shared_Wide_Wide_String_Access;
1809 Low : Natural;
1810 High : Natural;
1812 begin
1813 Low := Index_Non_Blank (Source, Forward);
1815 -- All blanks, reuse empty shared string
1817 if Low = 0 then
1818 Reference (Empty_Shared_Wide_Wide_String'Access);
1819 DR := Empty_Shared_Wide_Wide_String'Access;
1821 else
1822 case Side is
1823 when Left =>
1824 High := SR.Last;
1825 DL := SR.Last - Low + 1;
1827 when Right =>
1828 Low := 1;
1829 High := Index_Non_Blank (Source, Backward);
1830 DL := High;
1832 when Both =>
1833 High := Index_Non_Blank (Source, Backward);
1834 DL := High - Low + 1;
1835 end case;
1837 -- Length of the result is the same as length of the source string,
1838 -- reuse source shared string.
1840 if DL = SR.Last then
1841 Reference (SR);
1842 DR := SR;
1844 -- Otherwise, allocate new shared string
1846 else
1847 DR := Allocate (DL);
1848 DR.Data (1 .. DL) := SR.Data (Low .. High);
1849 DR.Last := DL;
1850 end if;
1851 end if;
1853 return (AF.Controlled with Reference => DR);
1854 end Trim;
1856 procedure Trim
1857 (Source : in out Unbounded_Wide_Wide_String;
1858 Side : Trim_End)
1860 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1861 DL : Natural;
1862 DR : Shared_Wide_Wide_String_Access;
1863 Low : Natural;
1864 High : Natural;
1866 begin
1867 Low := Index_Non_Blank (Source, Forward);
1869 -- All blanks, reuse empty shared string
1871 if Low = 0 then
1872 Reference (Empty_Shared_Wide_Wide_String'Access);
1873 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1874 Unreference (SR);
1876 else
1877 case Side is
1878 when Left =>
1879 High := SR.Last;
1880 DL := SR.Last - Low + 1;
1882 when Right =>
1883 Low := 1;
1884 High := Index_Non_Blank (Source, Backward);
1885 DL := High;
1887 when Both =>
1888 High := Index_Non_Blank (Source, Backward);
1889 DL := High - Low + 1;
1890 end case;
1892 -- Length of the result is the same as length of the source string,
1893 -- nothing to do.
1895 if DL = SR.Last then
1896 null;
1898 -- Try to reuse existent shared string
1900 elsif Can_Be_Reused (SR, DL) then
1901 SR.Data (1 .. DL) := SR.Data (Low .. High);
1902 SR.Last := DL;
1904 -- Otherwise, allocate new shared string
1906 else
1907 DR := Allocate (DL);
1908 DR.Data (1 .. DL) := SR.Data (Low .. High);
1909 DR.Last := DL;
1910 Source.Reference := DR;
1911 Unreference (SR);
1912 end if;
1913 end if;
1914 end Trim;
1916 function Trim
1917 (Source : Unbounded_Wide_Wide_String;
1918 Left : Wide_Wide_Maps.Wide_Wide_Character_Set;
1919 Right : Wide_Wide_Maps.Wide_Wide_Character_Set)
1920 return Unbounded_Wide_Wide_String
1922 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1923 DL : Natural;
1924 DR : Shared_Wide_Wide_String_Access;
1925 Low : Natural;
1926 High : Natural;
1928 begin
1929 Low := Index (Source, Left, Outside, Forward);
1931 -- Source includes only characters from Left set, reuse empty shared
1932 -- string.
1934 if Low = 0 then
1935 Reference (Empty_Shared_Wide_Wide_String'Access);
1936 DR := Empty_Shared_Wide_Wide_String'Access;
1938 else
1939 High := Index (Source, Right, Outside, Backward);
1940 DL := Integer'Max (0, High - Low + 1);
1942 -- Source includes only characters from Right set or result string
1943 -- is empty, reuse empty shared string.
1945 if High = 0 or else DL = 0 then
1946 Reference (Empty_Shared_Wide_Wide_String'Access);
1947 DR := Empty_Shared_Wide_Wide_String'Access;
1949 -- Otherwise, allocate new shared string and fill it
1951 else
1952 DR := Allocate (DL);
1953 DR.Data (1 .. DL) := SR.Data (Low .. High);
1954 DR.Last := DL;
1955 end if;
1956 end if;
1958 return (AF.Controlled with Reference => DR);
1959 end Trim;
1961 procedure Trim
1962 (Source : in out Unbounded_Wide_Wide_String;
1963 Left : Wide_Wide_Maps.Wide_Wide_Character_Set;
1964 Right : Wide_Wide_Maps.Wide_Wide_Character_Set)
1966 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1967 DL : Natural;
1968 DR : Shared_Wide_Wide_String_Access;
1969 Low : Natural;
1970 High : Natural;
1972 begin
1973 Low := Index (Source, Left, Outside, Forward);
1975 -- Source includes only characters from Left set, reuse empty shared
1976 -- string.
1978 if Low = 0 then
1979 Reference (Empty_Shared_Wide_Wide_String'Access);
1980 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1981 Unreference (SR);
1983 else
1984 High := Index (Source, Right, Outside, Backward);
1985 DL := Integer'Max (0, High - Low + 1);
1987 -- Source includes only characters from Right set or result string
1988 -- is empty, reuse empty shared string.
1990 if High = 0 or else DL = 0 then
1991 Reference (Empty_Shared_Wide_Wide_String'Access);
1992 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1993 Unreference (SR);
1995 -- Try to reuse existent shared string
1997 elsif Can_Be_Reused (SR, DL) then
1998 SR.Data (1 .. DL) := SR.Data (Low .. High);
1999 SR.Last := DL;
2001 -- Otherwise, allocate new shared string and fill it
2003 else
2004 DR := Allocate (DL);
2005 DR.Data (1 .. DL) := SR.Data (Low .. High);
2006 DR.Last := DL;
2007 Source.Reference := DR;
2008 Unreference (SR);
2009 end if;
2010 end if;
2011 end Trim;
2013 ---------------------
2014 -- Unbounded_Slice --
2015 ---------------------
2017 function Unbounded_Slice
2018 (Source : Unbounded_Wide_Wide_String;
2019 Low : Positive;
2020 High : Natural) return Unbounded_Wide_Wide_String
2022 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
2023 DL : Natural;
2024 DR : Shared_Wide_Wide_String_Access;
2026 begin
2027 -- Check bounds
2029 if Low > SR.Last + 1 or else High > SR.Last then
2030 raise Index_Error;
2032 -- Result is empty slice, reuse empty shared string
2034 elsif Low > High then
2035 Reference (Empty_Shared_Wide_Wide_String'Access);
2036 DR := Empty_Shared_Wide_Wide_String'Access;
2038 -- Otherwise, allocate new shared string and fill it
2040 else
2041 DL := High - Low + 1;
2042 DR := Allocate (DL);
2043 DR.Data (1 .. DL) := SR.Data (Low .. High);
2044 DR.Last := DL;
2045 end if;
2047 return (AF.Controlled with Reference => DR);
2048 end Unbounded_Slice;
2050 procedure Unbounded_Slice
2051 (Source : Unbounded_Wide_Wide_String;
2052 Target : out Unbounded_Wide_Wide_String;
2053 Low : Positive;
2054 High : Natural)
2056 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
2057 TR : constant Shared_Wide_Wide_String_Access := Target.Reference;
2058 DL : Natural;
2059 DR : Shared_Wide_Wide_String_Access;
2061 begin
2062 -- Check bounds
2064 if Low > SR.Last + 1 or else High > SR.Last then
2065 raise Index_Error;
2067 -- Result is empty slice, reuse empty shared string
2069 elsif Low > High then
2070 Reference (Empty_Shared_Wide_Wide_String'Access);
2071 Target.Reference := Empty_Shared_Wide_Wide_String'Access;
2072 Unreference (TR);
2074 else
2075 DL := High - Low + 1;
2077 -- Try to reuse existent shared string
2079 if Can_Be_Reused (TR, DL) then
2080 TR.Data (1 .. DL) := SR.Data (Low .. High);
2081 TR.Last := DL;
2083 -- Otherwise, allocate new shared string and fill it
2085 else
2086 DR := Allocate (DL);
2087 DR.Data (1 .. DL) := SR.Data (Low .. High);
2088 DR.Last := DL;
2089 Target.Reference := DR;
2090 Unreference (TR);
2091 end if;
2092 end if;
2093 end Unbounded_Slice;
2095 -----------------
2096 -- Unreference --
2097 -----------------
2099 procedure Unreference (Item : not null Shared_Wide_Wide_String_Access) is
2101 procedure Free is
2102 new Ada.Unchecked_Deallocation
2103 (Shared_Wide_Wide_String, Shared_Wide_Wide_String_Access);
2105 Aux : Shared_Wide_Wide_String_Access := Item;
2107 begin
2108 if System.Atomic_Counters.Decrement (Aux.Counter) then
2110 -- Reference counter of Empty_Shared_Wide_Wide_String must never
2111 -- reach zero.
2113 pragma Assert (Aux /= Empty_Shared_Wide_Wide_String'Access);
2115 Free (Aux);
2116 end if;
2117 end Unreference;
2119 end Ada.Strings.Wide_Wide_Unbounded;