/*
 * $RCSfile: idmap_templ.c,v $
 *
 * x-kernel v3.3
 *
 * Copyright (c) 1993,1991,1990,1996  Arizona Board of Regents
 *
 * $Log: idmap_templ.c,v $
 * Revision 1.2  1996/01/29 20:05:05  slm
 * Updated copyright and version.
 *
 * Revision 1.1  1995/07/28  21:47:49  slm
 * Initial revision
 *
 * Revision 1.19.4.2  1994/10/27  21:11:20  hkaram
 * Davids New Version
 *
 * Revision 1.1  1994/10/03  19:45:42  davidm
 * Initial revision
 *
 * Revision 1.19  1993/12/13  20:37:03  menze
 * Modifications from UMass:
 *
 *   [ 93/10/21          nahum ]
 *   Expanded out test for zero to get GCC 2.4.5 to stop whining.
 */
/*
 * The list of macros that need to be defined before including this file can
 * be found at the end of this file.
 */

#ifdef BIND_NAME

SCLASS Binding
BIND_NAME(m, key KEY_SIZE_ARG, value)
Map  m;
VOID *key;
KEY_SIZE_DECL
VOID *value;
{
    struct map_bucket *bucket;
    Binding elem, new_elem;

    bucket = &m->buckets[HASH(m, key)];

    elem = bucket->first;
    while (elem) {
	if (KEY_MATCH(elem, key)) {
	    if (elem->value == value)
		return elem;		/* (key,value) already bound */
	    else
		return ERR_BIND;	/* (key,???) already bound */
	} /* if */
	elem = elem->next;
    } /* while */

    GET_EL(m, new_elem);

    new_elem->value = value;
    SET_KEY(new_elem, key);

    new_elem->next = bucket->first;
    bucket->first = new_elem;

    m->cache = new_elem;

    if (!bucket->next) {
	/* insert this bucket into non-empty bucket list: */
	bucket->next = m->chain.next;
	m->chain.next = bucket;
    } /* if */
    return new_elem;
} /* BIND_NAME */

#endif /* BIND_NAME */

#ifdef RESOLVE_NAME

SCLASS XkReturn
RESOLVE_NAME(m, key KEY_SIZE_ARG, valuep)
Map  m;
VOID *key;
KEY_SIZE_DECL
VOID **valuep;
{
    XkReturn r = XK_FAILURE;
    Binding elem;

    elem = m->cache;
    if (elem && KEY_MATCH(elem, key) PREDICT_TRUE) {
	/* cache-hit: */
	if (valuep)
	    *valuep = elem->value;
	r = XK_SUCCESS;
    }
    else {
	elem = m->buckets[HASH(m, key)].first;
	while (elem) {
	    if (KEY_MATCH(elem, key)) {
		m->cache = elem;
		if (valuep)
		    *valuep = elem->value;
		r = XK_SUCCESS;
		break;
	    } /* if */
	    elem = elem->next;
	} /* while */
    } /* if */
    return r;
} /* RESOLVE_NAME */

#endif /* RESOLVE_NAME */

#ifdef UNBIND_NAME

/* UNBIND -- remove an entry based on the key->value pair */
SCLASS XkReturn
UNBIND_NAME(m, key KEY_SIZE_ARG)
Map  m;
VOID *key;
KEY_SIZE_DECL
{
    struct map_bucket *bucket;
    Binding elem, *prev_elem;

    bucket = &m->buckets[HASH(m, key)];
    prev_elem = &bucket->first;
    elem = bucket->first;
    m->cache = 0;
    while (elem) {
	if (KEY_MATCH(elem, key)) {
	    *prev_elem = elem->next;	/* remove ELEM from list */
	    FREE_EL(m, elem);
	    return XK_SUCCESS;
	} /* if */
	prev_elem = &elem->next;
	elem = elem->next;
    } /* if */
    return XK_FAILURE;
} /* UNBIND_NAME */

#endif /* UNBIND_NAME */

#ifdef REMOVE_NAME

/* REMOVE -- remove an entry based on the binding */
static XkReturn
REMOVE_NAME(m, b)
Map     m;
Binding b;
{
    struct map_bucket *bucket;
    Binding elem, *prev_elem;

    bucket = &m->buckets[HASH_EL(m, b)];
    prev_elem = &bucket->first;
    elem = bucket->first;
    m->cache = 0;
    while (elem) {
	if (elem == b) {
	    *prev_elem = elem->next;	/* remove ELEM from list */
	    FREE_EL(m, elem);
	    return XK_SUCCESS;
	} /* if */
	prev_elem = &elem->next;
	elem = elem->next;
    } /* while */
    return XK_FAILURE;
} /* REMOVE_NAME */

#endif /* REMOVE_NAME */

#ifdef INIT_NAME

static INLINE void
INIT_NAME(mf)
struct map_functions *mf;
{
#ifdef BIND_NAME
    mf->bind    = BIND_NAME;
#endif
#ifdef REMOVE_NAME
    mf->remove  = REMOVE_NAME;
#endif
#ifdef RESOLVE_NAME
    mf->resolve = RESOLVE_NAME;
#endif
#ifdef UNBIND_NAME
    mf->unbind  = UNBIND_NAME;
#endif
} /* INIT_NAME */

#endif /* INIT_NAME */

#undef BIND_NAME
#undef REMOVE_NAME
#undef RESOLVE_NAME
#undef UNBIND_NAME
#undef INIT_NAME
#undef SCLASS
#undef GET_EL
#undef FREE_EL
#undef HASH
#undef HASH_EL
#undef KEY_SIZE_DECL
#undef KEY_SIZE_ARG
#undef KEY_MATCH
#undef SET_KEY
