2 * Copyright (c) 2005 Zmanda, Inc. All Rights Reserved.
4 * This library is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 2.1 as
6 * published by the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
11 * License for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17 * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
18 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
27 /* these functions are only needed if Perl has 32-bit IV's */
28 /* Make sure Math::BigInt is loaded
31 load_Math_BigInt(void)
33 static int loaded = 0;
37 eval_pv("use Math::BigInt;", 1);
41 /* Given a string, create a Math::BigInt representing its value.
43 * @param num: string representation of a number
44 * @returns: BigInt representation of the same number
59 XPUSHs(sv_2mortal(newSVpv("Math::BigInt", 0)));
60 XPUSHs(sv_2mortal(newSVpv(num, 0)));
63 count = call_method("Math::BigInt::new", G_SCALAR);
68 croak("Expected a result from Math::Bigint->new");
81 amglue_newSVi64(gint64 v)
84 g_snprintf(numstr, sizeof(numstr), "%jd", (intmax_t)v);
85 numstr[sizeof(numstr)-1] = '\0';
86 return str2bigint(numstr);
90 amglue_newSVu64(guint64 v)
93 g_snprintf(numstr, sizeof(numstr), "%ju", (uintmax_t)v);
94 numstr[sizeof(numstr)-1] = '\0';
95 return str2bigint(numstr);
102 /* Conversion from Perl values handles BigInts regardless of whether
103 * Perl's IVs are 32- or 64-bit, for completeness' sake.
106 /* Convert a bigint to a signed integer, or croak trying.
108 * @param bigint: the perl object to convert
109 * @returns: signed integer
112 bigint2int64(SV *bigint)
117 gboolean negative = FALSE;
121 /* first, see if it's a BigInt */
122 if (!sv_isobject(bigint) || !sv_derived_from(bigint, "Math::BigInt"))
123 croak("Expected an integer or a Math::BigInt; cannot convert");
129 * strtoull($bigint->bstr()) */
135 count = call_method("Math::BigInt::bstr", G_SCALAR);
140 croak("Expected a result from Math::BigInt::bstr");
143 str = SvPV_nolen(sv);
145 croak("Math::BigInt::bstr did not return a string");
153 absval = g_ascii_strtoull(str, NULL, 0);
154 /* (the last branch of this || depends on G_MININT64 = -G_MAXINT64-1) */
155 if ((absval == G_MAXUINT64 && errno == ERANGE)
156 || (!negative && absval > (guint64)(G_MAXINT64))
157 || (negative && absval > (guint64)(G_MAXINT64)+1))
158 croak("Expected a signed 64-bit value or smaller; value '%s' out of range", str);
160 croak("Math::BigInt->bstr returned invalid number '%s'", str);
166 if (negative) return -absval;
170 /* Convert bigint to an unsigned integer, or croak trying.
172 * @param bigint: the perl object to convert
173 * @returns: unsigned integer
176 bigint2uint64(SV *bigint)
184 /* first, see if it's a BigInt */
185 if (!sv_isobject(bigint) || !sv_derived_from(bigint, "Math::BigInt"))
186 croak("Expected an integer or a Math::BigInt; cannot convert");
191 /* make sure the bigint is positive:
192 * croak(..) unless $bigint->sign() eq "+"; */
198 count = call_method("Math::BigInt::sign", G_SCALAR);
203 croak("Expected a result from Math::BigInt::sign");
206 str = SvPV_nolen(sv);
208 croak("Math::BigInt::sign did not return a string");
210 if (strcmp(str, "+") != 0)
211 croak("Expected a positive number; value out of range");
214 * strtoull($bigint->bstr()) */
220 count = call_method("Math::BigInt::bstr", G_SCALAR);
225 croak("Expected a result from Math::BigInt::bstr");
228 str = SvPV_nolen(sv);
230 croak("Math::BigInt::bstr did not return a string");
233 rv = g_ascii_strtoull(str, NULL, 0);
234 if (rv == G_MAXUINT64 && errno == ERANGE)
235 croak("Expected an unsigned 64-bit value or smaller; value '%s' out of range", str);
237 croak("Math::BigInt->bstr returned invalid number '%s'", str);
246 gint64 amglue_SvI64(SV *sv)
254 } else if (SvNOK(sv)) {
255 double dv = SvNV(sv);
257 /* preprocessor constants seem to have trouble here, so we convert to gint64 and
258 * back, and if the result differs, then we have lost something. Note that this will
259 * also error out on integer truncation .. which is probably OK */
260 gint64 iv = (gint64)dv;
261 if (dv != (double)iv) {
262 croak("Expected a signed 64-bit value or smaller; value '%.0f' out of range", (float)dv);
268 return bigint2int64(sv);
272 guint64 amglue_SvU64(SV *sv)
277 } else if (SvIV(sv) < 0) {
278 croak("Expected an unsigned value, got a negative integer");
281 return (guint64)SvIV(sv);
283 } else if (SvNOK(sv)) {
284 double dv = SvNV(sv);
286 croak("Expected an unsigned value, got a negative integer");
288 } else if (dv > (double)G_MAXUINT64) {
289 croak("Expected an unsigned 64-bit value or smaller; value out of range");
295 return bigint2uint64(sv);
299 gint32 amglue_SvI32(SV *sv)
301 gint64 v64 = amglue_SvI64(sv);
302 if (v64 < G_MININT32 || v64 > G_MAXINT32) {
303 croak("Expected a 32-bit integer; value out of range");
310 guint32 amglue_SvU32(SV *sv)
312 guint64 v64 = amglue_SvU64(sv);
313 if (v64 > G_MAXUINT32) {
314 croak("Expected a 32-bit unsigned integer; value out of range");
321 gint16 amglue_SvI16(SV *sv)
323 gint64 v64 = amglue_SvI64(sv);
324 if (v64 < G_MININT16 || v64 > G_MAXINT16) {
325 croak("Expected a 16-bit integer; value out of range");
332 guint16 amglue_SvU16(SV *sv)
334 guint64 v64 = amglue_SvU64(sv);
335 if (v64 > G_MAXUINT16) {
336 croak("Expected a 16-bit unsigned integer; value out of range");
343 gint8 amglue_SvI8(SV *sv)
345 gint64 v64 = amglue_SvI64(sv);
346 if (v64 < G_MININT8 || v64 > G_MAXINT8) {
347 croak("Expected a 8-bit integer; value out of range");
354 guint8 amglue_SvU8(SV *sv)
356 guint64 v64 = amglue_SvU64(sv);
357 if (v64 > G_MAXUINT8) {
358 croak("Expected a 8-bit unsigned integer; value out of range");