Speed up FcConfigCompareValue

Make FcConfigPromote use a switch instead of
an if-else cascade, and avoid calling it when
we can.

Note that we need to add a case for integers
in FcConfigCompareValue, since we are no longer
promoting integers to doubles unconditionally.
This commit is contained in:
Matthias Clasen 2020-08-20 23:45:19 -04:00
parent 922168afe8
commit 9d4e5d0f25
1 changed files with 247 additions and 211 deletions

View File

@ -934,35 +934,45 @@ FcConfigAddRule (FcConfig *config,
static FcValue static FcValue
FcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf) FcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf)
{ {
if (v.type == FcTypeInteger) switch (v.type)
{ {
v.type = FcTypeDouble; case FcTypeInteger:
v.u.d = (double) v.u.i; v.type = FcTypeDouble;
} v.u.d = (double) v.u.i;
else if (v.type == FcTypeVoid && u.type == FcTypeMatrix) break;
{ case FcTypeVoid:
v.u.m = &FcIdentityMatrix; if (u.type == FcTypeMatrix)
v.type = FcTypeMatrix; {
} v.u.m = &FcIdentityMatrix;
else if (buf && v.type == FcTypeString && u.type == FcTypeLangSet) v.type = FcTypeMatrix;
{ }
v.u.l = FcLangSetPromote (v.u.s, buf); else if (u.type == FcTypeLangSet && buf)
v.type = FcTypeLangSet; {
} v.u.l = FcLangSetPromote (NULL, buf);
else if (buf && v.type == FcTypeVoid && u.type == FcTypeLangSet) v.type = FcTypeLangSet;
{ }
v.u.l = FcLangSetPromote (NULL, buf); else if (u.type == FcTypeCharSet && buf)
v.type = FcTypeLangSet; {
} v.u.c = FcCharSetPromote (buf);
else if (buf && v.type == FcTypeVoid && u.type == FcTypeCharSet) v.type = FcTypeCharSet;
{ }
v.u.c = FcCharSetPromote (buf); break;
v.type = FcTypeCharSet; case FcTypeString:
} if (u.type == FcTypeLangSet && buf)
if (buf && v.type == FcTypeDouble && u.type == FcTypeRange) {
{ v.u.l = FcLangSetPromote (v.u.s, buf);
v.u.r = FcRangePromote (v.u.d, buf); v.type = FcTypeLangSet;
v.type = FcTypeRange; }
break;
case FcTypeDouble:
if (u.type == FcTypeRange && buf)
{
v.u.r = FcRangePromote (v.u.d, buf);
v.type = FcTypeRange;
}
break;
default:
break;
} }
return v; return v;
} }
@ -972,195 +982,221 @@ FcConfigCompareValue (const FcValue *left_o,
unsigned int op_, unsigned int op_,
const FcValue *right_o) const FcValue *right_o)
{ {
FcValue left = FcValueCanonicalize(left_o); FcValue left = FcValueCanonicalize(left_o);
FcValue right = FcValueCanonicalize(right_o); FcValue right = FcValueCanonicalize(right_o);
FcBool ret = FcFalse; FcBool ret = FcFalse;
FcOp op = FC_OP_GET_OP (op_); FcOp op = FC_OP_GET_OP (op_);
int flags = FC_OP_GET_FLAGS (op_); int flags = FC_OP_GET_FLAGS (op_);
FcValuePromotionBuffer buf1, buf2;
left = FcConfigPromote (left, right, &buf1); if (left.type != right.type)
right = FcConfigPromote (right, left, &buf2);
if (left.type == right.type)
{ {
switch (left.type) { FcValuePromotionBuffer buf1, buf2;
case FcTypeUnknown: left = FcConfigPromote (left, right, &buf1);
break; /* No way to guess how to compare for this object */ right = FcConfigPromote (right, left, &buf2);
case FcTypeInteger: if (left.type != right.type)
break; /* FcConfigPromote prevents this from happening */ {
case FcTypeDouble: if (op == FcOpNotEqual || op == FcOpNotContains)
switch ((int) op) { ret = FcTrue;
case FcOpEqual: return ret;
case FcOpContains: }
case FcOpListing:
ret = left.u.d == right.u.d;
break;
case FcOpNotEqual:
case FcOpNotContains:
ret = left.u.d != right.u.d;
break;
case FcOpLess:
ret = left.u.d < right.u.d;
break;
case FcOpLessEqual:
ret = left.u.d <= right.u.d;
break;
case FcOpMore:
ret = left.u.d > right.u.d;
break;
case FcOpMoreEqual:
ret = left.u.d >= right.u.d;
break;
default:
break;
}
break;
case FcTypeBool:
switch ((int) op) {
case FcOpEqual:
ret = left.u.b == right.u.b;
break;
case FcOpContains:
case FcOpListing:
ret = left.u.b == right.u.b || left.u.b >= FcDontCare;
break;
case FcOpNotEqual:
ret = left.u.b != right.u.b;
break;
case FcOpNotContains:
ret = !(left.u.b == right.u.b || left.u.b >= FcDontCare);
break;
case FcOpLess:
ret = left.u.b != right.u.b && right.u.b >= FcDontCare;
break;
case FcOpLessEqual:
ret = left.u.b == right.u.b || right.u.b >= FcDontCare;
break;
case FcOpMore:
ret = left.u.b != right.u.b && left.u.b >= FcDontCare;
break;
case FcOpMoreEqual:
ret = left.u.b == right.u.b || left.u.b >= FcDontCare;
break;
default:
break;
}
break;
case FcTypeString:
switch ((int) op) {
case FcOpEqual:
case FcOpListing:
if (flags & FcOpFlagIgnoreBlanks)
ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) == 0;
else
ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
break;
case FcOpContains:
ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
break;
case FcOpNotEqual:
if (flags & FcOpFlagIgnoreBlanks)
ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) != 0;
else
ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
break;
case FcOpNotContains:
ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0;
break;
default:
break;
}
break;
case FcTypeMatrix:
switch ((int) op) {
case FcOpEqual:
case FcOpContains:
case FcOpListing:
ret = FcMatrixEqual (left.u.m, right.u.m);
break;
case FcOpNotEqual:
case FcOpNotContains:
ret = !FcMatrixEqual (left.u.m, right.u.m);
break;
default:
break;
}
break;
case FcTypeCharSet:
switch ((int) op) {
case FcOpContains:
case FcOpListing:
/* left contains right if right is a subset of left */
ret = FcCharSetIsSubset (right.u.c, left.u.c);
break;
case FcOpNotContains:
/* left contains right if right is a subset of left */
ret = !FcCharSetIsSubset (right.u.c, left.u.c);
break;
case FcOpEqual:
ret = FcCharSetEqual (left.u.c, right.u.c);
break;
case FcOpNotEqual:
ret = !FcCharSetEqual (left.u.c, right.u.c);
break;
default:
break;
}
break;
case FcTypeLangSet:
switch ((int) op) {
case FcOpContains:
case FcOpListing:
ret = FcLangSetContains (left.u.l, right.u.l);
break;
case FcOpNotContains:
ret = !FcLangSetContains (left.u.l, right.u.l);
break;
case FcOpEqual:
ret = FcLangSetEqual (left.u.l, right.u.l);
break;
case FcOpNotEqual:
ret = !FcLangSetEqual (left.u.l, right.u.l);
break;
default:
break;
}
break;
case FcTypeVoid:
switch ((int) op) {
case FcOpEqual:
case FcOpContains:
case FcOpListing:
ret = FcTrue;
break;
default:
break;
}
break;
case FcTypeFTFace:
switch ((int) op) {
case FcOpEqual:
case FcOpContains:
case FcOpListing:
ret = left.u.f == right.u.f;
break;
case FcOpNotEqual:
case FcOpNotContains:
ret = left.u.f != right.u.f;
break;
default:
break;
}
break;
case FcTypeRange:
ret = FcRangeCompare (op, left.u.r, right.u.r);
break;
}
} }
else switch (left.type) {
{ case FcTypeUnknown:
if (op == FcOpNotEqual || op == FcOpNotContains) break; /* No way to guess how to compare for this object */
ret = FcTrue; case FcTypeInteger:
switch ((int) op) {
case FcOpEqual:
case FcOpContains:
case FcOpListing:
ret = left.u.i == right.u.i;
break;
case FcOpNotEqual:
case FcOpNotContains:
ret = left.u.i != right.u.i;
break;
case FcOpLess:
ret = left.u.i < right.u.i;
break;
case FcOpLessEqual:
ret = left.u.i <= right.u.i;
break;
case FcOpMore:
ret = left.u.i > right.u.i;
break;
case FcOpMoreEqual:
ret = left.u.i >= right.u.i;
break;
default:
break;
}
break;
case FcTypeDouble:
switch ((int) op) {
case FcOpEqual:
case FcOpContains:
case FcOpListing:
ret = left.u.d == right.u.d;
break;
case FcOpNotEqual:
case FcOpNotContains:
ret = left.u.d != right.u.d;
break;
case FcOpLess:
ret = left.u.d < right.u.d;
break;
case FcOpLessEqual:
ret = left.u.d <= right.u.d;
break;
case FcOpMore:
ret = left.u.d > right.u.d;
break;
case FcOpMoreEqual:
ret = left.u.d >= right.u.d;
break;
default:
break;
}
break;
case FcTypeBool:
switch ((int) op) {
case FcOpEqual:
ret = left.u.b == right.u.b;
break;
case FcOpContains:
case FcOpListing:
ret = left.u.b == right.u.b || left.u.b >= FcDontCare;
break;
case FcOpNotEqual:
ret = left.u.b != right.u.b;
break;
case FcOpNotContains:
ret = !(left.u.b == right.u.b || left.u.b >= FcDontCare);
break;
case FcOpLess:
ret = left.u.b != right.u.b && right.u.b >= FcDontCare;
break;
case FcOpLessEqual:
ret = left.u.b == right.u.b || right.u.b >= FcDontCare;
break;
case FcOpMore:
ret = left.u.b != right.u.b && left.u.b >= FcDontCare;
break;
case FcOpMoreEqual:
ret = left.u.b == right.u.b || left.u.b >= FcDontCare;
break;
default:
break;
}
break;
case FcTypeString:
switch ((int) op) {
case FcOpEqual:
case FcOpListing:
if (flags & FcOpFlagIgnoreBlanks)
ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) == 0;
else
ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
break;
case FcOpContains:
ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
break;
case FcOpNotEqual:
if (flags & FcOpFlagIgnoreBlanks)
ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) != 0;
else
ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
break;
case FcOpNotContains:
ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0;
break;
default:
break;
}
break;
case FcTypeMatrix:
switch ((int) op) {
case FcOpEqual:
case FcOpContains:
case FcOpListing:
ret = FcMatrixEqual (left.u.m, right.u.m);
break;
case FcOpNotEqual:
case FcOpNotContains:
ret = !FcMatrixEqual (left.u.m, right.u.m);
break;
default:
break;
}
break;
case FcTypeCharSet:
switch ((int) op) {
case FcOpContains:
case FcOpListing:
/* left contains right if right is a subset of left */
ret = FcCharSetIsSubset (right.u.c, left.u.c);
break;
case FcOpNotContains:
/* left contains right if right is a subset of left */
ret = !FcCharSetIsSubset (right.u.c, left.u.c);
break;
case FcOpEqual:
ret = FcCharSetEqual (left.u.c, right.u.c);
break;
case FcOpNotEqual:
ret = !FcCharSetEqual (left.u.c, right.u.c);
break;
default:
break;
}
break;
case FcTypeLangSet:
switch ((int) op) {
case FcOpContains:
case FcOpListing:
ret = FcLangSetContains (left.u.l, right.u.l);
break;
case FcOpNotContains:
ret = !FcLangSetContains (left.u.l, right.u.l);
break;
case FcOpEqual:
ret = FcLangSetEqual (left.u.l, right.u.l);
break;
case FcOpNotEqual:
ret = !FcLangSetEqual (left.u.l, right.u.l);
break;
default:
break;
}
break;
case FcTypeVoid:
switch ((int) op) {
case FcOpEqual:
case FcOpContains:
case FcOpListing:
ret = FcTrue;
break;
default:
break;
}
break;
case FcTypeFTFace:
switch ((int) op) {
case FcOpEqual:
case FcOpContains:
case FcOpListing:
ret = left.u.f == right.u.f;
break;
case FcOpNotEqual:
case FcOpNotContains:
ret = left.u.f != right.u.f;
break;
default:
break;
}
break;
case FcTypeRange:
ret = FcRangeCompare (op, left.u.r, right.u.r);
break;
} }
return ret; return ret;
} }