1
0
Files
irix-657m-src/irix/cmd/netman/lib/index.c
2022-09-29 17:59:04 +03:00

251 lines
4.9 KiB
C

/*
* Copyright 1988 Silicon Graphics, Inc. All rights reserved.
*
* Numeric index implementation.
*/
#include <bstring.h>
#include <values.h>
#include <stdio.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include "address.h"
#include "debug.h"
#include "heap.h"
#include "index.h"
#include "macros.h"
Index *
index(int count, int keysize, struct indexops *ops)
{
Index *in;
in = new(Index);
in_init(in, count, keysize, ops);
return in;
}
void
in_destroy(Index *in)
{
in_finish(in);
delete(in);
}
void
in_create(int count, int keysize, struct indexops *ops, Index **inp)
{
if (*inp)
in_destroy(*inp);
*inp = index(count, keysize, ops);
}
/*
* Hashkey, cmpkeys, and xdrvalue operations used if an index creator doesn't
* specify its own virtual operations.
*/
#define A(cp) ((Address *)(cp))
#define UL(cp) (*(unsigned long *)(cp))
#define US(cp) (*(unsigned short *)(cp))
static unsigned int
default_hashkey(unsigned char *key, int keysize)
{
unsigned int hash;
switch (keysize) {
case sizeof(Address):
return A(key)->a_high + A(key)->a_low;
case sizeof(long):
return UL(key);
case sizeof(short):
return US(key);
case sizeof(char):
return *key;
}
hash = 0;
while (--keysize >= 0)
hash = (hash << 4) + (hash >> BITS(unsigned int) - 4) + *key++;
return hash;
}
static int
default_cmpkeys(unsigned char *key1, unsigned char *key2, int keysize)
{
switch (keysize) {
case sizeof(Address):
return A(key1)->a_high != A(key2)->a_high
|| A(key1)->a_low != A(key2)->a_low;
case sizeof(long):
return UL(key1) != UL(key2);
case sizeof(short):
return US(key1) != US(key2);
case sizeof(char):
return *key1 != *key2;
}
return bcmp(key1, key2, keysize);
}
#undef A
#undef UL
#undef US
static struct indexops default_indexops =
{ default_hashkey, default_cmpkeys, 0 };
/*
* Initialize a numeric-key hash table.
*/
static XDR freeing_xdr;
static char junk;
void
in_init(Index *in, int count, int keysize, struct indexops *ops)
{
LOG2CEIL(count, in->in_shift);
count = 1 << in->in_shift;
in->in_hashmask = count - 1;
in->in_buckets = count;
in->in_keysize = keysize;
in->in_hash = vnew(count, Entry *);
in->in_ops = (ops == 0) ? &default_indexops : ops;
bzero(in->in_hash, count * sizeof in->in_hash[0]);
#ifdef METERING
bzero(&in->in_meter, sizeof in->in_meter);
#endif
if (freeing_xdr.x_private == 0)
xdrmem_create(&freeing_xdr, &junk, sizeof junk, XDR_FREE);
}
void
in_finish(Index *in)
{
int count;
Entry **ep, *ent;
count = in->in_buckets;
for (ep = in->in_hash; --count >= 0; ep++) {
while ((ent = *ep) != 0) {
if (ent->ent_value)
in_freeval(in, ent);
*ep = ent->ent_next;
delete(ent);
}
}
delete(in->in_hash);
}
void
in_freeval(Index *in, Entry *ent)
{
in_xdrvalue(in, &freeing_xdr, &ent->ent_value, ent->ent_key);
}
/*
* Return a pointer to a pointer to the entry matching key if it exists,
* otherwise to the pointer with which key should be installed.
*/
Entry **
in_lookup(Index *in, void *key)
{
Entry **head, **ep, *ent;
METER(in->in_meter.im_searches++);
head = &in->in_hash[in_hashkey(in, key) & in->in_hashmask];
ep = head;
while ((ent = *ep) != 0) {
if (!in_cmpkeys(in, ent->ent_key, key)) {
/*
* Move ent to the front of its hash chain.
*/
*ep = ent->ent_next;
ent->ent_next = *head;
*head = ent;
METER(in->in_meter.im_hits++);
return head;
}
METER(in->in_meter.im_probes++);
ep = &ent->ent_next;
}
METER(in->in_meter.im_misses++);
return ep;
}
/*
* Add an entry for a key-value pair, using an entry pointer-pointer returned
* by a call to in_lookup(in, key). If an entry exists already, replace its
* value, otherwise create a new one.
*/
Entry *
in_add(Index *in, void *key, void *value, Entry **ep)
{
Entry *ent;
int keysize, extra;
ent = *ep;
if (ent) {
if (ent->ent_value)
in_freeval(in, ent);
ent->ent_value = value;
return ent;
}
METER(in->in_meter.im_enters++);
keysize = in->in_keysize;
extra = keysize - sizeof ent->ent_key;
ent = xnew(Entry, extra < 0 ? 0 : extra);
ent->ent_next = *ep;
ent->ent_value = value;
bcopy(key, ent->ent_key, keysize);
*ep = ent;
return ent;
}
/*
* Remove an entry given a pointer to the hash chain link that points at it.
*/
void
in_delete(Index *in, Entry **ep)
{
Entry *ent;
ent = *ep;
if (ent == 0)
return;
METER(in->in_meter.im_removes++);
if (ent->ent_value)
in_freeval(in, ent);
*ep = ent->ent_next;
delete(ent);
}
/*
* Return the value associated with key, or null no entry for key exists.
*/
void *
in_match(Index *in, void *key)
{
Entry *ent;
ent = *in_lookup(in, key);
if (ent)
return ent->ent_value;
return 0;
}
/*
* Add an entry for key and value, or update key's existing entry with value.
*/
Entry *
in_enter(Index *in, void *key, void *value)
{
return in_add(in, key, value, in_lookup(in, key));
}
/*
* Remove key's entry if it exists.
*/
void
in_remove(Index *in, void *key)
{
in_delete(in, in_lookup(in, key));
}