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