mirror of
https://github.com/brl/mutter.git
synced 2024-11-12 17:27:03 -05:00
cogl-bitmask: Use longs instead of ints
Instead of storing only 31 bits in the pointer for a CoglBitmask, it now assumes it can store a whole unsigned long minus the one bit used to mark whether it has been converted to a GArray or not. This works on the assumption that we can cast an unsigned long to a pointer and back without losing information which I think should be true for any platforms that Cogl is interested in. This has the advantage that on 64-bit architectures we can store 63 bits before we have to resort to using a GArray at no extra cost. The values in the GArray are now stored as unsigned longs as well on the assumption that it is more efficient to load and store data in chunks of longs rather than ints. Reviewed-by: Robert Bragg <robert@linux.intel.com>
This commit is contained in:
parent
70eaf037e9
commit
93321d9b89
@ -33,6 +33,17 @@
|
||||
|
||||
#include "cogl-bitmask.h"
|
||||
|
||||
/* This code assumes that we can cast an unsigned long to a pointer
|
||||
and back without losing any data */
|
||||
G_STATIC_ASSERT (sizeof (unsigned long) <= sizeof (void *));
|
||||
|
||||
#define ARRAY_INDEX(bit_num) \
|
||||
((bit_num) / (sizeof (unsigned long) * 8))
|
||||
#define BIT_INDEX(bit_num) \
|
||||
((bit_num) & (sizeof (unsigned long) * 8 - 1))
|
||||
#define BIT_MASK(bit_num) \
|
||||
(1UL << BIT_INDEX (bit_num))
|
||||
|
||||
gboolean
|
||||
_cogl_bitmask_get_from_array (const CoglBitmask *bitmask,
|
||||
unsigned int bit_num)
|
||||
@ -41,22 +52,23 @@ _cogl_bitmask_get_from_array (const CoglBitmask *bitmask,
|
||||
|
||||
/* If the index is off the end of the array then assume the bit is
|
||||
not set */
|
||||
if (bit_num >= sizeof (unsigned int) * 8 * array->len)
|
||||
if (bit_num >= sizeof (unsigned long) * 8 * array->len)
|
||||
return FALSE;
|
||||
else
|
||||
return !!(g_array_index (array, unsigned int,
|
||||
bit_num / (sizeof (unsigned int) * 8)) &
|
||||
(1 << (bit_num % (sizeof (unsigned int) * 8))));
|
||||
return !!(g_array_index (array, unsigned long, ARRAY_INDEX (bit_num)) &
|
||||
BIT_MASK (bit_num));
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_bitmask_convert_to_array (CoglBitmask *bitmask)
|
||||
{
|
||||
GArray *array;
|
||||
/* Fetch the old values, ignoring the least significant bit */
|
||||
unsigned int old_values = GPOINTER_TO_UINT (*bitmask) >> 1;
|
||||
/* Fetch the old values */
|
||||
unsigned long old_values = _cogl_bitmask_to_bits (bitmask);
|
||||
|
||||
array = g_array_new (FALSE, TRUE, sizeof (unsigned int));
|
||||
array = g_array_new (FALSE, /* not zero-terminated */
|
||||
TRUE, /* do clear new entries */
|
||||
sizeof (unsigned long));
|
||||
/* Copy the old values back in */
|
||||
g_array_append_val (array, old_values);
|
||||
|
||||
@ -69,7 +81,8 @@ _cogl_bitmask_set_in_array (CoglBitmask *bitmask,
|
||||
gboolean value)
|
||||
{
|
||||
GArray *array;
|
||||
unsigned int array_index, new_value_mask;
|
||||
unsigned int array_index;
|
||||
unsigned long new_value_mask;
|
||||
|
||||
/* If the bitmask is not already an array then we need to allocate one */
|
||||
if (!_cogl_bitmask_has_array (bitmask))
|
||||
@ -77,17 +90,17 @@ _cogl_bitmask_set_in_array (CoglBitmask *bitmask,
|
||||
|
||||
array = (GArray *) *bitmask;
|
||||
|
||||
array_index = bit_num / (sizeof (unsigned int) * 8);
|
||||
array_index = ARRAY_INDEX (bit_num);
|
||||
/* Grow the array if necessary. This will clear the new data */
|
||||
if (array_index >= array->len)
|
||||
g_array_set_size (array, array_index + 1);
|
||||
|
||||
new_value_mask = 1 << (bit_num % (sizeof (unsigned int) * 8));
|
||||
new_value_mask = BIT_MASK (bit_num);
|
||||
|
||||
if (value)
|
||||
g_array_index (array, unsigned int, array_index) |= new_value_mask;
|
||||
g_array_index (array, unsigned long, array_index) |= new_value_mask;
|
||||
else
|
||||
g_array_index (array, unsigned int, array_index) &= ~new_value_mask;
|
||||
g_array_index (array, unsigned long, array_index) &= ~new_value_mask;
|
||||
}
|
||||
|
||||
void
|
||||
@ -109,8 +122,8 @@ _cogl_bitmask_set_bits (CoglBitmask *dst,
|
||||
g_array_set_size (dst_array, src_array->len);
|
||||
|
||||
for (i = 0; i < src_array->len; i++)
|
||||
g_array_index (dst_array, unsigned int, i) |=
|
||||
g_array_index (src_array, unsigned int, i);
|
||||
g_array_index (dst_array, unsigned long, i) |=
|
||||
g_array_index (src_array, unsigned long, i);
|
||||
}
|
||||
else if (_cogl_bitmask_has_array (dst))
|
||||
{
|
||||
@ -118,12 +131,12 @@ _cogl_bitmask_set_bits (CoglBitmask *dst,
|
||||
|
||||
dst_array = (GArray *) *dst;
|
||||
|
||||
g_array_index (dst_array, unsigned int, 0) |=
|
||||
(GPOINTER_TO_UINT (*src) >> 1);
|
||||
g_array_index (dst_array, unsigned long, 0) |=
|
||||
_cogl_bitmask_to_bits (src);
|
||||
}
|
||||
else
|
||||
*dst = GUINT_TO_POINTER (GPOINTER_TO_UINT (*dst) |
|
||||
GPOINTER_TO_UINT (*src));
|
||||
*dst = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (dst) |
|
||||
_cogl_bitmask_to_bits (src));
|
||||
}
|
||||
|
||||
void
|
||||
@ -144,9 +157,9 @@ _cogl_bitmask_set_range_in_array (CoglBitmask *bitmask,
|
||||
array = (GArray *) *bitmask;
|
||||
|
||||
/* Get the array index of the top most value that will be touched */
|
||||
array_index = (n_bits - 1) / (sizeof (unsigned int) * 8);
|
||||
array_index = ARRAY_INDEX (n_bits - 1);
|
||||
/* Get the bit index of the top most value */
|
||||
bit_index = (n_bits - 1) % (sizeof (unsigned int) * 8);
|
||||
bit_index = BIT_INDEX (n_bits - 1);
|
||||
/* Grow the array if necessary. This will clear the new data */
|
||||
if (array_index >= array->len)
|
||||
g_array_set_size (array, array_index + 1);
|
||||
@ -154,20 +167,19 @@ _cogl_bitmask_set_range_in_array (CoglBitmask *bitmask,
|
||||
if (value)
|
||||
{
|
||||
/* Set the bits that are touching this index */
|
||||
g_array_index (array, unsigned int, array_index) |=
|
||||
~(unsigned int) 0 >> (sizeof (unsigned int) * 8 - 1 - bit_index);
|
||||
g_array_index (array, unsigned long, array_index) |=
|
||||
~0UL >> (sizeof (unsigned long) * 8 - 1 - bit_index);
|
||||
|
||||
/* Set all of the bits in any lesser indices */
|
||||
memset (array->data, 0xff, sizeof (unsigned int) * array_index);
|
||||
memset (array->data, 0xff, sizeof (unsigned long) * array_index);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Clear the bits that are touching this index */
|
||||
g_array_index (array, unsigned int, array_index) &=
|
||||
~(unsigned int) 1 << bit_index;
|
||||
g_array_index (array, unsigned long, array_index) &= ~1UL << bit_index;
|
||||
|
||||
/* Clear all of the bits in any lesser indices */
|
||||
memset (array->data, 0x00, sizeof (unsigned int) * array_index);
|
||||
memset (array->data, 0x00, sizeof (unsigned long) * array_index);
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,8 +202,8 @@ _cogl_bitmask_xor_bits (CoglBitmask *dst,
|
||||
g_array_set_size (dst_array, src_array->len);
|
||||
|
||||
for (i = 0; i < src_array->len; i++)
|
||||
g_array_index (dst_array, unsigned int, i) ^=
|
||||
g_array_index (src_array, unsigned int, i);
|
||||
g_array_index (dst_array, unsigned long, i) ^=
|
||||
g_array_index (src_array, unsigned long, i);
|
||||
}
|
||||
else if (_cogl_bitmask_has_array (dst))
|
||||
{
|
||||
@ -199,12 +211,12 @@ _cogl_bitmask_xor_bits (CoglBitmask *dst,
|
||||
|
||||
dst_array = (GArray *) *dst;
|
||||
|
||||
g_array_index (dst_array, unsigned int, 0) ^=
|
||||
(GPOINTER_TO_UINT (*src) >> 1);
|
||||
g_array_index (dst_array, unsigned long, 0) ^=
|
||||
_cogl_bitmask_to_bits (src);
|
||||
}
|
||||
else
|
||||
*dst = GUINT_TO_POINTER ((GPOINTER_TO_UINT (*dst) ^
|
||||
GPOINTER_TO_UINT (*src)) | 1);
|
||||
*dst = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (dst) ^
|
||||
_cogl_bitmask_to_bits (src));
|
||||
}
|
||||
|
||||
void
|
||||
@ -212,7 +224,7 @@ _cogl_bitmask_clear_all_in_array (CoglBitmask *bitmask)
|
||||
{
|
||||
GArray *array = (GArray *) *bitmask;
|
||||
|
||||
memset (array->data, 0, sizeof (unsigned int) * array->len);
|
||||
memset (array->data, 0, sizeof (unsigned long) * array->len);
|
||||
}
|
||||
|
||||
void
|
||||
@ -227,13 +239,15 @@ _cogl_bitmask_foreach (const CoglBitmask *bitmask,
|
||||
|
||||
for (array_index = 0; array_index < array->len; array_index++)
|
||||
{
|
||||
unsigned int mask = g_array_index (array, unsigned int, array_index);
|
||||
unsigned long mask =
|
||||
g_array_index (array, unsigned long, array_index);
|
||||
int bit = 0;
|
||||
|
||||
while (mask)
|
||||
{
|
||||
if (mask & 1)
|
||||
func (array_index * sizeof (unsigned int) * 8 + bit, user_data);
|
||||
if (mask & 1UL)
|
||||
func (array_index * sizeof (unsigned long) * 8 + bit,
|
||||
user_data);
|
||||
|
||||
bit++;
|
||||
mask >>= 1;
|
||||
@ -242,12 +256,12 @@ _cogl_bitmask_foreach (const CoglBitmask *bitmask,
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int mask = GPOINTER_TO_UINT (*bitmask) >> 1;
|
||||
unsigned long mask = _cogl_bitmask_to_bits (bitmask);
|
||||
int bit = 0;
|
||||
|
||||
while (mask)
|
||||
{
|
||||
if (mask & 1)
|
||||
if (mask & 1UL)
|
||||
func (bit, user_data);
|
||||
|
||||
bit++;
|
||||
|
@ -36,14 +36,17 @@ G_BEGIN_DECLS
|
||||
* be allocated on the stack but it must be initialised with
|
||||
* _cogl_bitmask_init() before use and then destroyed with
|
||||
* _cogl_bitmask_destroy(). A CoglBitmask will try to avoid allocating
|
||||
* any memory unless more than 31 bits are needed.
|
||||
* any memory unless more than the number of bits in a long - 1 bits
|
||||
* are needed.
|
||||
*
|
||||
* Internally a CoglBitmask is a pointer. If the least significant bit
|
||||
* of the pointer is 1 then the rest of the bits are directly used as
|
||||
* part of the bitmask, otherwise it is a pointer to a GArray of
|
||||
* unsigned ints. This relies on the fact the g_malloc will return a
|
||||
* pointer aligned to at least two bytes (so that the least
|
||||
* significant bit of the address is always 0)
|
||||
* significant bit of the address is always 0). It also assumes that
|
||||
* the size of a pointer is always greater than or equal to the size
|
||||
* of a long (although there is a compile time assert to verify this).
|
||||
*
|
||||
* If the maximum possible bit number in the set is known at compile
|
||||
* time, it may make more sense to use the macros in cogl-flags.h
|
||||
@ -52,13 +55,23 @@ G_BEGIN_DECLS
|
||||
|
||||
typedef struct _CoglBitmaskImaginaryType *CoglBitmask;
|
||||
|
||||
/* These are internal helper macros */
|
||||
#define _cogl_bitmask_to_number(bitmask) \
|
||||
((unsigned long) (*bitmask))
|
||||
#define _cogl_bitmask_to_bits(bitmask) \
|
||||
(_cogl_bitmask_to_number (bitmask) >> 1UL)
|
||||
/* The least significant bit is set to mark that no array has been
|
||||
allocated yet */
|
||||
#define _cogl_bitmask_from_bits(bits) \
|
||||
((void *) ((((unsigned long) (bits)) << 1UL) | 1UL))
|
||||
|
||||
/* Internal helper macro to determine whether this bitmask has a
|
||||
GArray allocated or whether the pointer is just used directly */
|
||||
#define _cogl_bitmask_has_array(bitmask) \
|
||||
(!(GPOINTER_TO_UINT (*bitmask) & 1))
|
||||
(!(_cogl_bitmask_to_number (bitmask) & 1UL))
|
||||
|
||||
/* Number of bits we can use before needing to allocate an array */
|
||||
#define COGL_BITMASK_MAX_DIRECT_BITS (sizeof (unsigned int) * 8 - 1)
|
||||
#define COGL_BITMASK_MAX_DIRECT_BITS (sizeof (unsigned long) * 8 - 1)
|
||||
|
||||
/*
|
||||
* _cogl_bitmask_init:
|
||||
@ -68,10 +81,8 @@ typedef struct _CoglBitmaskImaginaryType *CoglBitmask;
|
||||
* bitmask functions are called. Initially all of the values are
|
||||
* zero
|
||||
*/
|
||||
/* Set the last significant bit to mark that no array has been
|
||||
allocated yet */
|
||||
#define _cogl_bitmask_init(bitmask) \
|
||||
G_STMT_START { *(bitmask) = GUINT_TO_POINTER (1); } G_STMT_END
|
||||
G_STMT_START { *(bitmask) = _cogl_bitmask_from_bits (0); } G_STMT_END
|
||||
|
||||
gboolean
|
||||
_cogl_bitmask_get_from_array (const CoglBitmask *bitmask,
|
||||
@ -144,7 +155,7 @@ _cogl_bitmask_get (const CoglBitmask *bitmask, unsigned int bit_num)
|
||||
else if (bit_num >= COGL_BITMASK_MAX_DIRECT_BITS)
|
||||
return FALSE;
|
||||
else
|
||||
return !!(GPOINTER_TO_UINT (*bitmask) & (1 << (bit_num + 1)));
|
||||
return !!(_cogl_bitmask_to_bits (bitmask) & (1UL << bit_num));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -162,11 +173,11 @@ _cogl_bitmask_set (CoglBitmask *bitmask, unsigned int bit_num, gboolean value)
|
||||
bit_num >= COGL_BITMASK_MAX_DIRECT_BITS)
|
||||
_cogl_bitmask_set_in_array (bitmask, bit_num, value);
|
||||
else if (value)
|
||||
*bitmask = GUINT_TO_POINTER (GPOINTER_TO_UINT (*bitmask) |
|
||||
(1 << (bit_num + 1)));
|
||||
*bitmask = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (bitmask) |
|
||||
(1UL << bit_num));
|
||||
else
|
||||
*bitmask = GUINT_TO_POINTER (GPOINTER_TO_UINT (*bitmask) &
|
||||
~(1 << (bit_num + 1)));
|
||||
*bitmask = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (bitmask) &
|
||||
~(1UL << bit_num));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -186,11 +197,11 @@ _cogl_bitmask_set_range (CoglBitmask *bitmask,
|
||||
n_bits > COGL_BITMASK_MAX_DIRECT_BITS)
|
||||
_cogl_bitmask_set_range_in_array (bitmask, n_bits, value);
|
||||
else if (value)
|
||||
*bitmask = GUINT_TO_POINTER (GPOINTER_TO_UINT (*bitmask) |
|
||||
~(~(unsigned int) 1 << n_bits));
|
||||
*bitmask = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (bitmask) |
|
||||
~(~0UL << n_bits));
|
||||
else
|
||||
*bitmask = GUINT_TO_POINTER (GPOINTER_TO_UINT (*bitmask) &
|
||||
((~(unsigned int) 1 << n_bits) | 1));
|
||||
*bitmask = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (bitmask) &
|
||||
(~0UL << n_bits));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -218,7 +229,7 @@ _cogl_bitmask_clear_all (CoglBitmask *bitmask)
|
||||
if (_cogl_bitmask_has_array (bitmask))
|
||||
_cogl_bitmask_clear_all_in_array (bitmask);
|
||||
else
|
||||
*bitmask = GUINT_TO_POINTER (1);
|
||||
*bitmask = _cogl_bitmask_from_bits (0);
|
||||
}
|
||||
|
||||
G_END_DECLS
|
||||
|
Loading…
Reference in New Issue
Block a user