327 lines
7.0 KiB
C
327 lines
7.0 KiB
C
|
/*
|
||
|
* Copyright (c) 2000-2001
|
||
|
* The Regents of the University of California. All rights reserved.
|
||
|
*
|
||
|
* Redistribution and use in source and binary forms, with or without
|
||
|
* modification, are permitted provided that the following conditions
|
||
|
* are met:
|
||
|
* 1. Redistributions of source code must retain the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer.
|
||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer in the
|
||
|
* documentation and/or other materials provided with the distribution.
|
||
|
* 3. Neither the name of the University nor the names of its contributors
|
||
|
* may be used to endorse or promote products derived from this software
|
||
|
* without specific prior written permission.
|
||
|
*
|
||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||
|
* SUCH DAMAGE.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include <assert.h>
|
||
|
#include "jcollection.h"
|
||
|
#include "hashset.h"
|
||
|
#include "termhash.h"
|
||
|
|
||
|
|
||
|
/*
|
||
|
static term_hash jcoll_hash;
|
||
|
*/
|
||
|
|
||
|
struct jcoll_dict
|
||
|
{
|
||
|
region r;
|
||
|
term_hash hash;
|
||
|
get_stamp_fn_ptr get_stamp;
|
||
|
};
|
||
|
|
||
|
enum jcoll_type
|
||
|
{
|
||
|
j_single,
|
||
|
j_chain,
|
||
|
j_join
|
||
|
};
|
||
|
|
||
|
/* generic jcoll type */
|
||
|
struct jcoll
|
||
|
{
|
||
|
enum jcoll_type type;
|
||
|
stamp st;
|
||
|
};
|
||
|
|
||
|
struct jcoll_single
|
||
|
{
|
||
|
enum jcoll_type type;
|
||
|
stamp st;
|
||
|
gen_e entry;
|
||
|
};
|
||
|
|
||
|
struct jcoll_chain
|
||
|
{
|
||
|
enum jcoll_type type;
|
||
|
stamp st;
|
||
|
gen_e_list sameregion entries;
|
||
|
};
|
||
|
|
||
|
struct jcoll_join
|
||
|
{
|
||
|
enum jcoll_type type;
|
||
|
stamp st;
|
||
|
jcoll_list sameregion joins;
|
||
|
gen_e_list sameregion cache;
|
||
|
};
|
||
|
|
||
|
typedef struct jcoll_single *jcoll_single;
|
||
|
typedef struct jcoll_chain *jcoll_chain;
|
||
|
typedef struct jcoll_join *jcoll_join;
|
||
|
|
||
|
DEFINE_LIST(jcoll_list,jcoll)
|
||
|
|
||
|
|
||
|
|
||
|
jcoll jcoll_new(jcoll_dict d, gen_e e)
|
||
|
{
|
||
|
jcoll_single result = ralloc(d->r, struct jcoll_single);
|
||
|
result->type = j_single;
|
||
|
result->st = stamp_fresh();
|
||
|
result->entry = e;
|
||
|
return (jcoll)result;
|
||
|
}
|
||
|
|
||
|
jcoll jcoll_jjoin(jcoll_dict d,jcoll_list list)
|
||
|
{
|
||
|
|
||
|
if (jcoll_list_empty(list))
|
||
|
return NULL;
|
||
|
else if (jcoll_list_length(list) == 1)
|
||
|
return jcoll_list_head(list);
|
||
|
|
||
|
else
|
||
|
{
|
||
|
int i = 0,
|
||
|
length = jcoll_list_length(list) + 1;
|
||
|
stamp sts[length];
|
||
|
jcoll_join result;
|
||
|
|
||
|
jcoll_list_scanner scan;
|
||
|
jcoll temp;
|
||
|
|
||
|
sts[i++] = j_join;
|
||
|
|
||
|
jcoll_list_scan(list,&scan);
|
||
|
while (jcoll_list_next(&scan,&temp))
|
||
|
{
|
||
|
stamp st = temp ? temp->st : 0;
|
||
|
sts[i++] = st;
|
||
|
}
|
||
|
qsort(&sts[1],length-1,sizeof(int),ptr_cmp);
|
||
|
|
||
|
if ( NULL == (result = (jcoll_join)term_hash_find(d->hash,sts,length)) )
|
||
|
{
|
||
|
result = ralloc(d->r,struct jcoll_join);
|
||
|
|
||
|
result->type = j_join;
|
||
|
result->st = stamp_fresh();
|
||
|
result->joins = list;
|
||
|
result->cache = new_gen_e_list(d->r);
|
||
|
term_hash_insert(d->hash,(gen_e)result,sts,length);
|
||
|
}
|
||
|
return (jcoll)result;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Hash chains
|
||
|
*/
|
||
|
jcoll jcoll_create_chain(jcoll_dict d, gen_e_list elems)
|
||
|
{
|
||
|
int i = 0,
|
||
|
length = gen_e_list_length(elems) + 1;
|
||
|
stamp sts[length];
|
||
|
gen_e_list_scanner scan;
|
||
|
gen_e temp;
|
||
|
jcoll_chain result;
|
||
|
|
||
|
sts[i++] = j_chain;
|
||
|
|
||
|
gen_e_list_scan(elems,&scan);
|
||
|
while (gen_e_list_next(&scan,&temp))
|
||
|
{
|
||
|
sts[i++] = d->get_stamp(temp);
|
||
|
}
|
||
|
qsort(&sts[1],length-1,sizeof(int),ptr_cmp); /* FIX, first pos should always be chain */
|
||
|
|
||
|
if ( NULL == (result = (jcoll_chain)term_hash_find(d->hash,sts,length)) )
|
||
|
{
|
||
|
result = ralloc(d->r,struct jcoll_chain);
|
||
|
result->type = j_chain;
|
||
|
result->st = stamp_fresh();
|
||
|
result->entries = elems;
|
||
|
term_hash_insert(d->hash,(gen_e)result,sts,
|
||
|
length);
|
||
|
}
|
||
|
return (jcoll)result;
|
||
|
}
|
||
|
|
||
|
typedef void (*japp_fn_ptr) (void *, void *);
|
||
|
|
||
|
static void app_aux(hash_set h, get_stamp_fn_ptr get_stamp, japp_fn_ptr app,
|
||
|
jcoll j, void *data)
|
||
|
{
|
||
|
if (! j)
|
||
|
return;
|
||
|
|
||
|
switch(j->type)
|
||
|
{
|
||
|
case j_single:
|
||
|
{
|
||
|
jcoll_single single = (jcoll_single) j;
|
||
|
|
||
|
if (! hs_member(h,get_stamp(single->entry)) )
|
||
|
app(single->entry, data);
|
||
|
}
|
||
|
break;
|
||
|
case j_chain:
|
||
|
{
|
||
|
jcoll_chain chain = (jcoll_chain) j;
|
||
|
|
||
|
if (! hs_member(h,chain->st) )
|
||
|
{
|
||
|
gen_e_list_scanner scan;
|
||
|
gen_e entry;
|
||
|
|
||
|
gen_e_list_scan(chain->entries, &scan);
|
||
|
while (gen_e_list_next(&scan, &entry))
|
||
|
{
|
||
|
if (! hs_member(h, get_stamp(entry)) )
|
||
|
app(entry, data);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
break;
|
||
|
case j_join:
|
||
|
{
|
||
|
jcoll_join join = (jcoll_join) j;
|
||
|
|
||
|
if (! hs_member(h, join->st))
|
||
|
{
|
||
|
if (! gen_e_list_empty(join->cache))
|
||
|
{
|
||
|
gen_e_list_scanner scan;
|
||
|
gen_e entry;
|
||
|
|
||
|
gen_e_list_scan(join->cache, &scan);
|
||
|
while (gen_e_list_next(&scan, &entry))
|
||
|
{
|
||
|
if (! hs_member(h, get_stamp(entry)) )
|
||
|
app(entry, data);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
jcoll_list_scanner scan;
|
||
|
jcoll temp;
|
||
|
|
||
|
jcoll_list_scan(join->joins, &scan);
|
||
|
while (jcoll_list_next(&scan,&temp))
|
||
|
{
|
||
|
app_aux(h,get_stamp,app,temp, data);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
static void jcoll_app(jcoll_dict d, japp_fn_ptr app, jcoll j, void *data) deletes
|
||
|
{
|
||
|
region scratch_rgn = newregion();
|
||
|
hash_set hash = hs_create(scratch_rgn);
|
||
|
app_aux(hash,d->get_stamp, app, j, data);
|
||
|
hs_delete(hash);
|
||
|
deleteregion(scratch_rgn);
|
||
|
}
|
||
|
static void jcoll_accum(void *e, void *accum)
|
||
|
{
|
||
|
gen_e_list_cons((gen_e) e, (gen_e_list) accum);
|
||
|
}
|
||
|
|
||
|
gen_e_list jcoll_flatten(jcoll_dict d, jcoll j) deletes
|
||
|
{
|
||
|
|
||
|
gen_e_list accum = NULL;
|
||
|
|
||
|
|
||
|
if (j == NULL)
|
||
|
return new_gen_e_list(d->r);
|
||
|
|
||
|
switch (j->type)
|
||
|
{
|
||
|
case j_single:
|
||
|
{
|
||
|
jcoll_single single = (jcoll_single)j;
|
||
|
|
||
|
accum = new_gen_e_list(d->r);
|
||
|
gen_e_list_cons(single->entry,accum);
|
||
|
}
|
||
|
break;
|
||
|
case j_chain:
|
||
|
{
|
||
|
jcoll_chain chain = (jcoll_chain)j;
|
||
|
/* accum = gen_e_list_copy(r,chain->entries); */
|
||
|
accum = chain->entries;
|
||
|
}
|
||
|
break;
|
||
|
case j_join:
|
||
|
{
|
||
|
jcoll_join join = (jcoll_join)j;
|
||
|
|
||
|
if (! gen_e_list_empty(join->cache))
|
||
|
return join->cache;
|
||
|
else
|
||
|
{
|
||
|
accum = new_gen_e_list(d->r);
|
||
|
jcoll_app(d, jcoll_accum,j, accum);
|
||
|
|
||
|
gen_e_list_append(join->cache,accum /* gen_e_list_copy(r,accum)*/);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return accum;
|
||
|
}
|
||
|
|
||
|
jcoll_dict jcoll_create_dict(region r,get_stamp_fn_ptr get_stamp)
|
||
|
{
|
||
|
jcoll_dict result = ralloc(r,struct jcoll_dict);
|
||
|
|
||
|
result->r = r;
|
||
|
result->hash = make_term_hash(r);
|
||
|
result->get_stamp = get_stamp;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
void jcoll_delete_dict(jcoll_dict d)
|
||
|
{
|
||
|
term_hash_delete(d->hash);
|
||
|
}
|