1 | /* Keep a unique copy of strings. |
2 | |
3 | Copyright (C) 2002-2005, 2009-2015, 2018-2019 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 <http://www.gnu.org/licenses/>. */ |
20 | |
21 | #include <config.h> |
22 | #include "system.h" |
23 | |
24 | #include <error.h> |
25 | #include <hash.h> |
26 | #include <quotearg.h> |
27 | #include <stdarg.h> |
28 | |
29 | #include "uniqstr.h" |
30 | |
31 | /*-----------------------. |
32 | | A uniqstr hash table. | |
33 | `-----------------------*/ |
34 | |
35 | /* Initial capacity of uniqstr hash table. */ |
36 | #define HT_INITIAL_CAPACITY 257 |
37 | |
38 | static struct hash_table *uniqstrs_table = NULL; |
39 | |
40 | /*-------------------------------------. |
41 | | Create the uniqstr for S if needed. | |
42 | `-------------------------------------*/ |
43 | |
44 | uniqstr |
45 | uniqstr_new (char const *str) |
46 | { |
47 | uniqstr res = hash_lookup (uniqstrs_table, str); |
48 | if (!res) |
49 | { |
50 | /* First insertion in the hash. */ |
51 | res = xstrdup (str); |
52 | if (!hash_insert (uniqstrs_table, res)) |
53 | xalloc_die (); |
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_insert (uniqstrs_table, str); |
84 | if (!res) |
85 | xalloc_die (); |
86 | if (res != str) |
87 | free (str); |
88 | return res; |
89 | } |
90 | |
91 | /*------------------------------. |
92 | | Abort if S is not a uniqstr. | |
93 | `------------------------------*/ |
94 | |
95 | void |
96 | uniqstr_assert (char const *str) |
97 | { |
98 | uniqstr s = hash_lookup (uniqstrs_table, str); |
99 | if (!s || s != str) |
100 | { |
101 | error (0, 0, |
102 | "not a uniqstr: %s" , quotearg (str)); |
103 | abort (); |
104 | } |
105 | } |
106 | |
107 | |
108 | /*--------------------. |
109 | | Print the uniqstr. | |
110 | `--------------------*/ |
111 | |
112 | static inline bool |
113 | uniqstr_print (uniqstr ustr) |
114 | { |
115 | fprintf (stderr, "%s\n" , ustr); |
116 | return true; |
117 | } |
118 | |
119 | static bool |
120 | uniqstr_print_processor (void *ustr, void *null ATTRIBUTE_UNUSED) |
121 | { |
122 | return uniqstr_print (ustr); |
123 | } |
124 | |
125 | |
126 | int |
127 | uniqstr_cmp (uniqstr l, uniqstr r) |
128 | { |
129 | return (l == r ? 0 |
130 | : !l ? -1 |
131 | : !r ? +1 |
132 | : strcmp (l, r)); |
133 | } |
134 | |
135 | |
136 | /*-----------------------. |
137 | | A uniqstr hash table. | |
138 | `-----------------------*/ |
139 | |
140 | static bool |
141 | hash_compare_uniqstr (void const *m1, void const *m2) |
142 | { |
143 | return STREQ (m1, m2); |
144 | } |
145 | |
146 | static size_t |
147 | hash_uniqstr (void const *m, size_t tablesize) |
148 | { |
149 | return hash_string (m, tablesize); |
150 | } |
151 | |
152 | |
153 | /*----------------------------. |
154 | | Create the uniqstrs table. | |
155 | `----------------------------*/ |
156 | |
157 | void |
158 | uniqstrs_new (void) |
159 | { |
160 | uniqstrs_table = hash_xinitialize (HT_INITIAL_CAPACITY, |
161 | NULL, |
162 | hash_uniqstr, |
163 | hash_compare_uniqstr, |
164 | free); |
165 | } |
166 | |
167 | |
168 | /*-------------------------------------. |
169 | | Perform a task on all the uniqstrs. | |
170 | `-------------------------------------*/ |
171 | |
172 | static void |
173 | uniqstrs_do (Hash_processor processor, void *processor_data) |
174 | { |
175 | hash_do_for_each (uniqstrs_table, processor, processor_data); |
176 | } |
177 | |
178 | |
179 | /*-----------------. |
180 | | Print them all. | |
181 | `-----------------*/ |
182 | |
183 | void |
184 | uniqstrs_print (void) |
185 | { |
186 | uniqstrs_do (uniqstr_print_processor, NULL); |
187 | } |
188 | |
189 | |
190 | /*--------------------. |
191 | | Free the uniqstrs. | |
192 | `--------------------*/ |
193 | |
194 | void |
195 | uniqstrs_free (void) |
196 | { |
197 | hash_free (uniqstrs_table); |
198 | } |
199 | |