aboutsummaryrefslogtreecommitdiffstats
path: root/src/dyn_tables.adb
diff options
context:
space:
mode:
authorTristan Gingold <tgingold@free.fr>2016-11-08 08:11:01 +0100
committerTristan Gingold <tgingold@free.fr>2016-11-08 08:11:01 +0100
commit6235a6a731633a2727e3b0022c8aaccf942e7f60 (patch)
tree71c428dc1a92c824f74d35f8cfc2003dd1134ccd /src/dyn_tables.adb
parent619a818dde23dfc6361a2edce9fe0b18aa249d40 (diff)
downloadghdl-6235a6a731633a2727e3b0022c8aaccf942e7f60.tar.gz
ghdl-6235a6a731633a2727e3b0022c8aaccf942e7f60.tar.bz2
ghdl-6235a6a731633a2727e3b0022c8aaccf942e7f60.zip
Add dyn_tables package, rewrite tables using dyn_tables.
Diffstat (limited to 'src/dyn_tables.adb')
-rw-r--r--src/dyn_tables.adb129
1 files changed, 129 insertions, 0 deletions
diff --git a/src/dyn_tables.adb b/src/dyn_tables.adb
new file mode 100644
index 000000000..be733acc8
--- /dev/null
+++ b/src/dyn_tables.adb
@@ -0,0 +1,129 @@
+-- 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 : Natural)
+ is
+ -- For efficiency, directly call realloc.
+ function Crealloc (Ptr : Table_Thin_Ptr; Size : size_t)
+ return Table_Thin_Ptr;
+ pragma Import (C, Crealloc, "realloc");
+ begin
+ pragma Assert (T.Priv.Length /= 0);
+ pragma Assert (T.Table /= null);
+
+ -- Expand the bound.
+ T.Priv.Last_Pos := T.Priv.Last_Pos + Num;
+
+ -- Check if need to reallocate.
+ if T.Priv.Last_Pos < T.Priv.Length then
+ return;
+ else
+ -- Double the length.
+ loop
+ T.Priv.Length := T.Priv.Length * 2;
+ exit when T.Priv.Length > T.Priv.Last_Pos;
+ end loop;
+ end if;
+
+ -- Realloc and check result.
+ 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, 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 Natural :=
+ (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 := 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) + T.Priv.Last_Pos - 1);
+ end Last;
+
+ 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;