OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [ada/] [a-stwima.adb] - Rev 848

Go to most recent revision | Compare with Previous | Blame | View Log

------------------------------------------------------------------------------
--                                                                          --
--                         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-2009, 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 3,  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.                                     --
--                                                                          --
-- As a special exception under Section 7 of GPL version 3, you are granted --
-- additional permissions described in the GCC Runtime Library Exception,   --
-- version 3.1, as published by the Free Software Foundation.               --
--                                                                          --
-- You should have received a copy of the GNU General Public License and    --
-- a copy of the GCC Runtime Library Exception along with this program;     --
-- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
-- <http://www.gnu.org/licenses/>.                                          --
--                                                                          --
-- GNAT was originally developed  by the GNAT team at  New York University. --
-- Extensive contributions were provided by Ada Core Technologies Inc.      --
--                                                                          --
------------------------------------------------------------------------------
 
with Ada.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 Ada.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 Ada.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;
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.