From: Alexander Larsson Date: Wed, 9 Sep 2009 14:42:32 +0000 (+0200) Subject: Implement O(1) interface lookups X-Git-Tag: 2.23.1~41 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=69961d27a13b2083d864884b40c861c5e97a5c12;p=platform%2Fupstream%2Fglib.git 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. --- diff --git a/gobject/gtype.c b/gobject/gtype.c index 2915f48..16df69a 100644 --- a/gobject/gtype.c +++ b/gobject/gtype.c @@ -245,6 +245,7 @@ struct _TypeNode #define SIZEOF_BASE_TYPE_NODE() (G_STRUCT_OFFSET (TypeNode, supers)) #define MAX_N_SUPERS (255) #define MAX_N_CHILDREN (4095) +#define MAX_N_INTERFACES (255) /* Limited by offsets being 8 bits */ #define MAX_N_PREREQUISITES (511) #define NODE_TYPE(node) (node->supers[0]) #define NODE_PARENT_TYPE(node) (node->supers[1]) @@ -281,7 +282,7 @@ struct _IFaceEntry }; struct _IFaceEntries { - guint offset_index; /* not used yet */ + guint offset_index; IFaceEntry entry[1]; }; @@ -304,6 +305,7 @@ struct _IFaceData GClassFinalizeFunc dflt_finalize; gconstpointer dflt_data; gpointer dflt_vtable; + GAtomicArray offsets; }; struct _ClassData @@ -528,36 +530,44 @@ type_node_new_W (TypeNode *pnode, } static inline IFaceEntry* -lookup_iface_entry_I (IFaceEntries *entries, +lookup_iface_entry_I (volatile IFaceEntries *entries, TypeNode *iface_node) { - if (entries != NULL) - { - IFaceEntry *ifaces = &entries->entry[-1]; - guint n_ifaces = IFACE_ENTRIES_N_ENTRIES (entries); - GType iface_type = NODE_TYPE (iface_node); + guint8 *offsets; + guint offset_index; + IFaceEntry *check; + int index; + IFaceEntry *entry; - do - { - guint i; - IFaceEntry *check; - - i = (n_ifaces + 1) >> 1; - check = ifaces + i; - if (iface_type == check->iface_type) - return check; - else if (iface_type > check->iface_type) - { - n_ifaces -= i; - ifaces = check; - } - else /* if (iface_type < check->iface_type) */ - n_ifaces = i - 1; - } - while (n_ifaces); - } - - return NULL; + if (entries == NULL) + return NULL; + + G_ATOMIC_ARRAY_DO_TRANSACTION + (&iface_node->data->iface.offsets, guint8, + + entry = NULL; + offsets = transaction_data; + offset_index = entries->offset_index; + if (offsets != NULL && + offset_index < G_ATOMIC_ARRAY_DATA_SIZE(offsets)) + { + index = offsets[offset_index]; + if (index > 0) + { + /* zero means unset, subtract one to get real index */ + index -= 1; + + if (index < IFACE_ENTRIES_N_ENTRIES (entries)) + { + check = (IFaceEntry *)&entries->entry[index]; + if (check->iface_type == NODE_TYPE (iface_node)) + entry = check; + } + } + } + ); + + return entry; } 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 type_node_add_iface_entry_W (TypeNode *node, GType iface_type, @@ -1222,17 +1314,19 @@ type_node_add_iface_entry_W (TypeNode *node, { IFaceEntries *entries; IFaceEntry *entry; - guint i; + TypeNode *iface_node; + guint i, j; int num_entries; g_assert (node->is_instantiatable); entries = CLASSED_NODE_IFACES_ENTRIES_LOCKED (node); - i = 0; if (entries != NULL) { num_entries = IFACE_ENTRIES_N_ENTRIES (entries); + g_assert (num_entries < MAX_N_INTERFACES); + for (i = 0; i < num_entries; i++) { entry = &entries->entry[i]; @@ -1256,8 +1350,6 @@ type_node_add_iface_entry_W (TypeNode *node, } 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, sizeof (IFaceEntry)); num_entries = IFACE_ENTRIES_N_ENTRIES (entries); - g_memmove (&entries->entry[i + 1], &entries->entry[i], - sizeof (IFaceEntry) * (num_entries - i - 1)); + i = num_entries - 1; + if (i == 0) + entries->offset_index = 0; entries->entry[i].iface_type = iface_type; entries->entry[i].vtable = NULL; 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); if (parent_entry)