chiark / gitweb /
Merge branch '2.4.x' into 2.5.x
[catacomb] / math / mpint.h
1 /* -*-c-*-
2  *
3  * Conversion between MPs and standard C integers
4  *
5  * (c) 1999 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 #ifndef CATACOMB_MPINT_H
29 #define CATACOMB_MPINT_H
30
31 #ifdef __cplusplus
32   extern "C" {
33 #endif
34
35 /*----- Header files ------------------------------------------------------*/
36
37 #include <limits.h>
38
39 #include <mLib/macros.h>
40
41 #ifndef CATACOMB_MP_H
42 #  include "mp.h"
43 #endif
44
45 /*----- Generic translation macros ----------------------------------------*/
46
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 >
51  * MPW_MAX@, which would prove that @(type)MPW_MAX + 1 != 0@).
52  */
53
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                                                                         \
70   MP_DEST(_d, _sz, 0);                                                  \
71   _d->f &= ~(MP_NEG | MP_UNDEF);                                        \
72                                                                         \
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);                                            \
80       if (MUFFLE_WARNINGS_EXPR(                                         \
81             CLANG_WARNING("-Wtautological-constant-out-of-range-compare"), \
82             _i <= MPW_MAX))                                             \
83         break;                                                          \
84       else                                                              \
85         MUFFLE_WARNINGS_STMT(GCC_WARNING("-Wdiv-by-zero")               \
86                              CLANG_WARNING("-Wdivision-by-zero"), {     \
87           _i /= (type)MPW_MAX + 1;                                      \
88         });                                                             \
89     }                                                                   \
90   } else {                                                              \
91     _d->f |= MP_NEG;                                                    \
92     while (_i) {                                                        \
93       if (_o == _sz) {                                                  \
94         _sz <<= 1;                                                      \
95         MP_ENSURE(_d, _sz);                                             \
96       }                                                                 \
97       _d->v[_o++] = MPW(-_i);                                           \
98       if (MUFFLE_WARNINGS_EXPR(                                         \
99             CLANG_WARNING("-Wtautological-constant-out-of-range-compare"), \
100             _i >= -MPW_MAX))                                            \
101         break;                                                          \
102       else                                                              \
103         MUFFLE_WARNINGS_STMT(GCC_WARNING("-Wdiv-by-zero")               \
104                              CLANG_WARNING("-Wdivision-by-zero"), {     \
105           _i /= (type)MPW_MAX + 1;                                      \
106         });                                                             \
107     }                                                                   \
108   }                                                                     \
109                                                                         \
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 -= (type)*_v << _s;                                              \
143     _s += MPW_BITS;                                                     \
144     _v++;                                                               \
145     _max /= (mpd)MPW_MAX + 1;                                           \
146   }                                                                     \
147   if (!MP_NEGP(_m))                                                     \
148     _i = -_i;                                                           \
149   (i) = _i;                                                             \
150 } while (0)
151
152 /*----- Functions provided ------------------------------------------------*/
153
154 /* --- Build up the list of conversions to be supplied --- */
155
156 #ifdef ULLONG_MAX
157 #  ifndef LLONG_MAX
158 #    define LLONG_MAX LONG_LONG_MAX
159 #  endif
160 #  define MPINT_CONV_LLONG(_)                                           \
161   _(llong, long long, LLONG_MAX)                                        \
162   _(ullong, unsigned long long, ULLONG_MAX)
163 #else
164 #  define MPINT_CONV_LLONG(_)
165 #endif
166
167 #ifdef INTMAX_MAX
168 #  define MPINT_CONV_INTMAX(_)                                          \
169   _(intmax, intmax_t, INTMAX_MAX)                                       \
170   _(uintmax, uintmax_t, UINTMAX_MAX)
171 #else
172 #  define MPINT_CONV_INTMAX(_)
173 #endif
174
175 #ifdef HAVE_UINT64
176 #  define MPINT_CONV_U64(_) _(uint64, uint64, MASK64)
177 #else
178 #  define MPINT_CONV_U64(_)
179 #endif
180
181 #define MPINT_CONVERSIONS(_)                                            \
182   _(short, short, SHRT_MAX)                                             \
183   _(ushort, unsigned short, USHRT_MAX)                                  \
184   _(int, int, INT_MAX)                                                  \
185   _(uint, unsigned, UINT_MAX)                                           \
186   _(long, long, LONG_MAX)                                               \
187   _(ulong, unsigned long, ULONG_MAX)                                    \
188   MPINT_CONV_LLONG(_)                                                   \
189   _(uint8, uint8, MASK8)                                                \
190   _(uint16, uint16, MASK16)                                             \
191   _(uint24, uint24, MASK24)                                             \
192   _(uint32, uint32, MASK32)                                             \
193   MPINT_CONV_U64(_)                                                     \
194   MPINT_CONV_INTMAX(_)                                                  \
195   _(sizet, size_t, (size_t)-1)
196
197 /* --- @mp_fromINT@ --- *
198  *
199  * Arguments:   @mp *d@ = pointer to destination multiprecision integer
200  *              @INT i@ = standard C integer to convert
201  *
202  * Returns:     The resulting multiprecision integer.
203  *
204  * Use:         Converts a standard C integer to a multiprecision integer.
205  */
206
207 #define mp_fromINT(name, type, max)                                     \
208   extern mp *mp_from##name(mp */*d*/, type /*i*/);
209 MPINT_CONVERSIONS(mp_fromINT)
210 #undef mp_fromINT
211
212 /* --- @mp_toINT@ --- *
213  *
214  * Arguments:   @const mp *m@ = pointer to a multiprecision integer
215  *
216  * Returns:     The value of the integer @m@ as a C integer.
217  *
218  * Use:         Converts a multiprecision integer to a standard C integer.
219  *              If the value of the multiprecision integer cannot be
220  *              represented in the return type, and the return type is
221  *              unsigned, it is reduced modulo @TYPE_MAX + 1@; if the return
222  *              type is signed, the behaviour is undefined.
223  */
224
225 #define mp_toINT(name, type, max)                                       \
226   extern type mp_to##name(const mp */*m*/);
227 MPINT_CONVERSIONS(mp_toINT)
228 #undef mp_toINT
229
230 /*----- That's all, folks -------------------------------------------------*/
231
232 #ifdef __cplusplus
233   }
234 #endif
235
236 #endif