From 2c00c7c9240fc65fb5893c1d66ee157712dd6d9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Wed, 20 Dec 2023 06:29:40 +0100 Subject: [PATCH] girepository: Use an array to iterate over and return the search paths We used to store the search paths into a GSList but this is not efficient for various reasons, so replace this with an array so that we can replace return just a GStrv in the public API. --- girepository/girepository.c | 115 ++++++++++--------- girepository/girepository.h | 2 +- girepository/tests/repository-search-paths.c | 52 +++++---- girepository/tests/repository.c | 9 +- 4 files changed, 99 insertions(+), 79 deletions(-) diff --git a/girepository/girepository.c b/girepository/girepository.c index 51ecaac9b..33758f3e7 100644 --- a/girepository/girepository.c +++ b/girepository/girepository.c @@ -58,7 +58,7 @@ */ static GIRepository *default_repository = NULL; -static GSList *typelib_search_path = NULL; +static GPtrArray *typelib_search_path = NULL; typedef struct { guint n_interfaces; @@ -198,32 +198,24 @@ init_globals (void) */ type_lib_path_env = g_getenv ("GI_TYPELIB_PATH"); - typelib_search_path = NULL; if (type_lib_path_env) { gchar **custom_dirs; - gchar **d; custom_dirs = g_strsplit (type_lib_path_env, G_SEARCHPATH_SEPARATOR_S, 0); - - d = custom_dirs; - while (*d) - { - typelib_search_path = g_slist_prepend (typelib_search_path, *d); - d++; - } - - /* ownership of the array content was passed to the list */ - g_free (custom_dirs); + typelib_search_path = + g_ptr_array_new_take_null_terminated ((gpointer) g_steal_pointer (&custom_dirs), g_free); + } + else + { + typelib_search_path = g_ptr_array_new_null_terminated (1, g_free, TRUE); } libdir = GOBJECT_INTROSPECTION_LIBDIR; typelib_dir = g_build_filename (libdir, "girepository-1.0", NULL); - typelib_search_path = g_slist_prepend (typelib_search_path, typelib_dir); - - typelib_search_path = g_slist_reverse (typelib_search_path); + g_ptr_array_add (typelib_search_path, g_steal_pointer (&typelib_dir)); } g_once_init_leave (&initialized, 1); @@ -244,11 +236,12 @@ void gi_repository_prepend_search_path (const char *directory) { init_globals (); - typelib_search_path = g_slist_prepend (typelib_search_path, g_strdup (directory)); + g_ptr_array_insert (typelib_search_path, 0, g_strdup (directory)); } /** * gi_repository_get_search_path: + * @n_paths_out: (optional) (out): The number of search paths returned. * * Returns the current search path [class@GIRepository.Repository] will use when * loading typelib files. @@ -256,14 +249,27 @@ gi_repository_prepend_search_path (const char *directory) * The list is internal to [class@GIRepository.Repository] and should not be * freed, nor should its string elements. * - * Returns: (element-type filename) (transfer none): list of search paths, most + * Returns: (element-type filename) (transfer none) (array length=n_paths_out): list of search paths, most * important first * Since: 2.80 */ -GSList * -gi_repository_get_search_path (void) +const char * const * +gi_repository_get_search_path (size_t *n_paths_out) { - return typelib_search_path; + if G_UNLIKELY (!typelib_search_path || !typelib_search_path->pdata) + { + static const char * const empty_search_path[] = {NULL}; + + if (n_paths_out) + *n_paths_out = 0; + + return empty_search_path; + } + + if (n_paths_out) + *n_paths_out = typelib_search_path->len; + + return (const char * const *) typelib_search_path->pdata; } static char * @@ -1310,21 +1316,21 @@ gi_repository_get_typelib_path (GIRepository *repository, /* This simple search function looks for a specified namespace-version; it's faster than the full directory listing required for latest version. */ static GMappedFile * -find_namespace_version (const gchar *namespace, - const gchar *version, - GSList *search_path, - gchar **path_ret) +find_namespace_version (const char *namespace, + const char *version, + const char * const *search_paths, + size_t n_search_paths, + char **path_ret) { - GSList *ldir; GError *error = NULL; GMappedFile *mfile = NULL; char *fname; fname = g_strdup_printf ("%s-%s.typelib", namespace, version); - for (ldir = search_path; ldir; ldir = ldir->next) + for (size_t i = 0; i < n_search_paths; ++i) { - char *path = g_build_filename (ldir->data, fname, NULL); + char *path = g_build_filename (search_paths[i], fname, NULL); mfile = g_mapped_file_new (path, FALSE, &error); if (error) @@ -1434,14 +1440,14 @@ free_candidate (struct NamespaceVersionCandidadate *candidate) } static GSList * -enumerate_namespace_versions (const gchar *namespace, - GSList *search_path) +enumerate_namespace_versions (const char *namespace, + const char * const *search_paths, + size_t n_search_paths) { GSList *candidates = NULL; GHashTable *found_versions = g_hash_table_new (g_str_hash, g_str_equal); char *namespace_dash; char *namespace_typelib; - GSList *ldir; GError *error = NULL; int index; @@ -1449,13 +1455,13 @@ enumerate_namespace_versions (const gchar *namespace, namespace_typelib = g_strdup_printf ("%s.typelib", namespace); index = 0; - for (ldir = search_path; ldir; ldir = ldir->next) + for (size_t i = 0; i < n_search_paths; ++i) { GDir *dir; const char *dirname; const char *entry; - dirname = (const char*)ldir->data; + dirname = search_paths[i]; dir = g_dir_open (dirname, 0, NULL); if (dir == NULL) continue; @@ -1521,10 +1527,11 @@ enumerate_namespace_versions (const gchar *namespace, } static GMappedFile * -find_namespace_latest (const gchar *namespace, - GSList *search_path, - gchar **version_ret, - gchar **path_ret) +find_namespace_latest (const char *namespace, + const char * const *search_paths, + size_t n_search_paths, + char **version_ret, + char **path_ret) { GSList *candidates; GMappedFile *result = NULL; @@ -1532,7 +1539,7 @@ find_namespace_latest (const gchar *namespace, *version_ret = NULL; *path_ret = NULL; - candidates = enumerate_namespace_versions (namespace, search_path); + candidates = enumerate_namespace_versions (namespace, search_paths, n_search_paths); if (candidates != NULL) { @@ -1577,7 +1584,9 @@ gi_repository_enumerate_versions (GIRepository *repository, char **ret; init_globals (); - candidates = enumerate_namespace_versions (namespace_, typelib_search_path); + candidates = enumerate_namespace_versions (namespace_, + (const char * const *) typelib_search_path->pdata, + typelib_search_path->len); if (!candidates) { @@ -1614,12 +1623,13 @@ gi_repository_enumerate_versions (GIRepository *repository, } static GITypelib * -require_internal (GIRepository *repository, - const gchar *namespace, - const gchar *version, - GIRepositoryLoadFlags flags, - GSList *search_path, - GError **error) +require_internal (GIRepository *repository, + const char *namespace, + const char *version, + GIRepositoryLoadFlags flags, + const char * const *search_paths, + size_t n_search_paths, + GError **error) { GMappedFile *mfile; GITypelib *ret = NULL; @@ -1652,14 +1662,14 @@ require_internal (GIRepository *repository, if (version != NULL) { - mfile = find_namespace_version (namespace, version, - search_path, &path); + mfile = find_namespace_version (namespace, version, search_paths, + n_search_paths, &path); tmp_version = g_strdup (version); } else { - mfile = find_namespace_latest (namespace, search_path, - &tmp_version, &path); + mfile = find_namespace_latest (namespace, search_paths, n_search_paths, + &tmp_version, &path); } if (mfile == NULL) @@ -1759,7 +1769,8 @@ gi_repository_require (GIRepository *repository, init_globals (); typelib = require_internal (repository, namespace, version, flags, - typelib_search_path, error); + (const char * const *) typelib_search_path->pdata, + typelib_search_path->len, error); return typelib; } @@ -1794,10 +1805,10 @@ gi_repository_require_private (GIRepository *repository, GIRepositoryLoadFlags flags, GError **error) { - GSList search_path = { (gpointer) typelib_dir, NULL }; + const char * const search_path[] = { typelib_dir, NULL }; return require_internal (repository, namespace, version, flags, - &search_path, error); + search_path, 1, error); } static gboolean diff --git a/girepository/girepository.h b/girepository/girepository.h index 80474ebf2..05d7cf8c6 100644 --- a/girepository/girepository.h +++ b/girepository/girepository.h @@ -109,7 +109,7 @@ GI_AVAILABLE_IN_ALL void gi_repository_prepend_library_path (const char *directory); GI_AVAILABLE_IN_ALL -GSList * gi_repository_get_search_path (void); +const char * const * gi_repository_get_search_path (size_t *n_paths_out); GI_AVAILABLE_IN_ALL const char * gi_repository_load_typelib (GIRepository *repository, diff --git a/girepository/tests/repository-search-paths.c b/girepository/tests/repository-search-paths.c index d2051e172..55eebeff8 100644 --- a/girepository/tests/repository-search-paths.c +++ b/girepository/tests/repository-search-paths.c @@ -26,32 +26,39 @@ static void test_repository_search_paths_unset (void) { - GSList *search_paths; + const char * const *search_paths; + size_t n_search_paths; - search_paths = gi_repository_get_search_path (); - g_assert_null (search_paths); + search_paths = gi_repository_get_search_path (&n_search_paths); + g_assert_nonnull (search_paths); + g_assert_cmpstrv (search_paths, ((char *[]){NULL})); + g_assert_cmpuint (n_search_paths, ==, 0); + + search_paths = gi_repository_get_search_path (NULL); + g_assert_cmpuint (g_strv_length ((char **) search_paths), ==, 0); } static void test_repository_search_paths_default (void) { - GSList *search_paths; + const char * const *search_paths; + size_t n_search_paths; - search_paths = gi_repository_get_search_path (); - g_assert_null (search_paths); + search_paths = gi_repository_get_search_path (&n_search_paths); + g_assert_nonnull (search_paths); /* Init default paths */ g_assert_nonnull (gi_repository_get_default ()); - search_paths = gi_repository_get_search_path (); + search_paths = gi_repository_get_search_path (&n_search_paths); g_assert_nonnull (search_paths); - g_assert_cmpuint (g_slist_length (search_paths), ==, 2); + g_assert_cmpuint (g_strv_length ((char **) search_paths), ==, 2); - g_assert_cmpstr (g_slist_nth_data (search_paths, 0), ==, g_get_tmp_dir ()); + g_assert_cmpstr (search_paths[0], ==, g_get_tmp_dir ()); #ifndef G_PLATFORM_WIN32 char *expected_path = g_build_filename (GOBJECT_INTROSPECTION_LIBDIR, "girepository-1.0", NULL); - g_assert_cmpstr (g_slist_nth_data (search_paths, 1), ==, expected_path); + g_assert_cmpstr (search_paths[1], ==, expected_path); g_clear_pointer (&expected_path, g_free); #endif } @@ -59,34 +66,35 @@ test_repository_search_paths_default (void) static void test_repository_search_paths_prepend (void) { - GSList *search_paths; + const char * const *search_paths; + size_t n_search_paths; gi_repository_prepend_search_path (g_test_get_dir (G_TEST_BUILT)); - search_paths = gi_repository_get_search_path (); + search_paths = gi_repository_get_search_path (&n_search_paths); g_assert_nonnull (search_paths); - g_assert_cmpuint (g_slist_length (search_paths), ==, 3); + g_assert_cmpuint (g_strv_length ((char **) search_paths), ==, 3); - g_assert_cmpstr (g_slist_nth_data (search_paths, 0), ==, g_test_get_dir (G_TEST_BUILT)); - g_assert_cmpstr (g_slist_nth_data (search_paths, 1), ==, g_get_tmp_dir ()); + g_assert_cmpstr (search_paths[0], ==, g_test_get_dir (G_TEST_BUILT)); + g_assert_cmpstr (search_paths[1], ==, g_get_tmp_dir ()); #ifndef G_PLATFORM_WIN32 char *expected_path = g_build_filename (GOBJECT_INTROSPECTION_LIBDIR, "girepository-1.0", NULL); - g_assert_cmpstr (g_slist_nth_data (search_paths, 2), ==, expected_path); + g_assert_cmpstr (search_paths[2], ==, expected_path); g_clear_pointer (&expected_path, g_free); #endif gi_repository_prepend_search_path (g_test_get_dir (G_TEST_DIST)); - search_paths = gi_repository_get_search_path (); + search_paths = gi_repository_get_search_path (&n_search_paths); g_assert_nonnull (search_paths); - g_assert_cmpuint (g_slist_length (search_paths), ==, 4); + g_assert_cmpuint (g_strv_length ((char **) search_paths), ==, 4); - g_assert_cmpstr (g_slist_nth_data (search_paths, 0), ==, g_test_get_dir (G_TEST_DIST)); - g_assert_cmpstr (g_slist_nth_data (search_paths, 1), ==, g_test_get_dir (G_TEST_BUILT)); - g_assert_cmpstr (g_slist_nth_data (search_paths, 2), ==, g_get_tmp_dir ()); + g_assert_cmpstr (search_paths[0], ==, g_test_get_dir (G_TEST_DIST)); + g_assert_cmpstr (search_paths[1], ==, g_test_get_dir (G_TEST_BUILT)); + g_assert_cmpstr (search_paths[2], ==, g_get_tmp_dir ()); #ifndef G_PLATFORM_WIN32 expected_path = g_build_filename (GOBJECT_INTROSPECTION_LIBDIR, "girepository-1.0", NULL); - g_assert_cmpstr (g_slist_nth_data (search_paths, 3), ==, expected_path); + g_assert_cmpstr (search_paths[3], ==, expected_path); g_clear_pointer (&expected_path, g_free); #endif } diff --git a/girepository/tests/repository.c b/girepository/tests/repository.c index 6d85e5f3d..329cddb3f 100644 --- a/girepository/tests/repository.c +++ b/girepository/tests/repository.c @@ -27,7 +27,7 @@ test_repository_basic (void) { GIRepository *repository; char *gobject_typelib_dir = NULL; - GSList *search_path; + const char * const * search_paths; GITypelib *typelib = NULL; char **namespaces = NULL; const char *expected_namespaces[] = { "GLib", NULL }; @@ -55,9 +55,10 @@ test_repository_basic (void) g_assert_cmpstrv (versions, ((char *[]){"2.0", NULL})); g_clear_pointer (&versions, g_strfreev); - search_path = gi_repository_get_search_path (); - g_assert_nonnull (search_path); - g_assert_cmpstr (search_path->data, ==, gobject_typelib_dir); + search_paths = gi_repository_get_search_path (NULL); + g_assert_nonnull (search_paths); + g_assert_cmpuint (g_strv_length ((char **) search_paths), >, 0); + g_assert_cmpstr (search_paths[0], ==, gobject_typelib_dir); typelib = gi_repository_require (repository, "GLib", "2.0", 0, &local_error); g_assert_no_error (local_error);