No issues found
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) version 3.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with the program; if not, see <http://www.gnu.org/licenses/>
14 *
15 *
16 * Authors:
17 * Chris Lahey <clahey@ximian.com>
18 *
19 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
20 *
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "e-sorter-array.h"
31 #include "e-util.h"
32
33 #define d(x)
34
35 #define INCREMENT_AMOUNT 100
36
37 G_DEFINE_TYPE (
38 ESorterArray,
39 e_sorter_array,
40 E_SORTER_TYPE)
41
42 static void esa_sort (ESorterArray *esa);
43 static void esa_backsort (ESorterArray *esa);
44
45 static gint esa_model_to_sorted (ESorter *sorter, gint row);
46 static gint esa_sorted_to_model (ESorter *sorter, gint row);
47 static void esa_get_model_to_sorted_array (ESorter *sorter,
48 gint **array,
49 gint *count);
50 static void esa_get_sorted_to_model_array (ESorter *sorter,
51 gint **array,
52 gint *count);
53 static gboolean esa_needs_sorting (ESorter *esa);
54
55 #define ESA_NEEDS_SORTING(esa) (((ESorterArray *) (esa))->compare != NULL)
56
57 static gint
58 esort_callback (gconstpointer data1,
59 gconstpointer data2,
60 gpointer user_data)
61 {
62 ESorterArray *esa = user_data;
63 gint ret_val;
64 gint int1, int2;
65
66 int1 = *(gint *) data1;
67 int2 = *(gint *) data2;
68
69 ret_val = esa->compare (int1, int2, esa->cmp_cache, esa->closure);
70 if (ret_val != 0)
71 return ret_val;
72
73 if (int1 < int2)
74 return -1;
75 if (int1 > int2)
76 return 1;
77 return 0;
78 }
79
80 static void
81 esa_sort (ESorterArray *esa)
82 {
83 gint rows;
84 gint i;
85
86 if (esa->sorted)
87 return;
88
89 rows = esa->rows;
90
91 esa->sorted = g_new (int, rows);
92 for (i = 0; i < rows; i++)
93 esa->sorted[i] = i;
94
95 if (esa->compare) {
96 if (esa->create_cmp_cache)
97 esa->cmp_cache = esa->create_cmp_cache (esa->closure);
98
99 g_qsort_with_data (
100 esa->sorted, rows, sizeof (gint),
101 esort_callback, esa);
102
103 if (esa->cmp_cache) {
104 g_hash_table_destroy (esa->cmp_cache);
105 esa->cmp_cache = NULL;
106 }
107 }
108 }
109
110 static void
111 esa_backsort (ESorterArray *esa)
112 {
113 gint i, rows;
114
115 if (esa->backsorted)
116 return;
117
118 esa_sort (esa);
119
120 rows = esa->rows;
121
122 esa->backsorted = g_new0 (int, rows);
123
124 for (i = 0; i < rows; i++) {
125 esa->backsorted[esa->sorted[i]] = i;
126 }
127 }
128
129 static gint
130 esa_model_to_sorted (ESorter *es,
131 gint row)
132 {
133 ESorterArray *esa = E_SORTER_ARRAY (es);
134
135 g_return_val_if_fail (row >= 0, -1);
136 g_return_val_if_fail (row < esa->rows, -1);
137
138 if (ESA_NEEDS_SORTING (es))
139 esa_backsort (esa);
140
141 if (esa->backsorted)
142 return esa->backsorted[row];
143 else
144 return row;
145 }
146
147 static gint
148 esa_sorted_to_model (ESorter *es,
149 gint row)
150 {
151 ESorterArray *esa = (ESorterArray *) es;
152
153 g_return_val_if_fail (row >= 0, -1);
154 g_return_val_if_fail (row < esa->rows, -1);
155
156 if (ESA_NEEDS_SORTING (es))
157 esa_sort (esa);
158
159 if (esa->sorted)
160 return esa->sorted[row];
161 else
162 return row;
163 }
164
165 static void
166 esa_get_model_to_sorted_array (ESorter *es,
167 gint **array,
168 gint *count)
169 {
170 ESorterArray *esa = E_SORTER_ARRAY (es);
171 if (array || count) {
172 esa_backsort (esa);
173
174 if (array)
175 *array = esa->backsorted;
176 if (count)
177 *count = esa->rows;
178 }
179 }
180
181 static void
182 esa_get_sorted_to_model_array (ESorter *es,
183 gint **array,
184 gint *count)
185 {
186 ESorterArray *esa = E_SORTER_ARRAY (es);
187 if (array || count) {
188 esa_sort (esa);
189
190 if (array)
191 *array = esa->sorted;
192 if (count)
193 *count = esa->rows;
194 }
195 }
196
197 static gboolean
198 esa_needs_sorting (ESorter *es)
199 {
200 ESorterArray *esa = E_SORTER_ARRAY (es);
201 return esa->compare != NULL;
202 }
203
204 void
205 e_sorter_array_clean (ESorterArray *esa)
206 {
207 g_free (esa->sorted);
208 esa->sorted = NULL;
209
210 g_free (esa->backsorted);
211 esa->backsorted = NULL;
212 }
213
214 void
215 e_sorter_array_set_count (ESorterArray *esa,
216 gint count)
217 {
218 e_sorter_array_clean (esa);
219 esa->rows = count;
220 }
221
222 void
223 e_sorter_array_append (ESorterArray *esa,
224 gint count)
225 {
226 gint i;
227 g_free (esa->backsorted);
228 esa->backsorted = NULL;
229
230 if (esa->sorted) {
231 esa->sorted = g_renew (int, esa->sorted, esa->rows + count);
232 for (i = 0; i < count; i++) {
233 gint value = esa->rows;
234 gsize pos;
235
236 e_bsearch (
237 &value, esa->sorted, esa->rows,
238 sizeof (gint), esort_callback, esa, &pos, NULL);
239 memmove (
240 esa->sorted + pos + 1,
241 esa->sorted + pos,
242 sizeof (gint) * (esa->rows - pos));
243 esa->sorted[pos] = value;
244 esa->rows++;
245 }
246 } else {
247 esa->rows += count;
248 }
249 }
250
251 static void
252 esa_finalize (GObject *object)
253 {
254 ESorterArray *esa = E_SORTER_ARRAY (object);
255
256 if (esa)
257 e_sorter_array_clean (esa);
258
259 /* Chain up to parent's finalize() method. */
260 G_OBJECT_CLASS (e_sorter_array_parent_class)->finalize (object);
261 }
262
263 ESorterArray *
264 e_sorter_array_construct (ESorterArray *esa,
265 ECreateCmpCacheFunc create_cmp_cache,
266 ECompareRowsFunc compare,
267 gpointer closure)
268 {
269 esa->create_cmp_cache = create_cmp_cache;
270 esa->compare = compare;
271 esa->closure = closure;
272 return esa;
273 }
274
275 ESorterArray *
276 e_sorter_array_new (ECreateCmpCacheFunc create_cmp_cache,
277 ECompareRowsFunc compare,
278 gpointer closure)
279 {
280 ESorterArray *esa = g_object_new (E_SORTER_ARRAY_TYPE, NULL);
281
282 return e_sorter_array_construct (esa, create_cmp_cache, compare, closure);
283 }
284
285 static void
286 e_sorter_array_class_init (ESorterArrayClass *class)
287 {
288 GObjectClass *object_class = G_OBJECT_CLASS (class);
289 ESorterClass *sorter_class = E_SORTER_CLASS (class);
290
291 object_class->finalize = esa_finalize;
292
293 sorter_class->model_to_sorted = esa_model_to_sorted;
294 sorter_class->sorted_to_model = esa_sorted_to_model;
295 sorter_class->get_model_to_sorted_array = esa_get_model_to_sorted_array;
296 sorter_class->get_sorted_to_model_array = esa_get_sorted_to_model_array;
297 sorter_class->needs_sorting = esa_needs_sorting;
298 }
299
300 static void
301 e_sorter_array_init (ESorterArray *esa)
302 {
303 esa->rows = 0;
304 esa->cmp_cache = NULL;
305 esa->create_cmp_cache = NULL;
306 esa->compare = NULL;
307 esa->closure = NULL;
308 esa->sorted = NULL;
309 esa->backsorted = NULL;
310 }