/
githubmirror
/
libxmlb
Обзор
Документация
Войти
/
githubmirror
/
libxmlb
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/xb-value-bindings.c
386 строк
11 KB
Richard Hughes
trivial: Do not reset the XbValueBindings kind for a 0.5% speedup
29 июн 2026, 19:17
29 июн 2026, 19:17
4927fe9
Код
Авторство
О чём код?
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * vi:set noexpandtab tabstop=8 shiftwidth=8: * * Copyright 2020 Endless OS Foundation LLC * * Author: Philip Withnall <withnall@endlessm.com> * * SPDX-License-Identifier: LGPL-2.1-or-later */ #define G_LOG_DOMAIN "XbValueBindings" #include "config.h" #include <glib.h> #include "xb-opcode-private.h" #include "xb-silo-private.h" #include "xb-value-bindings-private.h" typedef struct { guint8 kind; /* XbBoundValueKind */ guint32 val; gpointer ptr; GDestroyNotify destroy_func; } XbBoundValue; typedef enum { XB_BOUND_VALUE_KIND_NONE, XB_BOUND_VALUE_KIND_TEXT, XB_BOUND_VALUE_KIND_INTEGER, XB_BOUND_VALUE_KIND_INDEXED_TEXT, } XbBoundValueKind; typedef struct { /* Currently limited to 4 values since that’s all that any client * uses. This could be expanded to dynamically allow more in future. */ XbBoundValue values[4]; gpointer dummy[3]; } RealValueBindings; G_DEFINE_BOXED_TYPE(XbValueBindings, xb_value_bindings, xb_value_bindings_copy, xb_value_bindings_free) /** * xb_value_bindings_init: * @self: an uninitialised #XbValueBindings to initialise * * Initialise a stack-allocated #XbValueBindings struct so it can be used. * * Stack-allocated #XbValueBindings instances should be freed once finished * with, using xb_value_bindings_clear() (or `g_auto(XbValueBindings)`, which is * equivalent). * * Since: 0.3.0 */ void xb_value_bindings_init(XbValueBindings *self) { RealValueBindings *_self = (RealValueBindings *)self; for (gsize i = 0; i < G_N_ELEMENTS(_self->values); i++) _self->values[i].kind = XB_BOUND_VALUE_KIND_NONE; } static void xb_value_bindings_clear_index(XbValueBindings *self, guint idx) { RealValueBindings *_self = (RealValueBindings *)self; if (_self->values[idx].ptr != NULL && _self->values[idx].destroy_func) { _self->values[idx].destroy_func(_self->values[idx].ptr); _self->values[idx].ptr = NULL; _self->values[idx].destroy_func = NULL; } } /** * xb_value_bindings_clear: * @self: an #XbValueBindings * * Clear an #XbValueBindings, freeing any allocated memory it points to. * * After this function has been called, the contents of the #XbValueBindings are * undefined, and it’s only safe to call xb_value_bindings_init() on it. * * Since: 0.3.0 */ void xb_value_bindings_clear(XbValueBindings *self) { RealValueBindings *_self = (RealValueBindings *)self; for (gsize i = 0; i < G_N_ELEMENTS(_self->values); i++) xb_value_bindings_clear_index(self, i); } /* private */ gchar * xb_value_bindings_to_string(XbValueBindings *self) { RealValueBindings *_self = (RealValueBindings *)self; g_autoptr(GString) str = g_string_new(""); for (guint i = 0; i < G_N_ELEMENTS(_self->values); i++) { XbBoundValue *value = &_self->values[i]; if (value->kind == XB_BOUND_VALUE_KIND_NONE) continue; if (str->len > 0) g_string_append(str, ", "); if (value->kind == XB_BOUND_VALUE_KIND_INTEGER) g_string_append_printf(str, "?%u → %u", i, value->val); else if (value->kind == XB_BOUND_VALUE_KIND_TEXT && value->val > 0) g_string_append_printf(str, "?%u → %s [%u]", i, (const gchar *)value->ptr, value->val); else if (value->kind == XB_BOUND_VALUE_KIND_TEXT) g_string_append_printf(str, "?%u → %s", i, (const gchar *)value->ptr); } return g_string_free(g_steal_pointer(&str), FALSE); } /** * xb_value_bindings_copy: * @self: an #XbValueBindings * * Copy @self into a new heap-allocated #XbValueBindings instance. * * Returns: (transfer full): a copy of @self * Since: 0.3.0 */ XbValueBindings * xb_value_bindings_copy(XbValueBindings *self) { RealValueBindings *_self = (RealValueBindings *)self; g_autoptr(XbValueBindings) copy = g_new0(XbValueBindings, 1); xb_value_bindings_init(copy); for (gsize i = 0; i < G_N_ELEMENTS(_self->values); i++) { gboolean copied = xb_value_bindings_copy_binding(self, i, copy, i); g_assert(copied); } return g_steal_pointer(©); } /** * xb_value_bindings_free: * @self: a heap-allocated #XbValueBindings * * Free a heap-allocated #XbValueBindings instance. This should be used on * #XbValueBindings instances created with xb_value_bindings_copy(). * * For stack-allocated instances, xb_value_bindings_clear() should be used * instead. * * Since: 0.3.0 */ void xb_value_bindings_free(XbValueBindings *self) { g_return_if_fail(self != NULL); xb_value_bindings_clear(self); g_free(self); } /** * xb_value_bindings_is_bound: * @self: an #XbValueBindings * @idx: 0-based index of the binding to check * * Check whether a value has been bound to the given index using (for example) * xb_value_bindings_bind_str(). * * Returns: %TRUE if a value is bound to @idx, %FALSE otherwise * Since: 0.3.0 */ gboolean xb_value_bindings_is_bound(XbValueBindings *self, guint idx) { RealValueBindings *_self = (RealValueBindings *)self; return (idx < G_N_ELEMENTS(_self->values) && _self->values[idx].kind != XB_BOUND_VALUE_KIND_NONE); } /** * xb_value_bindings_bind_str: * @self: an #XbValueBindings * @idx: 0-based index to bind to * @str: (transfer full) (not nullable): a string to bind to @idx * @destroy_func: (nullable): function to free @str * * Bind @str to @idx in the value bindings. * * This will overwrite any previous binding at @idx. It will take ownership of * @str, and an appropriate @destroy_func must be provided to free @str once the * binding is no longer needed. @destroy_func will be called exactly once at * some point before the #XbValueBindings is cleared or freed. * * Since: 0.3.0 */ void xb_value_bindings_bind_str(XbValueBindings *self, guint idx, const gchar *str, GDestroyNotify destroy_func) { RealValueBindings *_self = (RealValueBindings *)self; g_return_if_fail(self != NULL); g_return_if_fail(str != NULL); /* Currently limited to two values, but this restriction could be lifted * in future. */ g_return_if_fail(idx < G_N_ELEMENTS(_self->values)); xb_value_bindings_clear_index(self, idx); _self->values[idx].kind = XB_BOUND_VALUE_KIND_TEXT; _self->values[idx].ptr = (gpointer)str; _self->values[idx].destroy_func = destroy_func; } /** * xb_value_bindings_bind_val: * @self: an #XbValueBindings * @idx: 0-based index to bind to * @val: an integer to bind to @idx * * Bind @val to @idx in the value bindings. * * This will overwrite any previous binding at @idx. * * Since: 0.3.0 */ void xb_value_bindings_bind_val(XbValueBindings *self, guint idx, guint32 val) { RealValueBindings *_self = (RealValueBindings *)self; g_return_if_fail(self != NULL); /* Currently limited to two values, but this restriction could be lifted * in future. */ g_return_if_fail(idx < G_N_ELEMENTS(_self->values)); xb_value_bindings_clear_index(self, idx); _self->values[idx].kind = XB_BOUND_VALUE_KIND_INTEGER; _self->values[idx].val = val; _self->values[idx].destroy_func = NULL; } /** * xb_value_bindings_lookup_opcode: * @self: an #XbValueBindings * @idx: 0-based index to look up the binding from * @opcode_out: (out caller-allocates) (not nullable): pointer to an #XbOpcode * to initialise from the binding * * Initialises an #XbOpcode with the value bound to @idx, if a value is bound. * If no value is bound, @opcode_out is not touched and %FALSE is returned. * * @opcode_out is initialised to point to the data inside the #XbValueBindings, * so must have a shorter lifetime than the #XbValueBindings. It will be of kind * %XB_OPCODE_KIND_BOUND_TEXT or %XB_OPCODE_KIND_BOUND_INTEGER. * * Returns: %TRUE if @idx was bound, %FALSE otherwise * Since: 0.3.0 */ gboolean xb_value_bindings_lookup_opcode(XbValueBindings *self, guint idx, XbOpcode *opcode_out) { RealValueBindings *_self = (RealValueBindings *)self; if (!xb_value_bindings_is_bound(self, idx)) return FALSE; switch (_self->values[idx].kind) { case XB_BOUND_VALUE_KIND_TEXT: xb_opcode_init(opcode_out, XB_OPCODE_KIND_BOUND_TEXT, _self->values[idx].ptr, 0, NULL); break; case XB_BOUND_VALUE_KIND_INTEGER: xb_opcode_init(opcode_out, XB_OPCODE_KIND_BOUND_INTEGER, NULL, _self->values[idx].val, NULL); break; case XB_BOUND_VALUE_KIND_INDEXED_TEXT: xb_opcode_init(opcode_out, XB_OPCODE_KIND_BOUND_INDEXED_TEXT, _self->values[idx].ptr, _self->values[idx].val, NULL); break; case XB_BOUND_VALUE_KIND_NONE: default: g_assert_not_reached(); } return TRUE; } /** * xb_value_bindings_copy_binding: * @self: an #XbValueBindings to copy from * @idx: 0-based index to look up the binding from in @self * @dest: an #XbValueBindings to copy to * @dest_idx: 0-based index to copy the binding to in @dest * * Copies the value bound at @idx on @self to @dest_idx on @dest. If no value is * bound at @idx, @dest is not modified and %FALSE is returned. * * @dest must be initialised. If a binding already exists at @dest_idx, it will * be overwritten. * * Returns: %TRUE if @idx was bound, %FALSE otherwise * Since: 0.3.0 */ gboolean xb_value_bindings_copy_binding(XbValueBindings *self, guint idx, XbValueBindings *dest, guint dest_idx) { RealValueBindings *_self = (RealValueBindings *)self; RealValueBindings *_dest = (RealValueBindings *)dest; if (!xb_value_bindings_is_bound(self, idx)) return FALSE; switch (_self->values[idx].kind) { case XB_BOUND_VALUE_KIND_TEXT: xb_value_bindings_bind_str(dest, dest_idx, _self->values[idx].ptr, NULL); break; case XB_BOUND_VALUE_KIND_INTEGER: xb_value_bindings_bind_val(dest, dest_idx, _self->values[idx].val); break; case XB_BOUND_VALUE_KIND_INDEXED_TEXT: xb_value_bindings_bind_str(dest, dest_idx, _self->values[idx].ptr, NULL); _dest->values[dest_idx].kind = XB_BOUND_VALUE_KIND_INDEXED_TEXT; _dest->values[dest_idx].val = _self->values[idx].val; break; case XB_BOUND_VALUE_KIND_NONE: default: g_assert_not_reached(); } return TRUE; } /* private */ gboolean xb_value_bindings_indexed_text_lookup(XbValueBindings *self, XbSilo *silo, GError **error) { RealValueBindings *_self = (RealValueBindings *)self; for (guint i = 0; i < G_N_ELEMENTS(_self->values); i++) { XbBoundValue *value = &_self->values[i]; if (value->kind == XB_BOUND_VALUE_KIND_TEXT) { guint32 val = xb_silo_strtab_index_lookup(silo, (const gchar *)value->ptr); if (val == XB_SILO_UNSET) { g_set_error(error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "indexed string '%s' was unfound", (const gchar *)value->ptr); return FALSE; } value->kind = XB_BOUND_VALUE_KIND_INDEXED_TEXT; value->val = val; } } return TRUE; }