/* This file is part of cqual.
   Copyright (C) 2003 The Regents of the University of California.

cqual is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

cqual 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with cqual; see the file COPYING.  If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */

#ifndef TYPED_HASHSET_H
#define TYPED_HASHSET_H

#include "hash.h"
#include <regions.h>
#include "bool.h"

#if 0
#define DECLARE_HASHSET(name,element_type) \
static bool name ## _eqfn(element_type l, element_type r); \
static inline name empty_ ## name(region r); \
static inline name name ## _copy(region r, name s); \
static inline bool name ## _empty(name s); \
static inline bool name ## _member(name s, element_type elt); \
static inline bool name ## _hash_search(name s, \
                                        bool (*eqfn)(element_type, element_type), \
                                        element_type k, element_type *d); \
static inline unsigned long name ## _size(name s); \
static inline bool name ## _insert(region r, name *s, element_type elt); \
static inline void name ## _remove(name *s, element_type elt); \
static inline bool name ## _single(name s); \
static inline void name ## _scan(name s, name ## _scanner *ss); \
static inline element_type name ## _next(name ## _scanner *ss); \
static inline name name ## _union(name s1, name s2);
#endif

#define DEFINE_HASHSET(name,cmp_fn,hash_func,element_type) \
typedef struct { hash_table ht; } * name; \
typedef struct { hash_table_scanner hts; } name ## _scanner; \
static inline bool name ## _eqfn(element_type l, element_type r) { return cmp_fn(l,r) == 0; } \
static inline name empty_ ## name(region r) { return (name) make_hash_table(r, 16, (hash_fn) hash_func, (keyeq_fn) name ## _eqfn); } \
static inline name name ## _copy(region r, name s) { return (name) hash_table_copy(r, (hash_table) s); } \
static inline bool name ## _empty(name s) { return hash_table_size((hash_table) s) == 0; } \
static inline bool name ## _member(name s, element_type elt) { element_type dummy; return hash_table_lookup((hash_table) s, (hash_key) elt, (hash_data*) &dummy); } \
static inline bool name ## _hash_search(name s, bool (*eqfn)(element_type, element_type), element_type k, element_type *d) { return hash_table_hash_search((hash_table)s, (keyeq_fn)eqfn, (hash_key)k, (hash_data*)d); } \
static inline unsigned long name ## _size(name s) { return hash_table_size((hash_table) s); } \
static inline bool name ## _insert(region r, name *s, element_type elt) { return hash_table_insert((hash_table) *s, (hash_key) elt, (hash_data) elt); } \
static inline void name ## _remove(name *s, element_type elt) { hash_table_remove((hash_table) *s, (hash_key) elt); } \
static inline bool name ## _single(name s) { return name ## _size(s) == 1; } \
static inline void name ## _scan(name s, name ## _scanner *ss) { hash_table_scan((hash_table) s, &ss->hts); } \
static inline element_type name ## _next(name ## _scanner *ss) { element_type result; int dummy; if (hash_table_next(&ss->hts, (hash_key *) &result, (hash_data *) &dummy)) return result; return NULL; } \
static inline name name ## _union(name s1, name s2) { name ## _scanner ss; element_type elt; name ## _scan (s2, &ss); while ((elt = name ## _next (&ss))) name ## _insert (NULL, &s1, elt); return s1; }

#endif
