Use a hash table for families in FcConfigSubstitute

Use the same approach we used for FcFontMatch, and
keep a hash table of family names. We only speed
up the no-match case, for now.
This commit is contained in:
Matthias Clasen 2020-08-18 16:33:57 -04:00
parent 7deb07e38e
commit 13015a0a6e
1 changed files with 172 additions and 20 deletions

View File

@ -1579,12 +1579,128 @@ FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
return v; return v;
} }
/* The bulk of the time in FcConfigSubstitute is spent walking
* lists of family names. We speed this up with a hash table.
* Since we need to take the ignore-blanks option into account,
* we use two separate hash tables.
*/
typedef struct
{
int count;
} FamilyTableEntry;
typedef struct
{
FcHashTable *family_blank_hash;
FcHashTable *family_hash;
} FamilyTable;
static FcBool
FamilyTableLookup (FamilyTable *table,
FcOp _op,
const FcChar8 *s)
{
FamilyTableEntry *fe;
int flags = FC_OP_GET_FLAGS (_op);
FcHashTable *hash;
if (flags & FcOpFlagIgnoreBlanks)
hash = table->family_blank_hash;
else
hash = table->family_hash;
return FcHashTableFind (hash, (const void *)s, (void **)&fe);
}
static void
FamilyTableAdd (FamilyTable *table,
FcValueListPtr values)
{
FcValueListPtr ll;
for (ll = values; ll; ll = FcValueListNext (ll))
{
const FcChar8 *s = FcValueString (&ll->value);
FamilyTableEntry *fe;
if (!FcHashTableFind (table->family_hash, (const void *)s, (void **)&fe))
{
fe = malloc (sizeof (FamilyTableEntry));
fe->count = 0;
FcHashTableAdd (table->family_hash, (void *)s, fe);
}
fe->count++;
if (!FcHashTableFind (table->family_blank_hash, (const void *)s, (void **)&fe))
{
fe = malloc (sizeof (FamilyTableEntry));
fe->count = 0;
FcHashTableAdd (table->family_blank_hash, (void *)s, fe);
}
fe->count++;
}
}
static void
FamilyTableDel (FamilyTable *table,
const FcChar8 *s)
{
FamilyTableEntry *fe;
if (FcHashTableFind (table->family_hash, (void *)s, (void **)&fe))
{
fe->count--;
if (fe->count == 0)
FcHashTableRemove (table->family_hash, (void *)s);
}
if (FcHashTableFind (table->family_blank_hash, (void *)s, (void **)&fe))
{
fe->count--;
if (fe->count == 0)
FcHashTableRemove (table->family_blank_hash, (void *)s);
}
}
static void
FamilyTableInit (FamilyTable *table,
FcPattern *p)
{
FcPatternElt *e;
table->family_blank_hash = FcHashTableCreate ((FcHashFunc)FcStrHashIgnoreBlanksAndCase,
(FcCompareFunc)FcStrCmpIgnoreBlanksAndCase,
NULL,
NULL,
NULL,
free);
table->family_hash = FcHashTableCreate ((FcHashFunc)FcStrHashIgnoreCase,
(FcCompareFunc)FcStrCmpIgnoreCase,
NULL,
NULL,
NULL,
free);
e = FcPatternObjectFindElt (p, FC_FAMILY_OBJECT);
if (e)
FamilyTableAdd (table, FcPatternEltValues (e));
}
static void
FamilyTableClear (FamilyTable *table)
{
if (table->family_blank_hash)
FcHashTableDestroy (table->family_blank_hash);
if (table->family_hash)
FcHashTableDestroy (table->family_hash);
}
static FcValueList * static FcValueList *
FcConfigMatchValueList (FcPattern *p, FcConfigMatchValueList (FcPattern *p,
FcPattern *p_pat, FcPattern *p_pat,
FcMatchKind kind, FcMatchKind kind,
FcTest *t, FcTest *t,
FcValueList *values) FcValueList *values,
FamilyTable *table)
{ {
FcValueList *ret = 0; FcValueList *ret = 0;
FcExpr *e = t->expr; FcExpr *e = t->expr;
@ -1605,6 +1721,14 @@ FcConfigMatchValueList (FcPattern *p,
e = 0; e = 0;
} }
if (t->object == FC_FAMILY_OBJECT && table)
{
if (!FamilyTableLookup (table, t->op, FcValueString (&value)))
{
ret = 0;
goto done;
}
}
for (v = values; v; v = FcValueListNext(v)) for (v = values; v; v = FcValueListNext(v))
{ {
/* Compare the pattern value to the match expression value */ /* Compare the pattern value to the match expression value */
@ -1624,6 +1748,7 @@ FcConfigMatchValueList (FcPattern *p,
} }
} }
} }
done:
FcValueDestroy (value); FcValueDestroy (value);
} }
return ret; return ret;
@ -1666,7 +1791,8 @@ FcConfigAdd (FcValueListPtr *head,
FcValueList *position, FcValueList *position,
FcBool append, FcBool append,
FcValueList *new, FcValueList *new,
FcObject object) FcObject object,
FamilyTable *table)
{ {
FcValueListPtr *prev, l, last, v; FcValueListPtr *prev, l, last, v;
FcValueBinding sameBinding; FcValueBinding sameBinding;
@ -1692,6 +1818,11 @@ FcConfigAdd (FcValueListPtr *head,
} }
} }
if (object == FC_FAMILY_OBJECT && table)
{
FamilyTableAdd (table, new);
}
if (position) if (position)
sameBinding = position->binding; sameBinding = position->binding;
else else
@ -1758,10 +1889,17 @@ FcConfigAdd (FcValueListPtr *head,
static void static void
FcConfigDel (FcValueListPtr *head, FcConfigDel (FcValueListPtr *head,
FcValueList *position) FcValueList *position,
FcObject object,
FamilyTable *table)
{ {
FcValueListPtr *prev; FcValueListPtr *prev;
if (object == FC_FAMILY_OBJECT && table)
{
FamilyTableDel (table, FcValueString (&position->value));
}
for (prev = head; *prev != NULL; prev = &(*prev)->next) for (prev = head; *prev != NULL; prev = &(*prev)->next)
{ {
if (*prev == position) if (*prev == position)
@ -1776,9 +1914,10 @@ FcConfigDel (FcValueListPtr *head,
static void static void
FcConfigPatternAdd (FcPattern *p, FcConfigPatternAdd (FcPattern *p,
FcObject object, FcObject object,
FcValueList *list, FcValueList *list,
FcBool append) FcBool append,
FamilyTable *table)
{ {
if (list) if (list)
{ {
@ -1786,7 +1925,7 @@ FcConfigPatternAdd (FcPattern *p,
if (!e) if (!e)
return; return;
FcConfigAdd (&e->values, 0, append, list, object); FcConfigAdd (&e->values, 0, append, list, object, table);
} }
} }
@ -1795,13 +1934,14 @@ FcConfigPatternAdd (FcPattern *p,
*/ */
static void static void
FcConfigPatternDel (FcPattern *p, FcConfigPatternDel (FcPattern *p,
FcObject object) FcObject object,
FamilyTable *table)
{ {
FcPatternElt *e = FcPatternObjectFindElt (p, object); FcPatternElt *e = FcPatternObjectFindElt (p, object);
if (!e) if (!e)
return; return;
while (e->values != NULL) while (e->values != NULL)
FcConfigDel (&e->values, e->values); FcConfigDel (&e->values, e->values, object, table);
} }
static void static void
@ -1834,6 +1974,8 @@ FcConfigSubstituteWithPat (FcConfig *config,
int i, nobjs; int i, nobjs;
FcBool retval = FcTrue; FcBool retval = FcTrue;
FcTest **tst = NULL; FcTest **tst = NULL;
FamilyTable data;
FamilyTable *table = &data;
if (kind < FcMatchKindBegin || kind >= FcMatchKindEnd) if (kind < FcMatchKindBegin || kind >= FcMatchKindEnd)
return FcFalse; return FcFalse;
@ -1931,6 +2073,9 @@ FcConfigSubstituteWithPat (FcConfig *config,
printf ("FcConfigSubstitute "); printf ("FcConfigSubstitute ");
FcPatternPrint (p); FcPatternPrint (p);
} }
FamilyTableInit (&data, p);
FcPtrListIterInit (s, &iter); FcPtrListIterInit (s, &iter);
for (; FcPtrListIterIsValid (s, &iter); FcPtrListIterNext (s, &iter)) for (; FcPtrListIterIsValid (s, &iter); FcPtrListIterNext (s, &iter))
{ {
@ -1967,9 +2112,15 @@ FcConfigSubstituteWithPat (FcConfig *config,
FcTestPrint (r->u.test); FcTestPrint (r->u.test);
} }
if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern) if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern)
{
m = p_pat; m = p_pat;
table = NULL;
}
else else
{
m = p; m = p;
table = &data;
}
if (m) if (m)
e = FcPatternObjectFindElt (m, r->u.test->object); e = FcPatternObjectFindElt (m, r->u.test->object);
else else
@ -2002,7 +2153,7 @@ FcConfigSubstituteWithPat (FcConfig *config,
* Check to see if there is a match, mark the location * Check to see if there is a match, mark the location
* to apply match-relative edits * to apply match-relative edits
*/ */
vl = FcConfigMatchValueList (m, p_pat, kind, r->u.test, e->values); vl = FcConfigMatchValueList (m, p_pat, kind, r->u.test, e->values, table);
/* different 'kind' won't be the target of edit */ /* different 'kind' won't be the target of edit */
if (!value[object] && kind == r->u.test->kind) if (!value[object] && kind == r->u.test->kind)
value[object] = vl; value[object] = vl;
@ -2026,7 +2177,7 @@ FcConfigSubstituteWithPat (FcConfig *config,
/* /*
* Evaluate the list of expressions * Evaluate the list of expressions
*/ */
l = FcConfigValues (p, p_pat,kind, r->u.edit->expr, r->u.edit->binding); l = FcConfigValues (p, p_pat, kind, r->u.edit->expr, r->u.edit->binding);
if (tst[object] && (tst[object]->kind == FcMatchFont || kind == FcMatchPattern)) if (tst[object] && (tst[object]->kind == FcMatchFont || kind == FcMatchPattern))
elt[object] = FcPatternObjectFindElt (p, tst[object]->object); elt[object] = FcPatternObjectFindElt (p, tst[object]->object);
@ -2044,12 +2195,12 @@ FcConfigSubstituteWithPat (FcConfig *config,
/* /*
* Append the new list of values after the current value * Append the new list of values after the current value
*/ */
FcConfigAdd (&elt[object]->values, thisValue, FcTrue, l, r->u.edit->object); FcConfigAdd (&elt[object]->values, thisValue, FcTrue, l, r->u.edit->object, table);
/* /*
* Delete the marked value * Delete the marked value
*/ */
if (thisValue) if (thisValue)
FcConfigDel (&elt[object]->values, thisValue); FcConfigDel (&elt[object]->values, thisValue, object, table);
/* /*
* Adjust a pointer into the value list to ensure * Adjust a pointer into the value list to ensure
* future edits occur at the same place * future edits occur at the same place
@ -2063,8 +2214,8 @@ FcConfigSubstituteWithPat (FcConfig *config,
* Delete all of the values and insert * Delete all of the values and insert
* the new set * the new set
*/ */
FcConfigPatternDel (p, r->u.edit->object); FcConfigPatternDel (p, r->u.edit->object, table);
FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue); FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue, table);
/* /*
* Adjust a pointer into the value list as they no * Adjust a pointer into the value list as they no
* longer point to anything valid * longer point to anything valid
@ -2074,33 +2225,33 @@ FcConfigSubstituteWithPat (FcConfig *config,
case FcOpPrepend: case FcOpPrepend:
if (value[object]) if (value[object])
{ {
FcConfigAdd (&elt[object]->values, value[object], FcFalse, l, r->u.edit->object); FcConfigAdd (&elt[object]->values, value[object], FcFalse, l, r->u.edit->object, table);
break; break;
} }
/* fall through ... */ /* fall through ... */
case FcOpPrependFirst: case FcOpPrependFirst:
FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse); FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse, table);
break; break;
case FcOpAppend: case FcOpAppend:
if (value[object]) if (value[object])
{ {
FcConfigAdd (&elt[object]->values, value[object], FcTrue, l, r->u.edit->object); FcConfigAdd (&elt[object]->values, value[object], FcTrue, l, r->u.edit->object, table);
break; break;
} }
/* fall through ... */ /* fall through ... */
case FcOpAppendLast: case FcOpAppendLast:
FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue); FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue, table);
break; break;
case FcOpDelete: case FcOpDelete:
if (value[object]) if (value[object])
{ {
FcConfigDel (&elt[object]->values, value[object]); FcConfigDel (&elt[object]->values, value[object], object, table);
FcValueListDestroy (l); FcValueListDestroy (l);
break; break;
} }
/* fall through ... */ /* fall through ... */
case FcOpDeleteAll: case FcOpDeleteAll:
FcConfigPatternDel (p, r->u.edit->object); FcConfigPatternDel (p, r->u.edit->object, table);
FcValueListDestroy (l); FcValueListDestroy (l);
break; break;
default: default:
@ -2130,6 +2281,7 @@ FcConfigSubstituteWithPat (FcConfig *config,
FcPatternPrint (p); FcPatternPrint (p);
} }
bail1: bail1:
FamilyTableClear (&data);
if (elt) if (elt)
free (elt); free (elt);
if (value) if (value)