1 /********************************************************************\
2  * gtable.c -- glib -- basic datatype for 2D array of values        *
3  *                                                                  *
4  * This program is free software; you can redistribute it and/or    *
5  * modify it under the terms of the GNU General Public License as   *
6  * published by the Free Software Foundation; either version 2 of   *
7  * the License, or (at your option) any later version.              *
8  *                                                                  *
9  * This program is distributed in the hope that it will be useful,  *
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
12  * GNU General Public License for more details.                     *
13  *                                                                  *
14  * You should have received a copy of the GNU General Public License*
15  * along with this program; if not, contact:                        *
16  *                                                                  *
17  * Free Software Foundation           Voice:  +1-617-542-5942       *
18  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
19  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
20  *                                                                  *
21 \********************************************************************/
22 
23 #include <config.h>
24 
25 #include "gtable.h"
26 
27 
28 struct GTable
29 {
30     GArray *array;
31 
32     guint entry_size;
33 
34     int rows;
35     int cols;
36 
37     g_table_entry_constructor constructor;
38     g_table_entry_destroyer destroyer;
39 
40     gpointer user_data;
41 };
42 
43 GTable *
g_table_new(guint entry_size,g_table_entry_constructor constructor,g_table_entry_destroyer destroyer,gpointer user_data)44 g_table_new (guint entry_size,
45              g_table_entry_constructor constructor,
46              g_table_entry_destroyer destroyer,
47              gpointer user_data)
48 {
49     GTable *gtable;
50 
51     gtable = g_new(GTable, 1);
52 
53     gtable->array = g_array_new(FALSE, FALSE, entry_size);
54 
55     gtable->entry_size = entry_size;
56 
57     gtable->rows = 0;
58     gtable->cols = 0;
59 
60     gtable->constructor = constructor;
61     gtable->destroyer = destroyer;
62 
63     gtable->user_data = user_data;
64 
65     return gtable;
66 }
67 
68 void
g_table_destroy(GTable * gtable)69 g_table_destroy (GTable *gtable)
70 {
71     if (gtable == NULL)
72         return;
73 
74     g_table_resize (gtable, 0, 0);
75 
76     g_array_free (gtable->array, TRUE);
77 
78     gtable->array = NULL;
79 
80     g_free(gtable);
81 }
82 
83 gpointer
g_table_index(GTable * gtable,int row,int col)84 g_table_index (GTable *gtable, int row, int col)
85 {
86      guint index = row * gtable->cols + col;
87      guint offset = index * gtable->entry_size;
88 
89     if (gtable == NULL)
90         return NULL;
91     if ((row < 0) || (col < 0))
92         return NULL;
93     if (row >= gtable->rows)
94         return NULL;
95     if (col >= gtable->cols)
96         return NULL;
97 
98     g_return_val_if_fail (gtable->array != NULL, NULL);
99     g_return_val_if_fail (gtable->array->len > index, NULL);
100     return &gtable->array->data[offset];
101 }
102 
103 void
g_table_resize(GTable * gtable,int rows,int cols)104 g_table_resize (GTable *gtable, int rows, int cols)
105 {
106     guint old_len;
107     guint new_len;
108 
109     if (gtable == NULL)
110         return;
111     if ((rows < 0) || (cols < 0))
112         return;
113 
114     old_len = gtable->array->len;
115     new_len = rows * cols;
116 
117     if (new_len == old_len)
118         return;
119 
120     /* If shrinking, destroy extra cells */
121     if ((new_len < old_len) && gtable->destroyer)
122     {
123         gchar *entry;
124         guint i;
125 
126         entry = &gtable->array->data[new_len * gtable->entry_size];
127         for (i = new_len; i < old_len; i++)
128         {
129             gtable->destroyer(entry, gtable->user_data);
130             entry += gtable->entry_size;
131         }
132     }
133 
134     /* Change the size */
135     g_array_set_size(gtable->array, new_len);
136 
137     /* If expanding, construct the new cells */
138     if ((new_len > old_len) && gtable->constructor)
139     {
140         gchar *entry;
141         guint i;
142 
143         entry = &gtable->array->data[old_len * gtable->entry_size];
144         for (i = old_len; i < new_len; i++)
145         {
146             gtable->constructor(entry, gtable->user_data);
147             entry += gtable->entry_size;
148         }
149     }
150 
151     gtable->rows = rows;
152     gtable->cols = cols;
153 }
154 
155 int
g_table_rows(GTable * gtable)156 g_table_rows (GTable *gtable)
157 {
158     if (gtable == NULL)
159         return 0;
160 
161     return gtable->rows;
162 }
163 
164 int
g_table_cols(GTable * gtable)165 g_table_cols (GTable *gtable)
166 {
167     if (gtable == NULL)
168         return 0;
169 
170     return gtable->cols;
171 }
172