chiark / gitweb /
math/...: Make a number of functions be const-correct.
[catacomb] / math / genlimits.c
1 /* -*-c-*-
2  *
3  * Generate limit MPs for C types
4  *
5  * (c) 2006 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of Catacomb.
11  *
12  * Catacomb is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU Library General Public License as
14  * published by the Free Software Foundation; either version 2 of the
15  * License, or (at your option) any later version.
16  *
17  * Catacomb is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public
23  * License along with Catacomb; if not, write to the Free
24  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25  * MA 02111-1307, USA.
26  */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #define _GNU_SOURCE
31 #include <errno.h>
32 #include <limits.h>
33 #include <stdio.h>
34 #include <string.h>
35
36 #if __STDC_VERSION__ >= 199900l
37 #  include <stdint.h>
38 #  include <inttypes.h>
39 #endif
40
41 #include "mp.h"
42 #include "mpint.h"
43
44 /*----- Data types --------------------------------------------------------*/
45
46 /* --- Hack for GCC --- *
47  *
48  * WG14 in their infinite wisdom decided not to use the GCC constant name.
49  */
50
51 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 91)
52 #  define EXT __extension__
53 #else
54 #  define EXT
55 #endif
56
57 #if defined(LONG_LONG_MIN) && !defined(LLONG_MIN)
58 #  define LLONG_MIN EXT LONG_LONG_MIN
59 #endif
60
61 #if defined(LONG_LONG_MAX) && !defined(LLONG_MAX)
62 #  define LLONG_MAX EXT LONG_LONG_MAX
63 #endif
64
65 #if defined(ULONG_LONG_MAX) && !defined(ULLONG_MAX)
66 #  define ULLONG_MAX EXT ULONG_LONG_MAX
67 #endif
68
69 /* --- Choose the largest integer type --- */
70
71 #if defined(INTMAX_MAX)
72   typedef intmax_t imax;
73 #elif defined(LLONG_MAX)
74   EXT typedef long long imax;
75 #else
76   typedef long imax;
77 #endif
78
79 #if defined(UINTMAX_MAX)
80   typedef uintmax_t umax;
81 #elif defined(ULLONG_MAX)
82   EXT typedef unsigned long long umax;
83 #else
84   typedef unsigned long umax;
85 #endif
86
87 /*----- Main code ---------------------------------------------------------*/
88
89 #define TABSZ 64
90
91 enum { NEG, POS, NSIGN };
92
93 umax cmap[TABSZ];
94 int gmap[TABSZ][NSIGN];
95 struct { int g, s; } qmap[TABSZ];
96 int dumpp = 0;
97
98 static int n, q;
99
100 static void dump(mp *x)
101 {
102   int i, w, n;
103
104   fputs("  ", stdout);
105   w = (MPW_BITS + 3)/4;
106   n = 1;
107   while (2 + 2 * n * (4 + w) < 72) n <<= 1;
108   i = 0;
109   for (;;) {
110     printf("0x%0*x", w, x->v[i]);
111     i++;
112     if (i >= MP_LEN(x)) break;
113     fputs(",", stdout);
114     if (i % n) fputs(" ", stdout); else fputs("\n  ", stdout);
115   }
116   fputs("\n", stdout);
117 }
118
119 static void doemit(umax c, int s, int *gg, int *qq)
120 {
121   int i;
122   mp *x = MP_NEW;
123
124   for (i = 0; i < n; i++) {
125     if (cmap[i] == c)
126       goto found;
127   }
128
129   assert(i < TABSZ);
130   n = i + 1;
131   cmap[i] = c;
132   gmap[i][POS] = gmap[i][NEG] = -1;
133   if (dumpp) {
134     MP_FROMINT(x, umax, c);
135     printf("static mpw guts_%d[] = {\n", q);
136     dump(x);
137     fputs("};\n\n", stdout);
138     MP_DROP(x);
139   }
140
141 found:
142   *gg = i;
143   if (gmap[i][s] < 0) {
144     assert(q < TABSZ);
145     gmap[i][s] = q;
146     qmap[q].g = i;
147     qmap[q].s = s;
148     q++;
149   }
150   *qq = gmap[i][s];
151 }
152
153 static void emit(imax c, int *gg, int *qq)
154 {
155   umax uc;
156   int s;
157
158   if (c >= 0) { uc = c; s = POS; }
159   else { uc = -c; s = NEG; }
160   doemit(uc, s, gg, qq);
161 }
162
163 static void uemit(umax c, int *gg, int *qq) { doemit(c, POS, gg, qq); }
164
165 struct {
166   const char *name;
167   imax min;
168   umax max;
169   int gmin, gmax;
170   int qmin, qmax;
171 } tab[] = {
172   { "SCHAR",    SCHAR_MIN,      SCHAR_MAX },
173   { "CHAR",     CHAR_MIN,       CHAR_MAX },
174   { "UCHAR",    0,              UCHAR_MAX },
175   { "UINT8",    0,              0xff },
176   { "SHRT",     SHRT_MIN,       SHRT_MAX },
177   { "USHRT",    0,              USHRT_MAX },
178   { "UINT16",   0,              0xffff },
179   { "INT",      INT_MIN,        INT_MAX },
180   { "UINT",     0,              UINT_MAX },
181   { "LONG",     LONG_MIN,       LONG_MAX },
182   { "ULONG",    0,              ULONG_MAX },
183   { "UINT32",   0,              0xffffffff },
184 #ifdef LLONG_MAX
185   { "LLONG",    LLONG_MIN,      LLONG_MAX },
186   { "ULLONG",   0,              ULLONG_MAX },
187 #endif
188   { "SIZET",    0,              ~(size_t)0 },
189   { 0 }
190 };
191
192 static void dogen(void)
193 {
194   int i;
195
196   for (i = 0; tab[i].name; i++) {
197     if (tab[i].min)
198       emit(tab[i].min, &tab[i].gmin, &tab[i].qmin);
199     uemit(tab[i].max, &tab[i].gmax, &tab[i].qmax);
200   }
201 }
202
203 static void cgen(void)
204 {
205   int i;
206
207   fputs("\
208 /* -*-c-*-\n\
209  *\n\
210  * C integer limits [generated]\n\
211  */\n\
212 \n\
213 #include \"mplimits.h\"\n\
214 \n\
215 #define N(x) (sizeof(x)/sizeof(*x))\n\
216 #define MPpos(x) { x, x + N(x), N(x), 0, MP_CONST, 0 }\n\
217 #define MPneg(x) { x, x + N(x), N(x), 0, MP_CONST|MP_NEG, 0 }\n\
218 \n",
219         stdout);
220   dumpp = 1;
221   dogen();
222
223   fputs("mp mp_limits[] = {\n", stdout);
224   for (i = 0; i < q; i++)
225     printf("  MP%s(guts_%d),\n", qmap[i].s ? "pos" : "neg", qmap[i].g);
226   fputs("};\n", stdout);
227 }
228
229 static void hgen(void)
230 {
231   int i;
232
233   fputs("\
234 /* -*-c-*-\n\
235  *\n\
236  * C integer limits [generated]\n\
237  */\n\
238 \n\
239 #ifndef CATACOMB_MPLIMITS_H\n\
240 #define CATACOMB_MPLIMITS_H\n\
241 \n\
242 #ifndef CATACOMB_MP_H\n\
243 #  include \"mp.h\"\n\
244 #endif\n\
245 \n\
246 extern mp mp_limits[];\n\
247 \n",
248         stdout);
249   dogen();
250
251   for (i = 0; tab[i].name; i++) {
252     if (tab[i].min) {
253       printf("#define MP_%s_MIN (&mp_limits[%d])\n",
254              tab[i].name, gmap[tab[i].qmin][NEG]);
255     }
256     printf("#define MP_%s_MAX (&mp_limits[%d])\n",
257            tab[i].name, gmap[tab[i].qmax][POS]);
258   }
259   fputs("\n#endif\n", stdout);
260 }
261
262 int main(int argc, char *argv[])
263 {
264   const char *what = argc == 2 ? argv[1] : "<bogus>";
265
266   switch (what[0]) {
267     case 'c': cgen(); break;
268     case 'h': hgen(); break;
269     default:
270       fprintf(stderr, "unknown action `%s'\n", what);
271       exit(1);
272   }
273   if (fflush(stdout) || fclose(stdout)) {
274     fprintf(stderr, "error writing output: %s\n", strerror(errno));
275     exit(1);
276   }
277   return (0);
278 }
279
280 /*----- That's all, folks -------------------------------------------------*/