c43a070772158dddd00b2a911bb25deb7eb77be6
[platform/upstream/groff.git] / src / include / ptable.h
1 // -*- C++ -*-
2 /* Copyright (C) 1989-2014  Free Software Foundation, Inc.
3      Written by James Clark (jjc@jclark.com)
4
5 This file is part of groff.
6
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.
11
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
15 for more details.
16
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/>. */
19
20 #include <assert.h>
21 #include <string.h>
22
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 */
30
31 // `class PTABLE(T)' is the type of a hash table mapping a string
32 // (const char *) to an object of type T.
33 //
34 // `struct PASSOC(T)' is the type of a association (pair) between a
35 // string (const char *) and an object of type T.
36 //
37 // `class PTABLE_ITERATOR(T)' is the type of an iterator iterating through a
38 // `class PTABLE(T)'.
39 //
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)
45
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
51                                 // value.
52 #endif
53
54 extern unsigned long hash_string(const char *); // Return a hash code of the
55                                 // given string.  The hash function is
56                                 // platform dependent.  */
57
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)                                                     \
61                                                                               \
62 struct PASSOC(T) {                                                            \
63   char *key;                                                                  \
64   T *val;                                                                     \
65   PASSOC(T)();                                                                \
66 };                                                                            \
67                                                                               \
68 class PTABLE(T);                                                              \
69                                                                               \
70 class PTABLE_ITERATOR(T) {                                                    \
71   PTABLE(T) *p;                                                               \
72   unsigned i;                                                                 \
73 public:                                                                       \
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       \
80                                            table, return 0.  */               \
81 };                                                                            \
82                                                                               \
83 class PTABLE(T) {                                                             \
84   PASSOC(T) *v;                                                               \
85   unsigned size;                                                              \
86   unsigned used;                                                              \
87   enum {                                                                      \
88     FULL_NUM = 1,                                                             \
89     FULL_DEN = 4,                                                             \
90     INITIAL_SIZE = 17                                                         \
91   };                                                                          \
92 public:                                                                       \
93   PTABLE(T)();                          /* Create an empty table.  */         \
94   ~PTABLE(T)();                         /* Delete a table, including its      \
95                                            values.  */                        \
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)  \
100                                            is NULL.  */                       \
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);                                            \
111 };
112
113
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.
117
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)                                                   \
121                                                                               \
122 PASSOC(T)::PASSOC(T)()                                                        \
123 : key(0), val(0)                                                              \
124 {                                                                             \
125 }                                                                             \
126                                                                               \
127 PTABLE(T)::PTABLE(T)()                                                        \
128 {                                                                             \
129   v = new PASSOC(T)[size = INITIAL_SIZE];                                     \
130   used = 0;                                                                   \
131 }                                                                             \
132                                                                               \
133 PTABLE(T)::~PTABLE(T)()                                                       \
134 {                                                                             \
135   for (unsigned i = 0; i < size; i++) {                                       \
136     a_delete v[i].key;                                                        \
137     a_delete v[i].val;                                                        \
138   }                                                                           \
139   a_delete v;                                                                 \
140 }                                                                             \
141                                                                               \
142 const char *PTABLE(T)::define(const char *key, T *val)                        \
143 {                                                                             \
144   assert(key != 0);                                                           \
145   unsigned long h = hash_string(key);                                         \
146   unsigned n;                                                                 \
147   for (n = unsigned(h % size);                                                \
148        v[n].key != 0;                                                         \
149        n = (n == 0 ? size - 1 : n - 1))                                       \
150     if (strcmp(v[n].key, key) == 0) {                                         \
151       a_delete v[n].val;                                                      \
152       v[n].val = val;                                                         \
153       return v[n].key;                                                        \
154     }                                                                         \
155   if (val == 0)                                                               \
156     return 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;                                               \
166         else {                                                                \
167           unsigned j;                                                         \
168           for (j = unsigned(hash_string(oldv[i].key) % size);                 \
169                v[j].key != 0;                                                 \
170                j = (j == 0 ? size - 1 : j - 1))                               \
171                  ;                                                            \
172           v[j].key = oldv[i].key;                                             \
173           v[j].val = oldv[i].val;                                             \
174         }                                                                     \
175       }                                                                       \
176     for (n = unsigned(h % size);                                              \
177          v[n].key != 0;                                                       \
178          n = (n == 0 ? size - 1 : n - 1))                                     \
179       ;                                                                       \
180     a_delete oldv;                                                            \
181   }                                                                           \
182   char *temp = new char[strlen(key)+1];                                       \
183   strcpy(temp, key);                                                          \
184   v[n].key = temp;                                                            \
185   v[n].val = val;                                                             \
186   used++;                                                                     \
187   return temp;                                                                \
188 }                                                                             \
189                                                                               \
190 T *PTABLE(T)::lookup(const char *key)                                         \
191 {                                                                             \
192   assert(key != 0);                                                           \
193   for (unsigned n = unsigned(hash_string(key) % size);                        \
194        v[n].key != 0;                                                         \
195        n = (n == 0 ? size - 1 : n - 1))                                       \
196     if (strcmp(v[n].key, key) == 0)                                           \
197       return v[n].val;                                                        \
198   return 0;                                                                   \
199 }                                                                             \
200                                                                               \
201 T *PTABLE(T)::lookupassoc(const char **keyptr)                                \
202 {                                                                             \
203   const char *key = *keyptr;                                                  \
204   assert(key != 0);                                                           \
205   for (unsigned n = unsigned(hash_string(key) % size);                        \
206        v[n].key != 0;                                                         \
207        n = (n == 0 ? size - 1 : n - 1))                                       \
208     if (strcmp(v[n].key, key) == 0) {                                         \
209       *keyptr = v[n].key;                                                     \
210       return v[n].val;                                                        \
211     }                                                                         \
212   return 0;                                                                   \
213 }                                                                             \
214                                                                               \
215 PTABLE_ITERATOR(T)::PTABLE_ITERATOR(T)(PTABLE(T) *t)                          \
216 : p(t), i(0)                                                                  \
217 {                                                                             \
218 }                                                                             \
219                                                                               \
220 int PTABLE_ITERATOR(T)::next(const char **keyp, T **valp)                     \
221 {                                                                             \
222   unsigned size = p->size;                                                    \
223   PASSOC(T) *v = p->v;                                                        \
224   for (; i < size; i++)                                                       \
225     if (v[i].key != 0) {                                                      \
226       *keyp = v[i].key;                                                       \
227       *valp = v[i].val;                                                       \
228       i++;                                                                    \
229       return 1;                                                               \
230     }                                                                         \
231   return 0;                                                                   \
232 }
233
234 // end of ptable.h