/** * m_hash_table_new_full: * @hash_func: a function to create a hash value from a key. * @key_equal_func: a function to check two keys for equality. * @key_destroy_func: a function to free the memory allocated for the key * used when removing the entry from the #MHashTable or %null if you * don't want to supply such a function. * @value_destroy_func: a function to free the memory allocated for the * value used when removing the entry from the #MHashTable or %null if * you don't want to supply such a function. * * Creates a new #MHashTable like m_hash_table_new() with a reference count * of 1 and allows to specify functions to free the memory allocated for the * key and value that get called when removing the entry from the #MHashTable. * * Return value: a new #MHashTable. **/ public MHashTable(IntPtr hash_func, IntPtr key_equal_func, MDestroyNotify key_destroy_func, MDestroyNotify value_destroy_func) { this.size = 1 << HASH_TABLE_MIN_SHIFT; this.mod = prime_mod[HASH_TABLE_MIN_SHIFT]; uint mask = 0; for (int i = 0; i < HASH_TABLE_MIN_SHIFT; i++) { mask <<= 1; mask |= 1; } this.mask = mask; this.nnodes = 0; this.noccupied = 0; this.hash_func = hash_func != IntPtr.Zero ? hash_func : IntPtr.Zero; /*DirectHash;*/ this.key_equal_func = key_equal_func; this.ref_count = 1; this.version = 0; this.key_destroy_func = key_destroy_func; this.value_destroy_func = value_destroy_func; this.nodes = (MHashNode *)Marshal.AllocHGlobal(size * Marshal.SizeOf(typeof(MHashNode))); for (int i = 0; i < size; i++) { Marshal.WriteIntPtr((IntPtr)this.nodes, i * Marshal.SizeOf(typeof(MHashNode)), IntPtr.Zero); } }
/* * m_hash_table_foreach_remove_or_steal: * @hash_table: our #MHashTable * @func: the user's callback function * @user_data: data for @func * @notify: %true if the destroy notify handlers are to be called * * Implements the common logic for m_hash_table_foreach_remove() and * m_hash_table_foreach_steal(). * * Iterates over every node in the table, calling @func with the key * and value of the node (and @user_data). If @func returns %true the * node is removed from the table. * * If @notify is true then the destroy notify handlers will be called * for each removed node. */ private uint ForeachRemoveOrSteal(MHRFunc func, IntPtr user_data, bool notify) { uint deleted = 0; for (int i = 0; i < size; i++) { MHashNode *node = &nodes [i]; if (node->key_hash > 1 && func(node->key, node->value, user_data)) { RemoveNode(node, notify); deleted++; } } MaybeResize(); if (deleted > 0) { version++; } return(deleted); }
/* * m_hash_table_remove_all_nodes: * @hash_table: our #MHashTable * @notify: %true if the destroy notify handlers are to be called * * Removes all nodes from the table. Since this may be a precursor to * freeing the table entirely, no resize is performed. * * If @notify is %true then the destroy notify functions are called * for the key and value of the hash node. */ private void RemoveAllNodes(bool notify) { for (int i = 0; i < size; i++) { MHashNode *node = &nodes [i]; if (node->key_hash > 1) { if (notify && key_destroy_func != null) { key_destroy_func(node->key); } if (notify && value_destroy_func != null) { value_destroy_func(node->value); } } } /* We need to set node->key_hash = 0 for all nodes - might as well be GC * friendly and clear everything */ for (int i = 0; i < size; i++) { Marshal.WriteIntPtr((IntPtr)nodes, i * Marshal.SizeOf(typeof(MHashNode)), IntPtr.Zero); } nnodes = 0; noccupied = 0; }
/* * m_hash_table_resize: * @hash_table: our #MHashTable * * Resizes the hash table to the optimal size based on the number of * nodes currently held. If you call this function then a resize will * occur, even if one does not need to occur. Use * m_hash_table_maybe_resize() instead. * * This function may "resize" the hash table to its current size, with * the side effect of cleaning up tombstones and otherwise optimizing * the probe sequences. */ private void Resize() { MHashNode *new_nodes; int old_size; old_size = size; SetShiftFromSize(nnodes * 2); new_nodes = (MHashNode *)Marshal.AllocHGlobal(size * Marshal.SizeOf(typeof(MHashNode))); for (int i = 0; i < size; i++) { Marshal.WriteIntPtr((IntPtr)new_nodes, i * Marshal.SizeOf(typeof(MHashNode)), IntPtr.Zero); } for (int i = 0; i < old_size; i++) { MHashNode *node = &nodes [i]; MHashNode *new_node; uint hash_val; uint step = 0; if (node->key_hash <= 1) { continue; } hash_val = (uint)(node->key_hash % mod); new_node = &new_nodes [hash_val]; while (new_node->key_hash != 0) { step++; hash_val += step; hash_val &= mask; new_node = &new_nodes [hash_val]; } *new_node = *node; } Marshal.FreeHGlobal((IntPtr)nodes); nodes = new_nodes; noccupied = nnodes; }
public GList *GetValues() { GList *retval; retval = null; for (int i = 0; i < size; i++) { MHashNode *node = &nodes [i]; if (node->key_hash > 1) { retval = g_list_prepend(retval, node->value); } } return(retval); }
/** * m_hash_table_foreach: * @hash_table: a #MHashTable. * @func: the function to call for each key/value pair. * @user_data: user data to pass to the function. * * Calls the given function for each of the key/value pairs in the * #MHashTable. The function is passed the key and value of each * pair, and the given @user_data parameter. The hash table may not * be modified while iterating over it (you can't add/remove * items). To remove all items matching a predicate, use * m_hash_table_foreach_remove(). * * See m_hash_table_find() for performance caveats for linear * order searches in contrast to m_hash_table_lookup(). **/ public void Foreach(MHFunc func, IntPtr user_data) { if (func == null) { throw new ArgumentNullException("func"); } for (int i = 0; i < size; i++) { MHashNode *node = &nodes [i]; if (node->key_hash > 1) { func(node->key, node->value, user_data); } } }
/** * m_hash_table_find: * @hash_table: a #MHashTable. * @predicate: function to test the key/value pairs for a certain property. * @user_data: user data to pass to the function. * * Calls the given function for key/value pairs in the #MHashTable until * @predicate returns %true. The function is passed the key and value of * each pair, and the given @user_data parameter. The hash table may not * be modified while iterating over it (you can't add/remove items). * * Note, that hash tables are really only optimized for forward lookups, * i.e. m_hash_table_lookup(). * So code that frequently issues m_hash_table_find() or * m_hash_table_foreach() (e.g. in the order of once per every entry in a * hash table) should probably be reworked to use additional or different * data structures for reverse lookups (keep in mind that an O(n) find/foreach * operation issued for all n values in a hash table ends up needing O(n*n) * operations). * * Return value: The value of the first key/value pair is returned, for which * func evaluates to %true. If no pair with the requested property is found, * %null is returned. * * Since: 2.4 **/ public IntPtr Find(MHRFunc predicate, IntPtr user_data) { if (predicate == null) { throw new ArgumentNullException("predicate"); } for (int i = 0; i < size; i++) { MHashNode *node = &nodes [i]; if (node->key_hash > 1 && predicate(node->key, node->value, user_data)) { return(node->value); } } return(IntPtr.Zero); }
/* * m_hash_table_remove_node: * @hash_table: our #MHashTable * @node: pointer to node to remove * @notify: %true if the destroy notify handlers are to be called * * Removes a node from the hash table and updates the node count. * The node is replaced by a tombstone. No table resize is performed. * * If @notify is %true then the destroy notify functions are called * for the key and value of the hash node. */ private void RemoveNode(MHashNode *node, bool notify) { if (notify && key_destroy_func != null) { key_destroy_func(node->key); } if (notify && value_destroy_func != null) { value_destroy_func(node->value); } /* Erect tombstone */ node->key_hash = 1; /* Be GC friendly */ node->key = IntPtr.Zero; node->value = IntPtr.Zero; nnodes--; }
/* * m_hash_table_resize: * @hash_table: our #MHashTable * * Resizes the hash table to the optimal size based on the number of * nodes currently held. If you call this function then a resize will * occur, even if one does not need to occur. Use * m_hash_table_maybe_resize() instead. * * This function may "resize" the hash table to its current size, with * the side effect of cleaning up tombstones and otherwise optimizing * the probe sequences. */ private void Resize() { MHashNode *new_nodes; int old_size; old_size = size; SetShiftFromSize (nnodes * 2); new_nodes = (MHashNode*)Marshal.AllocHGlobal (size * Marshal.SizeOf (typeof (MHashNode))); for (int i = 0; i < size; i ++) Marshal.WriteIntPtr ((IntPtr)new_nodes, i * Marshal.SizeOf (typeof (MHashNode)), IntPtr.Zero); for (int i = 0; i < old_size; i++) { MHashNode *node = &nodes [i]; MHashNode *new_node; uint hash_val; uint step = 0; if (node->key_hash <= 1) continue; hash_val = (uint)(node->key_hash % mod); new_node = &new_nodes [hash_val]; while (new_node->key_hash != 0) { step++; hash_val += step; hash_val &= mask; new_node = &new_nodes [hash_val]; } *new_node = *node; } Marshal.FreeHGlobal ((IntPtr)nodes); nodes = new_nodes; noccupied = nnodes; }
/** * m_hash_table_new_full: * @hash_func: a function to create a hash value from a key. * @key_equal_func: a function to check two keys for equality. * @key_destroy_func: a function to free the memory allocated for the key * used when removing the entry from the #MHashTable or %null if you * don't want to supply such a function. * @value_destroy_func: a function to free the memory allocated for the * value used when removing the entry from the #MHashTable or %null if * you don't want to supply such a function. * * Creates a new #MHashTable like m_hash_table_new() with a reference count * of 1 and allows to specify functions to free the memory allocated for the * key and value that get called when removing the entry from the #MHashTable. * * Return value: a new #MHashTable. **/ public MHashTable(IntPtr hash_func, IntPtr key_equal_func, MDestroyNotify key_destroy_func, MDestroyNotify value_destroy_func) { this.size = 1 << HASH_TABLE_MIN_SHIFT; this.mod = prime_mod[HASH_TABLE_MIN_SHIFT]; uint mask = 0; for (int i = 0; i < HASH_TABLE_MIN_SHIFT; i++) { mask <<= 1; mask |= 1; } this.mask = mask; this.nnodes = 0; this.noccupied = 0; this.hash_func = hash_func != IntPtr.Zero ? hash_func : IntPtr.Zero; /*DirectHash;*/ this.key_equal_func = key_equal_func; this.ref_count = 1; this.version = 0; this.key_destroy_func = key_destroy_func; this.value_destroy_func = value_destroy_func; this.nodes = (MHashNode*)Marshal.AllocHGlobal (size * Marshal.SizeOf (typeof (MHashNode))); for (int i = 0; i < size; i ++) Marshal.WriteIntPtr ((IntPtr)this.nodes, i * Marshal.SizeOf (typeof (MHashNode)), IntPtr.Zero); }