1 /* Keep a unique copy of strings.
2
3 Copyright (C) 2002-2005, 2009-2015, 2018-2021 Free Software
4 Foundation, Inc.
5
6 This file is part of Bison, the GNU Compiler Compiler.
7
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <https://www.gnu.org/licenses/>. */
20
21 #include <config.h>
22 #include "system.h"
23
24 #include <attribute.h>
25 #include <error.h>
26 #include <hash.h>
27 #include <quotearg.h>
28 #include <stdarg.h>
29
30 #include "uniqstr.h"
31
32 /*-----------------------.
33 | A uniqstr hash table. |
34 `-----------------------*/
35
36 /* Initial capacity of uniqstr hash table. */
37 #define HT_INITIAL_CAPACITY 257
38
39 static struct hash_table *uniqstrs_table = NULL;
40
41 /*-------------------------------------.
42 | Create the uniqstr for S if needed. |
43 `-------------------------------------*/
44
45 uniqstr
46 uniqstr_new (char const *str)
47 {
48 uniqstr res = hash_lookup (uniqstrs_table, str);
49 if (!res)
50 {
51 /* First insertion in the hash. */
52 res = xstrdup (str);
53 hash_xinsert (uniqstrs_table, res);
54 }
55 return res;
56 }
57
58 uniqstr
59 uniqstr_concat (int nargs, ...)
60 {
61 va_list args;
62
63 va_start (args, nargs);
64 size_t reslen = 0;
65 for (int i = 0; i < nargs; i++)
66 reslen += strlen (va_arg (args, char const *));
67 va_end (args);
68
69 char *str = xmalloc (reslen + 1);
70 char *p = str;
71
72 va_start (args, nargs);
73 for (int i = 0; i < nargs; i++)
74 {
75 char const *arg = va_arg (args, char const *);
76 size_t arglen = strlen (arg);
77 memcpy (p, arg, arglen);
78 p += arglen;
79 }
80 va_end (args);
81
82 *p = '\0';
83 uniqstr res = hash_xinsert (uniqstrs_table, str);
84 if (res != str)
85 free (str);
86 return res;
87 }
88
89 /*------------------------------.
90 | Abort if S is not a uniqstr. |
91 `------------------------------*/
92
93 void
94 uniqstr_assert (char const *str)
95 {
96 uniqstr s = hash_lookup (uniqstrs_table, str);
97 if (!s || s != str)
98 {
99 error (0, 0,
100 "not a uniqstr: %s", quotearg (str));
101 abort ();
102 }
103 }
104
105
106 /*--------------------.
107 | Print the uniqstr. |
108 `--------------------*/
109
110 static inline bool
111 uniqstr_print (uniqstr ustr)
112 {
113 fprintf (stderr, "%s\n", ustr);
114 return true;
115 }
116
117 static bool
118 uniqstr_print_processor (void *ustr, void *null MAYBE_UNUSED)
119 {
120 return uniqstr_print (ustr);
121 }
122
123 int
124 uniqstr_cmp (uniqstr l, uniqstr r)
125 {
126 return (l == r ? 0
127 : !l ? -1
128 : !r ? +1
129 : strcmp (l, r));
130 }
131
132
133 /*-----------------------.
134 | A uniqstr hash table. |
135 `-----------------------*/
136
137 static bool
138 hash_compare_uniqstr (void const *m1, void const *m2)
139 {
140 return STREQ (m1, m2);
141 }
142
143 static size_t
144 hash_uniqstr (void const *m, size_t tablesize)
145 {
146 return hash_string (m, tablesize);
147 }
148
149
150 /*----------------------------.
151 | Create the uniqstrs table. |
152 `----------------------------*/
153
154 void
155 uniqstrs_new (void)
156 {
157 uniqstrs_table = hash_xinitialize (HT_INITIAL_CAPACITY,
158 NULL,
159 hash_uniqstr,
160 hash_compare_uniqstr,
161 free);
162 }
163
164
165 /*-------------------------------------.
166 | Perform a task on all the uniqstrs. |
167 `-------------------------------------*/
168
169 static void
170 uniqstrs_do (Hash_processor processor, void *processor_data)
171 {
172 hash_do_for_each (uniqstrs_table, processor, processor_data);
173 }
174
175
176 /*-----------------.
177 | Print them all. |
178 `-----------------*/
179
180 void
181 uniqstrs_print (void)
182 {
183 uniqstrs_do (uniqstr_print_processor, NULL);
184 }
185
186
187 /*--------------------.
188 | Free the uniqstrs. |
189 `--------------------*/
190
191 void
192 uniqstrs_free (void)
193 {
194 hash_free (uniqstrs_table);
195 }