Commit | Line | Data |
---|---|---|
70b904c5 | 1 | /* -*-c-*- |
70b904c5 | 2 | * |
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 | ||
23bbea75 MW |
39 | #include <mLib/macros.h> |
40 | ||
92c2a290 | 41 | #ifndef CATACOMB_MP_H |
70b904c5 | 42 | # include "mp.h" |
43 | #endif | |
44 | ||
45 | /*----- Generic translation macros ----------------------------------------*/ | |
46 | ||
aa02ed36 MW |
47 | /* --- Warning damage control --- * |
48 | * | |
49 | * GCC (at least) isn't clever enough to work out that the division in | |
50 | * @MP_FROMINT@ is actually safe (since it will only be executed if @_i > | |
23bbea75 | 51 | * MPW_MAX@, which would prove that @(type)MPW_MAX + 1 != 0@). |
aa02ed36 MW |
52 | */ |
53 | ||
70b904c5 | 54 | /* --- @MP_FROMINT@ --- * |
55 | * | |
56 | * Arguments: @d@ = destination multiprecision integer | |
57 | * @type@ = type of integer which @i@ is | |
58 | * @i@ = a standard C integer | |
59 | * | |
60 | * Use: Stores the value of @i@ in @d@. This macro is actually | |
61 | * rather subtle in places. Be careful what you change. | |
62 | */ | |
63 | ||
64 | #define MP_FROMINT(d, type, i) do { \ | |
65 | type _i = (i); \ | |
66 | size_t _o = 0; \ | |
67 | mp *_d = (d); \ | |
68 | size_t _sz = 4; \ | |
69 | \ | |
d34decd2 | 70 | MP_DEST(_d, _sz, 0); \ |
70b904c5 | 71 | _d->f &= ~(MP_NEG | MP_UNDEF); \ |
72 | \ | |
3485fc41 MW |
73 | if (_i >= 0) { \ |
74 | while (_i) { \ | |
75 | if (_o == _sz) { \ | |
76 | _sz <<= 1; \ | |
77 | MP_ENSURE(_d, _sz); \ | |
78 | } \ | |
79 | _d->v[_o++] = MPW(_i); \ | |
7eaaecf5 | 80 | if (_i <= MPW_MAX) \ |
3485fc41 MW |
81 | break; \ |
82 | else \ | |
23bbea75 MW |
83 | MUFFLE_WARNINGS_STMT(GCC_WARNING("-Wdiv-by-zero"), { \ |
84 | _i /= (type)MPW_MAX + 1; \ | |
85 | }); \ | |
3485fc41 MW |
86 | } \ |
87 | } else { \ | |
70b904c5 | 88 | _d->f |= MP_NEG; \ |
3485fc41 MW |
89 | while (_i) { \ |
90 | if (_o == _sz) { \ | |
91 | _sz <<= 1; \ | |
92 | MP_ENSURE(_d, _sz); \ | |
93 | } \ | |
94 | _d->v[_o++] = MPW(-_i); \ | |
7eaaecf5 | 95 | if (_i >= -MPW_MAX) \ |
3485fc41 MW |
96 | break; \ |
97 | else \ | |
23bbea75 MW |
98 | MUFFLE_WARNINGS_STMT(GCC_WARNING("-Wdiv-by-zero"), { \ |
99 | _i /= (type)MPW_MAX + 1; \ | |
100 | }); \ | |
70b904c5 | 101 | } \ |
70b904c5 | 102 | } \ |
3485fc41 | 103 | \ |
70b904c5 | 104 | _d->vl = _d->v + _o; \ |
105 | (d) = _d; \ | |
106 | } while (0) | |
107 | ||
108 | /* --- @MP_TOINT@ --- * | |
109 | * | |
110 | * Arguments: @m@ = a multiprecision integer | |
111 | * @type@ = the type of @i@ | |
112 | * @max@ = the largest value @i@ can represent | |
113 | * @i@ = an integer variable | |
114 | * | |
115 | * Use: Stores the value of a multiprecision integer in a standard C | |
116 | * integer. If the value won't fit, the behaviour is determined | |
117 | * by the type of @i@: if @i@ is unsigned, the value of the | |
118 | * multiprecision integer modulo @max + 1@ is stored; if @i@ is | |
119 | * signed, the behaviour is undefined. | |
120 | * | |
121 | * If you don't want to be bitten by these sorts of things, keep | |
122 | * copies of @INT_MAX@ or whatever is appropriate in | |
123 | * multiprecision form and compare before conversion. | |
124 | */ | |
125 | ||
126 | #define MP_TOINT(m, type, max, i) do { \ | |
127 | type _i = 0; \ | |
128 | type _max = (max); \ | |
129 | unsigned _s = 0; \ | |
130 | const mp *_m = (m); \ | |
131 | const mpw *_v = _m->v, *_vl = _m->vl; \ | |
132 | \ | |
133 | /* --- Do all the arithmetic in negative numbers --- */ \ | |
134 | \ | |
135 | while (_v < _vl && _max > 0) { \ | |
c973f431 | 136 | _i -= (type)*_v << _s; \ |
70b904c5 | 137 | _s += MPW_BITS; \ |
138 | _v++; \ | |
139 | _max /= (mpd)MPW_MAX + 1; \ | |
140 | } \ | |
a69a3efd | 141 | if (!MP_NEGP(_m)) \ |
70b904c5 | 142 | _i = -_i; \ |
143 | (i) = _i; \ | |
144 | } while (0) | |
145 | ||
146 | /*----- Functions provided ------------------------------------------------*/ | |
147 | ||
2302cd86 MW |
148 | /* --- Build up the list of conversions to be supplied --- */ |
149 | ||
cc08c570 MW |
150 | #ifdef ULLONG_MAX |
151 | # ifndef LLONG_MAX | |
152 | # define LLONG_MAX LONG_LONG_MAX | |
153 | # endif | |
154 | # define MPINT_CONV_LLONG(_) \ | |
155 | _(llong, long long, LLONG_MAX) \ | |
156 | _(ullong, unsigned long long, ULLONG_MAX) | |
157 | #else | |
158 | # define MPINT_CONV_LLONG(_) | |
159 | #endif | |
160 | ||
161 | #ifdef INTMAX_MAX | |
162 | # define MPINT_CONV_INTMAX(_) \ | |
163 | _(intmax, intmax_t, INTMAX_MAX) \ | |
164 | _(uintmax, uintmax_t, UINTMAX_MAX) | |
165 | #else | |
166 | # define MPINT_CONV_INTMAX(_) | |
167 | #endif | |
168 | ||
169 | #ifdef HAVE_UINT64 | |
170 | # define MPINT_CONV_U64(_) _(uint64, uint64, MASK64) | |
171 | #else | |
172 | # define MPINT_CONV_U64(_) | |
173 | #endif | |
174 | ||
2302cd86 MW |
175 | #define MPINT_CONVERSIONS(_) \ |
176 | _(short, short, SHRT_MAX) \ | |
177 | _(ushort, unsigned short, USHRT_MAX) \ | |
178 | _(int, int, INT_MAX) \ | |
179 | _(uint, unsigned, UINT_MAX) \ | |
180 | _(long, long, LONG_MAX) \ | |
181 | _(ulong, unsigned long, ULONG_MAX) \ | |
cc08c570 MW |
182 | MPINT_CONV_LLONG(_) \ |
183 | _(uint8, uint8, MASK8) \ | |
184 | _(uint16, uint16, MASK16) \ | |
185 | _(uint24, uint24, MASK24) \ | |
186 | _(uint32, uint32, MASK32) \ | |
187 | MPINT_CONV_U64(_) \ | |
188 | MPINT_CONV_INTMAX(_) \ | |
189 | _(sizet, size_t, (size_t)-1) | |
2302cd86 | 190 | |
70b904c5 | 191 | /* --- @mp_fromINT@ --- * |
192 | * | |
193 | * Arguments: @mp *d@ = pointer to destination multiprecision integer | |
194 | * @INT i@ = standard C integer to convert | |
195 | * | |
196 | * Returns: The resulting multiprecision integer. | |
197 | * | |
198 | * Use: Converts a standard C integer to a multiprecision integer. | |
199 | */ | |
200 | ||
2302cd86 MW |
201 | #define mp_fromINT(name, type, max) \ |
202 | extern mp *mp_from##name(mp */*d*/, type /*i*/); | |
203 | MPINT_CONVERSIONS(mp_fromINT) | |
70b904c5 | 204 | #undef mp_fromINT |
205 | ||
206 | /* --- @mp_toINT@ --- * | |
207 | * | |
208 | * Arguments: @const mp *m@ = pointer to a multiprecision integer | |
209 | * | |
210 | * Returns: The value of the integer @m@ as a C integer. | |
211 | * | |
212 | * Use: Converts a multiprecision integer to a standard C integer. | |
213 | * If the value of the multiprecision integer cannot be | |
214 | * represented in the return type, and the return type is | |
215 | * unsigned, it is reduced modulo @TYPE_MAX + 1@; if the return | |
216 | * type is signed, the behaviour is undefined. | |
217 | */ | |
218 | ||
2302cd86 MW |
219 | #define mp_toINT(name, type, max) \ |
220 | extern type mp_to##name(const mp */*m*/); | |
221 | MPINT_CONVERSIONS(mp_toINT) | |
70b904c5 | 222 | #undef mp_toINT |
223 | ||
224 | /*----- That's all, folks -------------------------------------------------*/ | |
225 | ||
226 | #ifdef __cplusplus | |
227 | } | |
228 | #endif | |
229 | ||
230 | #endif |