| -- { dg-do run } |
| |
| with Interfaces; use Interfaces; |
| |
| procedure Access7 is |
| type t_p_string is access constant String; |
| subtype t_hash is Unsigned_32; |
| |
| -- Return a hash value for a given string |
| function hash(s: String) return t_hash is |
| h: t_hash := 0; |
| g: t_hash; |
| begin |
| for i in s'Range loop |
| h := Shift_Left(h, 4) + t_hash'(Character'Pos(s(i))); |
| g := h and 16#F000_0000#; |
| if (h and g) /= 0 then |
| h := h xor ((Shift_Right(g, 24) and 16#FF#) or g); |
| end if; |
| end loop; |
| return h; |
| end hash; |
| |
| type hash_entry is record |
| v: t_p_string; |
| hash: t_hash; |
| next: access hash_entry; |
| end record; |
| |
| type hashtable is array(t_hash range <>) of access hash_entry; |
| |
| protected pool is |
| procedure allocate (sp: out t_p_string; s: String; h: t_hash); |
| private |
| tab: hashtable(0..199999-1) := (others => null); |
| end pool; |
| |
| protected body pool is |
| procedure allocate(sp: out t_p_string; s: String; h: t_hash) is |
| p: access hash_entry; |
| slot: t_hash; |
| begin |
| slot := h mod tab'Length; |
| p := tab(slot); |
| while p /= null loop |
| -- quickly check hash, then length, only then slow comparison |
| if p.hash = h and then p.v.all'Length = s'Length |
| and then p.v.all = s |
| then |
| sp := p.v; -- shared string |
| return; |
| end if; |
| p := p.next; |
| end loop; |
| -- add to table |
| p := new hash_entry'(v => new String'(s), |
| hash => h, |
| next => tab(slot)); |
| tab(slot) := p; -- { dg-warning "accessibility check fails|Program_Error will be raised at run time" } |
| sp := p.v; -- shared string |
| end allocate; |
| end pool; |
| |
| -- Return the pooled string equal to a given String |
| function new_p_string(s: String) return t_p_string is |
| sp: t_p_string; |
| begin |
| pool.allocate(sp, s, hash(s)); |
| return sp; |
| end new_p_string; |
| |
| foo_string : t_p_string; |
| begin |
| foo_string := new_p_string("foo"); |
| raise Constraint_Error; |
| exception |
| when Program_Error => |
| null; |
| end Access7; |