mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-08-21 08:28:53 +02:00
Implement O(1) interface lookups
Currently interface lookups are do a binary search over all the interfaces an object implements. Its possible to do this lookup in constant time using for instance the gcj algorighm described at: http://gcc.gnu.org/ml/java/1999-q3/msg00377.html This is an implementation of that based on GAtomicArray.
This commit is contained in:
185
gobject/gtype.c
185
gobject/gtype.c
@@ -245,6 +245,7 @@ struct _TypeNode
|
|||||||
#define SIZEOF_BASE_TYPE_NODE() (G_STRUCT_OFFSET (TypeNode, supers))
|
#define SIZEOF_BASE_TYPE_NODE() (G_STRUCT_OFFSET (TypeNode, supers))
|
||||||
#define MAX_N_SUPERS (255)
|
#define MAX_N_SUPERS (255)
|
||||||
#define MAX_N_CHILDREN (4095)
|
#define MAX_N_CHILDREN (4095)
|
||||||
|
#define MAX_N_INTERFACES (255) /* Limited by offsets being 8 bits */
|
||||||
#define MAX_N_PREREQUISITES (511)
|
#define MAX_N_PREREQUISITES (511)
|
||||||
#define NODE_TYPE(node) (node->supers[0])
|
#define NODE_TYPE(node) (node->supers[0])
|
||||||
#define NODE_PARENT_TYPE(node) (node->supers[1])
|
#define NODE_PARENT_TYPE(node) (node->supers[1])
|
||||||
@@ -281,7 +282,7 @@ struct _IFaceEntry
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct _IFaceEntries {
|
struct _IFaceEntries {
|
||||||
guint offset_index; /* not used yet */
|
guint offset_index;
|
||||||
IFaceEntry entry[1];
|
IFaceEntry entry[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -304,6 +305,7 @@ struct _IFaceData
|
|||||||
GClassFinalizeFunc dflt_finalize;
|
GClassFinalizeFunc dflt_finalize;
|
||||||
gconstpointer dflt_data;
|
gconstpointer dflt_data;
|
||||||
gpointer dflt_vtable;
|
gpointer dflt_vtable;
|
||||||
|
GAtomicArray offsets;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _ClassData
|
struct _ClassData
|
||||||
@@ -528,36 +530,44 @@ type_node_new_W (TypeNode *pnode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline IFaceEntry*
|
static inline IFaceEntry*
|
||||||
lookup_iface_entry_I (IFaceEntries *entries,
|
lookup_iface_entry_I (volatile IFaceEntries *entries,
|
||||||
TypeNode *iface_node)
|
TypeNode *iface_node)
|
||||||
{
|
{
|
||||||
if (entries != NULL)
|
guint8 *offsets;
|
||||||
{
|
guint offset_index;
|
||||||
IFaceEntry *ifaces = &entries->entry[-1];
|
IFaceEntry *check;
|
||||||
guint n_ifaces = IFACE_ENTRIES_N_ENTRIES (entries);
|
int index;
|
||||||
GType iface_type = NODE_TYPE (iface_node);
|
IFaceEntry *entry;
|
||||||
|
|
||||||
do
|
if (entries == NULL)
|
||||||
{
|
return NULL;
|
||||||
guint i;
|
|
||||||
IFaceEntry *check;
|
G_ATOMIC_ARRAY_DO_TRANSACTION
|
||||||
|
(&iface_node->data->iface.offsets, guint8,
|
||||||
i = (n_ifaces + 1) >> 1;
|
|
||||||
check = ifaces + i;
|
entry = NULL;
|
||||||
if (iface_type == check->iface_type)
|
offsets = transaction_data;
|
||||||
return check;
|
offset_index = entries->offset_index;
|
||||||
else if (iface_type > check->iface_type)
|
if (offsets != NULL &&
|
||||||
{
|
offset_index < G_ATOMIC_ARRAY_DATA_SIZE(offsets))
|
||||||
n_ifaces -= i;
|
{
|
||||||
ifaces = check;
|
index = offsets[offset_index];
|
||||||
}
|
if (index > 0)
|
||||||
else /* if (iface_type < check->iface_type) */
|
{
|
||||||
n_ifaces = i - 1;
|
/* zero means unset, subtract one to get real index */
|
||||||
}
|
index -= 1;
|
||||||
while (n_ifaces);
|
|
||||||
}
|
if (index < IFACE_ENTRIES_N_ENTRIES (entries))
|
||||||
|
{
|
||||||
return NULL;
|
check = (IFaceEntry *)&entries->entry[index];
|
||||||
|
if (check->iface_type == NODE_TYPE (iface_node))
|
||||||
|
entry = check;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline IFaceEntry*
|
static inline IFaceEntry*
|
||||||
@@ -1215,6 +1225,88 @@ type_data_unref_WmREC (TypeNode *node,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
iface_node_has_available_offset_L (TypeNode *iface_node,
|
||||||
|
int offset,
|
||||||
|
int for_index)
|
||||||
|
{
|
||||||
|
guint8 *offsets;
|
||||||
|
|
||||||
|
offsets = G_ATOMIC_ARRAY_GET_LOCKED (&iface_node->data->iface.offsets, guint8);
|
||||||
|
if (offsets == NULL)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (G_ATOMIC_ARRAY_DATA_SIZE (offsets) <= offset)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (offsets[offset] == 0 ||
|
||||||
|
offsets[offset] == for_index+1)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
find_free_iface_offset_L (IFaceEntries *entries)
|
||||||
|
{
|
||||||
|
IFaceEntry *entry;
|
||||||
|
TypeNode *iface_node;
|
||||||
|
int offset;
|
||||||
|
int i;
|
||||||
|
int n_entries;
|
||||||
|
|
||||||
|
n_entries = IFACE_ENTRIES_N_ENTRIES (entries);
|
||||||
|
offset = -1;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
offset++;
|
||||||
|
for (i = 0; i < n_entries; i++)
|
||||||
|
{
|
||||||
|
entry = &entries->entry[i];
|
||||||
|
iface_node = lookup_type_node_I (entry->iface_type);
|
||||||
|
|
||||||
|
if (!iface_node_has_available_offset_L (iface_node, offset, i))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (i != n_entries);
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
iface_node_set_offset_L (TypeNode *iface_node,
|
||||||
|
int offset,
|
||||||
|
int index)
|
||||||
|
{
|
||||||
|
guint8 *offsets, *old_offsets;
|
||||||
|
int new_size, old_size;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
old_offsets = G_ATOMIC_ARRAY_GET_LOCKED (&iface_node->data->iface.offsets, guint8);
|
||||||
|
if (old_offsets == NULL)
|
||||||
|
old_size = 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
old_size = G_ATOMIC_ARRAY_DATA_SIZE (old_offsets);
|
||||||
|
if (offset < old_size &&
|
||||||
|
old_offsets[offset] == index + 1)
|
||||||
|
return; /* Already set to this index, return */
|
||||||
|
}
|
||||||
|
new_size = MAX (old_size, offset + 1);
|
||||||
|
|
||||||
|
offsets = _g_atomic_array_copy (&iface_node->data->iface.offsets,
|
||||||
|
0, new_size - old_size);
|
||||||
|
|
||||||
|
/* Mark new area as unused */
|
||||||
|
for (i = old_size; i < new_size; i++)
|
||||||
|
offsets[i] = 0;
|
||||||
|
|
||||||
|
offsets[offset] = index + 1;
|
||||||
|
|
||||||
|
_g_atomic_array_update (&iface_node->data->iface.offsets, offsets);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
type_node_add_iface_entry_W (TypeNode *node,
|
type_node_add_iface_entry_W (TypeNode *node,
|
||||||
GType iface_type,
|
GType iface_type,
|
||||||
@@ -1222,17 +1314,19 @@ type_node_add_iface_entry_W (TypeNode *node,
|
|||||||
{
|
{
|
||||||
IFaceEntries *entries;
|
IFaceEntries *entries;
|
||||||
IFaceEntry *entry;
|
IFaceEntry *entry;
|
||||||
guint i;
|
TypeNode *iface_node;
|
||||||
|
guint i, j;
|
||||||
int num_entries;
|
int num_entries;
|
||||||
|
|
||||||
g_assert (node->is_instantiatable);
|
g_assert (node->is_instantiatable);
|
||||||
|
|
||||||
entries = CLASSED_NODE_IFACES_ENTRIES_LOCKED (node);
|
entries = CLASSED_NODE_IFACES_ENTRIES_LOCKED (node);
|
||||||
i = 0;
|
|
||||||
if (entries != NULL)
|
if (entries != NULL)
|
||||||
{
|
{
|
||||||
num_entries = IFACE_ENTRIES_N_ENTRIES (entries);
|
num_entries = IFACE_ENTRIES_N_ENTRIES (entries);
|
||||||
|
|
||||||
|
g_assert (num_entries < MAX_N_INTERFACES);
|
||||||
|
|
||||||
for (i = 0; i < num_entries; i++)
|
for (i = 0; i < num_entries; i++)
|
||||||
{
|
{
|
||||||
entry = &entries->entry[i];
|
entry = &entries->entry[i];
|
||||||
@@ -1256,8 +1350,6 @@ type_node_add_iface_entry_W (TypeNode *node,
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (entry->iface_type > iface_type)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1265,8 +1357,9 @@ type_node_add_iface_entry_W (TypeNode *node,
|
|||||||
IFACE_ENTRIES_HEADER_SIZE,
|
IFACE_ENTRIES_HEADER_SIZE,
|
||||||
sizeof (IFaceEntry));
|
sizeof (IFaceEntry));
|
||||||
num_entries = IFACE_ENTRIES_N_ENTRIES (entries);
|
num_entries = IFACE_ENTRIES_N_ENTRIES (entries);
|
||||||
g_memmove (&entries->entry[i + 1], &entries->entry[i],
|
i = num_entries - 1;
|
||||||
sizeof (IFaceEntry) * (num_entries - i - 1));
|
if (i == 0)
|
||||||
|
entries->offset_index = 0;
|
||||||
entries->entry[i].iface_type = iface_type;
|
entries->entry[i].iface_type = iface_type;
|
||||||
entries->entry[i].vtable = NULL;
|
entries->entry[i].vtable = NULL;
|
||||||
entries->entry[i].init_state = UNINITIALIZED;
|
entries->entry[i].init_state = UNINITIALIZED;
|
||||||
@@ -1280,6 +1373,30 @@ type_node_add_iface_entry_W (TypeNode *node,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Update offsets in iface */
|
||||||
|
iface_node = lookup_type_node_I (iface_type);
|
||||||
|
|
||||||
|
if (iface_node_has_available_offset_L (iface_node,
|
||||||
|
entries->offset_index,
|
||||||
|
i))
|
||||||
|
{
|
||||||
|
iface_node_set_offset_L (iface_node,
|
||||||
|
entries->offset_index, i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entries->offset_index =
|
||||||
|
find_free_iface_offset_L (entries);
|
||||||
|
for (j = 0; j < IFACE_ENTRIES_N_ENTRIES (entries); j++)
|
||||||
|
{
|
||||||
|
entry = &entries->entry[j];
|
||||||
|
iface_node =
|
||||||
|
lookup_type_node_I (entry->iface_type);
|
||||||
|
iface_node_set_offset_L (iface_node,
|
||||||
|
entries->offset_index, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_g_atomic_array_update (CLASSED_NODE_IFACES_ENTRIES (node), entries);
|
_g_atomic_array_update (CLASSED_NODE_IFACES_ENTRIES (node), entries);
|
||||||
|
|
||||||
if (parent_entry)
|
if (parent_entry)
|
||||||
|
Reference in New Issue
Block a user