2 /* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2004, 2009
3 Free Software Foundation, Inc.
4 Written by James Clark (jjc@jclark.com)
6 This file is part of groff.
8 groff is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 groff is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
23 #include "dictionary.h"
25 // is `p' a good size for a hash table
27 static int is_good_size(unsigned int p)
29 const unsigned int SMALL = 10;
31 for (i = 2; i <= p/2; i++)
34 for (i = 0x100; i != 0; i <<= 8)
35 if (i % p <= SMALL || i % p > p - SMALL)
40 dictionary::dictionary(int n) : size(n), used(0), threshold(0.5), factor(1.5)
42 table = new association[n];
45 // see Knuth, Sorting and Searching, p518, Algorithm L
46 // we can't use double-hashing because we want a remove function
48 void *dictionary::lookup(symbol s, void *v)
51 for (i = int(s.hash() % size);
53 i == 0 ? i = size - 1: --i)
54 if (s == table[i].s) {
56 void *temp = table[i].v;
68 if ((double)used/(double)size >= threshold || used + 1 >= size) {
70 size = int(size*factor);
71 while (!is_good_size(size))
73 association *old_table = table;
74 table = new association[size];
76 for (i = 0; i < old_size; i++)
77 if (old_table[i].v != 0)
78 (void)lookup(old_table[i].s, old_table[i].v);
84 void *dictionary::lookup(const char *p)
86 symbol s(p, MUST_ALREADY_EXIST);
93 // see Knuth, Sorting and Searching, p527, Algorithm R
95 void *dictionary::remove(symbol s)
97 // this relies on the fact that we are using linear probing
99 for (i = int(s.hash() % size);
100 table[i].v != 0 && s != table[i].s;
101 i == 0 ? i = size - 1: --i)
103 void *p = table[i].v;
104 while (table[i].v != 0) {
114 r = int(table[i].s.hash() % size);
115 } while ((i <= r && r < j) || (r < j && j < i) || (j < i && i <= r));
123 dictionary_iterator::dictionary_iterator(dictionary &d) : dict(&d), i(0)
127 int dictionary_iterator::get(symbol *sp, void **vp)
129 for (; i < dict->size; i++)
130 if (dict->table[i].v) {
131 *sp = dict->table[i].s;
132 *vp = dict->table[i].v;
139 object_dictionary_iterator::object_dictionary_iterator(object_dictionary &od)
144 object::object() : rcount(0)
152 void object::add_reference()
157 void object::remove_reference()
163 object_dictionary::object_dictionary(int n) : d(n)
167 object *object_dictionary::lookup(symbol nm)
169 return (object *)d.lookup(nm);
172 void object_dictionary::define(symbol nm, object *obj)
174 obj->add_reference();
175 obj = (object *)d.lookup(nm, obj);
177 obj->remove_reference();
180 void object_dictionary::rename(symbol oldnm, symbol newnm)
182 object *obj = (object *)d.remove(oldnm);
184 obj = (object *)d.lookup(newnm, obj);
186 obj->remove_reference();
190 void object_dictionary::remove(symbol nm)
192 object *obj = (object *)d.remove(nm);
194 obj->remove_reference();
197 // Return non-zero if oldnm was defined.
199 int object_dictionary::alias(symbol newnm, symbol oldnm)
201 object *obj = (object *)d.lookup(oldnm);
203 obj->add_reference();
204 obj = (object *)d.lookup(newnm, obj);
206 obj->remove_reference();