2006-02-13 Robert Dewar <dewar@adacore.com> * s-gloloc-mingw.adb, a-cgaaso.ads, a-stzmap.adb, a-stzmap.adb, a-stzmap.ads, a-ztcoio.adb, a-ztedit.adb, a-ztedit.ads, a-ztenau.adb, a-ztenau.ads, a-colien.adb, a-colien.ads, a-colire.adb, a-colire.ads, a-comlin.adb, a-decima.adb, a-decima.ads, a-direio.adb, a-direio.adb, a-direio.adb, a-direio.ads, a-ngcoty.adb, a-ngcoty.ads, a-nuflra.adb, a-nuflra.ads, a-sequio.adb, a-sequio.ads, a-sequio.ads, a-storio.ads, a-stream.ads, a-ststio.adb, a-ststio.adb, a-ststio.ads, a-ststio.ads, a-stwima.adb, a-stwima.adb, a-stwima.ads, a-stwise.adb, a-teioed.adb, a-teioed.ads, a-ticoau.adb, a-ticoau.ads, a-ticoio.adb, a-tasatt.ads, a-tideau.adb, a-tideau.ads, a-tideio.adb, a-tideio.ads, a-tienau.adb, a-tienau.ads, a-tienio.adb, a-tienio.ads, a-tifiio.ads, a-tiflau.adb, a-tiflau.ads, a-tiflio.adb, a-tiflio.adb, a-tiflio.ads, a-tigeau.ads, a-tiinau.adb, a-tiinau.ads, a-tiinio.adb, a-tiinio.ads, a-timoio.adb, a-timoio.ads, a-titest.adb, a-titest.ads, a-wtcoio.adb, a-wtdeau.adb, a-wtdeau.ads, a-wtdeio.adb, a-wtdeio.ads, a-wtedit.adb, a-wtedit.adb, a-wtedit.ads, a-wtenau.adb, a-wtenau.ads, a-wtenau.ads, a-wtenio.adb, a-wtenio.ads, a-wtfiio.adb, a-wtfiio.ads, a-wtflau.adb, a-wtflau.ads, a-wtflio.adb, a-wtflio.adb, a-wtflio.ads, a-wtgeau.ads, a-wtinau.adb, a-wtinau.ads, a-wtinio.adb, a-wtinio.ads, a-wtmoau.adb, a-wtmoau.ads, a-wtmoio.adb, a-wtmoio.ads, xref_lib.adb, xref_lib.ads, xr_tabls.adb, g-boubuf.adb, g-boubuf.ads, g-cgideb.adb, g-io.adb, gnatdll.adb, g-pehage.adb, i-c.ads, g-spitbo.adb, g-spitbo.ads, mdll.adb, mlib-fil.adb, mlib-utl.adb, mlib-utl.ads, prj-env.adb, prj-tree.adb, prj-tree.ads, prj-util.adb, s-arit64.adb, s-asthan.ads, s-auxdec.adb, s-auxdec.ads, s-chepoo.ads, s-direio.adb, s-direio.ads, s-errrep.adb, s-errrep.ads, s-fileio.adb, s-fileio.ads, s-finroo.adb, s-finroo.ads, s-gloloc.adb, s-gloloc.ads, s-io.adb, s-io.ads, s-rpc.adb, s-rpc.ads, s-shasto.ads, s-sequio.adb, s-stopoo.ads, s-stratt.adb, s-stratt.ads, s-taasde.adb, s-taasde.ads, s-tadert.adb, s-sequio.ads, s-taskin.adb, s-tasque.adb, s-tasque.ads, s-wchjis.ads, makegpr.adb, a-coinve.adb, a-cidlli.adb, eval_fat.adb, exp_dist.ads, exp_smem.adb, fmap.adb, g-dyntab.ads, g-expect.adb, lib-xref.ads, osint.adb, par-load.adb, restrict.adb, sinput-c.ads, a-cdlili.adb, system-vms.ads, system-vms-zcx.ads, system-vms_64.ads: Minor reformatting. From-SVN: r111023
740 lines
20 KiB
Ada
740 lines
20 KiB
Ada
------------------------------------------------------------------------------
|
|
-- --
|
|
-- GNAT RUN-TIME COMPONENTS --
|
|
-- --
|
|
-- A D A . S T R I N G S . W I D E _ M A P S --
|
|
-- --
|
|
-- B o d y --
|
|
-- --
|
|
-- Copyright (C) 1992-2006, Free Software Foundation, Inc. --
|
|
-- --
|
|
-- GNAT is free software; you can redistribute it and/or modify it under --
|
|
-- terms of the GNU General Public License as published by the Free Soft- --
|
|
-- ware Foundation; either version 2, or (at your option) any later ver- --
|
|
-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
|
|
-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
|
|
-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
|
|
-- for more details. You should have received a copy of the GNU General --
|
|
-- Public License distributed with GNAT; see file COPYING. If not, write --
|
|
-- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
|
|
-- Boston, MA 02110-1301, USA. --
|
|
-- --
|
|
-- As a special exception, if other files instantiate generics from this --
|
|
-- unit, or you link this unit with other files to produce an executable, --
|
|
-- this unit does not by itself cause the resulting executable to be --
|
|
-- covered by the GNU General Public License. This exception does not --
|
|
-- however invalidate any other reasons why the executable file might be --
|
|
-- covered by the GNU Public License. --
|
|
-- --
|
|
-- GNAT was originally developed by the GNAT team at New York University. --
|
|
-- Extensive contributions were provided by Ada Core Technologies Inc. --
|
|
-- --
|
|
------------------------------------------------------------------------------
|
|
|
|
with Unchecked_Deallocation;
|
|
|
|
package body Ada.Strings.Wide_Maps is
|
|
|
|
---------
|
|
-- "-" --
|
|
---------
|
|
|
|
function "-"
|
|
(Left, Right : Wide_Character_Set) return Wide_Character_Set
|
|
is
|
|
LS : constant Wide_Character_Ranges_Access := Left.Set;
|
|
RS : constant Wide_Character_Ranges_Access := Right.Set;
|
|
|
|
Result : Wide_Character_Ranges (1 .. LS'Last + RS'Last);
|
|
-- Each range on the right can generate at least one more range in
|
|
-- the result, by splitting one of the left operand ranges.
|
|
|
|
N : Natural := 0;
|
|
R : Natural := 1;
|
|
L : Natural := 1;
|
|
|
|
Left_Low : Wide_Character;
|
|
-- Left_Low is lowest character of the L'th range not yet dealt with
|
|
|
|
begin
|
|
if LS'Last = 0 or else RS'Last = 0 then
|
|
return Left;
|
|
end if;
|
|
|
|
Left_Low := LS (L).Low;
|
|
while R <= RS'Last loop
|
|
|
|
-- If next right range is below current left range, skip it
|
|
|
|
if RS (R).High < Left_Low then
|
|
R := R + 1;
|
|
|
|
-- If next right range above current left range, copy remainder
|
|
-- of the left range to the result
|
|
|
|
elsif RS (R).Low > LS (L).High then
|
|
N := N + 1;
|
|
Result (N).Low := Left_Low;
|
|
Result (N).High := LS (L).High;
|
|
L := L + 1;
|
|
exit when L > LS'Last;
|
|
Left_Low := LS (L).Low;
|
|
|
|
else
|
|
-- Next right range overlaps bottom of left range
|
|
|
|
if RS (R).Low <= Left_Low then
|
|
|
|
-- Case of right range complete overlaps left range
|
|
|
|
if RS (R).High >= LS (L).High then
|
|
L := L + 1;
|
|
exit when L > LS'Last;
|
|
Left_Low := LS (L).Low;
|
|
|
|
-- Case of right range eats lower part of left range
|
|
|
|
else
|
|
Left_Low := Wide_Character'Succ (RS (R).High);
|
|
R := R + 1;
|
|
end if;
|
|
|
|
-- Next right range overlaps some of left range, but not bottom
|
|
|
|
else
|
|
N := N + 1;
|
|
Result (N).Low := Left_Low;
|
|
Result (N).High := Wide_Character'Pred (RS (R).Low);
|
|
|
|
-- Case of right range splits left range
|
|
|
|
if RS (R).High < LS (L).High then
|
|
Left_Low := Wide_Character'Succ (RS (R).High);
|
|
R := R + 1;
|
|
|
|
-- Case of right range overlaps top of left range
|
|
|
|
else
|
|
L := L + 1;
|
|
exit when L > LS'Last;
|
|
Left_Low := LS (L).Low;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end loop;
|
|
|
|
-- Copy remainder of left ranges to result
|
|
|
|
if L <= LS'Last then
|
|
N := N + 1;
|
|
Result (N).Low := Left_Low;
|
|
Result (N).High := LS (L).High;
|
|
|
|
loop
|
|
L := L + 1;
|
|
exit when L > LS'Last;
|
|
N := N + 1;
|
|
Result (N) := LS (L);
|
|
end loop;
|
|
end if;
|
|
|
|
return (AF.Controlled with
|
|
Set => new Wide_Character_Ranges'(Result (1 .. N)));
|
|
end "-";
|
|
|
|
---------
|
|
-- "=" --
|
|
---------
|
|
|
|
-- The sorted, discontiguous form is canonical, so equality can be used
|
|
|
|
function "=" (Left, Right : Wide_Character_Set) return Boolean is
|
|
begin
|
|
return Left.Set.all = Right.Set.all;
|
|
end "=";
|
|
|
|
-----------
|
|
-- "and" --
|
|
-----------
|
|
|
|
function "and"
|
|
(Left, Right : Wide_Character_Set) return Wide_Character_Set
|
|
is
|
|
LS : constant Wide_Character_Ranges_Access := Left.Set;
|
|
RS : constant Wide_Character_Ranges_Access := Right.Set;
|
|
|
|
Result : Wide_Character_Ranges (1 .. LS'Last + RS'Last);
|
|
N : Natural := 0;
|
|
L, R : Natural := 1;
|
|
|
|
begin
|
|
-- Loop to search for overlapping character ranges
|
|
|
|
while L <= LS'Last and then R <= RS'Last loop
|
|
|
|
if LS (L).High < RS (R).Low then
|
|
L := L + 1;
|
|
|
|
elsif RS (R).High < LS (L).Low then
|
|
R := R + 1;
|
|
|
|
-- Here we have LS (L).High >= RS (R).Low
|
|
-- and RS (R).High >= LS (L).Low
|
|
-- so we have an overlapping range
|
|
|
|
else
|
|
N := N + 1;
|
|
Result (N).Low := Wide_Character'Max (LS (L).Low, RS (R).Low);
|
|
Result (N).High :=
|
|
Wide_Character'Min (LS (L).High, RS (R).High);
|
|
|
|
if RS (R).High = LS (L).High then
|
|
L := L + 1;
|
|
R := R + 1;
|
|
elsif RS (R).High < LS (L).High then
|
|
R := R + 1;
|
|
else
|
|
L := L + 1;
|
|
end if;
|
|
end if;
|
|
end loop;
|
|
|
|
return (AF.Controlled with
|
|
Set => new Wide_Character_Ranges'(Result (1 .. N)));
|
|
end "and";
|
|
|
|
-----------
|
|
-- "not" --
|
|
-----------
|
|
|
|
function "not"
|
|
(Right : Wide_Character_Set) return Wide_Character_Set
|
|
is
|
|
RS : constant Wide_Character_Ranges_Access := Right.Set;
|
|
|
|
Result : Wide_Character_Ranges (1 .. RS'Last + 1);
|
|
N : Natural := 0;
|
|
|
|
begin
|
|
if RS'Last = 0 then
|
|
N := 1;
|
|
Result (1) := (Low => Wide_Character'First,
|
|
High => Wide_Character'Last);
|
|
|
|
else
|
|
if RS (1).Low /= Wide_Character'First then
|
|
N := N + 1;
|
|
Result (N).Low := Wide_Character'First;
|
|
Result (N).High := Wide_Character'Pred (RS (1).Low);
|
|
end if;
|
|
|
|
for K in 1 .. RS'Last - 1 loop
|
|
N := N + 1;
|
|
Result (N).Low := Wide_Character'Succ (RS (K).High);
|
|
Result (N).High := Wide_Character'Pred (RS (K + 1).Low);
|
|
end loop;
|
|
|
|
if RS (RS'Last).High /= Wide_Character'Last then
|
|
N := N + 1;
|
|
Result (N).Low := Wide_Character'Succ (RS (RS'Last).High);
|
|
Result (N).High := Wide_Character'Last;
|
|
end if;
|
|
end if;
|
|
|
|
return (AF.Controlled with
|
|
Set => new Wide_Character_Ranges'(Result (1 .. N)));
|
|
end "not";
|
|
|
|
----------
|
|
-- "or" --
|
|
----------
|
|
|
|
function "or"
|
|
(Left, Right : Wide_Character_Set) return Wide_Character_Set
|
|
is
|
|
LS : constant Wide_Character_Ranges_Access := Left.Set;
|
|
RS : constant Wide_Character_Ranges_Access := Right.Set;
|
|
|
|
Result : Wide_Character_Ranges (1 .. LS'Last + RS'Last);
|
|
N : Natural;
|
|
L, R : Natural;
|
|
|
|
begin
|
|
N := 0;
|
|
L := 1;
|
|
R := 1;
|
|
|
|
-- Loop through ranges in output file
|
|
|
|
loop
|
|
-- If no left ranges left, copy next right range
|
|
|
|
if L > LS'Last then
|
|
exit when R > RS'Last;
|
|
N := N + 1;
|
|
Result (N) := RS (R);
|
|
R := R + 1;
|
|
|
|
-- If no right ranges left, copy next left range
|
|
|
|
elsif R > RS'Last then
|
|
N := N + 1;
|
|
Result (N) := LS (L);
|
|
L := L + 1;
|
|
|
|
else
|
|
-- We have two ranges, choose lower one
|
|
|
|
N := N + 1;
|
|
|
|
if LS (L).Low <= RS (R).Low then
|
|
Result (N) := LS (L);
|
|
L := L + 1;
|
|
else
|
|
Result (N) := RS (R);
|
|
R := R + 1;
|
|
end if;
|
|
|
|
-- Loop to collapse ranges into last range
|
|
|
|
loop
|
|
-- Collapse next length range into current result range
|
|
-- if possible.
|
|
|
|
if L <= LS'Last
|
|
and then LS (L).Low <= Wide_Character'Succ (Result (N).High)
|
|
then
|
|
Result (N).High :=
|
|
Wide_Character'Max (Result (N).High, LS (L).High);
|
|
L := L + 1;
|
|
|
|
-- Collapse next right range into current result range
|
|
-- if possible
|
|
|
|
elsif R <= RS'Last
|
|
and then RS (R).Low <=
|
|
Wide_Character'Succ (Result (N).High)
|
|
then
|
|
Result (N).High :=
|
|
Wide_Character'Max (Result (N).High, RS (R).High);
|
|
R := R + 1;
|
|
|
|
-- If neither range collapses, then done with this range
|
|
|
|
else
|
|
exit;
|
|
end if;
|
|
end loop;
|
|
end if;
|
|
end loop;
|
|
|
|
return (AF.Controlled with
|
|
Set => new Wide_Character_Ranges'(Result (1 .. N)));
|
|
end "or";
|
|
|
|
-----------
|
|
-- "xor" --
|
|
-----------
|
|
|
|
function "xor"
|
|
(Left, Right : Wide_Character_Set) return Wide_Character_Set
|
|
is
|
|
begin
|
|
return (Left or Right) - (Left and Right);
|
|
end "xor";
|
|
|
|
------------
|
|
-- Adjust --
|
|
------------
|
|
|
|
procedure Adjust (Object : in out Wide_Character_Mapping) is
|
|
begin
|
|
Object.Map := new Wide_Character_Mapping_Values'(Object.Map.all);
|
|
end Adjust;
|
|
|
|
procedure Adjust (Object : in out Wide_Character_Set) is
|
|
begin
|
|
Object.Set := new Wide_Character_Ranges'(Object.Set.all);
|
|
end Adjust;
|
|
|
|
--------------
|
|
-- Finalize --
|
|
--------------
|
|
|
|
procedure Finalize (Object : in out Wide_Character_Mapping) is
|
|
|
|
procedure Free is new Unchecked_Deallocation
|
|
(Wide_Character_Mapping_Values,
|
|
Wide_Character_Mapping_Values_Access);
|
|
|
|
begin
|
|
if Object.Map /= Null_Map'Unrestricted_Access then
|
|
Free (Object.Map);
|
|
end if;
|
|
end Finalize;
|
|
|
|
procedure Finalize (Object : in out Wide_Character_Set) is
|
|
|
|
procedure Free is new Unchecked_Deallocation
|
|
(Wide_Character_Ranges,
|
|
Wide_Character_Ranges_Access);
|
|
|
|
begin
|
|
if Object.Set /= Null_Range'Unrestricted_Access then
|
|
Free (Object.Set);
|
|
end if;
|
|
end Finalize;
|
|
|
|
----------------
|
|
-- Initialize --
|
|
----------------
|
|
|
|
procedure Initialize (Object : in out Wide_Character_Mapping) is
|
|
begin
|
|
Object := Identity;
|
|
end Initialize;
|
|
|
|
procedure Initialize (Object : in out Wide_Character_Set) is
|
|
begin
|
|
Object := Null_Set;
|
|
end Initialize;
|
|
|
|
-----------
|
|
-- Is_In --
|
|
-----------
|
|
|
|
function Is_In
|
|
(Element : Wide_Character;
|
|
Set : Wide_Character_Set) return Boolean
|
|
is
|
|
L, R, M : Natural;
|
|
SS : constant Wide_Character_Ranges_Access := Set.Set;
|
|
|
|
begin
|
|
L := 1;
|
|
R := SS'Last;
|
|
|
|
-- Binary search loop. The invariant is that if Element is in any of
|
|
-- of the constituent ranges it is in one between Set (L) and Set (R).
|
|
|
|
loop
|
|
if L > R then
|
|
return False;
|
|
|
|
else
|
|
M := (L + R) / 2;
|
|
|
|
if Element > SS (M).High then
|
|
L := M + 1;
|
|
elsif Element < SS (M).Low then
|
|
R := M - 1;
|
|
else
|
|
return True;
|
|
end if;
|
|
end if;
|
|
end loop;
|
|
end Is_In;
|
|
|
|
---------------
|
|
-- Is_Subset --
|
|
---------------
|
|
|
|
function Is_Subset
|
|
(Elements : Wide_Character_Set;
|
|
Set : Wide_Character_Set) return Boolean
|
|
is
|
|
ES : constant Wide_Character_Ranges_Access := Elements.Set;
|
|
SS : constant Wide_Character_Ranges_Access := Set.Set;
|
|
|
|
S : Positive := 1;
|
|
E : Positive := 1;
|
|
|
|
begin
|
|
loop
|
|
-- If no more element ranges, done, and result is true
|
|
|
|
if E > ES'Last then
|
|
return True;
|
|
|
|
-- If more element ranges, but no more set ranges, result is false
|
|
|
|
elsif S > SS'Last then
|
|
return False;
|
|
|
|
-- Remove irrelevant set range
|
|
|
|
elsif SS (S).High < ES (E).Low then
|
|
S := S + 1;
|
|
|
|
-- Get rid of element range that is properly covered by set
|
|
|
|
elsif SS (S).Low <= ES (E).Low
|
|
and then ES (E).High <= SS (S).High
|
|
then
|
|
E := E + 1;
|
|
|
|
-- Otherwise we have a non-covered element range, result is false
|
|
|
|
else
|
|
return False;
|
|
end if;
|
|
end loop;
|
|
end Is_Subset;
|
|
|
|
---------------
|
|
-- To_Domain --
|
|
---------------
|
|
|
|
function To_Domain
|
|
(Map : Wide_Character_Mapping) return Wide_Character_Sequence
|
|
is
|
|
begin
|
|
return Map.Map.Domain;
|
|
end To_Domain;
|
|
|
|
----------------
|
|
-- To_Mapping --
|
|
----------------
|
|
|
|
function To_Mapping
|
|
(From, To : Wide_Character_Sequence) return Wide_Character_Mapping
|
|
is
|
|
Domain : Wide_Character_Sequence (1 .. From'Length);
|
|
Rangev : Wide_Character_Sequence (1 .. To'Length);
|
|
N : Natural := 0;
|
|
|
|
begin
|
|
if From'Length /= To'Length then
|
|
raise Translation_Error;
|
|
|
|
else
|
|
pragma Warnings (Off); -- apparent uninit use of Domain
|
|
|
|
for J in From'Range loop
|
|
for M in 1 .. N loop
|
|
if From (J) = Domain (M) then
|
|
raise Translation_Error;
|
|
elsif From (J) < Domain (M) then
|
|
Domain (M + 1 .. N + 1) := Domain (M .. N);
|
|
Rangev (M + 1 .. N + 1) := Rangev (M .. N);
|
|
Domain (M) := From (J);
|
|
Rangev (M) := To (J);
|
|
goto Continue;
|
|
end if;
|
|
end loop;
|
|
|
|
Domain (N + 1) := From (J);
|
|
Rangev (N + 1) := To (J);
|
|
|
|
<<Continue>>
|
|
N := N + 1;
|
|
end loop;
|
|
|
|
pragma Warnings (On);
|
|
|
|
return (AF.Controlled with
|
|
Map => new Wide_Character_Mapping_Values'(
|
|
Length => N,
|
|
Domain => Domain (1 .. N),
|
|
Rangev => Rangev (1 .. N)));
|
|
end if;
|
|
end To_Mapping;
|
|
|
|
--------------
|
|
-- To_Range --
|
|
--------------
|
|
|
|
function To_Range
|
|
(Map : Wide_Character_Mapping) return Wide_Character_Sequence
|
|
is
|
|
begin
|
|
return Map.Map.Rangev;
|
|
end To_Range;
|
|
|
|
---------------
|
|
-- To_Ranges --
|
|
---------------
|
|
|
|
function To_Ranges
|
|
(Set : Wide_Character_Set) return Wide_Character_Ranges
|
|
is
|
|
begin
|
|
return Set.Set.all;
|
|
end To_Ranges;
|
|
|
|
-----------------
|
|
-- To_Sequence --
|
|
-----------------
|
|
|
|
function To_Sequence
|
|
(Set : Wide_Character_Set) return Wide_Character_Sequence
|
|
is
|
|
SS : constant Wide_Character_Ranges_Access := Set.Set;
|
|
|
|
Result : Wide_String (Positive range 1 .. 2 ** 16);
|
|
N : Natural := 0;
|
|
|
|
begin
|
|
for J in SS'Range loop
|
|
for K in SS (J).Low .. SS (J).High loop
|
|
N := N + 1;
|
|
Result (N) := K;
|
|
end loop;
|
|
end loop;
|
|
|
|
return Result (1 .. N);
|
|
end To_Sequence;
|
|
|
|
------------
|
|
-- To_Set --
|
|
------------
|
|
|
|
-- Case of multiple range input
|
|
|
|
function To_Set
|
|
(Ranges : Wide_Character_Ranges) return Wide_Character_Set
|
|
is
|
|
Result : Wide_Character_Ranges (Ranges'Range);
|
|
N : Natural := 0;
|
|
J : Natural;
|
|
|
|
begin
|
|
-- The output of To_Set is required to be sorted by increasing Low
|
|
-- values, and discontiguous, so first we sort them as we enter them,
|
|
-- using a simple insertion sort.
|
|
|
|
pragma Warnings (Off);
|
|
-- Kill bogus warning on Result being uninitialized
|
|
|
|
for J in Ranges'Range loop
|
|
for K in 1 .. N loop
|
|
if Ranges (J).Low < Result (K).Low then
|
|
Result (K + 1 .. N + 1) := Result (K .. N);
|
|
Result (K) := Ranges (J);
|
|
goto Continue;
|
|
end if;
|
|
end loop;
|
|
|
|
Result (N + 1) := Ranges (J);
|
|
|
|
<<Continue>>
|
|
N := N + 1;
|
|
end loop;
|
|
|
|
pragma Warnings (On);
|
|
|
|
-- Now collapse any contiguous or overlapping ranges
|
|
|
|
J := 1;
|
|
while J < N loop
|
|
if Result (J).High < Result (J).Low then
|
|
N := N - 1;
|
|
Result (J .. N) := Result (J + 1 .. N + 1);
|
|
|
|
elsif Wide_Character'Succ (Result (J).High) >= Result (J + 1).Low then
|
|
Result (J).High :=
|
|
Wide_Character'Max (Result (J).High, Result (J + 1).High);
|
|
|
|
N := N - 1;
|
|
Result (J + 1 .. N) := Result (J + 2 .. N + 1);
|
|
|
|
else
|
|
J := J + 1;
|
|
end if;
|
|
end loop;
|
|
|
|
if N > 0 and then Result (N).High < Result (N).Low then
|
|
N := N - 1;
|
|
end if;
|
|
|
|
return (AF.Controlled with
|
|
Set => new Wide_Character_Ranges'(Result (1 .. N)));
|
|
end To_Set;
|
|
|
|
-- Case of single range input
|
|
|
|
function To_Set
|
|
(Span : Wide_Character_Range) return Wide_Character_Set
|
|
is
|
|
begin
|
|
if Span.Low > Span.High then
|
|
return Null_Set;
|
|
-- This is safe, because there is no procedure with parameter
|
|
-- Wide_Character_Set of mode "out" or "in out".
|
|
|
|
else
|
|
return (AF.Controlled with
|
|
Set => new Wide_Character_Ranges'(1 => Span));
|
|
end if;
|
|
end To_Set;
|
|
|
|
-- Case of wide string input
|
|
|
|
function To_Set
|
|
(Sequence : Wide_Character_Sequence) return Wide_Character_Set
|
|
is
|
|
R : Wide_Character_Ranges (1 .. Sequence'Length);
|
|
|
|
begin
|
|
for J in R'Range loop
|
|
R (J) := (Sequence (J), Sequence (J));
|
|
end loop;
|
|
|
|
return To_Set (R);
|
|
end To_Set;
|
|
|
|
-- Case of single wide character input
|
|
|
|
function To_Set
|
|
(Singleton : Wide_Character) return Wide_Character_Set
|
|
is
|
|
begin
|
|
return
|
|
(AF.Controlled with
|
|
Set => new Wide_Character_Ranges'(1 => (Singleton, Singleton)));
|
|
end To_Set;
|
|
|
|
-----------
|
|
-- Value --
|
|
-----------
|
|
|
|
function Value
|
|
(Map : Wide_Character_Mapping;
|
|
Element : Wide_Character) return Wide_Character
|
|
is
|
|
L, R, M : Natural;
|
|
|
|
MV : constant Wide_Character_Mapping_Values_Access := Map.Map;
|
|
|
|
begin
|
|
L := 1;
|
|
R := MV.Domain'Last;
|
|
|
|
-- Binary search loop
|
|
|
|
loop
|
|
-- If not found, identity
|
|
|
|
if L > R then
|
|
return Element;
|
|
|
|
-- Otherwise do binary divide
|
|
|
|
else
|
|
M := (L + R) / 2;
|
|
|
|
if Element < MV.Domain (M) then
|
|
R := M - 1;
|
|
|
|
elsif Element > MV.Domain (M) then
|
|
L := M + 1;
|
|
|
|
else -- Element = MV.Domain (M) then
|
|
return MV.Rangev (M);
|
|
end if;
|
|
end if;
|
|
end loop;
|
|
end Value;
|
|
|
|
end Ada.Strings.Wide_Maps;
|