libnm: support lookup of property-info by param-spec

We also need to find efficiently the property-info for a given
GParamSpec. Add a lookup index for that.
This commit is contained in:
Thomas Haller 2021-06-28 23:00:21 +02:00
parent 102a1f5c31
commit f1cb07e438
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
4 changed files with 146 additions and 4 deletions

View file

@ -332,6 +332,10 @@ gboolean _nm_setting_property_is_regular_secret_flags(NMSetting * setting,
/*****************************************************************************/
const NMSettInfoProperty *
_nm_sett_info_property_lookup_by_param_spec(const NMSettInfoSetting *sett_info,
const GParamSpec * param_spec);
static inline GArray *
_nm_sett_info_property_override_create_array_sized(guint reserved_size)
{

View file

@ -263,6 +263,16 @@ _property_infos_sort(const NMSettInfoProperty *property_infos,
return arr;
}
static int
_property_lookup_by_param_spec_sort(gconstpointer p_a, gconstpointer p_b, gpointer user_data)
{
const NMSettInfoPropertLookupByParamSpec *a = p_a;
const NMSettInfoPropertLookupByParamSpec *b = p_b;
NM_CMP_DIRECT(a->param_spec_as_uint, b->param_spec_as_uint);
return 0;
}
void
_nm_setting_class_commit(NMSettingClass * setting_class,
NMMetaSettingType meta_type,
@ -271,10 +281,11 @@ _nm_setting_class_commit(NMSettingClass * setting_class,
gint16 private_offset)
{
NMSettInfoSetting *sett_info;
gs_free GParamSpec **property_specs = NULL;
guint n_property_specs;
guint override_len;
guint i;
gs_free GParamSpec ** property_specs = NULL;
guint n_property_specs;
NMSettInfoPropertLookupByParamSpec *lookup_by_iter;
guint override_len;
guint i;
nm_assert(NM_IS_SETTING_CLASS(setting_class));
nm_assert(!setting_class->setting_info);
@ -424,6 +435,33 @@ has_property_type:
sett_info->property_infos_len,
setting_class);
nm_assert(sett_info->property_infos_len < G_MAXUINT16);
sett_info->property_lookup_by_param_spec_len = 0;
for (i = 0; i < sett_info->property_infos_len; i++) {
if (sett_info->property_infos[i].param_spec) {
sett_info->property_lookup_by_param_spec_len++;
}
}
sett_info->property_lookup_by_param_spec =
g_new(NMSettInfoPropertLookupByParamSpec, sett_info->property_lookup_by_param_spec_len);
lookup_by_iter =
(NMSettInfoPropertLookupByParamSpec *) sett_info->property_lookup_by_param_spec;
for (i = 0; i < sett_info->property_infos_len; i++) {
const NMSettInfoProperty *property_info = &sett_info->property_infos[i];
if (property_info->param_spec) {
*(lookup_by_iter++) = (NMSettInfoPropertLookupByParamSpec){
.param_spec_as_uint = (uintptr_t) ((gpointer) property_info->param_spec),
.property_info = property_info,
};
}
}
g_qsort_with_data(sett_info->property_lookup_by_param_spec,
sett_info->property_lookup_by_param_spec_len,
sizeof(NMSettInfoPropertLookupByParamSpec),
_property_lookup_by_param_spec_sort,
NULL);
g_array_free(properties_override, TRUE);
}
@ -473,6 +511,47 @@ _nm_setting_class_get_sett_info(NMSettingClass *setting_class)
return sett_info;
}
const NMSettInfoProperty *
_nm_sett_info_property_lookup_by_param_spec(const NMSettInfoSetting *sett_info,
const GParamSpec * param_spec)
{
NMSettInfoPropertLookupByParamSpec needle;
int imin;
int imax;
int imid;
int cmp;
nm_assert(sett_info);
nm_assert(param_spec);
/* ensure that "int" is large enough to contain the index variables. */
G_STATIC_ASSERT_EXPR(sizeof(int) > sizeof(sett_info->property_lookup_by_param_spec_len));
if (sett_info->property_lookup_by_param_spec_len == 0)
return NULL;
needle.param_spec_as_uint = (uintptr_t) ((gpointer) param_spec);
imin = 0;
imax = sett_info->property_lookup_by_param_spec_len - 1;
while (imin <= imax) {
imid = imin + (imax - imin) / 2;
cmp = _property_lookup_by_param_spec_sort(&sett_info->property_lookup_by_param_spec[imid],
&needle,
NULL);
if (cmp == 0)
return sett_info->property_lookup_by_param_spec[imid].property_info;
if (cmp < 0)
imin = imid + 1;
else
imax = imid - 1;
}
return NULL;
}
/*****************************************************************************/
void

View file

@ -4388,6 +4388,9 @@ test_setting_metadata(void)
guint prop_idx;
gs_free GParamSpec **property_specs = NULL;
guint n_property_specs;
guint n_param_spec;
guint i;
guint j;
g_assert(sis);
@ -4418,6 +4421,8 @@ test_setting_metadata(void)
h_properties = g_hash_table_new(nm_str_hash, g_str_equal);
n_param_spec = 0;
for (prop_idx = 0; prop_idx < sis->property_infos_len; prop_idx++) {
const NMSettInfoProperty *sip = &sis->property_infos[prop_idx];
GArray * property_types_data;
@ -4426,6 +4431,9 @@ test_setting_metadata(void)
g_assert(sip->name);
if (sip->param_spec)
n_param_spec++;
if (prop_idx > 0)
g_assert_cmpint(strcmp(sis->property_infos[prop_idx - 1].name, sip->name), <, 0);
@ -4587,6 +4595,44 @@ check_done:;
g_assert_cmpstr(sis->property_infos[0].name, ==, NM_SETTING_NAME);
} else
g_assert_cmpint(meta_type, !=, NM_META_SETTING_TYPE_ETHTOOL);
g_assert_cmpint(n_param_spec, >, 0);
g_assert_cmpint(n_param_spec, ==, sis->property_lookup_by_param_spec_len);
g_assert(sis->property_lookup_by_param_spec);
for (i = 0; i < sis->property_lookup_by_param_spec_len; i++) {
const NMSettInfoPropertLookupByParamSpec *p = &sis->property_lookup_by_param_spec[i];
guint n_found;
if (i > 0) {
g_assert_cmpint(sis->property_lookup_by_param_spec[i - 1].param_spec_as_uint,
<,
p->param_spec_as_uint);
}
g_assert(p->property_info);
g_assert(p->property_info >= sis->property_infos);
g_assert(p->property_info < &sis->property_infos[sis->property_infos_len]);
g_assert(p->property_info
== &sis->property_infos[p->property_info - sis->property_infos]);
g_assert(p->property_info->param_spec);
g_assert(p->param_spec_as_uint
== ((uintptr_t) ((gpointer) p->property_info->param_spec)));
g_assert(_nm_sett_info_property_lookup_by_param_spec(sis, p->property_info->param_spec)
== p->property_info);
n_found = 0;
for (j = 0; j < sis->property_infos_len; j++) {
const NMSettInfoProperty *pip2 = &sis->property_infos[j];
if (pip2->param_spec
&& p->param_spec_as_uint == ((uintptr_t) ((gpointer) pip2->param_spec))) {
g_assert(pip2 == p->property_info);
n_found++;
}
}
g_assert(n_found == 1);
}
}
{

View file

@ -745,6 +745,15 @@ struct _NMSettInfoProperty {
} to_dbus_data;
};
typedef struct {
/* we want to do binary search by "GParamSpec *", but unrelated pointers
* are not directly comparable in C. No problem, we convert them to
* uintptr_t for the search, that is guaranteed to work. */
uintptr_t param_spec_as_uint;
const NMSettInfoProperty *property_info;
} NMSettInfoPropertLookupByParamSpec;
typedef struct {
const GVariantType *(*get_variant_type)(const struct _NMSettInfoSetting *sett_info,
const char * name,
@ -784,8 +793,12 @@ struct _NMSettInfoSetting {
*/
const NMSettInfoProperty *const *property_infos_sorted;
const NMSettInfoPropertLookupByParamSpec *property_lookup_by_param_spec;
guint property_infos_len;
guint16 property_lookup_by_param_spec_len;
/* the offset in bytes to get the private data from the @self pointer. */
gint16 private_offset;