2 /* Copyright (C) 1989-2014 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
5 This file is part of groff.
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
23 // name2(a,b) concatenates two C identifiers.
24 #ifdef TRADITIONAL_CPP
25 # define name2(a,b) a/**/b
26 #else /* not TRADITIONAL_CPP */
27 # define name2(a,b) name2x(a,b)
28 # define name2x(a,b) a ## b
29 #endif /* not TRADITIONAL_CPP */
31 // `class PTABLE(T)' is the type of a hash table mapping a string
32 // (const char *) to an object of type T.
34 // `struct PASSOC(T)' is the type of a association (pair) between a
35 // string (const char *) and an object of type T.
37 // `class PTABLE_ITERATOR(T)' is the type of an iterator iterating through a
40 // Nowadays one would use templates for this; this code predates the addition
41 // of templates to C++.
42 #define PTABLE(T) name2(T,_ptable)
43 #define PASSOC(T) name2(T,_passoc)
44 #define PTABLE_ITERATOR(T) name2(T,_ptable_iterator)
46 // itable.h declares this too
47 #ifndef NEXT_PTABLE_SIZE_DEFINED
48 # define NEXT_PTABLE_SIZE_DEFINED
49 extern unsigned next_ptable_size(unsigned); // Return the first suitable
50 // hash table size greater than the given
54 extern unsigned long hash_string(const char *); // Return a hash code of the
55 // given string. The hash function is
56 // platform dependent. */
58 // Declare the types `class PTABLE(T)', `struct PASSOC(T)', and `class
59 // PTABLE_ITERATOR(T)' for the type `T'.
60 #define declare_ptable(T) \
70 class PTABLE_ITERATOR(T) { \
74 PTABLE_ITERATOR(T)(PTABLE(T) *); /* Initialize an iterator running \
75 through the given table. */ \
76 int next(const char **, T **); /* Fetch the next pair, store the key \
77 and value in arg1 and arg2, \
78 respectively, and return 1. If \
79 there is no more pair in the \
93 PTABLE(T)(); /* Create an empty table. */ \
94 ~PTABLE(T)(); /* Delete a table, including its \
96 const char *define(const char *, T *);/* Define the value (arg2) for a key \
97 (arg1). Return the copy in the \
98 table of the key (arg1), or \
99 possibly NULL if the value (arg2) \
101 T *lookup(const char *); /* Return a pointer to the value of \
102 the given key, if found in the \
103 table, or NULL otherwise. */ \
104 T *lookupassoc(const char **); /* Return a pointer to the value of \
105 the given key, passed by reference,\
106 and replace the key argument with \
107 the copy found in the table, if \
108 the key is found in the table. \
109 Return NULL otherwise. */ \
110 friend class PTABLE_ITERATOR(T); \
114 // Keys (which are strings) are allocated and freed by PTABLE.
115 // Values must be allocated by the caller (always using new[], not new)
116 // and are freed by PTABLE.
118 // Define the implementations of the members of the types `class PTABLE(T)',
119 // `struct PASSOC(T)', `class PTABLE_ITERATOR(T)' for the type `T'.
120 #define implement_ptable(T) \
122 PASSOC(T)::PASSOC(T)() \
127 PTABLE(T)::PTABLE(T)() \
129 v = new PASSOC(T)[size = INITIAL_SIZE]; \
133 PTABLE(T)::~PTABLE(T)() \
135 for (unsigned i = 0; i < size; i++) { \
142 const char *PTABLE(T)::define(const char *key, T *val) \
145 unsigned long h = hash_string(key); \
147 for (n = unsigned(h % size); \
149 n = (n == 0 ? size - 1 : n - 1)) \
150 if (strcmp(v[n].key, key) == 0) { \
157 if (used*FULL_DEN >= size*FULL_NUM) { \
158 PASSOC(T) *oldv = v; \
159 unsigned old_size = size; \
160 size = next_ptable_size(size); \
161 v = new PASSOC(T)[size]; \
162 for (unsigned i = 0; i < old_size; i++) \
163 if (oldv[i].key != 0) { \
164 if (oldv[i].val == 0) \
165 a_delete oldv[i].key; \
168 for (j = unsigned(hash_string(oldv[i].key) % size); \
170 j = (j == 0 ? size - 1 : j - 1)) \
172 v[j].key = oldv[i].key; \
173 v[j].val = oldv[i].val; \
176 for (n = unsigned(h % size); \
178 n = (n == 0 ? size - 1 : n - 1)) \
182 char *temp = new char[strlen(key)+1]; \
190 T *PTABLE(T)::lookup(const char *key) \
193 for (unsigned n = unsigned(hash_string(key) % size); \
195 n = (n == 0 ? size - 1 : n - 1)) \
196 if (strcmp(v[n].key, key) == 0) \
201 T *PTABLE(T)::lookupassoc(const char **keyptr) \
203 const char *key = *keyptr; \
205 for (unsigned n = unsigned(hash_string(key) % size); \
207 n = (n == 0 ? size - 1 : n - 1)) \
208 if (strcmp(v[n].key, key) == 0) { \
209 *keyptr = v[n].key; \
215 PTABLE_ITERATOR(T)::PTABLE_ITERATOR(T)(PTABLE(T) *t) \
220 int PTABLE_ITERATOR(T)::next(const char **keyp, T **valp) \
222 unsigned size = p->size; \
223 PASSOC(T) *v = p->v; \
224 for (; i < size; i++) \
225 if (v[i].key != 0) { \