|
|
DataMuseum.dkPresents historical artifacts from the history of: Rational R1000/400 Tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Rational R1000/400 Tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: B T
Length: 14114 (0x3722)
Types: TextFile
Names: »B«
└─⟦85b835f43⟧ Bits:30000549 8mm tape, Rational 1000, Xlib rev 6.00
└─⟦0c20f784e⟧ »DATA«
└─⟦1abbe589f⟧
└─⟦591c5b094⟧
└─⟦this⟧
with Unchecked_Deallocation;
with Arithmetic;
use Arithmetic;
with Vstring_Case;
with Vstring_Type;
use Vstring_Type;
package body String_Heap is
------------------------------------------------------------------------------
-- Copyright 1989 - 1991 by Rational, Santa Clara, California.
--
-- All Rights Reserved.
--
-- Permission to use, copy, modify, and distribute this software and its
-- documentation for any purpose and without fee is hereby granted,
-- provided that the above copyright notice(s) appear in all copies and that
-- both that copyright notice(s) and this permission notice appear in
-- supporting documentation, and that the name of Rational not be used in
-- advertising or publicity pertaining to distribution of the software
-- without specific, written prior permission.
--
-- Rational disclaims all warranties with regard to this software, including
-- all implied warranties of merchantability and fitness, in no event shall
-- Rational be liable for any special, indirect or consequential damages or
-- any damages whatsoever resulting from loss of use, data or profits, whether
-- in an action of contract, negligence or other tortious action, arising out
-- of or in connection with the use or performance of this software.
------------------------------------------------------------------------------
type S_Natural_Array is array (S_Natural range <>) of S_Natural;
----Elements are simply pairs of string Keys and Range_Type values.
type Elem_Rec is
record
Hash : S_Natural := 0;
Key : E_String_Pointer := null;
Next : Element := null;
end record;
----Maps are simply a table of Element linked lists.
type Element_Array is array (S_Natural range 0 .. Hash_Size - 1) of Element;
type Map_Rec is
record
Count : S_Natural := 0;
Table : Element_Array := (0 .. Hash_Size - 1 => null);
end record;
--\f
procedure Free_String_Ptr is new Unchecked_Deallocation (E_String,
E_String_Pointer);
procedure Free_Element is new Unchecked_Deallocation (Elem_Rec,
Element);
procedure Free_Map_Internal is new Unchecked_Deallocation (Map_Rec,
Map);
--\f
function Hash (Key : E_String) return S_Natural is
------------------------------------------------------------------------------
-- Key - Specfies the string to hash
--
-- Returns a hash value for the indicated string.
------------------------------------------------------------------------------
Xl : S_Natural_Array (Key'Range);
use Vstring_Case;
begin
if Exact_Case_Match then
for I in Key'Range loop
Xl (I) := Character'Pos (Key (I));
end loop;
else
for I in Key'Range loop
Xl (I) := Character'Pos (Vstring_Case.Uc_Char (Key (I)));
end loop;
end if;
case Key'Length is
when 0 =>
return 0;
when 1 =>
return Xl (Xl'First);
when 2 =>
return Xl (Xl'First) * 128
+ Xl (Xl'Last);
when 3 =>
return Xl (Xl'First) * 64
+ Xl (Xl'First + 1) * 128
+ Xl (Xl'Last);
when 4 =>
return Xl (Xl'First) * 32
+ Xl (Xl'First + 1) * 64
+ Xl (Xl'First + 2) * 128
+ Xl (Xl'Last);
when others =>
declare
I : S_Natural := Xl'First;
H : S_Natural := 0;
begin
while I + 3 <= Xl'Last loop
if S_Natural'Last / 3 < H then
----Prevent overflow on long strings.
H := H / 3;
end if;
H := H + Xl (I) * 32
+ Xl (I + 1) * 64
+ Xl (I + 2) * 128
+ Xl (I + 3);
I := I + 4;
end loop;
for J in I .. Xl'Last loop
H := H + Xl (J);
end loop;
return H;
end;
end case;
end Hash;
--\f
function Equal (A : E_String; B : E_String) return Boolean is
------------------------------------------------------------------------------
-- A - Specifies the first string
-- B - Specifies the second string
--
-- Returns TRUE if A = B when both are upper case.
------------------------------------------------------------------------------
Ai : S_Natural := A'First;
Bi : S_Natural := B'First;
begin
----The lengths must be the same.
if A'Length /= B'Length then
return False;
end if;
----Check for any differences.
for I in S_Natural range 0 .. A'Length - 1 loop
if Vstring_Case.Uc_Char (A (Ai + I)) /=
Vstring_Case.Uc_Char (B (Bi + I)) then
return False;
end if;
end loop;
----They are the same.
return True;
end Equal;
--\f
procedure Lookup (H : S_Natural;
Key : E_String;
Prev : out Element;
Elem : in out Element) is
------------------------------------------------------------------------------
-- H - Specifies the hash value for the Key
-- Key - Specifies the key we are looking for
-- Prev - Receives the last element in the initial Elem list or else the
-- Element whose .Next is Elem.
-- Elem - Receives NULL or else the Element that matches the Key/H values;
-- initially is the M.Table(H) value
------------------------------------------------------------------------------
El : Element := Elem;
begin
----Initially there is no Prev vaue.
Prev := null;
----Loop over all of the chained elements looking for matching H/Key values.
while El /= null loop
if El.Hash = H then
if Exact_Case_Match then
if El.Key.all = Key then
Elem := El;
return;
end if;
else
if Equal (Key, El.Key.all) then
Elem := El;
return;
end if;
end if;
end if;
Prev := El;
El := El.Next;
end loop;
----Nothing was found. Return null.
Elem := null;
end Lookup;
--\f
procedure New_Map (M : out Map) is
------------------------------------------------------------------------------
-- M - Receives a new Map.
--
-- Called to create and initialize a new Map. The Map Is_Empty.
------------------------------------------------------------------------------
begin
M := new Map_Rec;
end New_Map;
--\f
procedure Free_Map (M : in out Map) is
------------------------------------------------------------------------------
-- M - Specifies the existing Map to deallocate.
--
-- Called to destroy an existing Map. Map may have a None_Map value. All map
-- entries are destroyed. The Range_Type values contained in the map are
-- merely dropped and are not deallocated or manipulated in any way.
------------------------------------------------------------------------------
Elem1 : Element;
Elem2 : Element;
begin
----Free any existing table entries.
if M.Count > 0 then
for I in M.Table'Range loop
Elem1 := M.Table (I);
----Free elements on this chain; including the Key strings.
while Elem1 /= null loop
Elem2 := Elem1.Next;
Free_String_Ptr (Elem1.Key);
Free_Element (Elem1);
Elem1 := Elem2;
end loop;
end loop;
end if;
----Free the map itself.
Free_Map_Internal (M);
end Free_Map;
--\f
function Is_Empty (M : in Map) return Boolean is
------------------------------------------------------------------------------
-- M - Specifies the map
--
-- Returns TRUE if the map is completely empty.
------------------------------------------------------------------------------
begin
return M.Count = 0;
end Is_Empty;
--\f
function Cardinality (M : in Map) return S_Natural is
------------------------------------------------------------------------------
-- M - Specifies the map
--
-- Returns the number of entries in the map.
------------------------------------------------------------------------------
begin
return M.Count;
end Cardinality;
--\f
function Share (M : in Map;
Key : in E_String) return E_String_Pointer is
------------------------------------------------------------------------------
-- M - Specifies the map to use
-- Key - Specifies the string value to use for the lookup
--
-- Returns a shared string containing the same characters as are found in Key.
------------------------------------------------------------------------------
H : S_Natural := Hash (Key);
Prev : Element;
Elem : Element := M.Table (H rem Hash_Size);
begin
----Lookup the entry in the table with this hash value. Replace any existing
-- entry if that is ok.
Lookup (H, Key, Prev, Elem);
if Elem /= null then
return Elem.Key;
end if;
----Create a new map element and put it into the map.
Elem := new Elem_Rec'(Hash => H,
Key => new E_String'(Key),
Next => null);
H := H rem Hash_Size;
Elem.Next := M.Table (H);
M.Table (H) := Elem;
M.Count := M.Count + 1;
return Elem.Key;
end Share;
--\f
procedure Initialize (M : in Map;
I : in out Iter) is
------------------------------------------------------------------------------
-- M - Specifies the map
-- I - Receives the new iteration value
--
-- Called to initialize an iterator for a particular map. Iterators are
-- used in this fashion:
-- declare
-- I : Iter;
-- M : Map;
-- Vl : E_String_Pointer;
-- begin
-- Initilize (M, I);
-- while not Done (I) loop
-- Vl := Key (I);
-- .... Code using the Vl value ....
-- Next (I);
-- end loop;
-- end;
-- Iterators are affected by changes to the map. Deletions can cause
-- dereferencing of null pointers. Insertions are benign and new map entries
-- may or may not appear as Values in the iteration depending upon the
-- state of the Iter when the Insert is performed and also depending upon the
-- value of the Key string.
--
-- The iterator will advance through all entries within the map and the
-- processing order of the entries is determined by the hash value of the
-- Key strings and may or may not have any externally sensible ordering.
------------------------------------------------------------------------------
begin
----Search for any element whatsoever.
I.M := M;
for Ind in 0 .. Hash_Size - 1 loop
if M.Table (Ind) /= null then
I.Elem := M.Table (Ind);
I.Index := Ind;
return;
end if;
end loop;
----Map is empty. Finish the initialization.
I.Elem := null;
I.Index := Hash_Size;
end Initialize;
--\f
function Done (I : in Iter) return Boolean is
------------------------------------------------------------------------------
-- I - Specifies the iterator to check
--
-- Returns TRUE when there are no more map entries to iterate through.
------------------------------------------------------------------------------
begin
----If we have an element waiting then we are not done.
if I.Elem /= null then
return False;
end if;
----We must be done.
return True;
end Done;
--\f
function Key (I : in Iter) return E_String_Pointer is
------------------------------------------------------------------------------
-- I - Specifies the iterator to check
--
-- Returns the key string value associated with the current value of the
-- map iterator. Raises Missing_Entry if Done(I) = TRUE.
------------------------------------------------------------------------------
begin
if I.Elem = null then
raise Missing_Entry;
end if;
return I.Elem.Key;
end Key;
--\f
procedure Next (I : in out Iter) is
------------------------------------------------------------------------------
-- I - Specifies the iterator
--
-- Advances the map iterator by one entry. Raises Missing_Entry if
-- Done(I) = TRUE already. Done(I) = TRUE will be true when this routine
-- returns if there are no more entries to be processed.
------------------------------------------------------------------------------
Elem : Element;
begin
----Locate the next element.
if I.Elem = null then
raise Missing_Entry;
end if;
if I.Elem.Next /= null then
I.Elem := I.Elem.Next;
return;
end if;
for Ind in I.Index + 1 .. Hash_Size - 1 loop
if I.M.Table (Ind) /= null then
I.Elem := I.M.Table (Ind);
I.Index := Ind;
return;
end if;
end loop;
----Nothing Next; we are Done.
I.Elem := null;
end Next;
--\f
end String_Heap;