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