commit: a4001925cff4414eca5c205fb4abe09422f246da
Author: Fabian Groffen <grobian <AT> gentoo <DOT> org>
AuthorDate: Sat Jan 24 16:57:02 2026 +0000
Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org>
CommitDate: Sat Jan 24 16:57:02 2026 +0000
URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=a4001925
libq/tree: avoid many strcmps to match metadata keys
Use a lookup based on the first character to jump to a few candidates,
instead of scanning the full list until match for every key. This saves
some time.
Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>
libq/tree.c | 382 ++++++++++++++++++++++++++++++++++++++----------------------
1 file changed, 246 insertions(+), 136 deletions(-)
diff --git a/libq/tree.c b/libq/tree.c
index 7dfaad4..2990cec 100644
--- a/libq/tree.c
+++ b/libq/tree.c
@@ -338,52 +338,77 @@ static int tree_foreach_pkg_gtree
p != NULL;
p = strtok_r(NULL, "=", &nexttok))
{
- char **ptr = NULL;
+ char *key = p;
- if (1 == 0) {
- /* dummy case for syntax */
- }
-#define match(K) \
- else if (strcmp(p, #K) == 0) \
- do { \
- ptr = &pkg->meta[Q_##K]; \
- } while (0)
- match(DEPEND);
- match(RDEPEND);
- match(SLOT);
- match(SRC_URI);
- match(RESTRICT);
- match(LICENSE);
- match(DESCRIPTION);
- match(KEYWORDS);
- match(INHERITED);
- match(IUSE);
- match(CDEPEND);
- match(PDEPEND);
- match(PROVIDE);
- match(EAPI);
- match(PROPERTIES);
- match(BDEPEND);
- match(IDEPEND);
- match(DEFINED_PHASES);
- match(REQUIRED_USE);
- match(CONTENTS);
- match(USE);
- match(EPREFIX);
- match(PATH);
- match(BUILD_ID);
- match(SIZE);
- match(_eclasses_);
-#undef match
-
- /* always advance to end of line, even when nothing
- * matched */
+ /* always advance to end of line */
p = strtok_r(NULL, "\n", &nexttok);
if (p == NULL)
+ break; /* end of input */
+
+ switch (key[0])
+ {
+ case '_':
+#define keycmp(P,K) \
+ if (strcmp(&P[1], &(#K)[1]) == 0) \
+ { \
+ if (pkg->meta[Q_##K] == NULL) \
+ pkg->meta[Q_##K] = xstrdup(p); \
+ continue; \
+ }
+ keycmp(key, _eclasses_);
+ break;
+ case 'B':
+ keycmp(key, BDEPEND);
+ keycmp(key, BUILD_ID);
+ break;
+ case 'C':
+ keycmp(key, CDEPEND);
+ keycmp(key, CONTENTS);
+ break;
+ case 'D':
+ keycmp(key, DEFINED_PHASES);
+ keycmp(key, DEPEND);
+ keycmp(key, DESCRIPTION);
+ break;
+ case 'E':
+ keycmp(key, EAPI);
+ keycmp(key, EPREFIX);
+ break;
+ case 'I':
+ keycmp(key, IDEPEND);
+ keycmp(key, INHERITED);
+ keycmp(key, IUSE);
break;
- if (ptr != NULL &&
- *ptr == NULL)
- *ptr = xstrdup(p);
+ case 'K':
+ keycmp(key, KEYWORDS);
+ break;
+ case 'L':
+ keycmp(key, LICENSE);
+ break;
+ case 'P':
+ keycmp(key, PATH);
+ keycmp(key, PDEPEND);
+ keycmp(key, PROPERTIES);
+ keycmp(key, PROVIDE);
+ break;
+ case 'R':
+ keycmp(key, RDEPEND);
+ keycmp(key, REQUIRED_USE);
+ keycmp(key, RESTRICT);
+ break;
+ case 'S':
+ keycmp(key, SIZE);
+ keycmp(key, SLOT);
+ keycmp(key, SRC_URI);
+ break;
+ case 'U':
+ keycmp(key, USE);
+ break;
+#undef keycmp
+ default:
+ /* don't care/unknown */
+ break;
+ }
}
pkg->meta_complete = true;
@@ -656,51 +681,78 @@ static bool tree_pkg_md5_read
p != NULL;
p = strtok_r(NULL, "=", &nexttok))
{
- char **ptr = NULL;
+ char *key = p;
- if (1 == 0) {
- /* dummy case for syntax */
- }
-#define match(K) \
- else if (strcmp(p, #K) == 0) \
- ptr = &pkg->meta[Q_##K]
- match(DEPEND);
- match(RDEPEND);
- match(SLOT);
- match(SRC_URI);
- match(RESTRICT);
- match(LICENSE);
- match(DESCRIPTION);
- match(KEYWORDS);
- match(INHERITED);
- match(IUSE);
- match(CDEPEND);
- match(PDEPEND);
- match(PROVIDE);
- match(EAPI);
- match(PROPERTIES);
- match(BDEPEND);
- match(IDEPEND);
- match(DEFINED_PHASES);
- match(REQUIRED_USE);
- match(CONTENTS);
- match(USE);
- match(EPREFIX);
- match(PATH);
- match(BUILD_ID);
- match(SIZE);
- match(_eclasses_);
- match(_md5_);
-#undef match
-
- /* always advance to end of line, even when nothing
- * matched */
+ /* always advance to end of line */
p = strtok_r(NULL, "\n", &nexttok);
if (p == NULL)
+ break; /* end of input */
+
+ switch (key[0])
+ {
+ case '_':
+#define keycmp(P,K) \
+ if (strcmp(&P[1], &(#K)[1]) == 0) \
+ { \
+ if (pkg->meta[Q_##K] == NULL) \
+ pkg->meta[Q_##K] = xstrdup(p); \
+ continue; \
+ }
+ keycmp(key, _eclasses_);
+ keycmp(key, _md5_);
+ break;
+ case 'B':
+ keycmp(key, BDEPEND);
+ keycmp(key, BUILD_ID);
+ break;
+ case 'C':
+ keycmp(key, CDEPEND);
+ keycmp(key, CONTENTS);
+ break;
+ case 'D':
+ keycmp(key, DEFINED_PHASES);
+ keycmp(key, DEPEND);
+ keycmp(key, DESCRIPTION);
+ break;
+ case 'E':
+ keycmp(key, EAPI);
+ keycmp(key, EPREFIX);
+ break;
+ case 'I':
+ keycmp(key, IDEPEND);
+ keycmp(key, INHERITED);
+ keycmp(key, IUSE);
break;
- if (ptr != NULL &&
- *ptr == NULL)
- *ptr = xstrdup(p);
+ case 'K':
+ keycmp(key, KEYWORDS);
+ break;
+ case 'L':
+ keycmp(key, LICENSE);
+ break;
+ case 'P':
+ keycmp(key, PATH);
+ keycmp(key, PDEPEND);
+ keycmp(key, PROPERTIES);
+ keycmp(key, PROVIDE);
+ break;
+ case 'R':
+ keycmp(key, RDEPEND);
+ keycmp(key, REQUIRED_USE);
+ keycmp(key, RESTRICT);
+ break;
+ case 'S':
+ keycmp(key, SIZE);
+ keycmp(key, SLOT);
+ keycmp(key, SRC_URI);
+ break;
+ case 'U':
+ keycmp(key, USE);
+ break;
+ default:
+ /* don't care/unknown */
+ break;
+#undef keycmp
+ }
}
free(data);
@@ -751,26 +803,57 @@ static bool tree_pkg_ebuild_read
{
*p++ = '\0';
/* match variable against which ones we look for */
- if (1 == 0); /* dummy for syntax */
-#define match_key(X) \
- else if (strcmp(q, #X) == 0) key = &pkg->meta[Q_##X]
- match_key(DEPEND);
- match_key(RDEPEND);
- match_key(SLOT);
- match_key(SRC_URI);
- match_key(RESTRICT);
- match_key(HOMEPAGE);
- match_key(LICENSE);
- match_key(DESCRIPTION);
- match_key(KEYWORDS);
- match_key(IUSE);
- match_key(CDEPEND);
- match_key(PDEPEND);
- match_key(EAPI);
- match_key(REQUIRED_USE);
- match_key(BDEPEND);
- match_key(IDEPEND);
-#undef match_key
+ switch (q[0])
+ {
+ case 'B':
+#define keycmp(P,K) \
+ if (strcmp(&P[1], &(#K)[1]) == 0) \
+ { \
+ key = &pkg->meta[Q_##K]; \
+ break; \
+ }
+ keycmp(q, BDEPEND);
+ break;
+ case 'C':
+ keycmp(q, CDEPEND);
+ break;
+ case 'D':
+ keycmp(q, DEPEND);
+ keycmp(q, DESCRIPTION);
+ break;
+ case 'E':
+ keycmp(q, EAPI);
+ break;
+ case 'H':
+ keycmp(q, HOMEPAGE);
+ break;
+ case 'I':
+ keycmp(q, IDEPEND);
+ keycmp(q, IUSE);
+ break;
+ case 'K':
+ keycmp(q, KEYWORDS);
+ break;
+ case 'L':
+ keycmp(q, LICENSE);
+ break;
+ case 'P':
+ keycmp(q, PDEPEND);
+ break;
+ case 'R':
+ keycmp(q, RDEPEND);
+ keycmp(q, REQUIRED_USE);
+ keycmp(q, RESTRICT);
+ break;
+ case 'S':
+ keycmp(q, SLOT);
+ keycmp(q, SRC_URI);
+ break;
+ default:
+ /* don't care/unknown */
+ break;
+#undef keycmp
+ }
}
findnl = true;
@@ -863,40 +946,67 @@ static void tree_pkg_xpak_read_cb
tree_pkg_ctx *pkg = ctx;
char **key;
-#define match_path(K) \
- else if (pathname_len == (sizeof(#K) - 1) && \
- strcmp(pathname, #K) == 0) \
- do { \
- key = &pkg->meta[Q_##K]; \
- } while (false)
-
- if (1 == 0); /* dummy for syntax */
- match_path(DEPEND);
- match_path(RDEPEND);
- match_path(SLOT);
- match_path(SRC_URI);
- match_path(RESTRICT);
- match_path(HOMEPAGE);
- match_path(DESCRIPTION);
- match_path(KEYWORDS);
- match_path(INHERITED);
- match_path(IUSE);
- match_path(CDEPEND);
- match_path(PDEPEND);
- match_path(PROVIDE);
- match_path(EAPI);
- match_path(PROPERTIES);
- match_path(DEFINED_PHASES);
- match_path(REQUIRED_USE);
- match_path(BDEPEND);
- match_path(IDEPEND);
- match_path(CONTENTS);
- match_path(USE);
- match_path(EPREFIX);
- match_path(repository);
- else
+ if (pathname_len < 3)
return;
-#undef match_path
+
+ switch (pathname[0])
+ {
+ case 'B':
+#define keycmp(P,K) \
+ if (pathname_len == sizeof(#K) - 1 && \
+ strcmp(&P[1], &(#K)[1]) == 0) \
+ { \
+ key = &pkg->meta[Q_##K]; \
+ break; \
+ }
+ keycmp(pathname, BDEPEND);
+ break;
+ case 'C':
+ keycmp(pathname, CDEPEND);
+ keycmp(pathname, CONTENTS);
+ break;
+ case 'D':
+ keycmp(pathname, DEFINED_PHASES);
+ keycmp(pathname, DEPEND);
+ keycmp(pathname, DESCRIPTION);
+ break;
+ case 'E':
+ keycmp(pathname, EAPI);
+ keycmp(pathname, EPREFIX);
+ break;
+ case 'H':
+ keycmp(pathname, HOMEPAGE);
+ break;
+ case 'I':
+ keycmp(pathname, IDEPEND);
+ keycmp(pathname, INHERITED);
+ keycmp(pathname, IUSE);
+ break;
+ case 'K':
+ keycmp(pathname, KEYWORDS);
+ break;
+ case 'P':
+ keycmp(pathname, PDEPEND);
+ keycmp(pathname, PROPERTIES);
+ keycmp(pathname, PROVIDE);
+ break;
+ case 'R':
+ keycmp(pathname, RDEPEND);
+ keycmp(pathname, REQUIRED_USE);
+ keycmp(pathname, RESTRICT);
+ break;
+ case 'r':
+ keycmp(pathname, repository);
+ break;
+ case 'S':
+ keycmp(pathname, SLOT);
+ keycmp(pathname, SRC_URI);
+ break;
+ case 'U':
+ keycmp(pathname, USE);
+ break;
+#undef keycmp
+ }
/* don't overwrite entries */
if (*key != NULL)