gmpy2_convert_utils.c
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 * gmpy2_convert_utils.c * 3 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 4 * Python interface to the GMP or MPIR, MPFR, and MPC multiple precision * 5 * libraries. * 6 * * 7 * Copyright 2000 - 2009 Alex Martelli * 8 * * 9 * Copyright 2008 - 2021 Case Van Horsen * 10 * * 11 * This file is part of GMPY2. * 12 * * 13 * GMPY2 is free software: you can redistribute it and/or modify it under * 14 * the terms of the GNU Lesser General Public License as published by the * 15 * Free Software Foundation, either version 3 of the License, or (at your * 16 * option) any later version. * 17 * * 18 * GMPY2 is distributed in the hope that it will be useful, but WITHOUT * 19 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * 20 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * 21 * License for more details. * 22 * * 23 * You should have received a copy of the GNU Lesser General Public * 24 * License along with GMPY2; if not, see <http://www.gnu.org/licenses/> * 25 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 26 27 /* ======================================================================== * 28 * Conversion between Integer objects and C types. * 29 * ======================================================================== * 30 * 31 * Optimized routines for converting an Integer object (Python's integer 32 * type(s), mpz, plus types defining __mpz__) to various C types. 33 * 34 * Note: These functions will not set any exceptions! 35 * 36 */ 37 38 #include "longintrepr.h" 39 40 #define PY_ABS_LONG_MIN (0-(unsigned long)LONG_MIN) 41 42 /* The various ...AndError functions indicate exceptions as follows: 43 * 1) If error is -1, then the argument is negative and the result could 44 * not fit into the desired return type. 45 * 2) If error is 1, then the argument is positive and the result could 46 * not fit into the desired return type. 47 * 3) If error is 2, then the argument is not a recognized type. 48 * 4) If error is 0, then a valid result has been returned. 49 * 50 * The functions special-case the most common paths and then call the 51 * corresponding Python functions to support the general case. 52 * 53 */ 54 55 static long 56 GMPy_Integer_AsLongAndError(PyObject *obj, int *error) 57 { 58 register PyLongObject *v; 59 MPZ_Object *temp_mpz = NULL; 60 unsigned long x, prev; 61 long res = 0; 62 Py_ssize_t i; 63 int sign; 64 65 *error = 0; 66 67 #ifdef PY2 68 if (PyInt_Check(obj)) { 69 return PyInt_AS_LONG(obj); 70 } 71 #endif 72 73 if (PyLong_Check(obj)) { 74 v = (PyLongObject *)obj; 75 i = Py_SIZE(v); 76 77 switch (i) { 78 case -1: 79 res = -(sdigit)v->ob_digit[0]; 80 break; 81 case 0: 82 break; 83 case 1: 84 res = v->ob_digit[0]; 85 break; 86 default: 87 sign = 1; 88 x = 0; 89 if (i < 0) { 90 sign = -1; 91 i = -(i); 92 } 93 while (--i >= 0) { 94 prev = x; 95 x = (x << PyLong_SHIFT) + v->ob_digit[i]; 96 if ((x >> PyLong_SHIFT) != prev) { 97 *error = sign; 98 return res; 99 } 100 } 101 /* Haven't lost any bits, but casting to long requires extra care. 102 */ 103 if (x <= (unsigned long)LONG_MAX) { 104 res = (long)x * sign; 105 } 106 else if (sign < 0 && x == PY_ABS_LONG_MIN) { 107 res = LONG_MIN; 108 } 109 else { 110 *error = sign; 111 } 112 } 113 return res; 114 } 115 116 if (CHECK_MPZANY(obj)) { 117 if (mpz_fits_slong_p(MPZ(obj))) { 118 res = (long) mpz_get_si(MPZ(obj)); 119 } 120 else { 121 *error = mpz_sgn(MPZ(obj)); 122 res = 0; 123 } 124 return res; 125 } 126 127 if (HAS_STRICT_MPZ_CONVERSION(obj)) { 128 temp_mpz = (MPZ_Object *) PyObject_CallMethod(obj, "__mpz__", NULL); 129 130 if (temp_mpz != NULL && MPZ_Check(temp_mpz)) { 131 if (mpz_fits_slong_p(MPZ(temp_mpz))) { 132 res = (long) mpz_get_si(MPZ(temp_mpz)); 133 } 134 else { 135 *error = mpz_sgn(MPZ(temp_mpz)); 136 res = 0; 137 } 138 } 139 Py_XDECREF((PyObject*)temp_mpz); 140 return res; 141 } 142 143 *error = 2; 144 return 0; 145 /* Fall back to using PyLong_AsLongAndOverFlow. This allows gmpy2 to 146 * follow the same semantics as Python for conversion. 147 */ 148 149 /* res = PyLong_AsLongAndOverflow(obj, error); 150 151 if ((res == -1) && PyErr_Occurred()) { 152 PyErr_Clear(); 153 *error = 2; 154 return 0; 155 } 156 else { 157 if (*error) { 158 return 0; 159 } 160 else { 161 return res; 162 } 163 } 164 */ 165 } 166 167 static unsigned long 168 GMPy_Integer_AsUnsignedLongAndError(PyObject *obj, int *error) 169 { 170 register PyLongObject *v; 171 MPZ_Object *temp_mpz = NULL; 172 unsigned long x, prev; 173 unsigned long res = 0; 174 Py_ssize_t i; 175 176 *error = 0; 177 178 #ifdef PY2 179 if (PyInt_Check(obj)) { 180 long temp = PyInt_AS_LONG(obj); 181 if (temp < 0) { 182 *error = -1; 183 return 0; 184 } 185 else { 186 return (unsigned long)temp; 187 } 188 } 189 #endif 190 191 if (PyLong_Check(obj)) { 192 v = (PyLongObject *)obj; 193 i = Py_SIZE(v); 194 195 if (i < 0) { 196 *error = -1; 197 return res; 198 } 199 200 switch (i) { 201 case 0: 202 break; 203 case 1: 204 res = v->ob_digit[0]; 205 break; 206 default: 207 x = 0; 208 while (--i >= 0) { 209 prev = x; 210 x = (x << PyLong_SHIFT) + v->ob_digit[i]; 211 if ((x >> PyLong_SHIFT) != prev) { 212 *error = 1; 213 return res; 214 } 215 } 216 res = x; 217 } 218 return res; 219 } 220 221 if (CHECK_MPZANY(obj)) { 222 if (mpz_fits_ulong_p(MPZ(obj))) { 223 res = (unsigned long) mpz_get_ui(MPZ(obj)); 224 } 225 else { 226 *error = mpz_sgn(MPZ(obj)); 227 res = 0; 228 } 229 return res; 230 } 231 232 if (HAS_STRICT_MPZ_CONVERSION(obj)) { 233 temp_mpz = (MPZ_Object *) PyObject_CallMethod(obj, "__mpz__", NULL); 234 235 if (temp_mpz != NULL && MPZ_Check(temp_mpz)) { 236 if (mpz_fits_ulong_p(MPZ(temp_mpz))) { 237 res = (unsigned long) mpz_get_ui(MPZ(temp_mpz)); 238 } 239 else { 240 *error = mpz_sgn(MPZ(temp_mpz)); 241 res = 0; 242 } 243 } 244 Py_XDECREF((PyObject*)temp_mpz); 245 return res; 246 } 247 248 *error = 2; 249 return 0; 250 } 251 252 static long 253 c_long_From_Integer(PyObject *obj) 254 { 255 long result; 256 int error; 257 258 result = GMPy_Integer_AsLongAndError(obj, &error); 259 if (!error) { 260 return result; 261 } 262 else { 263 if (error == 2) { 264 TYPE_ERROR("could not convert object to integer"); 265 } 266 else { 267 OVERFLOW_ERROR("value too large to convert to C long"); 268 } 269 return -1; 270 } 271 } 272 273 static unsigned long 274 c_ulong_From_Integer(PyObject *obj) 275 { 276 unsigned long result; 277 int error; 278 279 result = GMPy_Integer_AsUnsignedLongAndError(obj, &error); 280 if (!error) { 281 return result; 282 } 283 else { 284 if (error == 2) { 285 TYPE_ERROR("could not convert object to integer"); 286 } 287 else if (error == 1) { 288 OVERFLOW_ERROR("value too large to convert to C unsigned long"); 289 } 290 else if (error < 0) { 291 VALUE_ERROR("a non-negative value is required"); 292 } 293 return (unsigned long)(-1); 294 } 295 } 296 297 /* The follow code is only used on Windows x64 platform. We check for _WIN64 298 * but we then assume the PY_LONG_LONG is defined. 299 */ 300 301 #ifdef _WIN64 302 303 #define PY_ABS_LLONG_MIN (0-(unsigned PY_LONG_LONG)PY_LLONG_MIN) 304 305 static PY_LONG_LONG 306 GMPy_Integer_AsLongLongAndError(PyObject *obj, int *error) 307 { 308 register PyLongObject *v; 309 MPZ_Object *temp_mpz = NULL; 310 unsigned PY_LONG_LONG x, prev; 311 PY_LONG_LONG res = 0; 312 Py_ssize_t i; 313 int sign; 314 315 *error = 0; 316 317 #ifdef PY2 318 if (PyInt_Check(obj)) { 319 return (PY_LONG_LONG)PyInt_AS_LONG(obj); 320 } 321 #endif 322 323 if (PyLong_Check(obj)) { 324 v = (PyLongObject *)obj; 325 i = Py_SIZE(v); 326 327 switch (i) { 328 case -1: 329 res = -(sdigit)v->ob_digit[0]; 330 break; 331 case 0: 332 break; 333 case 1: 334 res = v->ob_digit[0]; 335 break; 336 default: 337 sign = 1; 338 x = 0; 339 if (i < 0) { 340 sign = -1; 341 i = -(i); 342 } 343 while (--i >= 0) { 344 prev = x; 345 x = (x << PyLong_SHIFT) + v->ob_digit[i]; 346 if ((x >> PyLong_SHIFT) != prev) { 347 *error = sign; 348 return res; 349 } 350 } 351 /* Haven't lost any bits, but casting to long requires extra care. 352 */ 353 if (x <= (unsigned PY_LONG_LONG)PY_LLONG_MAX) { 354 res = (PY_LONG_LONG)x * sign; 355 } 356 else if (sign < 0 && x == PY_ABS_LLONG_MIN) { 357 res = PY_LLONG_MIN; 358 } 359 else { 360 *error = sign; 361 } 362 } 363 return res; 364 } 365 366 if (CHECK_MPZANY(obj)) { 367 sign = mpz_sgn(MPZ(obj)); 368 if (sign) { 369 if (mpz_sizeinbase(MPZ(obj), 256) <= sizeof(x)) { 370 x = 0; 371 mpz_export(&x, NULL, 1, sizeof(x), 0, 0, MPZ(obj)); 372 } 373 if (x <= (unsigned PY_LONG_LONG)PY_LLONG_MAX) { 374 res = (PY_LONG_LONG)x * sign; 375 } 376 else if (sign < 0 && x == PY_ABS_LLONG_MIN) { 377 res = PY_LLONG_MIN; 378 } 379 else { 380 *error = sign; 381 } 382 } 383 return res; 384 } 385 386 if (HAS_STRICT_MPZ_CONVERSION(obj)) { 387 temp_mpz = (MPZ_Object *) PyObject_CallMethod(obj, "__mpz__", NULL); 388 389 if (temp_mpz != NULL && MPZ_Check(temp_mpz)) { 390 sign = mpz_sgn(MPZ(obj)); 391 if (sign) { 392 if (mpz_sizeinbase(MPZ(obj), 256) <= sizeof(x)) { 393 x = 0; 394 mpz_export(&x, NULL, 1, sizeof(x), 0, 0, MPZ(obj)); 395 } 396 if (x <= (unsigned PY_LONG_LONG)PY_LLONG_MAX) { 397 res = (PY_LONG_LONG)x * sign; 398 } 399 else if (sign < 0 && x == PY_ABS_LLONG_MIN) { 400 res = PY_LLONG_MIN; 401 } 402 else { 403 *error = sign; 404 } 405 } 406 Py_XDECREF((PyObject*)temp_mpz); 407 } 408 return res; 409 } 410 411 *error = 2; 412 return 0; 413 } 414 415 static unsigned PY_LONG_LONG 416 GMPy_Integer_AsUnsignedLongLongAndError(PyObject *obj, int *error) 417 { 418 register PyLongObject *v; 419 MPZ_Object *temp_mpz = NULL; 420 unsigned PY_LONG_LONG x, prev, res = 0; 421 Py_ssize_t i; 422 int sign; 423 424 *error = 0; 425 426 #ifdef PY2 427 if (PyInt_Check(obj)) { 428 long temp = PyInt_AS_LONG(obj); 429 if (temp < 0) { 430 *error = -1; 431 return res; 432 } 433 else { 434 return (unsigned PY_LONG_LONG)temp; 435 } 436 } 437 #endif 438 439 if (PyLong_Check(obj)) { 440 v = (PyLongObject *)obj; 441 i = Py_SIZE(v); 442 443 if (i < 0) { 444 *error = -1; 445 return res; 446 } 447 448 switch (i) { 449 case 0: 450 break; 451 case 1: 452 res = v->ob_digit[0]; 453 break; 454 default: 455 x = 0; 456 while (--i >= 0) { 457 prev = x; 458 x = (x << PyLong_SHIFT) + v->ob_digit[i]; 459 if ((x >> PyLong_SHIFT) != prev) { 460 *error = 1; 461 return res; 462 } 463 } 464 res = x; 465 } 466 return res; 467 } 468 469 if (CHECK_MPZANY(obj)) { 470 sign = mpz_sgn(MPZ(obj)); 471 if (sign < 0) { 472 *error = -1; 473 return res; 474 } 475 else if (sign) { 476 if (mpz_sizeinbase(MPZ(obj), 256) <= sizeof(res)) { 477 mpz_export(&res, NULL, 1, sizeof(x), 0, 0, MPZ(obj)); 478 } 479 else { 480 *error = 1; 481 } 482 } 483 return res; 484 } 485 486 if (HAS_STRICT_MPZ_CONVERSION(obj)) { 487 temp_mpz = (MPZ_Object *) PyObject_CallMethod(obj, "__mpz__", NULL); 488 489 if (temp_mpz != NULL && MPZ_Check(temp_mpz)) { 490 sign = mpz_sgn(MPZ(obj)); 491 if (sign < 0) { 492 *error = -1; 493 } 494 else if (sign) { 495 if (mpz_sizeinbase(MPZ(obj), 256) <= sizeof(res)) { 496 mpz_export(&res, NULL, 1, sizeof(x), 0, 0, MPZ(obj)); 497 } 498 } 499 else { 500 *error = 1; 501 } 502 Py_XDECREF((PyObject*)temp_mpz); 503 } 504 return res; 505 } 506 507 *error = 2; 508 return 0; 509 } 510 511 static PY_LONG_LONG 512 c_longlong_From_Integer(PyObject *obj) 513 { 514 PY_LONG_LONG result; 515 int error; 516 517 result = GMPy_Integer_AsLongLongAndError(obj, &error); 518 if (!error) { 519 return result; 520 } 521 else { 522 if (error == 2) { 523 TYPE_ERROR("could not convert object to integer"); 524 } 525 else { 526 OVERFLOW_ERROR("value too large to convert to C long long"); 527 } 528 return -1; 529 } 530 } 531 532 static unsigned PY_LONG_LONG 533 c_ulonglong_From_Integer(PyObject *obj) 534 { 535 unsigned PY_LONG_LONG result; 536 int error; 537 538 result = GMPy_Integer_AsUnsignedLongLongAndError(obj, &error); 539 if (!error) { 540 return result; 541 } 542 else { 543 if (error == 2) { 544 TYPE_ERROR("could not convert object to integer"); 545 } 546 else if (error == 1) { 547 OVERFLOW_ERROR("value too large to convert to C unsigned long long"); 548 } 549 else if (error < 0) { 550 VALUE_ERROR("a non-negative value is required"); 551 } 552 return (unsigned PY_LONG_LONG)(-1); 553 } 554 } 555 556 #endif 557