groff: update vendor branch to v1.20.1
[dragonfly.git] / contrib / groff / src / roff / troff / dictionary.cpp
CommitLineData
92d0a6a6 1// -*- C++ -*-
4d3e9548 2/* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2004, 2009
92d0a6a6
JR
3 Free Software Foundation, Inc.
4 Written by James Clark (jjc@jclark.com)
5
6This file is part of groff.
7
8groff is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
4d3e9548
JL
10Software Foundation, either version 3 of the License, or
11(at your option) any later version.
92d0a6a6
JR
12
13groff is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
17
4d3e9548
JL
18You should have received a copy of the GNU General Public License
19along with this program. If not, see <http://www.gnu.org/licenses/>. */
92d0a6a6
JR
20
21
22#include "troff.h"
23#include "dictionary.h"
24
25// is `p' a good size for a hash table
26
27static int is_good_size(unsigned int p)
28{
29 const unsigned int SMALL = 10;
30 unsigned int i;
31 for (i = 2; i <= p/2; i++)
32 if (p % i == 0)
33 return 0;
34 for (i = 0x100; i != 0; i <<= 8)
35 if (i % p <= SMALL || i % p > p - SMALL)
36 return 0;
37 return 1;
38}
39
40dictionary::dictionary(int n) : size(n), used(0), threshold(0.5), factor(1.5)
41{
42 table = new association[n];
43}
44
45// see Knuth, Sorting and Searching, p518, Algorithm L
46// we can't use double-hashing because we want a remove function
47
48void *dictionary::lookup(symbol s, void *v)
49{
50 int i;
51 for (i = int(s.hash() % size);
52 table[i].v != 0;
53 i == 0 ? i = size - 1: --i)
54 if (s == table[i].s) {
55 if (v != 0) {
56 void *temp = table[i].v;
57 table[i].v = v;
58 return temp;
59 }
60 else
61 return table[i].v;
62 }
63 if (v == 0)
64 return 0;
65 ++used;
66 table[i].v = v;
67 table[i].s = s;
68 if ((double)used/(double)size >= threshold || used + 1 >= size) {
69 int old_size = size;
70 size = int(size*factor);
71 while (!is_good_size(size))
72 ++size;
73 association *old_table = table;
74 table = new association[size];
75 used = 0;
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);
79 a_delete old_table;
80 }
81 return 0;
82}
83
84void *dictionary::lookup(const char *p)
85{
86 symbol s(p, MUST_ALREADY_EXIST);
87 if (s.is_null())
88 return 0;
89 else
90 return lookup(s);
91}
92
93// see Knuth, Sorting and Searching, p527, Algorithm R
94
95void *dictionary::remove(symbol s)
96{
97 // this relies on the fact that we are using linear probing
98 int i;
99 for (i = int(s.hash() % size);
100 table[i].v != 0 && s != table[i].s;
101 i == 0 ? i = size - 1: --i)
102 ;
103 void *p = table[i].v;
104 while (table[i].v != 0) {
105 table[i].v = 0;
106 int j = i;
107 int r;
108 do {
109 --i;
110 if (i < 0)
111 i = size - 1;
112 if (table[i].v == 0)
113 break;
114 r = int(table[i].s.hash() % size);
115 } while ((i <= r && r < j) || (r < j && j < i) || (j < i && i <= r));
116 table[j] = table[i];
117 }
118 if (p != 0)
119 --used;
120 return p;
121}
122
123dictionary_iterator::dictionary_iterator(dictionary &d) : dict(&d), i(0)
124{
125}
126
127int dictionary_iterator::get(symbol *sp, void **vp)
128{
129 for (; i < dict->size; i++)
130 if (dict->table[i].v) {
131 *sp = dict->table[i].s;
132 *vp = dict->table[i].v;
133 i++;
134 return 1;
135 }
136 return 0;
137}
138
139object_dictionary_iterator::object_dictionary_iterator(object_dictionary &od)
140: di(od.d)
141{
142}
143
144object::object() : rcount(0)
145{
146}
147
148object::~object()
149{
150}
151
152void object::add_reference()
153{
154 rcount += 1;
155}
156
157void object::remove_reference()
158{
159 if (--rcount == 0)
160 delete this;
161}
162
163object_dictionary::object_dictionary(int n) : d(n)
164{
165}
166
167object *object_dictionary::lookup(symbol nm)
168{
169 return (object *)d.lookup(nm);
170}
171
172void object_dictionary::define(symbol nm, object *obj)
173{
174 obj->add_reference();
175 obj = (object *)d.lookup(nm, obj);
176 if (obj)
177 obj->remove_reference();
178}
179
180void object_dictionary::rename(symbol oldnm, symbol newnm)
181{
182 object *obj = (object *)d.remove(oldnm);
183 if (obj) {
184 obj = (object *)d.lookup(newnm, obj);
185 if (obj)
186 obj->remove_reference();
187 }
188}
189
190void object_dictionary::remove(symbol nm)
191{
192 object *obj = (object *)d.remove(nm);
193 if (obj)
194 obj->remove_reference();
195}
196
197// Return non-zero if oldnm was defined.
198
199int object_dictionary::alias(symbol newnm, symbol oldnm)
200{
201 object *obj = (object *)d.lookup(oldnm);
202 if (obj) {
203 obj->add_reference();
204 obj = (object *)d.lookup(newnm, obj);
205 if (obj)
206 obj->remove_reference();
207 return 1;
208 }
209 return 0;
210}