2015-06-23 Paolo Carlini <paolo.carlini@oracle.com>
[official-gcc.git] / gcc / ada / a-stzunb-shared.adb
blobbf2ed256334b02e4688f3fc853fe5d97a5d0cab0
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-2014, 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 (DL);
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 : Shared_Wide_Wide_String_Access;
1636 begin
1637 if Source'Length = 0 then
1638 Reference (Empty_Shared_Wide_Wide_String'Access);
1639 DR := Empty_Shared_Wide_Wide_String'Access;
1641 else
1642 DR := Allocate (Source'Length);
1643 DR.Data (1 .. Source'Length) := Source;
1644 DR.Last := Source'Length;
1645 end if;
1647 return (AF.Controlled with Reference => DR);
1648 end To_Unbounded_Wide_Wide_String;
1650 function To_Unbounded_Wide_Wide_String
1651 (Length : Natural) return Unbounded_Wide_Wide_String
1653 DR : Shared_Wide_Wide_String_Access;
1655 begin
1656 if Length = 0 then
1657 Reference (Empty_Shared_Wide_Wide_String'Access);
1658 DR := Empty_Shared_Wide_Wide_String'Access;
1660 else
1661 DR := Allocate (Length);
1662 DR.Last := Length;
1663 end if;
1665 return (AF.Controlled with Reference => DR);
1666 end To_Unbounded_Wide_Wide_String;
1668 ---------------
1669 -- Translate --
1670 ---------------
1672 function Translate
1673 (Source : Unbounded_Wide_Wide_String;
1674 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping)
1675 return Unbounded_Wide_Wide_String
1677 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1678 DR : Shared_Wide_Wide_String_Access;
1680 begin
1681 -- Nothing to translate, reuse empty shared string
1683 if SR.Last = 0 then
1684 Reference (Empty_Shared_Wide_Wide_String'Access);
1685 DR := Empty_Shared_Wide_Wide_String'Access;
1687 -- Otherwise, allocate new shared string and fill it
1689 else
1690 DR := Allocate (SR.Last);
1692 for J in 1 .. SR.Last loop
1693 DR.Data (J) := Value (Mapping, SR.Data (J));
1694 end loop;
1696 DR.Last := SR.Last;
1697 end if;
1699 return (AF.Controlled with Reference => DR);
1700 end Translate;
1702 procedure Translate
1703 (Source : in out Unbounded_Wide_Wide_String;
1704 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping)
1706 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1707 DR : Shared_Wide_Wide_String_Access;
1709 begin
1710 -- Nothing to translate
1712 if SR.Last = 0 then
1713 null;
1715 -- Try to reuse shared string
1717 elsif Can_Be_Reused (SR, SR.Last) then
1718 for J in 1 .. SR.Last loop
1719 SR.Data (J) := Value (Mapping, SR.Data (J));
1720 end loop;
1722 -- Otherwise, allocate new shared string
1724 else
1725 DR := Allocate (SR.Last);
1727 for J in 1 .. SR.Last loop
1728 DR.Data (J) := Value (Mapping, SR.Data (J));
1729 end loop;
1731 DR.Last := SR.Last;
1732 Source.Reference := DR;
1733 Unreference (SR);
1734 end if;
1735 end Translate;
1737 function Translate
1738 (Source : Unbounded_Wide_Wide_String;
1739 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
1740 return Unbounded_Wide_Wide_String
1742 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1743 DR : Shared_Wide_Wide_String_Access;
1745 begin
1746 -- Nothing to translate, reuse empty shared string
1748 if SR.Last = 0 then
1749 Reference (Empty_Shared_Wide_Wide_String'Access);
1750 DR := Empty_Shared_Wide_Wide_String'Access;
1752 -- Otherwise, allocate new shared string and fill it
1754 else
1755 DR := Allocate (SR.Last);
1757 for J in 1 .. SR.Last loop
1758 DR.Data (J) := Mapping.all (SR.Data (J));
1759 end loop;
1761 DR.Last := SR.Last;
1762 end if;
1764 return (AF.Controlled with Reference => DR);
1766 exception
1767 when others =>
1768 Unreference (DR);
1770 raise;
1771 end Translate;
1773 procedure Translate
1774 (Source : in out Unbounded_Wide_Wide_String;
1775 Mapping : Wide_Wide_Maps.Wide_Wide_Character_Mapping_Function)
1777 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1778 DR : Shared_Wide_Wide_String_Access;
1780 begin
1781 -- Nothing to translate
1783 if SR.Last = 0 then
1784 null;
1786 -- Try to reuse shared string
1788 elsif Can_Be_Reused (SR, SR.Last) then
1789 for J in 1 .. SR.Last loop
1790 SR.Data (J) := Mapping.all (SR.Data (J));
1791 end loop;
1793 -- Otherwise allocate new shared string and fill it
1795 else
1796 DR := Allocate (SR.Last);
1798 for J in 1 .. SR.Last loop
1799 DR.Data (J) := Mapping.all (SR.Data (J));
1800 end loop;
1802 DR.Last := SR.Last;
1803 Source.Reference := DR;
1804 Unreference (SR);
1805 end if;
1807 exception
1808 when others =>
1809 if DR /= null then
1810 Unreference (DR);
1811 end if;
1813 raise;
1814 end Translate;
1816 ----------
1817 -- Trim --
1818 ----------
1820 function Trim
1821 (Source : Unbounded_Wide_Wide_String;
1822 Side : Trim_End) return Unbounded_Wide_Wide_String
1824 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1825 DL : Natural;
1826 DR : Shared_Wide_Wide_String_Access;
1827 Low : Natural;
1828 High : Natural;
1830 begin
1831 Low := Index_Non_Blank (Source, Forward);
1833 -- All blanks, reuse empty shared string
1835 if Low = 0 then
1836 Reference (Empty_Shared_Wide_Wide_String'Access);
1837 DR := Empty_Shared_Wide_Wide_String'Access;
1839 else
1840 case Side is
1841 when Left =>
1842 High := SR.Last;
1843 DL := SR.Last - Low + 1;
1845 when Right =>
1846 Low := 1;
1847 High := Index_Non_Blank (Source, Backward);
1848 DL := High;
1850 when Both =>
1851 High := Index_Non_Blank (Source, Backward);
1852 DL := High - Low + 1;
1853 end case;
1855 -- Length of the result is the same as length of the source string,
1856 -- reuse source shared string.
1858 if DL = SR.Last then
1859 Reference (SR);
1860 DR := SR;
1862 -- Otherwise, allocate new shared string
1864 else
1865 DR := Allocate (DL);
1866 DR.Data (1 .. DL) := SR.Data (Low .. High);
1867 DR.Last := DL;
1868 end if;
1869 end if;
1871 return (AF.Controlled with Reference => DR);
1872 end Trim;
1874 procedure Trim
1875 (Source : in out Unbounded_Wide_Wide_String;
1876 Side : Trim_End)
1878 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1879 DL : Natural;
1880 DR : Shared_Wide_Wide_String_Access;
1881 Low : Natural;
1882 High : Natural;
1884 begin
1885 Low := Index_Non_Blank (Source, Forward);
1887 -- All blanks, reuse empty shared string
1889 if Low = 0 then
1890 Reference (Empty_Shared_Wide_Wide_String'Access);
1891 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1892 Unreference (SR);
1894 else
1895 case Side is
1896 when Left =>
1897 High := SR.Last;
1898 DL := SR.Last - Low + 1;
1900 when Right =>
1901 Low := 1;
1902 High := Index_Non_Blank (Source, Backward);
1903 DL := High;
1905 when Both =>
1906 High := Index_Non_Blank (Source, Backward);
1907 DL := High - Low + 1;
1908 end case;
1910 -- Length of the result is the same as length of the source string,
1911 -- nothing to do.
1913 if DL = SR.Last then
1914 null;
1916 -- Try to reuse existent shared string
1918 elsif Can_Be_Reused (SR, DL) then
1919 SR.Data (1 .. DL) := SR.Data (Low .. High);
1920 SR.Last := DL;
1922 -- Otherwise, allocate new shared string
1924 else
1925 DR := Allocate (DL);
1926 DR.Data (1 .. DL) := SR.Data (Low .. High);
1927 DR.Last := DL;
1928 Source.Reference := DR;
1929 Unreference (SR);
1930 end if;
1931 end if;
1932 end Trim;
1934 function Trim
1935 (Source : Unbounded_Wide_Wide_String;
1936 Left : Wide_Wide_Maps.Wide_Wide_Character_Set;
1937 Right : Wide_Wide_Maps.Wide_Wide_Character_Set)
1938 return Unbounded_Wide_Wide_String
1940 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1941 DL : Natural;
1942 DR : Shared_Wide_Wide_String_Access;
1943 Low : Natural;
1944 High : Natural;
1946 begin
1947 Low := Index (Source, Left, Outside, Forward);
1949 -- Source includes only characters from Left set, reuse empty shared
1950 -- string.
1952 if Low = 0 then
1953 Reference (Empty_Shared_Wide_Wide_String'Access);
1954 DR := Empty_Shared_Wide_Wide_String'Access;
1956 else
1957 High := Index (Source, Right, Outside, Backward);
1958 DL := Integer'Max (0, High - Low + 1);
1960 -- Source includes only characters from Right set or result string
1961 -- is empty, reuse empty shared string.
1963 if High = 0 or else DL = 0 then
1964 Reference (Empty_Shared_Wide_Wide_String'Access);
1965 DR := Empty_Shared_Wide_Wide_String'Access;
1967 -- Otherwise, allocate new shared string and fill it
1969 else
1970 DR := Allocate (DL);
1971 DR.Data (1 .. DL) := SR.Data (Low .. High);
1972 DR.Last := DL;
1973 end if;
1974 end if;
1976 return (AF.Controlled with Reference => DR);
1977 end Trim;
1979 procedure Trim
1980 (Source : in out Unbounded_Wide_Wide_String;
1981 Left : Wide_Wide_Maps.Wide_Wide_Character_Set;
1982 Right : Wide_Wide_Maps.Wide_Wide_Character_Set)
1984 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
1985 DL : Natural;
1986 DR : Shared_Wide_Wide_String_Access;
1987 Low : Natural;
1988 High : Natural;
1990 begin
1991 Low := Index (Source, Left, Outside, Forward);
1993 -- Source includes only characters from Left set, reuse empty shared
1994 -- string.
1996 if Low = 0 then
1997 Reference (Empty_Shared_Wide_Wide_String'Access);
1998 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
1999 Unreference (SR);
2001 else
2002 High := Index (Source, Right, Outside, Backward);
2003 DL := Integer'Max (0, High - Low + 1);
2005 -- Source includes only characters from Right set or result string
2006 -- is empty, reuse empty shared string.
2008 if High = 0 or else DL = 0 then
2009 Reference (Empty_Shared_Wide_Wide_String'Access);
2010 Source.Reference := Empty_Shared_Wide_Wide_String'Access;
2011 Unreference (SR);
2013 -- Try to reuse existent shared string
2015 elsif Can_Be_Reused (SR, DL) then
2016 SR.Data (1 .. DL) := SR.Data (Low .. High);
2017 SR.Last := DL;
2019 -- Otherwise, allocate new shared string and fill it
2021 else
2022 DR := Allocate (DL);
2023 DR.Data (1 .. DL) := SR.Data (Low .. High);
2024 DR.Last := DL;
2025 Source.Reference := DR;
2026 Unreference (SR);
2027 end if;
2028 end if;
2029 end Trim;
2031 ---------------------
2032 -- Unbounded_Slice --
2033 ---------------------
2035 function Unbounded_Slice
2036 (Source : Unbounded_Wide_Wide_String;
2037 Low : Positive;
2038 High : Natural) return Unbounded_Wide_Wide_String
2040 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
2041 DL : Natural;
2042 DR : Shared_Wide_Wide_String_Access;
2044 begin
2045 -- Check bounds
2047 if Low > SR.Last + 1 or else High > SR.Last then
2048 raise Index_Error;
2050 -- Result is empty slice, reuse empty shared string
2052 elsif Low > High then
2053 Reference (Empty_Shared_Wide_Wide_String'Access);
2054 DR := Empty_Shared_Wide_Wide_String'Access;
2056 -- Otherwise, allocate new shared string and fill it
2058 else
2059 DL := High - Low + 1;
2060 DR := Allocate (DL);
2061 DR.Data (1 .. DL) := SR.Data (Low .. High);
2062 DR.Last := DL;
2063 end if;
2065 return (AF.Controlled with Reference => DR);
2066 end Unbounded_Slice;
2068 procedure Unbounded_Slice
2069 (Source : Unbounded_Wide_Wide_String;
2070 Target : out Unbounded_Wide_Wide_String;
2071 Low : Positive;
2072 High : Natural)
2074 SR : constant Shared_Wide_Wide_String_Access := Source.Reference;
2075 TR : constant Shared_Wide_Wide_String_Access := Target.Reference;
2076 DL : Natural;
2077 DR : Shared_Wide_Wide_String_Access;
2079 begin
2080 -- Check bounds
2082 if Low > SR.Last + 1 or else High > SR.Last then
2083 raise Index_Error;
2085 -- Result is empty slice, reuse empty shared string
2087 elsif Low > High then
2088 Reference (Empty_Shared_Wide_Wide_String'Access);
2089 Target.Reference := Empty_Shared_Wide_Wide_String'Access;
2090 Unreference (TR);
2092 else
2093 DL := High - Low + 1;
2095 -- Try to reuse existent shared string
2097 if Can_Be_Reused (TR, DL) then
2098 TR.Data (1 .. DL) := SR.Data (Low .. High);
2099 TR.Last := DL;
2101 -- Otherwise, allocate new shared string and fill it
2103 else
2104 DR := Allocate (DL);
2105 DR.Data (1 .. DL) := SR.Data (Low .. High);
2106 DR.Last := DL;
2107 Target.Reference := DR;
2108 Unreference (TR);
2109 end if;
2110 end if;
2111 end Unbounded_Slice;
2113 -----------------
2114 -- Unreference --
2115 -----------------
2117 procedure Unreference (Item : not null Shared_Wide_Wide_String_Access) is
2119 procedure Free is
2120 new Ada.Unchecked_Deallocation
2121 (Shared_Wide_Wide_String, Shared_Wide_Wide_String_Access);
2123 Aux : Shared_Wide_Wide_String_Access := Item;
2125 begin
2126 if System.Atomic_Counters.Decrement (Aux.Counter) then
2128 -- Reference counter of Empty_Shared_Wide_Wide_String must never
2129 -- reach zero.
2131 pragma Assert (Aux /= Empty_Shared_Wide_Wide_String'Access);
2133 Free (Aux);
2134 end if;
2135 end Unreference;
2137 end Ada.Strings.Wide_Wide_Unbounded;