a0441778ad
Since the Cogl 1.18 branch is actively maintained in parallel with the
master branch; this is a counter part to commit 1b83ef938fc16b which
re-licensed the master branch to use the MIT license.
This re-licensing is a follow up to the proposal that was sent to the
Cogl mailing list:
http://lists.freedesktop.org/archives/cogl/2013-December/001465.html
Note: there was a copyright assignment policy in place for Clutter (and
therefore Cogl which was part of Clutter at the time) until the 11th of
June 2010 and so we only checked the details after that point (commit
0bbf50f905
)
For each file, authors were identified via this Git command:
$ git blame -p -C -C -C20 -M -M10 0bbf50f905..HEAD
We received blanket approvals for re-licensing all Red Hat and Collabora
contributions which reduced how many people needed to be contacted
individually:
- http://lists.freedesktop.org/archives/cogl/2013-December/001470.html
- http://lists.freedesktop.org/archives/cogl/2014-January/001536.html
Individual approval requests were sent to all the other identified authors
who all confirmed the re-license on the Cogl mailinglist:
http://lists.freedesktop.org/archives/cogl/2014-January
As well as updating the copyright header in all sources files, the
COPYING file has been updated to reflect the license change and also
document the other licenses used in Cogl such as the SGI Free Software
License B, version 2.0 and the 3-clause BSD license.
This patch was not simply cherry-picked from master; but the same
methodology was used to check the source files.
490 lines
13 KiB
C
490 lines
13 KiB
C
/*
|
|
* Cogl
|
|
*
|
|
* A Low Level GPU Graphics and Utilities API
|
|
*
|
|
* Copyright (C) 2010 Intel Corporation.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person
|
|
* obtaining a copy of this software and associated documentation
|
|
* files (the "Software"), to deal in the Software without
|
|
* restriction, including without limitation the rights to use, copy,
|
|
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
* of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*
|
|
*
|
|
*
|
|
* Authors:
|
|
* Neil Roberts <neil@linux.intel.com>
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <glib.h>
|
|
#include <string.h>
|
|
|
|
#include <test-fixtures/test-unit.h>
|
|
|
|
#include "cogl-bitmask.h"
|
|
#include "cogl-util.h"
|
|
#include "cogl-flags.h"
|
|
|
|
/* This code assumes that we can cast an unsigned long to a pointer
|
|
and back without losing any data */
|
|
_COGL_STATIC_ASSERT (sizeof (unsigned long) <= sizeof (void *),
|
|
"This toolchain breaks Cogl's assumption that it can "
|
|
"safely cast an unsigned long to a pointer without "
|
|
"loosing data");
|
|
|
|
#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))
|
|
|
|
CoglBool
|
|
_cogl_bitmask_get_from_array (const CoglBitmask *bitmask,
|
|
unsigned int bit_num)
|
|
{
|
|
GArray *array = (GArray *) *bitmask;
|
|
|
|
/* If the index is off the end of the array then assume the bit is
|
|
not set */
|
|
if (bit_num >= sizeof (unsigned long) * 8 * array->len)
|
|
return FALSE;
|
|
else
|
|
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 */
|
|
unsigned long old_values = _cogl_bitmask_to_bits (bitmask);
|
|
|
|
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);
|
|
|
|
*bitmask = (struct _CoglBitmaskImaginaryType *) array;
|
|
}
|
|
|
|
void
|
|
_cogl_bitmask_set_in_array (CoglBitmask *bitmask,
|
|
unsigned int bit_num,
|
|
CoglBool value)
|
|
{
|
|
GArray *array;
|
|
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))
|
|
_cogl_bitmask_convert_to_array (bitmask);
|
|
|
|
array = (GArray *) *bitmask;
|
|
|
|
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 = BIT_MASK (bit_num);
|
|
|
|
if (value)
|
|
g_array_index (array, unsigned long, array_index) |= new_value_mask;
|
|
else
|
|
g_array_index (array, unsigned long, array_index) &= ~new_value_mask;
|
|
}
|
|
|
|
void
|
|
_cogl_bitmask_set_bits (CoglBitmask *dst,
|
|
const CoglBitmask *src)
|
|
{
|
|
if (_cogl_bitmask_has_array (src))
|
|
{
|
|
GArray *src_array, *dst_array;
|
|
int i;
|
|
|
|
if (!_cogl_bitmask_has_array (dst))
|
|
_cogl_bitmask_convert_to_array (dst);
|
|
|
|
dst_array = (GArray *) *dst;
|
|
src_array = (GArray *) *src;
|
|
|
|
if (dst_array->len < src_array->len)
|
|
g_array_set_size (dst_array, src_array->len);
|
|
|
|
for (i = 0; i < src_array->len; i++)
|
|
g_array_index (dst_array, unsigned long, i) |=
|
|
g_array_index (src_array, unsigned long, i);
|
|
}
|
|
else if (_cogl_bitmask_has_array (dst))
|
|
{
|
|
GArray *dst_array;
|
|
|
|
dst_array = (GArray *) *dst;
|
|
|
|
g_array_index (dst_array, unsigned long, 0) |=
|
|
_cogl_bitmask_to_bits (src);
|
|
}
|
|
else
|
|
*dst = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (dst) |
|
|
_cogl_bitmask_to_bits (src));
|
|
}
|
|
|
|
void
|
|
_cogl_bitmask_set_range_in_array (CoglBitmask *bitmask,
|
|
unsigned int n_bits,
|
|
CoglBool value)
|
|
{
|
|
GArray *array;
|
|
unsigned int array_index, bit_index;
|
|
|
|
if (n_bits == 0)
|
|
return;
|
|
|
|
/* If the bitmask is not already an array then we need to allocate one */
|
|
if (!_cogl_bitmask_has_array (bitmask))
|
|
_cogl_bitmask_convert_to_array (bitmask);
|
|
|
|
array = (GArray *) *bitmask;
|
|
|
|
/* Get the array index of the top most value that will be touched */
|
|
array_index = ARRAY_INDEX (n_bits - 1);
|
|
/* Get the bit index of the top most value */
|
|
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);
|
|
|
|
if (value)
|
|
{
|
|
/* Set the bits that are touching this 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 long) * array_index);
|
|
}
|
|
else
|
|
{
|
|
/* Clear the bits that are touching this 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 long) * array_index);
|
|
}
|
|
}
|
|
|
|
void
|
|
_cogl_bitmask_xor_bits (CoglBitmask *dst,
|
|
const CoglBitmask *src)
|
|
{
|
|
if (_cogl_bitmask_has_array (src))
|
|
{
|
|
GArray *src_array, *dst_array;
|
|
int i;
|
|
|
|
if (!_cogl_bitmask_has_array (dst))
|
|
_cogl_bitmask_convert_to_array (dst);
|
|
|
|
dst_array = (GArray *) *dst;
|
|
src_array = (GArray *) *src;
|
|
|
|
if (dst_array->len < src_array->len)
|
|
g_array_set_size (dst_array, src_array->len);
|
|
|
|
for (i = 0; i < src_array->len; i++)
|
|
g_array_index (dst_array, unsigned long, i) ^=
|
|
g_array_index (src_array, unsigned long, i);
|
|
}
|
|
else if (_cogl_bitmask_has_array (dst))
|
|
{
|
|
GArray *dst_array;
|
|
|
|
dst_array = (GArray *) *dst;
|
|
|
|
g_array_index (dst_array, unsigned long, 0) ^=
|
|
_cogl_bitmask_to_bits (src);
|
|
}
|
|
else
|
|
*dst = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (dst) ^
|
|
_cogl_bitmask_to_bits (src));
|
|
}
|
|
|
|
void
|
|
_cogl_bitmask_clear_all_in_array (CoglBitmask *bitmask)
|
|
{
|
|
GArray *array = (GArray *) *bitmask;
|
|
|
|
memset (array->data, 0, sizeof (unsigned long) * array->len);
|
|
}
|
|
|
|
void
|
|
_cogl_bitmask_foreach (const CoglBitmask *bitmask,
|
|
CoglBitmaskForeachFunc func,
|
|
void *user_data)
|
|
{
|
|
if (_cogl_bitmask_has_array (bitmask))
|
|
{
|
|
GArray *array = (GArray *) *bitmask;
|
|
const unsigned long *values = &g_array_index (array, unsigned long, 0);
|
|
int bit_num;
|
|
|
|
COGL_FLAGS_FOREACH_START (values, array->len, bit_num)
|
|
{
|
|
if (!func (bit_num, user_data))
|
|
return;
|
|
}
|
|
COGL_FLAGS_FOREACH_END;
|
|
}
|
|
else
|
|
{
|
|
unsigned long mask = _cogl_bitmask_to_bits (bitmask);
|
|
int bit_num;
|
|
|
|
COGL_FLAGS_FOREACH_START (&mask, 1, bit_num)
|
|
{
|
|
if (!func (bit_num, user_data))
|
|
return;
|
|
}
|
|
COGL_FLAGS_FOREACH_END;
|
|
}
|
|
}
|
|
|
|
void
|
|
_cogl_bitmask_set_flags_array (const CoglBitmask *bitmask,
|
|
unsigned long *flags)
|
|
{
|
|
const GArray *array = (const GArray *) *bitmask;
|
|
int i;
|
|
|
|
for (i = 0; i < array->len; i++)
|
|
flags[i] |= g_array_index (array, unsigned long, i);
|
|
}
|
|
|
|
int
|
|
_cogl_bitmask_popcount_in_array (const CoglBitmask *bitmask)
|
|
{
|
|
const GArray *array = (const GArray *) *bitmask;
|
|
int pop = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < array->len; i++)
|
|
pop += _cogl_util_popcountl (g_array_index (array, unsigned long, i));
|
|
|
|
return pop;
|
|
}
|
|
|
|
int
|
|
_cogl_bitmask_popcount_upto_in_array (const CoglBitmask *bitmask,
|
|
int upto)
|
|
{
|
|
const GArray *array = (const GArray *) *bitmask;
|
|
|
|
if (upto >= array->len * sizeof (unsigned long) * 8)
|
|
return _cogl_bitmask_popcount_in_array (bitmask);
|
|
else
|
|
{
|
|
unsigned long top_mask;
|
|
int array_index = ARRAY_INDEX (upto);
|
|
int bit_index = BIT_INDEX (upto);
|
|
int pop = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < array_index; i++)
|
|
pop += _cogl_util_popcountl (g_array_index (array, unsigned long, i));
|
|
|
|
top_mask = g_array_index (array, unsigned long, array_index);
|
|
|
|
return pop + _cogl_util_popcountl (top_mask & ((1UL << bit_index) - 1));
|
|
}
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
int n_bits;
|
|
int *bits;
|
|
} CheckData;
|
|
|
|
static CoglBool
|
|
check_bit (int bit_num, void *user_data)
|
|
{
|
|
CheckData *data = user_data;
|
|
int i;
|
|
|
|
for (i = 0; i < data->n_bits; i++)
|
|
if (data->bits[i] == bit_num)
|
|
{
|
|
data->bits[i] = -1;
|
|
return TRUE;
|
|
}
|
|
|
|
g_assert_not_reached ();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
verify_bits (const CoglBitmask *bitmask,
|
|
...)
|
|
{
|
|
CheckData data;
|
|
va_list ap, ap_copy;
|
|
int i;
|
|
|
|
va_start (ap, bitmask);
|
|
G_VA_COPY (ap_copy, ap);
|
|
|
|
for (data.n_bits = 0; va_arg (ap, int) != -1; data.n_bits++);
|
|
|
|
data.bits = alloca (data.n_bits * (sizeof (int)));
|
|
|
|
G_VA_COPY (ap, ap_copy);
|
|
|
|
for (i = 0; i < data.n_bits; i++)
|
|
data.bits[i] = va_arg (ap, int);
|
|
|
|
_cogl_bitmask_foreach (bitmask, check_bit, &data);
|
|
|
|
for (i = 0; i < data.n_bits; i++)
|
|
g_assert_cmpint (data.bits[i], ==, -1);
|
|
|
|
g_assert_cmpint (_cogl_bitmask_popcount (bitmask), ==, data.n_bits);
|
|
|
|
for (i = 0; i < 1024; i++)
|
|
{
|
|
int upto_popcount = 0;
|
|
int j;
|
|
|
|
G_VA_COPY (ap, ap_copy);
|
|
|
|
for (j = 0; j < data.n_bits; j++)
|
|
if (va_arg (ap, int) < i)
|
|
upto_popcount++;
|
|
|
|
g_assert_cmpint (_cogl_bitmask_popcount_upto (bitmask, i),
|
|
==,
|
|
upto_popcount);
|
|
|
|
G_VA_COPY (ap, ap_copy);
|
|
|
|
for (j = 0; j < data.n_bits; j++)
|
|
if (va_arg (ap, int) == i)
|
|
break;
|
|
|
|
g_assert_cmpint (_cogl_bitmask_get (bitmask, i), ==, (j < data.n_bits));
|
|
}
|
|
}
|
|
|
|
UNIT_TEST (check_bitmask_api,
|
|
0 /* no requirements */,
|
|
0 /* no failure cases */)
|
|
{
|
|
CoglBitmask bitmask;
|
|
CoglBitmask other_bitmask;
|
|
/* A dummy bit to make it use arrays sometimes */
|
|
int dummy_bit;
|
|
int i;
|
|
|
|
for (dummy_bit = -1; dummy_bit < 256; dummy_bit += 40)
|
|
{
|
|
_cogl_bitmask_init (&bitmask);
|
|
_cogl_bitmask_init (&other_bitmask);
|
|
|
|
if (dummy_bit != -1)
|
|
_cogl_bitmask_set (&bitmask, dummy_bit, TRUE);
|
|
|
|
verify_bits (&bitmask, dummy_bit, -1);
|
|
|
|
_cogl_bitmask_set (&bitmask, 1, TRUE);
|
|
_cogl_bitmask_set (&bitmask, 4, TRUE);
|
|
_cogl_bitmask_set (&bitmask, 5, TRUE);
|
|
|
|
verify_bits (&bitmask, 1, 4, 5, dummy_bit, -1);
|
|
|
|
_cogl_bitmask_set (&bitmask, 4, FALSE);
|
|
|
|
verify_bits (&bitmask, 1, 5, dummy_bit, -1);
|
|
|
|
_cogl_bitmask_clear_all (&bitmask);
|
|
|
|
verify_bits (&bitmask, -1);
|
|
|
|
if (dummy_bit != -1)
|
|
_cogl_bitmask_set (&bitmask, dummy_bit, TRUE);
|
|
|
|
verify_bits (&bitmask, dummy_bit, -1);
|
|
|
|
_cogl_bitmask_set (&bitmask, 1, TRUE);
|
|
_cogl_bitmask_set (&bitmask, 4, TRUE);
|
|
_cogl_bitmask_set (&bitmask, 5, TRUE);
|
|
_cogl_bitmask_set (&other_bitmask, 5, TRUE);
|
|
_cogl_bitmask_set (&other_bitmask, 6, TRUE);
|
|
|
|
_cogl_bitmask_set_bits (&bitmask, &other_bitmask);
|
|
|
|
verify_bits (&bitmask, 1, 4, 5, 6, dummy_bit, -1);
|
|
verify_bits (&other_bitmask, 5, 6, -1);
|
|
|
|
_cogl_bitmask_set (&bitmask, 6, FALSE);
|
|
|
|
verify_bits (&bitmask, 1, 4, 5, dummy_bit, -1);
|
|
|
|
_cogl_bitmask_xor_bits (&bitmask, &other_bitmask);
|
|
|
|
verify_bits (&bitmask, 1, 4, 6, dummy_bit, -1);
|
|
verify_bits (&other_bitmask, 5, 6, -1);
|
|
|
|
_cogl_bitmask_set_range (&bitmask, 5, TRUE);
|
|
|
|
verify_bits (&bitmask, 0, 1, 2, 3, 4, 6, dummy_bit, -1);
|
|
|
|
_cogl_bitmask_set_range (&bitmask, 4, FALSE);
|
|
|
|
verify_bits (&bitmask, 4, 6, dummy_bit, -1);
|
|
|
|
_cogl_bitmask_destroy (&other_bitmask);
|
|
_cogl_bitmask_destroy (&bitmask);
|
|
}
|
|
|
|
/* Extra tests for really long bitmasks */
|
|
_cogl_bitmask_init (&bitmask);
|
|
_cogl_bitmask_set_range (&bitmask, 400, TRUE);
|
|
_cogl_bitmask_init (&other_bitmask);
|
|
_cogl_bitmask_set (&other_bitmask, 5, TRUE);
|
|
_cogl_bitmask_xor_bits (&bitmask, &other_bitmask);
|
|
|
|
for (i = 0; i < 1024; i++)
|
|
g_assert_cmpint (_cogl_bitmask_get (&bitmask, i),
|
|
==,
|
|
(i == 5 ? FALSE :
|
|
i < 400 ? TRUE :
|
|
FALSE));
|
|
|
|
_cogl_bitmask_set_range (&other_bitmask, 500, TRUE);
|
|
_cogl_bitmask_set_bits (&bitmask, &other_bitmask);
|
|
|
|
for (i = 0; i < 1024; i++)
|
|
g_assert_cmpint (_cogl_bitmask_get (&bitmask, i), ==, (i < 500));
|
|
}
|