Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / groff / src / include / ptable.h
1 // -*- C++ -*-
2 /* Copyright (C) 1989, 1990, 1991, 1992 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 2, or (at your option) any later
10 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 along
18 with groff; see the file COPYING.  If not, write to the Free Software
19 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20
21 #include <assert.h>
22 #include <string.h>
23
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 #define PTABLE(T) name2(T,_ptable)
32 #define PASSOC(T) name2(T,_passoc)
33 #define PTABLE_ITERATOR(T) name2(T,_ptable_iterator)
34
35 extern unsigned next_ptable_size(unsigned);
36 extern unsigned long hash_string(const char *);
37
38 #define declare_ptable(T)                                                     \
39                                                                               \
40 struct PASSOC(T) {                                                            \
41   char *key;                                                                  \
42   T *val;                                                                     \
43   PASSOC(T)();                                                                \
44 };                                                                            \
45                                                                               \
46 struct PTABLE(T);                                                             \
47                                                                               \
48 class PTABLE_ITERATOR(T) {                                                    \
49   PTABLE(T) *p;                                                               \
50   unsigned i;                                                                 \
51 public:                                                                       \
52   PTABLE_ITERATOR(T)(PTABLE(T) *);                                            \
53   int next(const char **, T **);                                              \
54 };                                                                            \
55                                                                               \
56 class PTABLE(T) {                                                             \
57   PASSOC(T) *v;                                                               \
58   unsigned size;                                                              \
59   unsigned used;                                                              \
60   enum { FULL_NUM = 2, FULL_DEN = 3, INITIAL_SIZE = 17 };                     \
61 public:                                                                       \
62   PTABLE(T)();                                                                \
63   ~PTABLE(T)();                                                               \
64   void define(const char *, T *);                                             \
65   T *lookup(const char *);                                                    \
66   friend class PTABLE_ITERATOR(T);                                            \
67 };
68
69
70 #define implement_ptable(T)                                                   \
71                                                                               \
72 PASSOC(T)::PASSOC(T)()                                                        \
73 : key(0), val(0)                                                              \
74 {                                                                             \
75 }                                                                             \
76                                                                               \
77 PTABLE(T)::PTABLE(T)()                                                        \
78 {                                                                             \
79   v = new PASSOC(T)[size = INITIAL_SIZE];                                     \
80   used = 0;                                                                   \
81 }                                                                             \
82                                                                               \
83 PTABLE(T)::~PTABLE(T)()                                                       \
84 {                                                                             \
85   for (unsigned i = 0; i < size; i++) {                                       \
86     a_delete v[i].key;                                                        \
87     delete v[i].val;                                                          \
88   }                                                                           \
89   a_delete v;                                                                 \
90 }                                                                             \
91                                                                               \
92 void PTABLE(T)::define(const char *key, T *val)                               \
93 {                                                                             \
94   assert(key != 0);                                                           \
95   unsigned long h = hash_string(key);                                         \
96   unsigned n;                                                                 \
97   for (n = unsigned(h % size);                                                \
98        v[n].key != 0;                                                         \
99        n = (n == 0 ? size - 1 : n - 1))                                       \
100     if (strcmp(v[n].key, key) == 0) {                                         \
101       delete v[n].val;                                                        \
102       v[n].val = val;                                                         \
103       return;                                                                 \
104     }                                                                         \
105   if (val == 0)                                                               \
106     return;                                                                   \
107   if (used*FULL_DEN >= size*FULL_NUM) {                                       \
108     PASSOC(T) *oldv = v;                                                      \
109     unsigned old_size = size;                                                 \
110     size = next_ptable_size(size);                                            \
111     v = new PASSOC(T)[size];                                                  \
112     for (unsigned i = 0; i < old_size; i++)                                   \
113       if (oldv[i].key != 0) {                                                 \
114         if (oldv[i].val == 0)                                                 \
115           a_delete oldv[i].key;                                               \
116         else {                                                                \
117           unsigned j;                                                         \
118           for (j = unsigned(hash_string(oldv[i].key) % size);                 \
119                v[j].key != 0;                                                 \
120                j = (j == 0 ? size - 1 : j - 1))                               \
121                  ;                                                            \
122           v[j].key = oldv[i].key;                                             \
123           v[j].val = oldv[i].val;                                             \
124         }                                                                     \
125       }                                                                       \
126     for (n = unsigned(h % size);                                              \
127          v[n].key != 0;                                                       \
128          n = (n == 0 ? size - 1 : n - 1))                                     \
129       ;                                                                       \
130     a_delete oldv;                                                            \
131   }                                                                           \
132   char *temp = new char[strlen(key)+1];                                       \
133   strcpy(temp, key);                                                          \
134   v[n].key = temp;                                                            \
135   v[n].val = val;                                                             \
136   used++;                                                                     \
137 }                                                                             \
138                                                                               \
139 T *PTABLE(T)::lookup(const char *key)                                         \
140 {                                                                             \
141   assert(key != 0);                                                           \
142   for (unsigned n = unsigned(hash_string(key) % size);                        \
143        v[n].key != 0;                                                         \
144        n = (n == 0 ? size - 1 : n - 1))                                       \
145     if (strcmp(v[n].key, key) == 0)                                           \
146       return v[n].val;                                                        \
147   return 0;                                                                   \
148 }                                                                             \
149                                                                               \
150 PTABLE_ITERATOR(T)::PTABLE_ITERATOR(T)(PTABLE(T) *t)                          \
151 : p(t), i(0)                                                                  \
152 {                                                                             \
153 }                                                                             \
154                                                                               \
155 int PTABLE_ITERATOR(T)::next(const char **keyp, T **valp)                     \
156 {                                                                             \
157   unsigned size = p->size;                                                    \
158   PASSOC(T) *v = p->v;                                                        \
159   for (; i < size; i++)                                                       \
160     if (v[i].key != 0) {                                                      \
161       *keyp = v[i].key;                                                       \
162       *valp = v[i].val;                                                       \
163       i++;                                                                    \
164       return 1;                                                               \
165     }                                                                         \
166   return 0;                                                                   \
167 }
168