/
githubmirror
/
pkgconf
Обзор
Документация
Войти
/
githubmirror
/
pkgconf
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
pkgconf-3.0.5
libpkgconf/cache.c
228 строк
6 KB
Ariadne Conill
libpkgconf: cache: use binary insertion instead of tail-append + qsort
22 июл 2026, 09:14
22 июл 2026, 09:14
502d531
Код
Авторство
О чём код?
/* * cache.c * package object cache * * SPDX-License-Identifier: pkgconf * * Copyright (c) 2013 pkgconf authors (see AUTHORS). * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #include <libpkgconf/stdinc.h> #include <libpkgconf/libpkgconf.h> #include <assert.h> /* * !doc * * libpkgconf `cache` module * ========================= * * The libpkgconf `cache` module manages a package/module object cache, allowing it to * avoid loading duplicate copies of a package/module. * * A cache is tied to a specific pkgconf client object, so package objects should not * be shared across threads. */ static int cache_member_cmp(const void *a, const void *b) { const char *key = a; const pkgconf_pkg_t *pkg = *(void **) b; return strcmp(key, pkg->id); } /* * !doc * * .. c:function:: pkgconf_pkg_t *pkgconf_cache_lookup(const pkgconf_client_t *client, const char *id) * * Looks up a package in the cache given an `id` atom, * such as ``gtk+-3.0`` and returns the already loaded version * if present. * * :param pkgconf_client_t* client: The client object to access. * :param char* id: The package atom to look up in the client object's cache. * :return: A package object if present, else ``NULL``. * :rtype: pkgconf_pkg_t * */ pkgconf_pkg_t * pkgconf_cache_lookup(pkgconf_client_t *client, const char *id) { if (client->cache_table == NULL) return NULL; pkgconf_pkg_t **pkg; pkg = bsearch(id, client->cache_table, client->cache_count, sizeof (void *), cache_member_cmp); if (pkg != NULL) { PKGCONF_TRACE(client, "found: %s @%p", id, *pkg); return pkgconf_pkg_ref(client, *pkg); } PKGCONF_TRACE(client, "miss: %s", id); return NULL; } /* * !doc * * .. c:function:: void pkgconf_cache_add(pkgconf_client_t *client, pkgconf_pkg_t *pkg) * * Adds an entry for the package to the package cache. * The cache entry must be removed if the package is freed. * * :param pkgconf_client_t* client: The client object to modify. * :param pkgconf_pkg_t* pkg: The package object to add to the client object's cache. * :return: nothing */ void pkgconf_cache_add(pkgconf_client_t *client, pkgconf_pkg_t *pkg) { if (pkg == NULL) return; pkgconf_pkg_t *cached_pkg = pkgconf_cache_lookup(client, pkg->id); if (cached_pkg != NULL) { pkgconf_pkg_unref(client, cached_pkg); return; } pkgconf_pkg_ref(client, pkg); pkgconf_pkg_t **new_table; /* mark package as cached */ pkg->flags |= PKGCONF_PKG_PROPF_CACHED; ++client->cache_count; new_table = pkgconf_reallocarray(client->cache_table, client->cache_count, sizeof (void *)); /* if we are out of memory, roll back adding to cache and bail */ if (new_table == NULL) { --client->cache_count; pkg->flags &= ~PKGCONF_PKG_PROPF_CACHED; pkgconf_pkg_unref(client, pkg); return; } client->cache_table = new_table; size_t lo = 0, hi = client->cache_count - 1; while (lo < hi) { size_t mid = lo + (hi - lo) / 2; if (strcmp(client->cache_table[mid]->id, pkg->id) < 0) lo = mid + 1; else hi = mid; } memmove(&client->cache_table[lo + 1], &client->cache_table[lo], (client->cache_count - 1 - lo) * sizeof(void *)); client->cache_table[lo] = pkg; PKGCONF_TRACE(client, "added @%p to cache", pkg); } /* * !doc * * .. c:function:: void pkgconf_cache_remove(pkgconf_client_t *client, pkgconf_pkg_t *pkg) * * Deletes a package from the client object's package cache. * * :param pkgconf_client_t* client: The client object to modify. * :param pkgconf_pkg_t* pkg: The package object to remove from the client object's cache. * :return: nothing */ void pkgconf_cache_remove(pkgconf_client_t *client, pkgconf_pkg_t *pkg) { if (client->cache_table == NULL) return; if (pkg == NULL) return; if (!(pkg->flags & PKGCONF_PKG_PROPF_CACHED)) return; PKGCONF_TRACE(client, "removed @%p from cache", pkg); pkgconf_pkg_t **slot; slot = bsearch(pkg->id, client->cache_table, client->cache_count, sizeof (void *), cache_member_cmp); if (slot == NULL) return; (*slot)->flags &= ~PKGCONF_PKG_PROPF_CACHED; pkgconf_pkg_unref(client, *slot); size_t idx = (size_t)(slot - client->cache_table); memmove(&client->cache_table[idx], &client->cache_table[idx + 1], (client->cache_count - idx - 1) * sizeof(void *)); client->cache_count--; if (client->cache_count > 0) { pkgconf_pkg_t **new_table = pkgconf_reallocarray(client->cache_table, client->cache_count, sizeof(void *)); if (new_table != NULL) client->cache_table = new_table; } else { free(client->cache_table); client->cache_table = NULL; } } /* * !doc * * .. c:function:: void pkgconf_cache_free(pkgconf_client_t *client) * * Releases all resources related to a client object's package cache. * This function should only be called to clear a client object's package cache, * as it may release any package in the cache. * * :param pkgconf_client_t* client: The client object to modify. */ void pkgconf_cache_free(pkgconf_client_t *client) { if (client->cache_table == NULL) return; while (client->cache_count > 0) pkgconf_cache_remove(client, client->cache_table[0]); free(client->cache_table); client->cache_table = NULL; client->cache_count = 0; PKGCONF_TRACE(client, "cleared package cache"); }