aboutsummaryrefslogtreecommitdiffstats
path: root/src/tables.adb
blob: ca867426908d560726e192805eb2429af821fe12 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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
133
134
135
136
137
138
139
140
141
142
143
--  Efficient expandable one dimensional array.
--  Copyright (C) 2015 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 Tables is
   --  Number of allocated elements in the table.
   Length : Natural := 0;

   --  Number of used elements in the table.
   Last_Pos : Natural := 0;

   --  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 (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 (Length /= 0);
      pragma Assert (Table /= null);

      --  Expand the bound.
      Last_Pos := Last_Pos + Num;

      --  Check if need to reallocate.
      if Last_Pos < Length then
         return;
      else
         --  Double the length.
         loop
            Length := Length * 2;
            exit when Length > Last_Pos;
         end loop;
      end if;

      --  Realloc and check result.
      Table := Crealloc (Table, size_t (Length) * El_Size);
      if Table = null then
         raise Storage_Error;
      end if;
   end Expand;

   function Allocate (Num : Natural := 1) return Table_Index_Type
   is
      Res : constant Table_Index_Type := Table_Index_Type'Val
        (Table_Index_Type'Pos (Table_Low_Bound) + Last_Pos);
   begin
      Expand (Num);

      return Res;
   end Allocate;

   procedure Increment_Last is
   begin
      --  Increase by 1.
      Expand (1);
   end Increment_Last;

   procedure Decrement_Last is
   begin
      Last_Pos := Last_Pos - 1;
   end Decrement_Last;

   procedure Set_Last (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 < Last_Pos then
         --  Decrease length.
         Last_Pos := New_Last;
      else
         --  Increase length.
         Expand (New_Last - Last_Pos);
      end if;
   end Set_Last;

   procedure Init
   is
      --  Direct interface to malloc.
      function Cmalloc (Size : size_t) return Table_Thin_Ptr;
      pragma Import (C, Cmalloc, "malloc");
   begin
      if Table = null then
         --  Allocate memory if not already allocated.
         Length := Table_Initial;
         Table := Cmalloc (size_t (Length) * El_Size);
      end if;

      --  Table is initially empty.
      Last_Pos := 0;
   end Init;

   function Last return Table_Index_Type is
   begin
      return Table_Index_Type'Val
        (Table_Index_Type'Pos (Table_Low_Bound) + Last_Pos - 1);
   end Last;

   procedure Free is
      --  Direct interface to free.
      procedure Cfree (Ptr : Table_Thin_Ptr);
      pragma Import (C, Cfree, "free");
   begin
      Cfree (Table);
      Table := null;
      Length := 0;
      Last_Pos := 0;
   end Free;

   procedure Append (Val : Table_Component_Type) is
   begin
      Increment_Last;
      Table (Last) := Val;
   end Append;

begin
   Init;
end Tables;