1 /* GENIUS Calculator
2 * Copyright (C) 1997-2011 Jiri (George) Lebl
3 *
4 * Author: Jiri (George) Lebl
5 *
6 * This file is part of Genius.
7 *
8 * Genius is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "config.h"
23
24 #include <glib.h>
25 #include "matrix.h"
26 #include "eval.h"
27 #include <string.h>
28
29 /* we cast matrix to this structure to stuff it onto
30 the free matrix list, we could just cast it to a
31 pointer but this gives the impression of being
32 cleaner*/
33 typedef struct _GelMatrixFreeList GelMatrixFreeList;
34 struct _GelMatrixFreeList {
35 GelMatrixFreeList *next;
36 };
37
38 #ifndef MEM_DEBUG_FRIENDLY
39 static GelMatrixFreeList *free_matrices = NULL;
40 #endif
41
42 /*make new matrix*/
43 GelMatrix *
gel_matrix_new(void)44 gel_matrix_new(void)
45 {
46 GelMatrix *m;
47 #ifdef MEM_DEBUG_FRIENDLY
48 m = g_new0(GelMatrix,1);
49 #else
50 if(!free_matrices)
51 m = g_new(GelMatrix,1);
52 else {
53 m = (GelMatrix *)free_matrices;
54 free_matrices = free_matrices->next;
55 }
56 #endif
57
58 m->width = 0;
59 m->height = 0;
60
61 m->thedata = NULL;
62
63 m->realwidth = 0;
64 m->fullsize = 0;
65
66 m->use = 0;
67
68 return m;
69 }
70
71 /*set size of a matrix*/
72 void
gel_matrix_set_size(GelMatrix * matrix,int width,int height,gboolean padding)73 gel_matrix_set_size (GelMatrix *matrix, int width, int height, gboolean padding)
74 {
75 gpointer *na;
76 int i;
77 int wpadding;
78 int hpadding;
79
80 g_return_if_fail(matrix != NULL);
81 g_return_if_fail(width>0);
82 g_return_if_fail(height>0);
83
84 if (! padding) {
85 wpadding = 0;
86 hpadding = 0;
87 } else {
88 wpadding = width >> 4;
89 hpadding = height >> 4;
90 if(wpadding > 10) wpadding = 10;
91 if(hpadding > 10) hpadding = 10;
92 }
93
94 if (matrix->thedata == NULL) {
95 matrix->width = width;
96 matrix->realwidth = width+wpadding;
97 matrix->height = height;
98 matrix->fullsize=(width+wpadding)*(height+hpadding);
99
100 matrix->thedata = g_new0 (gpointer, matrix->fullsize);
101 return;
102 }
103
104 if (width <= matrix->realwidth) {
105 int newsize = matrix->realwidth*height;
106 if (newsize > matrix->fullsize) {
107 matrix->thedata = g_renew (gpointer, matrix->thedata, newsize);
108 memset (matrix->thedata + matrix->fullsize, 0, (newsize - matrix->fullsize) * sizeof(void *));
109 matrix->fullsize = newsize;
110 }
111 if (width < matrix->width) {
112 for(i=0;i<matrix->height;i++)
113 memset(matrix->thedata+((matrix->realwidth*i)+width),0,(matrix->width-width)*sizeof(void *));
114 }
115 if (height < matrix->height) {
116 memset(matrix->thedata+(matrix->realwidth*height),0,
117 ((matrix->realwidth*matrix->height)-(matrix->realwidth*height))*sizeof(void *));
118 }
119 matrix->width = width;
120 matrix->height = height;
121 return;
122 }
123
124 matrix->fullsize = (width+wpadding)*(height+hpadding);
125 na = g_new0 (gpointer, matrix->fullsize);
126
127 for(i=0;i<matrix->height;i++) {
128 memcpy(na+((width+wpadding)*i),
129 matrix->thedata+(matrix->realwidth*i),
130 matrix->width*sizeof(void *));
131 }
132
133 matrix->realwidth = width+wpadding;
134 matrix->width = width;
135 matrix->height = height;
136
137 g_free (matrix->thedata);
138
139 matrix->thedata = na;
140 }
141
142 /*set the size of the matrix to be at least this*/
143 void
gel_matrix_set_at_least_size(GelMatrix * matrix,int width,int height)144 gel_matrix_set_at_least_size(GelMatrix *matrix, int width, int height)
145 {
146 g_return_if_fail(matrix != NULL);
147 g_return_if_fail(width>=0);
148 g_return_if_fail(height>=0);
149
150 if(width>matrix->width || height>matrix->height)
151 gel_matrix_set_size (matrix,
152 MAX(width,matrix->width),
153 MAX(height,matrix->height),
154 TRUE /* padding */);
155 }
156
157 /*set element*/
158 void
gel_matrix_set_element(GelMatrix * matrix,int x,int y,gpointer data)159 gel_matrix_set_element(GelMatrix *matrix, int x, int y, gpointer data)
160 {
161 g_return_if_fail(matrix != NULL);
162 g_return_if_fail(x>=0);
163 g_return_if_fail(y>=0);
164
165 if(x>=matrix->width || y>=matrix->height)
166 gel_matrix_set_size (matrix,
167 MAX(x+1,matrix->width),
168 MAX(y+1,matrix->height),
169 TRUE /* padding */);
170 g_return_if_fail(matrix->thedata!=NULL);
171
172 matrix->thedata[x+y*matrix->realwidth]=data;
173 }
174
175 /*copy a matrix*/
176 GelMatrix *
gel_matrix_copy(GelMatrix * source,GelElementCopyFunc el_copy,gpointer func_data)177 gel_matrix_copy(GelMatrix *source, GelElementCopyFunc el_copy, gpointer func_data)
178 {
179 GelMatrix *matrix;
180 int i,j;
181
182 g_return_val_if_fail(source != NULL,NULL);
183
184 matrix = gel_matrix_new();
185
186 /*copy over the structure*/
187 *matrix = *source;
188
189 matrix->thedata = NULL;
190
191 if(source->thedata==NULL)
192 return matrix;
193
194 /*make us a new matrix data array*/
195 gel_matrix_set_size (matrix, source->width,source->height, TRUE /* padding */);
196
197 /*copy the data*/
198 if(el_copy) {
199 for(j=0;j<source->height;j++) {
200 for(i=0;i<source->width;i++) {
201 gpointer data = gel_matrix_index(source,i,j);
202 if(data)
203 gel_matrix_index(matrix,i,j) =
204 (*el_copy)(data, func_data);
205 }
206 }
207 } else {
208 for(j=0;j<source->height;j++)
209 for(i=0;i<source->width;i++)
210 gel_matrix_index(matrix,i,j) =
211 gel_matrix_index(source,i,j);
212 }
213 return matrix;
214 }
215
216 /*transpose a matrix*/
217 GelMatrix *
gel_matrix_transpose(GelMatrix * matrix)218 gel_matrix_transpose(GelMatrix *matrix)
219 {
220 int i,j;
221 GelMatrix *new;
222
223 g_return_val_if_fail(matrix != NULL,NULL);
224
225 new = gel_matrix_new();
226
227 if (matrix->thedata == NULL)
228 return new;
229
230 gel_matrix_set_size (new, matrix->height, matrix->width, TRUE /* padding */);
231
232 for(i=0;i<matrix->width;i++)
233 for(j=0;j<matrix->height;j++)
234 gel_matrix_index(new,j,i) = gel_matrix_index(matrix,i,j);
235
236 return new;
237 }
238
239 /*run a GFunc for each non-null element*/
240 void
gel_matrix_foreach(GelMatrix * matrix,GFunc func,gpointer func_data)241 gel_matrix_foreach(GelMatrix *matrix, GFunc func, gpointer func_data)
242 {
243 int i,j;
244
245 g_return_if_fail(matrix != NULL);
246 g_return_if_fail(func != NULL);
247
248 if (matrix->thedata == NULL)
249 return;
250
251 for(j=0;j<matrix->height;j++) {
252 for(i=0;i<matrix->width;i++) {
253 gpointer data = gel_matrix_index(matrix,i,j);
254 if(data)
255 (*func)(data,func_data);
256 }
257 }
258 }
259
260 /*free a matrix*/
261 void
gel_matrix_free(GelMatrix * matrix)262 gel_matrix_free(GelMatrix *matrix)
263 {
264 GelMatrixFreeList *mf;
265
266 g_return_if_fail(matrix != NULL);
267
268 mf = (GelMatrixFreeList *)matrix;
269
270 if (matrix->thedata != NULL) {
271 g_free (matrix->thedata);
272 matrix->thedata = NULL;
273 }
274 #ifdef MEM_DEBUG_FRIENDLY
275 memset (matrix, 0xaa, sizeof (GelMatrix));
276 g_free (matrix);
277 #else
278 mf->next = free_matrices;
279 free_matrices = mf;
280 #endif
281 }
282