Пример #1
0
        /**
         * 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);
            }
        }
Пример #2
0
        /*
         * 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);
        }
Пример #3
0
        /*
         * 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;
        }
Пример #4
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;
        }
Пример #5
0
        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);
        }
Пример #6
0
        /**
         * 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);
                }
            }
        }
Пример #7
0
        /**
         * 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);
        }
Пример #8
0
        /*
         * 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--;
        }
Пример #9
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;
        }
Пример #10
0
        /**
         * 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);
        }