Commit | Line | Data |
---|---|---|
70b904c5 | 1 | /* -*-c-*- |
2 | * | |
70b904c5 | 3 | * Conversion between MPs and standard C integers |
4 | * | |
5 | * (c) 1999 Straylight/Edgeware | |
6 | */ | |
7 | ||
45c0fd36 | 8 | /*----- Licensing notice --------------------------------------------------* |
70b904c5 | 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. | |
45c0fd36 | 16 | * |
70b904c5 | 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. | |
45c0fd36 | 21 | * |
70b904c5 | 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 | ||
92c2a290 | 28 | #ifndef CATACOMB_MPINT_H |
29 | #define CATACOMB_MPINT_H | |
70b904c5 | 30 | |
31 | #ifdef __cplusplus | |
32 | extern "C" { | |
33 | #endif | |
34 | ||
35 | /*----- Header files ------------------------------------------------------*/ | |
36 | ||
37 | #include <limits.h> | |
38 | ||
92c2a290 | 39 | #ifndef CATACOMB_MP_H |
70b904c5 | 40 | # include "mp.h" |
41 | #endif | |
42 | ||
43 | /*----- Generic translation macros ----------------------------------------*/ | |
44 | ||
aa02ed36 MW |
45 | /* --- Warning damage control --- * |
46 | * | |
47 | * GCC (at least) isn't clever enough to work out that the division in | |
48 | * @MP_FROMINT@ is actually safe (since it will only be executed if @_i > | |
49 | * MPW_MAX@, which would prove that @(type)MPW_MAX + 1 != 0@). So here's | |
50 | * some machinery to shut it up. | |
51 | */ | |
52 | ||
53 | #if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) | |
54 | # define MP_FROMINT_MUFFLE_WARNING(x) do { \ | |
55 | _Pragma("GCC diagnostic push") \ | |
56 | _Pragma("GCC diagnostic ignored \"-Wdiv-by-zero\"") \ | |
57 | x \ | |
58 | _Pragma("GCC diagnostic pop") \ | |
59 | } while (0) | |
60 | #else | |
61 | # define MP_FROMINT_MUFFLE_WARNING(x) do { x } while (0) | |
62 | #endif | |
63 | ||
70b904c5 | 64 | /* --- @MP_FROMINT@ --- * |
65 | * | |
66 | * Arguments: @d@ = destination multiprecision integer | |
67 | * @type@ = type of integer which @i@ is | |
68 | * @i@ = a standard C integer | |
69 | * | |
70 | * Use: Stores the value of @i@ in @d@. This macro is actually | |
71 | * rather subtle in places. Be careful what you change. | |
72 | */ | |
73 | ||
74 | #define MP_FROMINT(d, type, i) do { \ | |
75 | type _i = (i); \ | |
76 | size_t _o = 0; \ | |
77 | mp *_d = (d); \ | |
78 | size_t _sz = 4; \ | |
79 | \ | |
d34decd2 | 80 | MP_DEST(_d, _sz, 0); \ |
70b904c5 | 81 | _d->f &= ~(MP_NEG | MP_UNDEF); \ |
82 | \ | |
3485fc41 MW |
83 | if (_i >= 0) { \ |
84 | while (_i) { \ | |
85 | if (_o == _sz) { \ | |
86 | _sz <<= 1; \ | |
87 | MP_ENSURE(_d, _sz); \ | |
88 | } \ | |
89 | _d->v[_o++] = MPW(_i); \ | |
7eaaecf5 | 90 | if (_i <= MPW_MAX) \ |
3485fc41 MW |
91 | break; \ |
92 | else \ | |
aa02ed36 | 93 | MP_FROMINT_MUFFLE_WARNING({ _i /= (type)MPW_MAX + 1; }); \ |
3485fc41 MW |
94 | } \ |
95 | } else { \ | |
70b904c5 | 96 | _d->f |= MP_NEG; \ |
3485fc41 MW |
97 | while (_i) { \ |
98 | if (_o == _sz) { \ | |
99 | _sz <<= 1; \ | |
100 | MP_ENSURE(_d, _sz); \ | |
101 | } \ | |
102 | _d->v[_o++] = MPW(-_i); \ | |
7eaaecf5 | 103 | if (_i >= -MPW_MAX) \ |
3485fc41 MW |
104 | break; \ |
105 | else \ | |
aa02ed36 | 106 | MP_FROMINT_MUFFLE_WARNING({ _i /= (type)MPW_MAX + 1; }); \ |
70b904c5 | 107 | } \ |
70b904c5 | 108 | } \ |
3485fc41 | 109 | \ |
70b904c5 | 110 | _d->vl = _d->v + _o; \ |
111 | (d) = _d; \ | |
112 | } while (0) | |
113 | ||
114 | /* --- @MP_TOINT@ --- * | |
115 | * | |
116 | * Arguments: @m@ = a multiprecision integer | |
117 | * @type@ = the type of @i@ | |
118 | * @max@ = the largest value @i@ can represent | |
119 | * @i@ = an integer variable | |
120 | * | |
121 | * Use: Stores the value of a multiprecision integer in a standard C | |
122 | * integer. If the value won't fit, the behaviour is determined | |
123 | * by the type of @i@: if @i@ is unsigned, the value of the | |
124 | * multiprecision integer modulo @max + 1@ is stored; if @i@ is | |
125 | * signed, the behaviour is undefined. | |
126 | * | |
127 | * If you don't want to be bitten by these sorts of things, keep | |
128 | * copies of @INT_MAX@ or whatever is appropriate in | |
129 | * multiprecision form and compare before conversion. | |
130 | */ | |
131 | ||
132 | #define MP_TOINT(m, type, max, i) do { \ | |
133 | type _i = 0; \ | |
134 | type _max = (max); \ | |
135 | unsigned _s = 0; \ | |
136 | const mp *_m = (m); \ | |
137 | const mpw *_v = _m->v, *_vl = _m->vl; \ | |
138 | \ | |
139 | /* --- Do all the arithmetic in negative numbers --- */ \ | |
140 | \ | |
141 | while (_v < _vl && _max > 0) { \ | |
142 | _i -= *_v << _s; \ | |
143 | _s += MPW_BITS; \ | |
144 | _v++; \ | |
145 | _max /= (mpd)MPW_MAX + 1; \ | |
146 | } \ | |
a69a3efd | 147 | if (!MP_NEGP(_m)) \ |
70b904c5 | 148 | _i = -_i; \ |
149 | (i) = _i; \ | |
150 | } while (0) | |
151 | ||
152 | /*----- Functions provided ------------------------------------------------*/ | |
153 | ||
154 | /* --- @mp_fromINT@ --- * | |
155 | * | |
156 | * Arguments: @mp *d@ = pointer to destination multiprecision integer | |
157 | * @INT i@ = standard C integer to convert | |
158 | * | |
159 | * Returns: The resulting multiprecision integer. | |
160 | * | |
161 | * Use: Converts a standard C integer to a multiprecision integer. | |
162 | */ | |
163 | ||
164 | #define mp_fromINT(name, type) \ | |
165 | extern mp *mp_from##name(mp */*d*/, type /*i*/) | |
166 | ||
167 | mp_fromINT(short, short); | |
168 | mp_fromINT(ushort, unsigned short); | |
169 | mp_fromINT(int, int); | |
170 | mp_fromINT(uint, unsigned); | |
92c2a290 | 171 | mp_fromINT(uint32, uint32); |
70b904c5 | 172 | mp_fromINT(long, long); |
173 | mp_fromINT(ulong, unsigned long); | |
174 | ||
175 | #undef mp_fromINT | |
176 | ||
177 | /* --- @mp_toINT@ --- * | |
178 | * | |
179 | * Arguments: @const mp *m@ = pointer to a multiprecision integer | |
180 | * | |
181 | * Returns: The value of the integer @m@ as a C integer. | |
182 | * | |
183 | * Use: Converts a multiprecision integer to a standard C integer. | |
184 | * If the value of the multiprecision integer cannot be | |
185 | * represented in the return type, and the return type is | |
186 | * unsigned, it is reduced modulo @TYPE_MAX + 1@; if the return | |
187 | * type is signed, the behaviour is undefined. | |
188 | */ | |
189 | ||
190 | #define mp_toINT(name, type) \ | |
cfcaafa7 | 191 | extern type mp_to##name(const mp */*m*/) |
70b904c5 | 192 | |
193 | mp_toINT(short, short); | |
194 | mp_toINT(ushort, unsigned short); | |
195 | mp_toINT(int, int); | |
196 | mp_toINT(uint, unsigned); | |
92c2a290 | 197 | mp_toINT(uint32, uint32); |
70b904c5 | 198 | mp_toINT(long, long); |
199 | mp_toINT(ulong, unsigned long); | |
200 | ||
201 | #undef mp_toINT | |
202 | ||
203 | /*----- That's all, folks -------------------------------------------------*/ | |
204 | ||
205 | #ifdef __cplusplus | |
206 | } | |
207 | #endif | |
208 | ||
209 | #endif |