------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2010-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY 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 -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Containers; use Ada.Containers; with Ada.Strings.Hash; with Ada.Unchecked_Conversion; with Ada.Unchecked_Deallocation; with GNAT.IO; use GNAT.IO; with GNAT.Strings; with System.Address_Image; package body GNATCOLL.Symbols is use String_Htable; Table_Size : constant := 98_317; -- The initial capacity of the htable. This was computed from inserting -- all entities from the GPS project, using Ada.Strings.Hash for the hash, -- but seems to be the same when using other hash codes. -- The table will readjust itself anyway, but setting this properly avoids -- a few resizing. ----------------- -- Debug_Print -- ----------------- function Debug_Print (S : Symbol) return String is begin if S = No_Symbol then return ""; else return ""; end if; end Debug_Print; ---------- -- Hash -- ---------- function Hash (Str : Cst_String_Access) return Hash_Type is begin return Ada.Strings.Hash (Str.all); end Hash; --------------- -- Key_Equal -- --------------- function Key_Equal (Key1, Key2 : Cst_String_Access) return Boolean is begin return Key1.all = Key2.all; end Key_Equal; ---------- -- Find -- ---------- function Find (Table : access Symbol_Table_Record; Str : String) return Symbol is Result : String_Htable.Cursor; Tmp : Cst_String_Access; begin if Str'Length = 0 then return Empty_String; else Table.Calls_To_Find := Table.Calls_To_Find + 1; Result := Table.Hash.Find (Str'Unrestricted_Access); if not Has_Element (Result) then Table.Total_Size := Table.Total_Size + Str'Length; Tmp := new String'(Str); Table.Hash.Include (Tmp); return Symbol (Tmp); else Table.Size_Saved := Table.Size_Saved + Str'Length; end if; return Symbol (Element (Result)); end if; end Find; ------------------- -- Display_Stats -- ------------------- procedure Display_Stats (Self : access Symbol_Table_Record) is C : String_Htable.Cursor := Self.Hash.First; Tmp : Cst_String_Access; Count : Natural := 0; Last : Hash_Type := Hash_Type'Last; H : Hash_Type; Bucket_Count : Natural := 0; begin while Has_Element (C) loop Tmp := Element (C); H := Hash (Tmp); if H = Last then Count := Count + 1; else if Last /= Hash_Type'Last then Put_Line ("Bucket" & Last'Img & " =>" & Count'Img & " entries"); end if; Last := H; Count := 1; Bucket_Count := Bucket_Count + 1; end if; Put_Line (Hash (Tmp)'Img & " => " & Tmp.all); Next (C); end loop; Put_Line ("Total calls to Find: " & Self.Calls_To_Find'Img); Put_Line ("Number of entries in the symbols table:" & Self.Hash.Length'Img); Put_Line ("Maximum number of buckets:" & Self.Hash.Capacity'Img); Put_Line ("Number of buckets used:" & Bucket_Count'Img); Put_Line ("Mean entries per bucket:" & Integer'Image (Integer (Self.Hash.Length) / Bucket_Count)); Put_Line ("Total size in strings:" & Self.Total_Size'Img); Put_Line ("Size that would have been allocated for strings:" & Self.Size_Saved'Img); end Display_Stats; --------- -- Get -- --------- function Get (Sym : Symbol; Empty_If_Null : Boolean := True) return Cst_String_Access is begin if Sym = No_Symbol then if Empty_If_Null then return Cst_String_Access (Empty_String); else return null; end if; else return Cst_String_Access (Sym); end if; end Get; ---------- -- Free -- ---------- procedure Free (Table : in out Symbol_Table_Record) is function Convert is new Ada.Unchecked_Conversion (Cst_String_Access, GNAT.Strings.String_Access); procedure Unchecked_Free is new Ada.Unchecked_Deallocation (String, GNAT.Strings.String_Access); S : GNAT.Strings.String_Access; C : String_Htable.Cursor := Table.Hash.First; Tmp : Cst_String_Access; begin while Has_Element (C) loop Tmp := Element (C); Next (C); S := Convert (Tmp); Unchecked_Free (S); end loop; Table.Hash.Clear; end Free; ---------- -- Free -- ---------- procedure Free (Table : in out Symbol_Table_Access) is procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Symbol_Table_Record'Class, Symbol_Table_Access); begin if Table /= null then Free (Table.all); Unchecked_Free (Table); end if; end Free; ---------- -- Hash -- ---------- function Hash (S : Symbol) return Hash_Type is begin return Hash (Cst_String_Access (S)); end Hash; -------------- -- Allocate -- -------------- function Allocate return Symbol_Table_Access is T : constant Symbol_Table_Access := new Symbol_Table_Record; begin T.Hash.Reserve_Capacity (Table_Size); return T; end Allocate; end GNATCOLL.Symbols;