reactos/dll/win32/ole32/dictionary.c

188 lines
4.8 KiB
C

/* Simple dictionary implementation using a linked list.
* FIXME: a skip list would be faster.
*
* Copyright 2005 Juan Lang
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "precomp.h"
WINE_DEFAULT_DEBUG_CHANNEL(storage);
struct dictionary_entry
{
void *key;
void *value;
struct dictionary_entry *next;
};
struct dictionary
{
comparefunc comp;
destroyfunc destroy;
void *extra;
struct dictionary_entry *head;
UINT num_entries;
};
struct dictionary *dictionary_create(comparefunc c, destroyfunc d, void *extra)
{
struct dictionary *ret;
TRACE("(%p, %p, %p)\n", c, d, extra);
if (!c)
return NULL;
ret = HeapAlloc(GetProcessHeap(), 0, sizeof(struct dictionary));
if (ret)
{
ret->comp = c;
ret->destroy = d;
ret->extra = extra;
ret->head = NULL;
ret->num_entries = 0;
}
TRACE("returning %p\n", ret);
return ret;
}
void dictionary_destroy(struct dictionary *d)
{
TRACE("(%p)\n", d);
if (d)
{
struct dictionary_entry *p;
for (p = d->head; p; )
{
struct dictionary_entry *next = p->next;
if (d->destroy)
d->destroy(p->key, p->value, d->extra);
HeapFree(GetProcessHeap(), 0, p);
p = next;
}
HeapFree(GetProcessHeap(), 0, d);
}
}
UINT dictionary_num_entries(struct dictionary *d)
{
return d ? d->num_entries : 0;
}
/* Returns the address of the pointer to the node containing k. (It returns
* the address of either h->head or the address of the next member of the
* prior node. It's useful when you want to delete.)
* Assumes h and prev are not NULL.
*/
static struct dictionary_entry **dictionary_find_internal(struct dictionary *d,
const void *k)
{
struct dictionary_entry **ret = NULL;
struct dictionary_entry *p;
assert(d);
/* special case for head containing the desired element */
if (d->head && d->comp(k, d->head->key, d->extra) == 0)
ret = &d->head;
for (p = d->head; !ret && p && p->next; p = p->next)
{
if (d->comp(k, p->next->key, d->extra) == 0)
ret = &p->next;
}
return ret;
}
void dictionary_insert(struct dictionary *d, const void *k, const void *v)
{
struct dictionary_entry **prior;
TRACE("(%p, %p, %p)\n", d, k, v);
if (!d)
return;
if ((prior = dictionary_find_internal(d, k)))
{
if (d->destroy)
d->destroy((*prior)->key, (*prior)->value, d->extra);
(*prior)->key = (void *)k;
(*prior)->value = (void *)v;
}
else
{
struct dictionary_entry *elem = HeapAlloc(GetProcessHeap(), 0,
sizeof(struct dictionary_entry));
if (!elem)
return;
elem->key = (void *)k;
elem->value = (void *)v;
elem->next = d->head;
d->head = elem;
d->num_entries++;
}
}
BOOL dictionary_find(struct dictionary *d, const void *k, void **value)
{
struct dictionary_entry **prior;
BOOL ret = FALSE;
TRACE("(%p, %p, %p)\n", d, k, value);
if (!d)
return FALSE;
if (!value)
return FALSE;
if ((prior = dictionary_find_internal(d, k)))
{
*value = (*prior)->value;
ret = TRUE;
}
TRACE("returning %d (%p)\n", ret, *value);
return ret;
}
void dictionary_remove(struct dictionary *d, const void *k)
{
struct dictionary_entry **prior, *temp;
TRACE("(%p, %p)\n", d, k);
if (!d)
return;
if ((prior = dictionary_find_internal(d, k)))
{
temp = *prior;
if (d->destroy)
d->destroy((*prior)->key, (*prior)->value, d->extra);
*prior = (*prior)->next;
HeapFree(GetProcessHeap(), 0, temp);
d->num_entries--;
}
}
void dictionary_enumerate(struct dictionary *d, enumeratefunc e, void *closure)
{
struct dictionary_entry *p;
TRACE("(%p, %p, %p)\n", d, e, closure);
if (!d)
return;
if (!e)
return;
for (p = d->head; p; p = p->next)
if (!e(p->key, p->value, d->extra, closure))
break;
}