groff: update vendor branch to v1.20.1
[dragonfly.git] / contrib / groff / src / include / ptable.h
CommitLineData
92d0a6a6 1// -*- C++ -*-
4d3e9548 2/* Copyright (C) 1989, 1990, 1991, 1992, 2003, 2004, 2006, 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#include <assert.h>
22#include <string.h>
23
4d3e9548 24// name2(a,b) concatenates two C identifiers.
92d0a6a6 25#ifdef TRADITIONAL_CPP
4d3e9548 26# define name2(a,b) a/**/b
92d0a6a6 27#else /* not TRADITIONAL_CPP */
4d3e9548
JL
28# define name2(a,b) name2x(a,b)
29# define name2x(a,b) a ## b
92d0a6a6
JR
30#endif /* not TRADITIONAL_CPP */
31
4d3e9548
JL
32// `class PTABLE(T)' is the type of a hash table mapping a string
33// (const char *) to an object of type T.
34//
35// `struct PASSOC(T)' is the type of a association (pair) between a
36// string (const char *) and an object of type T.
37//
38// `class PTABLE_ITERATOR(T)' is the type of an iterator iterating through a
39// `class PTABLE(T)'.
40//
41// Nowadays one would use templates for this; this code predates the addition
42// of templates to C++.
92d0a6a6
JR
43#define PTABLE(T) name2(T,_ptable)
44#define PASSOC(T) name2(T,_passoc)
45#define PTABLE_ITERATOR(T) name2(T,_ptable_iterator)
46
4d3e9548
JL
47// itable.h declares this too
48#ifndef NEXT_PTABLE_SIZE_DEFINED
49# define NEXT_PTABLE_SIZE_DEFINED
50extern unsigned next_ptable_size(unsigned); // Return the first suitable
51 // hash table size greater than the given
52 // value.
53#endif
92d0a6a6 54
4d3e9548
JL
55extern unsigned long hash_string(const char *); // Return a hash code of the
56 // given string. The hash function is
57 // platform dependent. */
58
59// Declare the types `class PTABLE(T)', `struct PASSOC(T)', and `class
60// PTABLE_ITERATOR(T)' for the type `T'.
92d0a6a6
JR
61#define declare_ptable(T) \
62 \
63struct PASSOC(T) { \
64 char *key; \
65 T *val; \
66 PASSOC(T)(); \
67}; \
68 \
69class PTABLE(T); \
70 \
71class PTABLE_ITERATOR(T) { \
72 PTABLE(T) *p; \
73 unsigned i; \
74public: \
4d3e9548
JL
75 PTABLE_ITERATOR(T)(PTABLE(T) *); /* Initialize an iterator running \
76 through the given table. */ \
77 int next(const char **, T **); /* Fetch the next pair, store the key \
78 and value in arg1 and arg2, \
79 respectively, and return 1. If \
80 there is no more pair in the \
81 table, return 0. */ \
92d0a6a6
JR
82}; \
83 \
84class PTABLE(T) { \
85 PASSOC(T) *v; \
86 unsigned size; \
87 unsigned used; \
4d3e9548
JL
88 enum { \
89 FULL_NUM = 2, \
90 FULL_DEN = 3, \
91 INITIAL_SIZE = 17 \
92 }; \
92d0a6a6 93public: \
4d3e9548
JL
94 PTABLE(T)(); /* Create an empty table. */ \
95 ~PTABLE(T)(); /* Delete a table, including its \
96 values. */ \
97 const char *define(const char *, T *);/* Define the value (arg2) for a key \
98 (arg1). Return the copy in the \
99 table of the key (arg1), or \
100 possibly NULL if the value (arg2) \
101 is NULL. */ \
102 T *lookup(const char *); /* Return a pointer to the value of \
103 the given key, if found in the \
104 table, or NULL otherwise. */ \
105 T *lookupassoc(const char **); /* Return a pointer to the value of \
106 the given key, passed by reference,\
107 and replace the key argument with \
108 the copy found in the table, if \
109 the key is found in the table. \
110 Return NULL otherwise. */ \
92d0a6a6
JR
111 friend class PTABLE_ITERATOR(T); \
112};
113
114
115// Keys (which are strings) are allocated and freed by PTABLE.
116// Values must be allocated by the caller (always using new[], not new)
117// and are freed by PTABLE.
118
4d3e9548
JL
119// Define the implementations of the members of the types `class PTABLE(T)',
120// `struct PASSOC(T)', `class PTABLE_ITERATOR(T)' for the type `T'.
92d0a6a6
JR
121#define implement_ptable(T) \
122 \
123PASSOC(T)::PASSOC(T)() \
124: key(0), val(0) \
125{ \
126} \
127 \
128PTABLE(T)::PTABLE(T)() \
129{ \
130 v = new PASSOC(T)[size = INITIAL_SIZE]; \
131 used = 0; \
132} \
133 \
134PTABLE(T)::~PTABLE(T)() \
135{ \
136 for (unsigned i = 0; i < size; i++) { \
137 a_delete v[i].key; \
138 a_delete v[i].val; \
139 } \
140 a_delete v; \
141} \
142 \
4d3e9548 143const char *PTABLE(T)::define(const char *key, T *val) \
92d0a6a6
JR
144{ \
145 assert(key != 0); \
146 unsigned long h = hash_string(key); \
147 unsigned n; \
148 for (n = unsigned(h % size); \
149 v[n].key != 0; \
150 n = (n == 0 ? size - 1 : n - 1)) \
151 if (strcmp(v[n].key, key) == 0) { \
152 a_delete v[n].val; \
153 v[n].val = val; \
4d3e9548 154 return v[n].key; \
92d0a6a6
JR
155 } \
156 if (val == 0) \
4d3e9548 157 return 0; \
92d0a6a6
JR
158 if (used*FULL_DEN >= size*FULL_NUM) { \
159 PASSOC(T) *oldv = v; \
160 unsigned old_size = size; \
161 size = next_ptable_size(size); \
162 v = new PASSOC(T)[size]; \
163 for (unsigned i = 0; i < old_size; i++) \
164 if (oldv[i].key != 0) { \
165 if (oldv[i].val == 0) \
166 a_delete oldv[i].key; \
167 else { \
168 unsigned j; \
169 for (j = unsigned(hash_string(oldv[i].key) % size); \
170 v[j].key != 0; \
171 j = (j == 0 ? size - 1 : j - 1)) \
172 ; \
173 v[j].key = oldv[i].key; \
174 v[j].val = oldv[i].val; \
175 } \
176 } \
177 for (n = unsigned(h % size); \
178 v[n].key != 0; \
179 n = (n == 0 ? size - 1 : n - 1)) \
180 ; \
181 a_delete oldv; \
182 } \
183 char *temp = new char[strlen(key)+1]; \
184 strcpy(temp, key); \
185 v[n].key = temp; \
186 v[n].val = val; \
187 used++; \
4d3e9548 188 return temp; \
92d0a6a6
JR
189} \
190 \
191T *PTABLE(T)::lookup(const char *key) \
192{ \
193 assert(key != 0); \
194 for (unsigned n = unsigned(hash_string(key) % size); \
195 v[n].key != 0; \
196 n = (n == 0 ? size - 1 : n - 1)) \
197 if (strcmp(v[n].key, key) == 0) \
198 return v[n].val; \
199 return 0; \
200} \
201 \
4d3e9548
JL
202T *PTABLE(T)::lookupassoc(const char **keyptr) \
203{ \
204 const char *key = *keyptr; \
205 assert(key != 0); \
206 for (unsigned n = unsigned(hash_string(key) % size); \
207 v[n].key != 0; \
208 n = (n == 0 ? size - 1 : n - 1)) \
209 if (strcmp(v[n].key, key) == 0) { \
210 *keyptr = v[n].key; \
211 return v[n].val; \
212 } \
213 return 0; \
214} \
215 \
92d0a6a6
JR
216PTABLE_ITERATOR(T)::PTABLE_ITERATOR(T)(PTABLE(T) *t) \
217: p(t), i(0) \
218{ \
219} \
220 \
221int PTABLE_ITERATOR(T)::next(const char **keyp, T **valp) \
222{ \
223 unsigned size = p->size; \
224 PASSOC(T) *v = p->v; \
225 for (; i < size; i++) \
226 if (v[i].key != 0) { \
227 *keyp = v[i].key; \
228 *valp = v[i].val; \
229 i++; \
230 return 1; \
231 } \
232 return 0; \
233}
4d3e9548
JL
234
235// end of ptable.h