Merge branch 'wip/chergert/reduce-copies-for-gvarianttype-cache' into 'main'

gvarianttypeinfo: reduce caching overhead

See merge request GNOME/glib!4293
This commit is contained in:
Philip Withnall 2024-09-26 11:11:52 +00:00
commit 80e8bc7c0b
4 changed files with 131 additions and 41 deletions

View File

@ -0,0 +1,99 @@
/* gvarianttype-private.h
*
* Copyright © 2007, 2008 Ryan Lortie
* Copyright © 2009, 2010 Codethink Limited
* Copyright © 2024 Christian Hergert
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#pragma once
#include "gvarianttype.h"
G_BEGIN_DECLS
static inline gboolean
_g_variant_type_equal (const GVariantType *type1,
const GVariantType *type2)
{
const char *str1 = (const char *)type1;
const char *str2 = (const char *)type2;
gsize index = 0;
int brackets = 0;
if (str1 == str2)
return TRUE;
do
{
if (str1[index] != str2[index])
return FALSE;
while (str1[index] == 'a' || str1[index] == 'm')
{
index++;
if (str1[index] != str2[index])
return FALSE;
}
if (str1[index] == '(' || str1[index] == '{')
brackets++;
else if (str1[index] == ')' || str1[index] == '}')
brackets--;
index++;
}
while (brackets);
return TRUE;
}
static inline guint
_g_variant_type_hash (gconstpointer type)
{
const gchar *type_string = type;
guint value = 0;
gsize index = 0;
int brackets = 0;
do
{
value = (value << 5) - value + type_string[index];
while (type_string[index] == 'a' || type_string[index] == 'm')
{
index++;
value = (value << 5) - value + type_string[index];
}
if (type_string[index] == '(' || type_string[index] == '{')
brackets++;
else if (type_string[index] == ')' || type_string[index] == '}')
brackets--;
index++;
}
while (brackets);
return value;
}
G_END_DECLS

View File

@ -22,7 +22,7 @@
#include "config.h"
#include "gvarianttype.h"
#include "gvarianttype-private.h"
#include <glib/gtestutils.h>
#include <glib/gstrfuncs.h>
@ -777,20 +777,9 @@ g_variant_type_is_variant (const GVariantType *type)
guint
g_variant_type_hash (gconstpointer type)
{
const gchar *type_string;
guint value = 0;
gsize length;
gsize i;
g_return_val_if_fail (g_variant_type_check (type), 0);
type_string = g_variant_type_peek_string (type);
length = g_variant_type_get_string_length (type);
for (i = 0; i < length; i++)
value = (value << 5) - value + type_string[i];
return value;
return _g_variant_type_hash (type);
}
/**
@ -817,25 +806,10 @@ gboolean
g_variant_type_equal (gconstpointer type1,
gconstpointer type2)
{
const gchar *string1, *string2;
gsize size1, size2;
g_return_val_if_fail (g_variant_type_check (type1), FALSE);
g_return_val_if_fail (g_variant_type_check (type2), FALSE);
if (type1 == type2)
return TRUE;
size1 = g_variant_type_get_string_length (type1);
size2 = g_variant_type_get_string_length (type2);
if (size1 != size2)
return FALSE;
string1 = g_variant_type_peek_string (type1);
string2 = g_variant_type_peek_string (type2);
return memcmp (string1, string2, size1) == 0;
return _g_variant_type_equal (type1, type2);
}
/**

View File

@ -22,6 +22,7 @@
#include "config.h"
#include "gvarianttype-private.h"
#include "gvarianttypeinfo.h"
#include <glib/gtestutils.h>
@ -756,9 +757,8 @@ static GHashTable *g_variant_type_info_table;
GVariantTypeInfo *
g_variant_type_info_get (const GVariantType *type)
{
char type_char;
type_char = g_variant_type_peek_string (type)[0];
const gchar *type_string = g_variant_type_peek_string (type);
const char type_char = type_string[0];
if (type_char == G_VARIANT_TYPE_INFO_CHAR_MAYBE ||
type_char == G_VARIANT_TYPE_INFO_CHAR_ARRAY ||
@ -766,15 +766,12 @@ g_variant_type_info_get (const GVariantType *type)
type_char == G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY)
{
GVariantTypeInfo *info;
gchar *type_string;
type_string = g_variant_type_dup_string (type);
g_rec_mutex_lock (&g_variant_type_info_lock);
if (g_variant_type_info_table == NULL)
g_variant_type_info_table = g_hash_table_new (g_str_hash,
g_str_equal);
g_variant_type_info_table = g_hash_table_new ((GHashFunc)_g_variant_type_hash,
(GEqualFunc)_g_variant_type_equal);
info = g_hash_table_lookup (g_variant_type_info_table, type_string);
if (info == NULL)
@ -792,20 +789,19 @@ g_variant_type_info_get (const GVariantType *type)
}
info = (GVariantTypeInfo *) container;
container->type_string = type_string;
container->type_string = g_variant_type_dup_string (type);
g_atomic_ref_count_init (&container->ref_count);
TRACE(GLIB_VARIANT_TYPE_INFO_NEW(info, container->type_string));
g_hash_table_insert (g_variant_type_info_table, type_string, info);
type_string = NULL;
g_hash_table_replace (g_variant_type_info_table,
container->type_string, info);
}
else
g_variant_type_info_ref (info);
g_rec_mutex_unlock (&g_variant_type_info_lock);
g_variant_type_info_check (info, 0);
g_free (type_string);
return info;
}

View File

@ -5859,6 +5859,24 @@ test_unaligned_construction (void)
}
}
static void
test_g_variant_type_hash (void)
{
char mas[4] = {'m', 'a', 's', 0};
g_assert_cmpint (g_variant_type_hash (G_VARIANT_TYPE ("a(ay)")),
!=,
g_variant_type_hash (G_VARIANT_TYPE ("aay")));
g_assert_cmpint (g_variant_type_hash (G_VARIANT_TYPE ("a{sv}")),
!=,
g_variant_type_hash (G_VARIANT_TYPE ("a(sv)")));
g_assert_cmpint (g_variant_type_hash (G_VARIANT_TYPE ("mas")),
==,
g_variant_type_hash ((const GVariantType *)mas));
}
int
main (int argc, char **argv)
{
@ -5967,5 +5985,8 @@ main (int argc, char **argv)
g_test_add_func ("/gvariant/unaligned-construction",
test_unaligned_construction);
g_test_add_func ("/gvarianttype/hash",
test_g_variant_type_hash);
return g_test_run ();
}