more packages stuff
This commit is contained in:
427
packages/PLStream/pl-table.c
Normal file
427
packages/PLStream/pl-table.c
Normal file
@@ -0,0 +1,427 @@
|
||||
/* $Id$
|
||||
|
||||
Part of SWI-Prolog
|
||||
|
||||
Author: Jan Wielemaker
|
||||
E-mail: jan@swi.psy.uva.nl
|
||||
WWW: http://www.swi-prolog.org
|
||||
Copyright (C): 1985-2002, University of Amsterdam
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*#define O_DEBUG 1*/
|
||||
#include "pl-incl.h"
|
||||
#ifdef O_PLMT
|
||||
#define LOCK_TABLE(t) if ( t->mutex ) simpleMutexLock(t->mutex)
|
||||
#define UNLOCK_TABLE(t) if ( t->mutex ) simpleMutexUnlock(t->mutex)
|
||||
#else
|
||||
#define LOCK_TABLE(t) (void)0
|
||||
#define UNLOCK_TABLE(t) (void)0
|
||||
#endif
|
||||
|
||||
static inline Symbol rawAdvanceTableEnum(TableEnum e);
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
This file provides generic hash-tables. Most of the implementation is
|
||||
rather straightforward. Special are the *TableEnum() functions to
|
||||
create, advance over and destroy enumerator objects. These objects are
|
||||
used to enumerate the symbols of these tables, used primarily for the
|
||||
pl_current_* predicates.
|
||||
|
||||
The enumerators cause two things: (1) as intptr_t enumerators are
|
||||
associated, the table will not be rehashed and (2) if symbols are
|
||||
deleted that are referenced by an enumerator, the enumerator is
|
||||
automatically advanced to the next free symbol. This, in general, makes
|
||||
the enumeration of hash-tables safe.
|
||||
|
||||
TODO: abort should delete any pending enumerators. This should be
|
||||
thread-local, as thread_exit/1 should do the same.
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
static void
|
||||
allocHTableEntries(Table ht)
|
||||
{ int n;
|
||||
Symbol *p;
|
||||
|
||||
ht->entries = allocHeap(ht->buckets * sizeof(Symbol));
|
||||
|
||||
for(n=0, p = &ht->entries[0]; n < ht->buckets; n++, p++)
|
||||
*p = NULL;
|
||||
}
|
||||
|
||||
|
||||
Table
|
||||
newHTable(int buckets)
|
||||
{ Table ht;
|
||||
|
||||
ht = allocHeap(sizeof(struct table));
|
||||
ht->buckets = (buckets & ~TABLE_MASK);
|
||||
ht->size = 0;
|
||||
ht->enumerators = NULL;
|
||||
ht->free_symbol = NULL;
|
||||
ht->copy_symbol = NULL;
|
||||
#ifdef O_PLMT
|
||||
if ( (buckets & TABLE_UNLOCKED) )
|
||||
ht->mutex = NULL;
|
||||
else
|
||||
{ ht->mutex = allocHeap(sizeof(simpleMutex));
|
||||
simpleMutexInit(ht->mutex);
|
||||
}
|
||||
#endif
|
||||
|
||||
allocHTableEntries(ht);
|
||||
return ht;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
destroyHTable(Table ht)
|
||||
{
|
||||
#ifdef O_PLMT
|
||||
if ( ht->mutex )
|
||||
{ simpleMutexDelete(ht->mutex);
|
||||
freeHeap(ht->mutex, sizeof(*ht->mutex));
|
||||
ht->mutex = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
clearHTable(ht);
|
||||
freeHeap(ht->entries, ht->buckets * sizeof(Symbol));
|
||||
freeHeap(ht, sizeof(struct table));
|
||||
}
|
||||
|
||||
|
||||
#if O_DEBUG || O_HASHSTAT
|
||||
#define HASHSTAT(c) c
|
||||
static int lookups;
|
||||
static int cmps;
|
||||
|
||||
void
|
||||
exitTables(int status, void *arg)
|
||||
{ Sdprintf("hashstat: Anonymous tables: %d lookups using %d compares\n",
|
||||
lookups, cmps);
|
||||
}
|
||||
#else
|
||||
#define HASHSTAT(c)
|
||||
#endif /*O_DEBUG*/
|
||||
|
||||
|
||||
void
|
||||
initTables()
|
||||
{ static int done = FALSE;
|
||||
|
||||
if ( !done )
|
||||
{ done = TRUE;
|
||||
|
||||
HASHSTAT(PL_on_halt(exitTables, NULL));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Symbol
|
||||
lookupHTable(Table ht, void *name)
|
||||
{ Symbol s = ht->entries[pointerHashValue(name, ht->buckets)];
|
||||
|
||||
HASHSTAT(lookups++);
|
||||
for( ; s; s = s->next)
|
||||
{ HASHSTAT(cmps++);
|
||||
if ( s->name == name )
|
||||
return s;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef O_DEBUG
|
||||
void
|
||||
checkHTable(Table ht)
|
||||
{ int i;
|
||||
int n = 0;
|
||||
|
||||
for(i=0; i<ht->buckets; i++)
|
||||
{ Symbol s;
|
||||
|
||||
for(s=ht->entries[i]; s; s=s->next)
|
||||
{ assert(lookupHTable(ht, s->name) == s);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
assert(n == ht->size);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* MT: Locked by calling addHTable()
|
||||
*/
|
||||
|
||||
static void
|
||||
rehashHTable(Table ht)
|
||||
{ Symbol *oldtab;
|
||||
int oldbucks;
|
||||
int i;
|
||||
|
||||
oldtab = ht->entries;
|
||||
oldbucks = ht->buckets;
|
||||
ht->buckets *= 2;
|
||||
allocHTableEntries(ht);
|
||||
|
||||
DEBUG(1, Sdprintf("Rehashing table %p to %d entries\n", ht, ht->buckets));
|
||||
|
||||
for(i=0; i<oldbucks; i++)
|
||||
{ Symbol s, n;
|
||||
|
||||
for(s=oldtab[i]; s; s = n)
|
||||
{ int v = (int)pointerHashValue(s->name, ht->buckets);
|
||||
|
||||
n = s->next;
|
||||
s->next = ht->entries[v];
|
||||
ht->entries[v] = s;
|
||||
}
|
||||
}
|
||||
|
||||
freeHeap(oldtab, oldbucks * sizeof(Symbol));
|
||||
DEBUG(0, checkHTable(ht));
|
||||
}
|
||||
|
||||
|
||||
Symbol
|
||||
addHTable(Table ht, void *name, void *value)
|
||||
{ Symbol s;
|
||||
int v;
|
||||
|
||||
LOCK_TABLE(ht);
|
||||
v = (int)pointerHashValue(name, ht->buckets);
|
||||
if ( lookupHTable(ht, name) )
|
||||
{ UNLOCK_TABLE(ht);
|
||||
return NULL;
|
||||
}
|
||||
s = allocHeap(sizeof(struct symbol));
|
||||
s->name = name;
|
||||
s->value = value;
|
||||
s->next = ht->entries[v];
|
||||
ht->entries[v] = s;
|
||||
ht->size++;
|
||||
DEBUG(9, Sdprintf("addHTable(0x%x, 0x%x, 0x%x) --> size = %d\n",
|
||||
ht, name, value, ht->size));
|
||||
|
||||
if ( ht->buckets * 2 < ht->size && !ht->enumerators )
|
||||
rehashHTable(ht);
|
||||
UNLOCK_TABLE(ht);
|
||||
|
||||
DEBUG(1, checkHTable(ht));
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Note: s must be in the table!
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
void
|
||||
deleteSymbolHTable(Table ht, Symbol s)
|
||||
{ int v;
|
||||
Symbol *h;
|
||||
TableEnum e;
|
||||
|
||||
LOCK_TABLE(ht);
|
||||
v = (int)pointerHashValue(s->name, ht->buckets);
|
||||
h = &ht->entries[v];
|
||||
|
||||
for( e=ht->enumerators; e; e = e->next )
|
||||
{ if ( e->current == s )
|
||||
rawAdvanceTableEnum(e);
|
||||
}
|
||||
|
||||
for( ; *h; h = &(*h)->next )
|
||||
{ if ( *h == s )
|
||||
{ *h = (*h)->next;
|
||||
|
||||
freeHeap(s, sizeof(struct symbol));
|
||||
ht->size--;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UNLOCK_TABLE(ht);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
clearHTable(Table ht)
|
||||
{ int n;
|
||||
TableEnum e;
|
||||
|
||||
LOCK_TABLE(ht);
|
||||
for( e=ht->enumerators; e; e = e->next )
|
||||
{ e->current = NULL;
|
||||
e->key = ht->buckets;
|
||||
}
|
||||
|
||||
for(n=0; n < ht->buckets; n++)
|
||||
{ Symbol s, q;
|
||||
|
||||
for(s = ht->entries[n]; s; s = q)
|
||||
{ q = s->next;
|
||||
|
||||
if ( ht->free_symbol )
|
||||
(*ht->free_symbol)(s);
|
||||
|
||||
freeHeap(s, sizeof(struct symbol));
|
||||
}
|
||||
|
||||
ht->entries[n] = NULL;
|
||||
}
|
||||
|
||||
ht->size = 0;
|
||||
UNLOCK_TABLE(ht);
|
||||
}
|
||||
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Table copyHTable(Table org)
|
||||
Make a copy of a hash-table. This is used to realise the copy-on-write
|
||||
as defined by SharedTable. The table is copied to have exactly the
|
||||
same dimensions as the original. If the copy_symbol function is
|
||||
provided, it is called to allow duplicating the symbols name or value
|
||||
fields.
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
Table
|
||||
copyHTable(Table org)
|
||||
{ Table ht;
|
||||
int n;
|
||||
|
||||
ht = allocHeap(sizeof(struct table));
|
||||
LOCK_TABLE(org);
|
||||
*ht = *org; /* copy all attributes */
|
||||
#ifdef O_PLMT
|
||||
ht->mutex = NULL;
|
||||
#endif
|
||||
allocHTableEntries(ht);
|
||||
|
||||
for(n=0; n < ht->buckets; n++)
|
||||
{ Symbol s, *q;
|
||||
|
||||
q = &ht->entries[n];
|
||||
for(s = org->entries[n]; s; s = s->next)
|
||||
{ Symbol s2 = allocHeap(sizeof(*s2));
|
||||
|
||||
*q = s2;
|
||||
q = &s2->next;
|
||||
s2->name = s->name;
|
||||
s2->value = s->value;
|
||||
|
||||
if ( ht->copy_symbol )
|
||||
(*ht->copy_symbol)(s2);
|
||||
}
|
||||
*q = NULL;
|
||||
}
|
||||
#ifdef O_PLMT
|
||||
if ( org->mutex )
|
||||
{ ht->mutex = allocHeap(sizeof(simpleMutex));
|
||||
simpleMutexInit(ht->mutex);
|
||||
}
|
||||
#endif
|
||||
UNLOCK_TABLE(org);
|
||||
|
||||
return ht;
|
||||
}
|
||||
|
||||
|
||||
/*******************************
|
||||
* ENUMERATING *
|
||||
*******************************/
|
||||
|
||||
TableEnum
|
||||
newTableEnum(Table ht)
|
||||
{ TableEnum e = allocHeap(sizeof(struct table_enum));
|
||||
Symbol n;
|
||||
|
||||
LOCK_TABLE(ht);
|
||||
e->table = ht;
|
||||
e->key = 0;
|
||||
e->next = ht->enumerators;
|
||||
ht->enumerators = e;
|
||||
|
||||
n = ht->entries[0];
|
||||
while(!n && ++e->key < ht->buckets)
|
||||
n=ht->entries[e->key];
|
||||
e->current = n;
|
||||
UNLOCK_TABLE(ht);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
freeTableEnum(TableEnum e)
|
||||
{ TableEnum *ep;
|
||||
Table ht;
|
||||
|
||||
if ( !e )
|
||||
return;
|
||||
|
||||
ht = e->table;
|
||||
LOCK_TABLE(ht);
|
||||
for( ep=&ht->enumerators; *ep ; ep = &(*ep)->next )
|
||||
{ if ( *ep == e )
|
||||
{ *ep = (*ep)->next;
|
||||
|
||||
freeHeap(e, sizeof(*e));
|
||||
break;
|
||||
}
|
||||
}
|
||||
UNLOCK_TABLE(ht);
|
||||
}
|
||||
|
||||
|
||||
static inline Symbol
|
||||
rawAdvanceTableEnum(TableEnum e)
|
||||
{ Symbol s, n;
|
||||
Table ht = e->table;
|
||||
|
||||
if ( !(s = e->current) )
|
||||
return s;
|
||||
n = s->next;
|
||||
|
||||
while(!n)
|
||||
{ if ( ++e->key >= ht->buckets )
|
||||
{ e->current = NULL;
|
||||
return s;
|
||||
}
|
||||
|
||||
n=ht->entries[e->key];
|
||||
}
|
||||
e->current = n;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
Symbol
|
||||
advanceTableEnum(TableEnum e)
|
||||
{ Symbol s;
|
||||
#ifdef O_PLMT
|
||||
Table ht = e->table;
|
||||
#endif
|
||||
|
||||
LOCK_TABLE(ht);
|
||||
s = rawAdvanceTableEnum(e);
|
||||
UNLOCK_TABLE(ht);
|
||||
|
||||
return s;
|
||||
}
|
Reference in New Issue
Block a user