-- Efficient expandable one dimensional array. -- Copyright (C) 2015 - 2016 Tristan Gingold -- -- GHDL is free software; you can redistribute it and/or modify it under -- the terms of the GNU General Public License as published by the Free -- Software Foundation; either version 2, or (at your option) any later -- version. -- -- GHDL is distributed in the hope that it will be useful, but WITHOUT 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 -- along with GHDL; see the file COPYING. If not, write to the Free -- Software Foundation, 59 Temple Place - Suite 330, Boston, MA -- 02111-1307, USA. with Interfaces.C; use Interfaces.C; with System; package body Dyn_Tables is -- Size of an element in storage units (bytes). El_Size : constant size_t := size_t (Table_Type'Component_Size / System.Storage_Unit); -- Expand the table by doubling its size. The table must have been -- initialized. procedure Expand (T : in out Instance; Num : Unsigned) is -- For efficiency, directly call realloc. function Crealloc (Ptr : Table_Thin_Ptr; Size : size_t) return Table_Thin_Ptr; pragma Import (C, Crealloc, "realloc"); New_Len : Unsigned; New_Last : Unsigned; begin pragma Assert (T.Priv.Length /= 0); pragma Assert (T.Table /= null); -- Expand the bound. New_Last := T.Priv.Last_Pos + Num; if New_Last < T.Priv.Last_Pos then raise Constraint_Error; end if; T.Priv.Last_Pos := New_Last; -- Check if need to reallocate. if T.Priv.Last_Pos < T.Priv.Length then return; end if; -- Double the length. loop New_Len := T.Priv.Length * 2; -- Check overflow. if New_Len < T.Priv.Length then raise Constraint_Error; end if; T.Priv.Length := New_Len; exit when New_Len > T.Priv.Last_Pos; end loop; -- Realloc and check result. if size_t (T.Priv.Length) > size_t'Last / El_Size then raise Constraint_Error; end if; T.Table := Crealloc (T.Table, size_t (T.Priv.Length) * El_Size); if T.Table = null then raise Storage_Error; end if; end Expand; procedure Allocate (T : in out Instance; Num : Natural := 1) is begin Expand (T, Unsigned (Num)); end Allocate; procedure Increment_Last (T : in out Instance) is begin -- Increase by 1. Expand (T, 1); end Increment_Last; procedure Decrement_Last (T : in out Instance) is begin T.Priv.Last_Pos := T.Priv.Last_Pos - 1; end Decrement_Last; procedure Set_Last (T : in out Instance; Index : Table_Index_Type) is New_Last : constant Unsigned := (Table_Index_Type'Pos (Index) - Table_Index_Type'Pos (Table_Low_Bound) + 1); begin if New_Last < T.Priv.Last_Pos then -- Decrease length. T.Priv.Last_Pos := New_Last; else -- Increase length. Expand (T, New_Last - T.Priv.Last_Pos); end if; end Set_Last; procedure Init (T : in out Instance) is -- Direct interface to malloc. function Cmalloc (Size : size_t) return Table_Thin_Ptr; pragma Import (C, Cmalloc, "malloc"); begin if T.Table = null then -- Allocate memory if not already allocated. T.Priv.Length := Unsigned (Table_Initial); T.Table := Cmalloc (size_t (T.Priv.Length) * El_Size); end if; -- Table is initially empty. T.Priv.Last_Pos := 0; end Init; function Last (T : Instance) return Table_Index_Type is begin return Table_Index_Type'Val (Table_Index_Type'Pos (Table_Low_Bound) + Unsigned'Pos (T.Priv.Last_Pos) - 1); end Last; function Next (T : Instance) return Table_Index_Type is begin return Table_Index_Type'Val (Table_Index_Type'Pos (Table_Low_Bound) + T.Priv.Last_Pos); end Next; procedure Free (T : in out Instance) is -- Direct interface to free. procedure Cfree (Ptr : Table_Thin_Ptr); pragma Import (C, Cfree, "free"); begin Cfree (T.Table); T := (Table => null, Priv => (Length => 0, Last_Pos => 0)); end Free; procedure Append (T : in out Instance; Val : Table_Component_Type) is begin Increment_Last (T); T.Table (Last (T)) := Val; end Append; end Dyn_Tables; ef='#n47'>47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132