4 * An object oriented GL/GLES Abstraction/Utility Layer
6 * Copyright (C) 2010 Intel Corporation.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library 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 GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
24 * Neil Roberts <neil@linux.intel.com>
34 #include "cogl-bitmask.h"
35 #include "cogl-util.h"
36 #include "cogl-flags.h"
38 /* This code assumes that we can cast an unsigned long to a pointer
39 and back without losing any data */
40 G_STATIC_ASSERT (sizeof (unsigned long) <= sizeof (void *));
42 #define ARRAY_INDEX(bit_num) \
43 ((bit_num) / (sizeof (unsigned long) * 8))
44 #define BIT_INDEX(bit_num) \
45 ((bit_num) & (sizeof (unsigned long) * 8 - 1))
46 #define BIT_MASK(bit_num) \
47 (1UL << BIT_INDEX (bit_num))
50 _cogl_bitmask_get_from_array (const CoglBitmask *bitmask,
53 GArray *array = (GArray *) *bitmask;
55 /* If the index is off the end of the array then assume the bit is
57 if (bit_num >= sizeof (unsigned long) * 8 * array->len)
60 return !!(g_array_index (array, unsigned long, ARRAY_INDEX (bit_num)) &
65 _cogl_bitmask_convert_to_array (CoglBitmask *bitmask)
68 /* Fetch the old values */
69 unsigned long old_values = _cogl_bitmask_to_bits (bitmask);
71 array = g_array_new (FALSE, /* not zero-terminated */
72 TRUE, /* do clear new entries */
73 sizeof (unsigned long));
74 /* Copy the old values back in */
75 g_array_append_val (array, old_values);
77 *bitmask = (struct _CoglBitmaskImaginaryType *) array;
81 _cogl_bitmask_set_in_array (CoglBitmask *bitmask,
86 unsigned int array_index;
87 unsigned long new_value_mask;
89 /* If the bitmask is not already an array then we need to allocate one */
90 if (!_cogl_bitmask_has_array (bitmask))
91 _cogl_bitmask_convert_to_array (bitmask);
93 array = (GArray *) *bitmask;
95 array_index = ARRAY_INDEX (bit_num);
96 /* Grow the array if necessary. This will clear the new data */
97 if (array_index >= array->len)
98 g_array_set_size (array, array_index + 1);
100 new_value_mask = BIT_MASK (bit_num);
103 g_array_index (array, unsigned long, array_index) |= new_value_mask;
105 g_array_index (array, unsigned long, array_index) &= ~new_value_mask;
109 _cogl_bitmask_set_bits (CoglBitmask *dst,
110 const CoglBitmask *src)
112 if (_cogl_bitmask_has_array (src))
114 GArray *src_array, *dst_array;
117 if (!_cogl_bitmask_has_array (dst))
118 _cogl_bitmask_convert_to_array (dst);
120 dst_array = (GArray *) *dst;
121 src_array = (GArray *) *src;
123 if (dst_array->len < src_array->len)
124 g_array_set_size (dst_array, src_array->len);
126 for (i = 0; i < src_array->len; i++)
127 g_array_index (dst_array, unsigned long, i) |=
128 g_array_index (src_array, unsigned long, i);
130 else if (_cogl_bitmask_has_array (dst))
134 dst_array = (GArray *) *dst;
136 g_array_index (dst_array, unsigned long, 0) |=
137 _cogl_bitmask_to_bits (src);
140 *dst = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (dst) |
141 _cogl_bitmask_to_bits (src));
145 _cogl_bitmask_set_range_in_array (CoglBitmask *bitmask,
150 unsigned int array_index, bit_index;
155 /* If the bitmask is not already an array then we need to allocate one */
156 if (!_cogl_bitmask_has_array (bitmask))
157 _cogl_bitmask_convert_to_array (bitmask);
159 array = (GArray *) *bitmask;
161 /* Get the array index of the top most value that will be touched */
162 array_index = ARRAY_INDEX (n_bits - 1);
163 /* Get the bit index of the top most value */
164 bit_index = BIT_INDEX (n_bits - 1);
165 /* Grow the array if necessary. This will clear the new data */
166 if (array_index >= array->len)
167 g_array_set_size (array, array_index + 1);
171 /* Set the bits that are touching this index */
172 g_array_index (array, unsigned long, array_index) |=
173 ~0UL >> (sizeof (unsigned long) * 8 - 1 - bit_index);
175 /* Set all of the bits in any lesser indices */
176 memset (array->data, 0xff, sizeof (unsigned long) * array_index);
180 /* Clear the bits that are touching this index */
181 g_array_index (array, unsigned long, array_index) &= ~1UL << bit_index;
183 /* Clear all of the bits in any lesser indices */
184 memset (array->data, 0x00, sizeof (unsigned long) * array_index);
189 _cogl_bitmask_xor_bits (CoglBitmask *dst,
190 const CoglBitmask *src)
192 if (_cogl_bitmask_has_array (src))
194 GArray *src_array, *dst_array;
197 if (!_cogl_bitmask_has_array (dst))
198 _cogl_bitmask_convert_to_array (dst);
200 dst_array = (GArray *) *dst;
201 src_array = (GArray *) *src;
203 if (dst_array->len < src_array->len)
204 g_array_set_size (dst_array, src_array->len);
206 for (i = 0; i < src_array->len; i++)
207 g_array_index (dst_array, unsigned long, i) ^=
208 g_array_index (src_array, unsigned long, i);
210 else if (_cogl_bitmask_has_array (dst))
214 dst_array = (GArray *) *dst;
216 g_array_index (dst_array, unsigned long, 0) ^=
217 _cogl_bitmask_to_bits (src);
220 *dst = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (dst) ^
221 _cogl_bitmask_to_bits (src));
225 _cogl_bitmask_clear_all_in_array (CoglBitmask *bitmask)
227 GArray *array = (GArray *) *bitmask;
229 memset (array->data, 0, sizeof (unsigned long) * array->len);
233 _cogl_bitmask_foreach (const CoglBitmask *bitmask,
234 CoglBitmaskForeachFunc func,
237 if (_cogl_bitmask_has_array (bitmask))
239 GArray *array = (GArray *) *bitmask;
240 const unsigned long *values = &g_array_index (array, unsigned long, 0);
243 COGL_FLAGS_FOREACH_START (values, array->len, bit_num)
245 if (!func (bit_num, user_data))
248 COGL_FLAGS_FOREACH_END;
252 unsigned long mask = _cogl_bitmask_to_bits (bitmask);
255 COGL_FLAGS_FOREACH_START (&mask, 1, bit_num)
257 if (!func (bit_num, user_data))
260 COGL_FLAGS_FOREACH_END;
265 _cogl_bitmask_set_flags_array (const CoglBitmask *bitmask,
266 unsigned long *flags)
268 const GArray *array = (const GArray *) *bitmask;
271 for (i = 0; i < array->len; i++)
272 flags[i] |= g_array_index (array, unsigned long, i);
276 _cogl_bitmask_popcount_in_array (const CoglBitmask *bitmask)
278 const GArray *array = (const GArray *) *bitmask;
282 for (i = 0; i < array->len; i++)
283 pop += _cogl_util_popcountl (g_array_index (array, unsigned long, i));
289 _cogl_bitmask_popcount_upto_in_array (const CoglBitmask *bitmask,
292 const GArray *array = (const GArray *) *bitmask;
294 if (upto >= array->len * sizeof (unsigned long) * 8)
295 return _cogl_bitmask_popcount_in_array (bitmask);
298 unsigned long top_mask;
299 int array_index = ARRAY_INDEX (upto);
300 int bit_index = BIT_INDEX (upto);
304 for (i = 0; i < array_index; i++)
305 pop += _cogl_util_popcountl (g_array_index (array, unsigned long, i));
307 top_mask = g_array_index (array, unsigned long, array_index);
309 return pop + _cogl_util_popcountl (top_mask & ((1UL << bit_index) - 1));