1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
|
/*
* Copyright (C) 2002,2003 Daniel Heck
*
* This program 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
* of the License, or (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef ECL_DICT_HH
#define ECL_DICT_HH
#include "ecl_error.hh"
#include <utility>
#include <cstddef>
namespace ecl
{
extern unsigned hash(const std::string &key);
class XInvalidKey : XGeneric {
public:
XInvalidKey () : XGeneric("invalid dictionary key")
{}
};
template <class T>
class Dict {
public:
typedef std::string key_type;
typedef std::pair<key_type, T> value_type;
typedef size_t size_type;
private:
struct Entry {
Entry(const key_type &k, const T &v) : pair(k,v) {}
value_type pair;
Entry *next;
};
// ---------- Iterator ----------
template <class U>
class Iter {
public:
typedef U value_type;
typedef ptrdiff_t difference_type;
typedef std::forward_iterator_tag iterator_category;
typedef value_type &reference;
typedef value_type *pointer;
Iter() : dict(0), idx(0), cur(0) {}
Iter(const Dict<T> *d, size_type i, Entry *c)
: dict(d),idx(i),cur(c)
{}
Iter(const Dict<T> *d) :dict(d)
{
for (idx=0; idx<dict->nbuckets; ++idx)
if ((cur=dict->hashtab[idx]) != 0)
return;
dict = 0; // End
idx=0;
}
bool operator==(const Iter &i) {
return dict==i.dict && idx==i.idx && cur==i.cur;
}
bool operator!=(const Iter &i) {
return !this->operator==(i);
}
reference operator*() {return cur->pair;}
pointer operator->() {return &cur->pair;}
Iter &operator++() {
if ((cur=cur->next) == 0) {
for (++idx; idx<dict->nbuckets; ++idx)
if ((cur=dict->hashtab[idx]) != 0)
return *this;
dict = 0;
cur=0;
idx=0;
}
return *this;
}
Iter &operator++(int)
{
Iter tmp=*this;
++*this;
return tmp;
}
private:
friend class Dict<T>;
const Dict<T> *dict;
size_type idx;
Entry *cur;
};
public:
typedef Iter<value_type> iterator;
typedef Iter<const value_type> const_iterator;
friend class Iter<value_type>;
friend class Iter<const value_type>;
Dict(size_type table_size = 257);
~Dict();
size_type size() const { return nentries; }
iterator begin() { return iterator(this); }
iterator end() { return iterator(); }
const_iterator begin() const { return const_iterator(this); }
const_iterator end() const { return const_iterator(); }
iterator find (const key_type &key);
const_iterator find (const key_type &key) const;
T &lookup(const key_type &key) {
Entry *e = find_entry(key);
// if (!e) throw XInvalidKey();
return e->pair.second;
}
T &operator[] (const key_type &key) { return lookup(key); }
const T& lookup(const key_type &key) const {
Entry *e = find_entry(key);
if (!e) throw XInvalidKey();
return e->pair.second;
}
const T& operator[] (const key_type &key) const
{ return lookup(key); }
bool has_key(const key_type &key) const;
/*! Insert a new element into the table. */
void insert(const key_type &key, const T &val);
/*! Remove all entries from the hash table. */
void clear();
/*! Remove the entry with key \var key from the table. */
void remove(const key_type &key);
/*! Remove the element pointed to by an iterator. */
void remove (iterator i);
private:
Entry *find_entry(const key_type &key) const;
// ---------- Variables ----------
size_type nentries; // Number of entries
size_type nbuckets; // Number of buckets in `hashtab'
Entry **hashtab;
private:
// Copying not implemented yet
Dict (const Dict<T> &d)
: nentries(d.nentries),
nbuckets(d.nbuckets),
hashtab(new Entry*[nbuckets])
{
for (size_type i=0; i<nbuckets; ++i) {
Entry *e = d.hashtab[i];
hashtab[i] = 0; // XXX Fix
}
}
Dict &operator=(const Dict<T> &d);
};
/* -------------------- Dict implementation -------------------- */
template <class T>
Dict<T>::Dict(size_type table_size)
: nentries(0), nbuckets (table_size), hashtab (new Entry*[nbuckets])
{
for (size_type i=0; i<nbuckets; ++i)
hashtab[i] = 0;
}
template <class T>
Dict<T>::~Dict() {
clear();
delete [] hashtab;
}
template <class T>
typename Dict<T>::iterator
Dict<T>::find (const key_type &key)
{
unsigned h = hash(key) % nbuckets;
for (Entry *e = hashtab[h]; e != 0; e=e->next)
if (e->pair.first == key)
return iterator(this, h, e);
return end();
}
template <class T>
typename Dict<T>::const_iterator
Dict<T>::find (const key_type &key) const
{
unsigned h = hash(key) % nbuckets;
for (Entry *e = hashtab[h]; e != 0; e=e->next)
if (e->pair.first == key)
return const_iterator(this, h, e);
return end();
}
template <class T>
void Dict<T>::clear()
{
for (size_type i=0; i<nbuckets; ++i) {
Entry *cur, *next;
for (cur = hashtab[i]; cur != 0; cur=next) {
next = cur->next;
delete cur;
}
hashtab[i] = 0;
}
nentries = 0;
}
template <class T>
void Dict<T>::insert (const key_type &key, const T &val)
{
unsigned h = hash(key) % nbuckets;
Entry *e = new Entry(key, val);
e->next = hashtab[h];
hashtab[h] = e;
nentries += 1;
}
template <class T>
void Dict<T>::remove (const key_type &key)
{
unsigned h = hash(key) % nbuckets;
Entry *e = hashtab[h];
Entry **eptr = &hashtab[h];
while (e != 0) {
if (e->pair.first == key) {
*eptr = e->next; // Modify pointer referring to e
delete e;
nentries -= 1;
break;
}
eptr = &e->next;
e = e->next;
}
}
template <class T>
bool Dict<T>::has_key (const key_type &key) const
{
return find_entry(key) != 0;
}
template <class T>
typename Dict<T>::Entry *
Dict<T>::find_entry (const key_type &key) const
{
unsigned h = hash(key) % nbuckets;
for (Entry *e = hashtab[h]; e != 0; e=e->next)
if (e->pair.first == key)
return e;
return 0;
}
}
#endif
|