Files
Arquivotheca.Solaris-2.5/lib/fn/libxfn/Set.cc
seta75D 7c4988eac0 Init
2021-10-11 19:38:01 -03:00

265 lines
3.8 KiB
C++
Executable File

/*
* Copyright (c) 1992 - 1994 by Sun Microsystems, Inc.
*/
#pragma ident "@(#)Set.cc 1.3 94/08/04 SMI"
#include <memory.h>
#include "Set.hh"
#define MOD 19
SetItem::~SetItem()
{
}
Set::Set(int case_sense)
{
item_count = 0;
//first_item = 0;
if ((item_tab = new SetItem *[MOD])) {
memset(item_tab, 0, sizeof (item_tab[0]) * MOD);
item_tab_mod = MOD;
}
p_case_sense = case_sense;
}
void
Set::__delete_all()
{
SetItem *p, *np;
int i;
if (item_tab) {
for (i = 0; i < item_tab_mod; ++i) {
for (p = item_tab[i]; p; p = np) {
np = p->next;
delete p;
}
}
delete[] item_tab;
}
}
Set::~Set()
{
__delete_all();
}
/*
* head is set to the prev node or start of hash chain if not found.
*/
SetItem *
Set::__locate(SetItem *n, SetItem **&head, unsigned long &bucket)
{
SetItem *i, *p;
bucket = n->key_hash() % item_tab_mod;
head = &item_tab[bucket];
for (p = 0, i = *head; i; i = i->next) {
if (i->item_match(*n, p_case_sense)) {
if (p)
head = &p->next;
return (i);
}
p = i;
}
return (0);
}
/*
* this won't return the correct head if the set is empty
* don't use this for selecting a bucket for insert.
*/
SetItem *
Set::__locate(const void *key, SetItem **&head)
{
SetItem *n, *i, *p;
for (int j = 0; j < item_tab_mod; ++j) {
if ((n = item_tab[j]))
break;
}
if (j == item_tab_mod) {
head = 0;
return (0);
}
head = &item_tab[n->key_hash(key) % item_tab_mod];
for (p = 0, i = *head; i; i = i->next) {
if (i->key_match(key, p_case_sense)) {
if (p)
head = &p->next;
return (i);
}
p = i;
}
return (0);
}
void
Set::__copy(const Set& s)
{
SetItem *p, *pn, *n;
item_count = s.item_count;
int b;
if ((item_tab = new SetItem *[MOD])) {
memset(item_tab, 0, sizeof (item_tab[0]) * MOD);
item_tab_mod = MOD;
}
if (item_tab == 0 || s.item_tab == 0)
return;
for (b = 0; b < s.item_tab_mod; ++b) {
if (s.item_tab[b]) {
for (p = s.item_tab[b], pn = n = 0; p;
p = p->next, pn = n) {
n = p->copy();
if (pn)
pn->next = n;
else
item_tab[b] = n;
}
n->next = 0;
} else
item_tab[b] = 0;
}
}
Set::Set(const Set& s)
{
__copy(s);
}
Set &
Set::operator=(const Set& s)
{
if (&s != this) {
__delete_all();
__copy(s);
}
return (*this);
}
unsigned
Set::count() const
{
return (item_count);
}
const SetItem *
Set::first(void *&iter_pos)
{
SetItem *n;
if (item_tab) {
n = 0;
for (int j = 0; j < item_tab_mod; ++j) {
if ((n = item_tab[j]))
break;
}
iter_pos = n;
return ((SetItem *)n);
}
return (0);
}
const SetItem *
Set::next(void *&iter_pos)
{
SetItem *p;
if (iter_pos == 0)
return (0);
SetItem **h;
unsigned long bucket;
/*
* Walk all nodes on all lists.
*/
p = (SetItem *)iter_pos;
if (p->next) {
iter_pos = p->next;
return (p->next);
}
/*
* When we hit the last node on a list, jump to head of next list.
* We need to figure out which list the current node is on so that
* we can select the next list.
*/
__locate(p, h, bucket);
while (++bucket < item_tab_mod) {
if (item_tab[bucket]) {
iter_pos = item_tab[bucket];
return (item_tab[bucket]);
}
}
return (0);
}
SetItem *
Set::get(const void *key)
{
SetItem **h;
return (__locate(key, h));
}
int
Set::add(SetItem* n, unsigned int exclusive)
{
SetItem *i, **h;
if (exclusive == FN_OP_EXCLUSIVE) {
unsigned long bucket;
if (__locate(n, h, bucket)) {
delete n;
return (0);
}
n->next = *h;
*h = n;
} else {
// add replace (supercede)
unsigned long bucket;
if ((i = __locate(n, h, bucket))) {
n->next = i->next;
*h = n;
delete i;
return (1);
}
n->next = *h;
*h = n;
}
item_count++;
return (1);
}
int
Set::remove(const void *key)
{
SetItem *i;
SetItem **h;
if ((i = __locate(key, h))) {
*h = i->next;
--item_count;
delete i;
return (1);
}
return (0);
}