evolution-3.6.4/e-util/e-bit-array.c

No issues found

  1 /*
  2  *
  3  * This program is free software; you can redistribute it and/or
  4  * modify it under the terms of the GNU Lesser General Public
  5  * License as published by the Free Software Foundation; either
  6  * version 2 of the License, or (at your option) version 3.
  7  *
  8  * This program is distributed in the hope that it will be useful,
  9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 11  * Lesser General Public License for more details.
 12  *
 13  * You should have received a copy of the GNU Lesser General Public
 14  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 15  *
 16  *
 17  * Authors:
 18  *		Chris Lahey <clahey@ximian.com>
 19  *
 20  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 21  *
 22  */
 23 
 24 #ifdef HAVE_CONFIG_H
 25 #include <config.h>
 26 #endif
 27 
 28 #include <gtk/gtk.h>
 29 
 30 #include "e-bit-array.h"
 31 #include "e-util.h"
 32 
 33 #define ONES ((guint32) 0xffffffff)
 34 
 35 #define BOX(n) ((n) / 32)
 36 #define OFFSET(n) (31 - ((n) % 32))
 37 #define BITMASK(n) ((guint32)(((guint32) 0x1) << OFFSET((n))))
 38 #define BITMASK_LEFT(n) ((((n) % 32) == 0) ? 0 : (ONES << (32 - ((n) % 32))))
 39 #define BITMASK_RIGHT(n) ((guint32)(((guint32) ONES) >> ((n) % 32)))
 40 
 41 G_DEFINE_TYPE (
 42 	EBitArray,
 43 	e_bit_array,
 44 	G_TYPE_OBJECT)
 45 
 46 static void
 47 e_bit_array_insert_real (EBitArray *eba,
 48                          gint row)
 49 {
 50 	gint box;
 51 	gint i;
 52 	if (eba->bit_count >= 0) {
 53 		/* Add another word if needed. */
 54 		if ((eba->bit_count & 0x1f) == 0) {
 55 			eba->data = g_renew (
 56 				guint32, eba->data,
 57 				(eba->bit_count >> 5) + 1);
 58 			eba->data[eba->bit_count >> 5] = 0;
 59 		}
 60 
 61 		/* The box is the word that our row is in. */
 62 		box = BOX (row);
 63 		/* Shift all words to the right of our box right one bit. */
 64 		for (i = eba->bit_count >> 5; i > box; i--) {
 65 			eba->data[i] = (eba->data[i] >> 1) | (eba->data[i - 1] << 31);
 66 		}
 67 
 68 		/* Shift right half of box one bit to the right. */
 69 		eba->data[box] =
 70 			(eba->data[box] & BITMASK_LEFT (row)) |
 71 			((eba->data[box] & BITMASK_RIGHT (row)) >> 1);
 72 		eba->bit_count++;
 73 	}
 74 }
 75 
 76 static void
 77 e_bit_array_delete_real (EBitArray *eba,
 78                          gint row,
 79                          gboolean move_selection_mode)
 80 {
 81 	gint box;
 82 	gint i;
 83 	gint last;
 84 	gint selected = FALSE;
 85 
 86 	if (eba->bit_count > 0) {
 87 		guint32 bitmask;
 88 		box = row >> 5;
 89 		last = (eba->bit_count - 1) >> 5;
 90 
 91 		/* Build bitmasks for the left and right half of the box */
 92 		bitmask = BITMASK_RIGHT (row) >> 1;
 93 		if (move_selection_mode)
 94 			selected = e_bit_array_value_at (eba, row);
 95 		/* Shift right half of box one bit to the left. */
 96 		eba->data[box] =
 97 			(eba->data[box] & BITMASK_LEFT (row)) |
 98 			((eba->data[box] & bitmask) << 1);
 99 
100 		/* Shift all words to the right of our box left one bit. */
101 		if (box < last) {
102 			eba->data[box] &= eba->data[box + 1] >> 31;
103 
104 			for (i = box + 1; i < last; i++) {
105 				eba->data[i] =
106 					(eba->data[i] << 1) |
107 					(eba->data[i + 1] >> 31);
108 			}
109 			/* this over-runs our memory! */
110 			/*eba->data[i] = eba->data[i] << 1; */
111 		}
112 		eba->bit_count--;
113 		/* Remove the last word if not needed. */
114 		if ((eba->bit_count & 0x1f) == 0) {
115 			eba->data = g_renew (guint32, eba->data, eba->bit_count >> 5);
116 		}
117 		if (move_selection_mode && selected && eba->bit_count > 0) {
118 			e_bit_array_select_single_row (
119 				eba, row == eba->bit_count ? row - 1 : row);
120 		}
121 	}
122 }
123 
124 /* FIXME : Improve efficiency here. */
125 void
126 e_bit_array_delete (EBitArray *eba,
127                     gint row,
128                     gint count)
129 {
130 	gint i;
131 	for (i = 0; i < count; i++)
132 		e_bit_array_delete_real (eba, row, FALSE);
133 }
134 
135 /* FIXME : Improve efficiency here. */
136 void
137 e_bit_array_delete_single_mode (EBitArray *eba,
138                                 gint row,
139                                 gint count)
140 {
141 	gint i;
142 	for (i = 0; i < count; i++)
143 		e_bit_array_delete_real (eba, row, TRUE);
144 }
145 
146 /* FIXME : Improve efficiency here. */
147 void
148 e_bit_array_insert (EBitArray *eba,
149                     gint row,
150                     gint count)
151 {
152 	gint i;
153 	for (i = 0; i < count; i++)
154 		e_bit_array_insert_real (eba, row);
155 }
156 
157 /* FIXME: Implement this more efficiently. */
158 void
159 e_bit_array_move_row (EBitArray *eba,
160                       gint old_row,
161                       gint new_row)
162 {
163 	e_bit_array_delete_real (eba, old_row, FALSE);
164 	e_bit_array_insert_real (eba, new_row);
165 }
166 
167 static void
168 eba_dispose (GObject *object)
169 {
170 	EBitArray *eba;
171 
172 	eba = E_BIT_ARRAY (object);
173 
174 	if (eba->data)
175 		g_free (eba->data);
176 	eba->data = NULL;
177 
178 	/* Chain up to parent's dispose() method. */
179 	G_OBJECT_CLASS (e_bit_array_parent_class)->dispose (object);
180 }
181 
182 /**
183  * e_selection_model_is_row_selected
184  * @selection: #EBitArray to check
185  * @n: The row to check
186  *
187  * This routine calculates whether the given row is selected.
188  *
189  * Returns: %TRUE if the given row is selected
190  */
191 gboolean
192 e_bit_array_value_at (EBitArray *eba,
193                       gint n)
194 {
195 	if (eba->bit_count < n || eba->bit_count == 0)
196 		return 0;
197 	else
198 		return (eba->data[BOX (n)] >> OFFSET (n)) & 0x1;
199 }
200 
201 /**
202  * e_selection_model_foreach
203  * @selection: #EBitArray to traverse
204  * @callback: The callback function to call back.
205  * @closure: The closure
206  *
207  * This routine calls the given callback function once for each
208  * selected row, passing closure as the closure.
209  */
210 void
211 e_bit_array_foreach (EBitArray *eba,
212                      EForeachFunc callback,
213                      gpointer closure)
214 {
215 	gint i;
216 	gint last = (eba->bit_count + 31) / 32;
217 	for (i = 0; i < last; i++) {
218 		if (eba->data[i]) {
219 			gint j;
220 			guint32 value = eba->data[i];
221 			for (j = 0; j < 32; j++) {
222 				if (value & 0x80000000) {
223 					callback (i * 32 + j, closure);
224 				}
225 				value <<= 1;
226 			}
227 		}
228 	}
229 }
230 
231 #define PART(x,n) (((x) & (0x01010101 << n)) >> n)
232 #define SECTION(x, n) (((x) >> (n * 8)) & 0xff)
233 
234 /**
235  * e_selection_model_selected_count
236  * @selection: #EBitArray to count
237  *
238  * This routine calculates the number of rows selected.
239  *
240  * Returns: The number of rows selected in the given model.
241  */
242 gint
243 e_bit_array_selected_count (EBitArray *eba)
244 {
245 	gint count;
246 	gint i;
247 	gint last;
248 
249 	if (!eba->data)
250 		return 0;
251 
252 	count = 0;
253 
254 	last = BOX (eba->bit_count - 1);
255 
256 	for (i = 0; i <= last; i++) {
257 		gint j;
258 		guint32 thiscount = 0;
259 		for (j = 0; j < 8; j++)
260 			thiscount += PART (eba->data[i], j);
261 		for (j = 0; j < 4; j++)
262 			count += SECTION (thiscount, j);
263 	}
264 
265 	return count;
266 }
267 
268 /**
269  * e_selection_model_select_all
270  * @selection: #EBitArray to select all
271  *
272  * This routine selects all the rows in the given
273  * #EBitArray.
274  */
275 void
276 e_bit_array_select_all (EBitArray *eba)
277 {
278 	gint i;
279 
280 	if (!eba->data)
281 		eba->data = g_new0 (guint32, (eba->bit_count + 31) / 32);
282 
283 	for (i = 0; i < (eba->bit_count + 31) / 32; i++) {
284 		eba->data[i] = ONES;
285 	}
286 
287 	/* need to zero out the bits corresponding to the rows not
288 	 * selected in the last full 32 bit mask */
289 	if (eba->bit_count % 32) {
290 		gint unselected_mask = 0;
291 		gint num_unselected_in_last_byte = 32 - eba->bit_count % 32;
292 
293 		for (i = 0; i < num_unselected_in_last_byte; i++)
294 			unselected_mask |= 1 << i;
295 
296 		eba->data[(eba->bit_count + 31) / 32 - 1] &= ~unselected_mask;
297 	}
298 }
299 
300 /**
301  * e_selection_model_invert_selection
302  * @selection: #EBitArray to invert
303  *
304  * This routine inverts all the rows in the given
305  * #EBitArray.
306  */
307 void
308 e_bit_array_invert_selection (EBitArray *eba)
309 {
310 	gint i;
311 
312 	if (!eba->data)
313 		eba->data = g_new0 (guint32, (eba->bit_count + 31) / 32);
314 
315 	for (i = 0; i < (eba->bit_count + 31) / 32; i++) {
316 		eba->data[i] = ~eba->data[i];
317 	}
318 }
319 
320 gint
321 e_bit_array_bit_count (EBitArray *eba)
322 {
323 	return eba->bit_count;
324 }
325 
326 #define OPERATE(object, i,mask,grow) \
327 	((grow) ? (((object)->data[(i)]) |= ((guint32) ~(mask))) : \
328 	(((object)->data[(i)]) &= (mask)))
329 
330 void
331 e_bit_array_change_one_row (EBitArray *eba,
332                             gint row,
333                             gboolean grow)
334 {
335 	gint i;
336 	i = BOX (row);
337 
338 	OPERATE (eba, i, ~BITMASK (row), grow);
339 }
340 
341 void
342 e_bit_array_change_range (EBitArray *eba,
343                           gint start,
344                           gint end,
345                           gboolean grow)
346 {
347 	gint i, last;
348 	if (start != end) {
349 		i = BOX (start);
350 		last = BOX (end);
351 
352 		if (i == last) {
353 			OPERATE (
354 				eba, i, BITMASK_LEFT (start) |
355 				BITMASK_RIGHT (end), grow);
356 		} else {
357 			OPERATE (eba, i, BITMASK_LEFT (start), grow);
358 			if (grow)
359 				for (i++; i < last; i++)
360 					eba->data[i] = ONES;
361 			else
362 				for (i++; i < last; i++)
363 					eba->data[i] = 0;
364 			OPERATE (eba, i, BITMASK_RIGHT (end), grow);
365 		}
366 	}
367 }
368 
369 void
370 e_bit_array_select_single_row (EBitArray *eba,
371                                gint row)
372 {
373 	gint i;
374 	for (i = 0; i < ((eba->bit_count + 31) / 32); i++) {
375 		if (!((i == BOX (row) && eba->data[i] == BITMASK (row)) ||
376 		      (i != BOX (row) && eba->data[i] == 0))) {
377 			g_free (eba->data);
378 			eba->data = g_new0 (guint32, (eba->bit_count + 31) / 32);
379 			eba->data[BOX (row)] = BITMASK (row);
380 
381 			break;
382 		}
383 	}
384 }
385 
386 void
387 e_bit_array_toggle_single_row (EBitArray *eba,
388                                gint row)
389 {
390 	if (eba->data[BOX (row)] & BITMASK (row))
391 		eba->data[BOX (row)] &= ~BITMASK (row);
392 	else
393 		eba->data[BOX (row)] |= BITMASK (row);
394 }
395 
396 static void
397 e_bit_array_init (EBitArray *eba)
398 {
399 	eba->data = NULL;
400 	eba->bit_count = 0;
401 }
402 
403 static void
404 e_bit_array_class_init (EBitArrayClass *class)
405 {
406 	GObjectClass *object_class;
407 
408 	object_class = G_OBJECT_CLASS (class);
409 
410 	object_class->dispose = eba_dispose;
411 }
412 
413 EBitArray *
414 e_bit_array_new (gint count)
415 {
416 	EBitArray *eba = g_object_new (E_BIT_ARRAY_TYPE, NULL);
417 	eba->bit_count = count;
418 	eba->data = g_new0 (guint32, (eba->bit_count + 31) / 32);
419 	return eba;
420 }