mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-23 10:42:11 +01:00
girepository: Make gi_repository_find_by_error_domain() deterministic
As with the previous commit, finding a `GIBaseInfo` matching the given error domain was non-deterministic because it iterated through a hash table of typelibs. Hash table iteration is non-deterministic. Change the method to instead use the `ordered_typelibs` and `ordered_lazy_typelibs` arrays to give deterministic iteration order. Add a unit test, although it can’t test the interesting case of an error domain which is present in both `GioUnix`/`GioWin32` and `Gio`, because no such error domain exists. Signed-off-by: Philip Withnall <pwithnall@gnome.org> Helps: #3303
This commit is contained in:
parent
48988a4098
commit
400fac7c4a
@ -1078,28 +1078,27 @@ gi_repository_find_by_name (GIRepository *repository,
|
||||
NULL, typelib, entry->offset);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
GIRepository *repository;
|
||||
GQuark domain;
|
||||
|
||||
GITypelib *result_typelib;
|
||||
DirEntry *result;
|
||||
} FindByErrorDomainData;
|
||||
|
||||
static void
|
||||
find_by_error_domain_foreach (gpointer key,
|
||||
gpointer value,
|
||||
gpointer datap)
|
||||
static DirEntry *
|
||||
find_by_error_domain (GPtrArray *ordered_typelibs,
|
||||
GQuark target_domain,
|
||||
GITypelib **out_typelib)
|
||||
{
|
||||
GITypelib *typelib = (GITypelib*)value;
|
||||
FindByErrorDomainData *data = datap;
|
||||
/* Search in reverse order as the longest namespaces will be listed last, and
|
||||
* those are the ones we want to search first. */
|
||||
for (guint i = ordered_typelibs->len; i > 0; i--)
|
||||
{
|
||||
GITypelib *typelib = g_ptr_array_index (ordered_typelibs, i - 1);
|
||||
DirEntry *entry;
|
||||
|
||||
if (data->result != NULL)
|
||||
return;
|
||||
entry = gi_typelib_get_dir_entry_by_error_domain (typelib, target_domain);
|
||||
if (entry != NULL)
|
||||
{
|
||||
*out_typelib = typelib;
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
data->result = gi_typelib_get_dir_entry_by_error_domain (typelib, data->domain);
|
||||
if (data->result)
|
||||
data->result_typelib = typelib;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1122,8 +1121,9 @@ GIEnumInfo *
|
||||
gi_repository_find_by_error_domain (GIRepository *repository,
|
||||
GQuark domain)
|
||||
{
|
||||
FindByErrorDomainData data;
|
||||
GIEnumInfo *cached;
|
||||
DirEntry *result = NULL;
|
||||
GITypelib *result_typelib = NULL;
|
||||
|
||||
g_return_val_if_fail (GI_IS_REPOSITORY (repository), NULL);
|
||||
|
||||
@ -1133,20 +1133,15 @@ gi_repository_find_by_error_domain (GIRepository *repository,
|
||||
if (cached != NULL)
|
||||
return (GIEnumInfo *) gi_base_info_ref ((GIBaseInfo *)cached);
|
||||
|
||||
data.repository = repository;
|
||||
data.domain = domain;
|
||||
data.result_typelib = NULL;
|
||||
data.result = NULL;
|
||||
result = find_by_error_domain (repository->ordered_typelibs, domain, &result_typelib);
|
||||
if (result == NULL)
|
||||
result = find_by_error_domain (repository->ordered_lazy_typelibs, domain, &result_typelib);
|
||||
|
||||
g_hash_table_foreach (repository->typelibs, find_by_error_domain_foreach, &data);
|
||||
if (data.result == NULL)
|
||||
g_hash_table_foreach (repository->lazy_typelibs, find_by_error_domain_foreach, &data);
|
||||
|
||||
if (data.result != NULL)
|
||||
if (result != NULL)
|
||||
{
|
||||
cached = (GIEnumInfo *) gi_info_new_full (gi_typelib_blob_type_to_info_type (data.result->blob_type),
|
||||
cached = (GIEnumInfo *) gi_info_new_full (gi_typelib_blob_type_to_info_type (result->blob_type),
|
||||
repository,
|
||||
NULL, data.result_typelib, data.result->offset);
|
||||
NULL, result_typelib, result->offset);
|
||||
|
||||
g_hash_table_insert (repository->info_by_error_domain,
|
||||
GUINT_TO_POINTER (domain),
|
||||
|
@ -513,12 +513,31 @@ test_repository_error_quark (RepositoryFixture *fx,
|
||||
|
||||
g_test_summary ("Test finding an error quark by error domain");
|
||||
|
||||
/* Find a simple error domain. */
|
||||
error_info = gi_repository_find_by_error_domain (fx->repository, G_RESOLVER_ERROR);
|
||||
g_assert_nonnull (error_info);
|
||||
g_assert_true (GI_IS_ENUM_INFO (error_info));
|
||||
g_assert_cmpstr (gi_base_info_get_name (GI_BASE_INFO (error_info)), ==, "ResolverError");
|
||||
|
||||
g_clear_pointer (&error_info, gi_base_info_unref);
|
||||
|
||||
/* Find again to check the caching. */
|
||||
error_info = gi_repository_find_by_error_domain (fx->repository, G_RESOLVER_ERROR);
|
||||
g_assert_nonnull (error_info);
|
||||
g_assert_true (GI_IS_ENUM_INFO (error_info));
|
||||
g_assert_cmpstr (gi_base_info_get_name (GI_BASE_INFO (error_info)), ==, "ResolverError");
|
||||
|
||||
g_clear_pointer (&error_info, gi_base_info_unref);
|
||||
|
||||
/* Try and find an unknown error domain. */
|
||||
g_assert_null (gi_repository_find_by_error_domain (fx->repository, GI_REPOSITORY_ERROR));
|
||||
|
||||
/* And check caching for unknown error domains. */
|
||||
g_assert_null (gi_repository_find_by_error_domain (fx->repository, GI_REPOSITORY_ERROR));
|
||||
|
||||
/* It would be good to try and find one which will resolve in both Gio and
|
||||
* GioUnix/GioWin32, but neither of the platform-specific GIRs actually define
|
||||
* any error domains at the moment. */
|
||||
}
|
||||
|
||||
static void
|
||||
@ -861,7 +880,7 @@ main (int argc,
|
||||
ADD_REPOSITORY_TEST ("/repository/constructor-return-type", test_repository_constructor_return_type, &typelib_load_spec_gobject);
|
||||
ADD_REPOSITORY_TEST ("/repository/enum-info-c-identifier", test_repository_enum_info_c_identifier, &typelib_load_spec_glib);
|
||||
ADD_REPOSITORY_TEST ("/repository/enum-info-static-methods", test_repository_enum_info_static_methods, &typelib_load_spec_glib);
|
||||
ADD_REPOSITORY_TEST ("/repository/error-quark", test_repository_error_quark, &typelib_load_spec_gio);
|
||||
ADD_REPOSITORY_TEST ("/repository/error-quark", test_repository_error_quark, &typelib_load_spec_gio_platform);
|
||||
ADD_REPOSITORY_TEST ("/repository/flags-info-c-identifier", test_repository_flags_info_c_identifier, &typelib_load_spec_gobject);
|
||||
ADD_REPOSITORY_TEST ("/repository/fundamental-ref-func", test_repository_fundamental_ref_func, &typelib_load_spec_gobject);
|
||||
ADD_REPOSITORY_TEST ("/repository/instance-method-ownership-transfer", test_repository_instance_method_ownership_transfer, &typelib_load_spec_gio);
|
||||
|
Loading…
x
Reference in New Issue
Block a user