[charset] Grow internal FcCharset arrays exponentially

This commit is contained in:
Behdad Esfahbod 2009-06-05 18:16:38 -04:00
parent cce69b07ef
commit 900723f3d2
1 changed files with 36 additions and 29 deletions

View File

@ -68,11 +68,9 @@ FcCharSetDestroy (FcCharSet *fcs)
}
if (fcs->num)
{
/* the numbers here are estimates */
FcMemFree (FC_MEM_CHARSET, fcs->num * sizeof (intptr_t));
free (FcCharSetLeaves (fcs));
}
if (fcs->num)
{
FcMemFree (FC_MEM_CHARSET, fcs->num * sizeof (FcChar16));
free (FcCharSetNumbers (fcs));
}
@ -134,6 +132,8 @@ FcCharSetFindLeaf (const FcCharSet *fcs, FcChar32 ucs4)
return 0;
}
#define FC_IS_ZERO_OR_POWER_OF_TWO(x) (!((x) & ((x)-1)))
static FcBool
FcCharSetPutLeaf (FcCharSet *fcs,
FcChar32 ucs4,
@ -143,45 +143,52 @@ FcCharSetPutLeaf (FcCharSet *fcs,
intptr_t *leaves = FcCharSetLeaves (fcs);
FcChar16 *numbers = FcCharSetNumbers (fcs);
/* XXX We can't handle Unicode values in Plane 16 */
ucs4 >>= 8;
/* XXX We can't handle Unicode values in Plane 16 */
if (ucs4 >= 0x10000)
return FcFalse;
if (fcs->num == fcs->alloced)
if (FC_IS_ZERO_OR_POWER_OF_TWO (fcs->num))
{
intptr_t *new_leaves = realloc (leaves, (fcs->num + 1) *
sizeof (*leaves));
intptr_t distance = (intptr_t) new_leaves - (intptr_t) leaves;
if (!fcs->num)
{
unsigned int alloced = 8;
leaves = malloc (alloced * sizeof (*leaves));
numbers = malloc (alloced * sizeof (*numbers));
FcMemAlloc (FC_MEM_CHARSET, alloced * sizeof (*leaves));
FcMemAlloc (FC_MEM_CHARSET, alloced * sizeof (*numbers));
}
else
{
unsigned int alloced = fcs->num;
intptr_t *new_leaves, distance;
FcMemFree (FC_MEM_CHARSET, alloced * sizeof (*leaves));
FcMemFree (FC_MEM_CHARSET, alloced * sizeof (*numbers));
alloced *= 2;
new_leaves = realloc (leaves, alloced * sizeof (*leaves));
numbers = realloc (numbers, alloced * sizeof (*numbers));
FcMemAlloc (FC_MEM_CHARSET, alloced * sizeof (*leaves));
FcMemAlloc (FC_MEM_CHARSET, alloced * sizeof (*numbers));
distance = (intptr_t) new_leaves - (intptr_t) leaves;
if (new_leaves && distance)
{
int i;
for (i = 0; i < fcs->num; i++)
new_leaves[i] -= distance;
}
leaves = new_leaves;
}
if (!leaves || !numbers)
return FcFalse;
fcs->leaves_offset = FcPtrToOffset (fcs, leaves);
fcs->numbers_offset = FcPtrToOffset (fcs, numbers);
}
if (!leaves)
return FcFalse;
if (fcs->num)
FcMemFree (FC_MEM_CHARSET, fcs->num * sizeof (intptr_t));
FcMemAlloc (FC_MEM_CHARSET, (fcs->num + 1) * sizeof (intptr_t));
fcs->leaves_offset = FcPtrToOffset (fcs, leaves);
if (!fcs->num)
numbers = malloc (sizeof (FcChar16));
else
numbers = realloc (numbers, (fcs->num + 1) * sizeof (FcChar16));
if (!numbers)
return FcFalse;
if (fcs->num)
FcMemFree (FC_MEM_CHARSET, fcs->num * sizeof (FcChar16));
FcMemAlloc (FC_MEM_CHARSET, (fcs->num + 1) * sizeof (FcChar16));
fcs->numbers_offset = FcPtrToOffset (fcs, numbers);
memmove (leaves + pos + 1, leaves + pos,
(fcs->num - pos) * sizeof (*leaves));