diff --git a/build-wheels.conf b/build-wheels.conf deleted file mode 100644 index 62fe76e4..00000000 --- a/build-wheels.conf +++ /dev/null @@ -1,20 +0,0 @@ -# Edit this file to trigger builds of binary wheels. -# -# Recommend format: -# * (asterick) followed by comment. -* Test wheel build #1. -* Test wheel build #2. -* Test wheel build for 2.1.0b6 #1 -* Test wheel build for 2.1.0b6 #2 -* Test wheel build for 2.1.0b6 #3 -* Test wheel build for 2.1.0b6 #4 -* Test wheel build for 2.1.0b6 #5 -* Test wheel build for 2.1.0b6 #6 -* Test wheel build for 2.1.0b6 #7 -* Test wheel build for 2.1.0b6 #8 -* Test wheel build for 2.1.0b6 #9 -* Test wheel build for 2.1.0rc1 -* Test wheel build again for 2.1.0rc1. -* Test wheel build again for 2.1.0rc1. -* Trigger wheel build for 2.1.0rc2. -* Test wheel build for 2.1.0rc2. diff --git a/docs/history.rst b/docs/history.rst index f34b26e6..f697bd07 100644 --- a/docs/history.rst +++ b/docs/history.rst @@ -6,7 +6,82 @@ Release Notes Changes in gmpy2 2.2.0 ------------------------ -* Added prev_prime() when GMP >= 6.3 +* Remove support for versions of Python < 3.7. (skirpichev) +* Support more modern build tools. (skirpichev) +* Use contextvars to manage gmpy2 contexts. (casevh) +* _mpmath functions now use vectorcall protocol. (casevh) +* Many documentation updates. (skirpichev) +* Add :meth:`mpz.as_integer_ratio()` / :meth:`mpz.to_bytes()` and + :meth:`mpz.from_bytes()`. (skirpichev) +* Add :func:`is_probab_prime()` to directly expose the GMP + behavior. (skirpichev) +* :func:`gcd()`/:func:`lcm()` now uses vectorcall protocol. (skirpichev) +* Expose :class:`context` type. (skirpichev) +* Correct error in :func:`is_strong_bpsw_prp()`. (casevh) +* Added :func:`prev_prime()` when GMP >= 6.3. (sethtroisi) +* Change argument order of :func:`jn()` and :func:`yn()` to match + MPFR. (casevh) +* Fix documentation and code for + :func:`is_extra_strong_lucas_prp()`. (casevh) + +Changes in gmpy2 2.1.5 +---------------------- + +* Version bump to fix wheel issues. No code changes. + +Changes in gmpy2 2.1.4 +---------------------- + +* Version bump to fix wheel issues. No code changes. + +Changes in gmpy2 2.1.3 +---------------------- + +* Fix mpz(-3).is_prime(). +* Add powmod_sec(). +* Fix mpfr('inf') and mpfr('nan') if subnormalization is enabled. +* powmod() and powmod_sec() release the GIL. +* Fix error messages for iroot(x,n) for large n. +* Add powmod_base_list() and powmod_exp_list() (experimental). +* Fix gmpy2.mpq(mpq, int). +* Fix issues with INF, NAN, and mpfr("-0") when subnormalization is True + +Changes in gmpy2 2.1.2 +---------------------- + +* Code cleanup. +* Support Apple Silicon binary wheels. +* is_prime(-2) now returns False. Issue #312. + +Changes in gmpy2 2.1.1 +---------------------- + +* Code cleanup. +* Properly return NOTIMPLEMENTED for unsupported arguments in + ``**``. Issue #319. + +Changes in gmpy2 2.1.0 +---------------------- + +* Improvements to setup.py. +* Add thread-safe contexts. +* MPFR and MPC are now required. +* Invalid Operation exception now raised for addition, etc. +* inverse() now raises exception if inverse does not exist. +* Add context methods. +* Major code refactoring required to properly support thread-safe contexts. +* `` __str__`` and ``__repr__`` no longer append "L" on Python 2. +* mpq(mpfr) now returns the exact result. +* Fix repr(mpc) for precision >325 bits. +* Intermediate conversions of Integer to mpfr are now done with the + full precision of the Integer. +* Remove support for interaction with Decimal type. +* No longer attempt to override the memory allocation functions. +* Register gmpy2 types into the numeric tower. +* mpz(x) call int(x) if mpz() does not know how to convert x directly. +* Convert `mpz` to a type using ``__new__`` instead of a factory function. +* Bug fix for ``<> ** <>``. +* Compile with Python 3.11. Changes in gmpy2 2.1.0rc2 ------------------------- @@ -158,15 +233,14 @@ Changes in gmpy2 2.0.0 ---------------------- * Fix segmentation fault in ``_mpmath_normalize()`` (an undocumented helper - function for mpmath). -* Improved ``setup.py``. See below for documentation on the changes. -* Fix issues when compiled without support for MPFR. + function for mpmath). (casevh) +* Fix issues when compiled without support for MPFR. (casevh) * Conversion of too large an `mpz` to `float` now raises `OverflowError` - instead of returning ``inf``. -* Renamed ``min2()/max2()`` to `minnum()`/`maxnum()` + instead of returning ``inf``. (casevh) +* Renamed ``min2()/max2()`` to `minnum()`/`maxnum()`. (casevh) * The build and install process (i.e. ``setup.py``) has been completely - rewritten. See the Installation section for more information. -* `get_context()` no longer accepts keyword arguments. + rewritten. See the Installation section for more information. (casevh) +* `get_context()` no longer accepts keyword arguments. (casevh) Known issues in gmpy2 2.0.0 ----------------------------- @@ -177,16 +251,18 @@ Changes in gmpy2 2.0.0b4 ------------------------ * Added ``__ceil__()``, ``__floor__()``, ``__trunc__()``, and ``__round__()`` - methods to `mpz` and `mpq` types. -* Added ``__complex__()`` to `mpc` type. -* ``round(mpfr)`` now correctly returns an `mpz` type. + methods to `mpz` and `mpq` types. (casevh) +* Added ``__complex__()`` to `mpc` type. (casevh) +* ``round(mpfr)`` now correctly returns an `mpz` type. (casevh) +* Add mpz.denominator and mpz.numerator. (casevh) * If no arguments are given to `mpz`, `mpq`, `mpfr`, `mpc`, and `xmpz`, - return 0 of the appropriate type. -* Fix broken comparison between `mpz` and `mpq` when `mpz` is on the left. + return 0 of the appropriate type. (casevh) +* Fix broken comparison between `mpz` and `mpq` when `mpz` is on + the left. (casevh) * Added ``__sizeof__()`` to all types. Note: :func:`sys.getsizeof` calls ``__sizeof__()`` to get the memory size of a gmpy2 object. The returned value reflects the size of the allocated memory which may be larger than - the actual minimum memory required by the object. + the actual minimum memory required by the object. (casevh) Known issues in gmpy2 2.0.0b4 ----------------------------- @@ -198,85 +274,306 @@ Changes in gmpy2 2.0.0b3 ------------------------ * `mp_version()`, `mpc_version()`, and `mpfr_version()` now return normal - strings on Python 2.x instead of Unicode strings. -* Faster conversion of the standard library `~fractions.Fraction` type to `mpq`. -* Improved conversion of the `~decimal.Decimal` type to `mpfr`. -* Consistently return `OverflowError` when converting ``inf``. -* Fix `mpz.__format__()` when the format code includes "#". -* Add `is_infinite()` and deprecate ``is_inf()``. -* Add `is_finite()` and deprecate ``is_number()``. -* Fixed the various ``is_XXX()`` tests when used with `mpc`. -* Added caching for `mpc` objects. -* Faster code path for basic operation is both operands are `mpfr` or `mpc`. -* Fix `mpfr` + `float` segmentation fault. + strings on Python 2.x instead of Unicode strings. (casevh) +* Fix warnings when shifting 32-bit integer by 32 bits. (casevh) +* Faster conversion of the standard library `~fractions.Fraction` type + to `mpq`. (casevh) +* Improved conversion of the `~decimal.Decimal` type to `mpfr`. (casevh) +* Consistently return `OverflowError` when converting ``inf``. (casevh) +* Fix `mpz.__format__()` when the format code includes "#". (casevh) +* Add `is_infinite()` and deprecate ``is_inf()``. (casevh) +* Add `is_finite()` and deprecate ``is_number()``. (casevh) +* Fixed the various ``is_XXX()`` tests when used with `mpc`. (casevh) +* Fixed error handling with mpc(); mpc(1,"nan") is properly handled. (casevh) +* Added caching for `mpc` objects. (casevh) +* Faster code path for basic operation is both operands are `mpfr` + or `mpc`. (casevh) +* Fix `mpfr` + `float` segmentation fault. (casevh) Changes in gmpy2 2.0.0b2 ------------------------ * Allow `xmpz` slice assignment to increase length of `xmpz` instance by - specifying a value for stop. -* Fixed reference counting bug in several ``is_xxx_prp()`` tests. + specifying a value for stop. (casevh) +* Fixed reference counting bug in several ``is_xxx_prp()`` tests. (casevh) * Added `~xmpz.iter_bits()`, `~xmpz.iter_clear()`, `~xmpz.iter_set()` methods - to `xmpz`. -* Added `powmod()` for easy access to three argument :func:`pow()`. + to `xmpz`. (casevh) +* Added `powmod()` for easy access to three argument :func:`pow()`. (casevh) * Removed ``addmul()`` and ``submul()`` which were added in 2.0.0b1 since they - are slower than just using Python code. -* Bug fix in gcd_ext when both arguments are not `mpz`. -* Added `ieee()` to create contexts for 32, 64, or 128 bit `float`'s. + are slower than just using Python code. (casevh) +* Bug fix in gcd_ext when both arguments are not `mpz`. (casevh) +* Added `ieee()` to create contexts for 32, 64, or 128 bit `float`'s. (casevh) * Bug fix in `context()` not setting `~context.emax`/`~context.emin` correctly - if they had been changed earlier. + if they had been changed earlier. (casevh) * Contexts can be directly used in with statement without requiring - `set_context()`/`local_context()` sequence. -* `local_context()` now accepts an optional context. + `set_context()`/`local_context()` sequence. (casevh) +* `local_context()` now accepts an optional context. (casevh) -Changes in gmpy2 2.0.0b1 and earlier ------------------------------------- +Changes in gmpy2 2.0.0b1 +------------------------ +* Rename to gmpy2 to allow backwards incompatible changes (casevh) +* Renamed 'mpf' to 'mpfr' to reflect use of MPFR (casevh) * Renamed functions that manipulate individual bits to ``bit_XXX()`` to align with :meth:`~int.bit_length()`. -* Added caching for `mpq`. -* Added ``rootrem()``, `fib2()`, `lucas()`, `lucas2()`. -* Support changed hash function in Python 3.2. -* Added `is_even()`, `is_odd()`. -* Add caching of the calculated hash value. -* Add `xmpz` (mutable `mpz`) type. -* Fix `mpq` formatting issue. -* Add read/write bit access using slices to `xmpz`. -* Add read-only bit access using slices to `mpz`. +* Added caching for `mpq`. (casevh) +* Added ``rootrem()``, `fib2()`, `lucas()`, `lucas2()`. (casevh) +* Support changed hash function in Python 3.2. (casevh) +* Added `is_even()`, `is_odd()`. (casevh) +* Add caching of the calculated hash value. (casevh) +* Add `xmpz` (mutable `mpz`) type. (casevh) +* Fix `mpq` formatting issue. (casevh) +* Add read/write bit access using slices to `xmpz`. (casevh) +* Add read-only bit access using slices to `mpz`. (casevh) * Add `pack()`/`unpack()` methods to split/join an integer into n-bit - chunks. + chunks. (casevh) * Add support for MPFR (casevh) -* Removed fcoform float conversion modifier. -* Add support for MPC. -* Added context manager. -* Allow building with just GMP/MPIR if MPFR not available. -* Allow building with GMP/MPIR and MPFR if MPC not available. +* Removed fcoform float conversion modifier. (casevh) +* Add support for MPC. (casevh) +* Added context manager. (casevh) +* Allow building with just GMP/MPIR if MPFR not available. (casevh) +* Allow building with GMP/MPIR and MPFR if MPC not available. (casevh) * Removed most instance methods in favor of gmpy2.function. The general guideline is that *properties* of an instance can be done via instance methods but *functions* that return a new result are done using - gmpy2.function. + gmpy2.function. (casevh) * Added ``__ceil__()``, ``__floor__()``, and ``__trunc__()`` methods since they are called by :func:`math.ceil()`, :func:`math.floor()`, and - :func:`math.trunc()`. -* Removed ``gmpy2.pow()`` to avoid conflicts. -* Removed ``gmpy2._copy()`` and added `xmpz.copy()`. -* Added support for ``__format__()``. -* Added ``as_integer_ratio()``, ``as_mantissa_exp()``, ``as_simple_fraction()``. -* Updated rich_compare. -* Require MPFR 3.1.0+ to get divby0 support. -* Added `fsum()`, `degrees()`, `radians()`. -* Updated random number generation support. -* Changed license to LGPL 3+. -* Added `lucasu()`, `lucasu_mod()`, `lucasv()`, and `lucasv_mod()`. + :func:`math.trunc()`. (casevh) +* Removed ``gmpy2.pow()`` to avoid conflicts. (casevh) +* Removed ``gmpy2._copy()`` and added `xmpz.copy()`. (casevh) +* Added support for ``__format__()``. (casevh) +* Added ``as_integer_ratio()``, ``as_mantissa_exp()``, + ``as_simple_fraction()``. (casevh) +* Updated rich_compare. (casevh) +* Require MPFR 3.1.0+ to get divby0 support. (casevh) +* Added `fsum()`, `degrees()`, `radians()`. (casevh) +* Updated random number generation support. (casevh) +* Changed license to LGPL 3+. (casevh) +* Added `lucasu()`, `lucasu_mod()`, `lucasv()`, and `lucasv_mod()`. (casevh) *Based on code contributed by David Cleaver.* -* Added probable-prime tests. +* Added probable-prime tests. (casevh) *Based on code contributed by David Cleaver.* -* Added `to_binary()`/`from_binary()`. -* Renamed ``numdigits()`` to `~mpz.num_digits()`. -* Added keyword precision to constants. -* Added ``addmul()`` and ``submul()``. -* Added ``__round__()``, `round2()`, `round_away()` for `mpfr`. -* ``round()`` is no longer a module level function. -* Renamed module functions ``min()/max()`` to ``min2()/max2()``. -* No longer conflicts with builtin :func:`min()` and :func:`max()` -* Removed ``set_debug()`` and related functionality. +* Added `to_binary()`/`from_binary()`. (casevh) +* Renamed ``numdigits()`` to `~mpz.num_digits()`. (casevh) +* Added keyword precision to constants. (casevh) +* Added ``addmul()`` and ``submul()``. (casevh) +* Added ``__round__()``, `round2()`, `round_away()` for `mpfr`. (casevh) +* ``round()`` is no longer a module level function. (casevh) +* Renamed module functions ``min()/max()`` to ``min2()/max2()``. (casevh) + No longer conflicts with builtin :func:`min()` and :func:`max()` +* Removed ``set_debug()`` and related functionality. (casevh) +* Removed mpf.setprec(), use mpf.round() (casevh) +* Fix test compatibility with Python 3.1.2 and 3.2 (casevh) +* Remove old random number functions, to be replaced later (casevh) +* Remove tagoff option (casevh) +* Debug messages only available if compiled with -DDEBUG (casevh) +* Renamed context() -> local_context(), new_context() -> context() (casevh) +* Added get_context() (casevh) + +Changes in gmpy 1.11 +-------------------- + +* Recognize True/False (bug in 1.10) (casevh) +* Optimize argument handling (casevh) +* Added caching for mpz (casevh) + +Changes in gmpy 1.10 +-------------------- + +* Remove dependancy on pymemcompat.h (casevh) +* Remove callback (casevh) +* Added support for -DMPIR to include MPIR instead of GMP (casevh) +* Major code revisions to add support for Python 3.x (casevh) +* Fixed bug in binary() and qbinary() (casevh) +* Fixed bug in rich comparisons (casevh) +* Added % and divmod support to mpq and mpf (casevh) +* Changed memory allocation functions to use PyMem (casevh) +* Removed small number interning (casevh) +* Added tdivmod, cdivmod, and fdivmod (casevh) +* Added more helper functions for mpmath (casevh) +* Faster mpz<>PyLong conversion (casevh) +* Faster hash(mpz) (casevh) + +Changes in gmpy 1.04 +-------------------- + +* Avoid GMP/mingw32 bug when converting very small floats to mpz. (casevh) +* Significant performance improvement for long->mpz and mpz->long. (casevh) +* Added "rich comparisons" to mpz, mpq and mpf types (aleaxit) +* Added additional tests (casevh, aleaxit) +* Fixed bug when converting very large mpz to str (casevh) +* Faster conversion from mpz->binary and binary->mpz (casevh) +* Added support for pickling (casevh) +* Added divexact (casevh) +* Fixed mpf comparisons by rounding mpf results when GMP returns + a longer result. Added fround() (casevh) +* Added bit_length (Thanks Mario Pernici) +* Added helper functions for mpmath (casevh) +* Faster conversion from mpq->binary and binary->mpq (casevh) +* Recognize MPIR, mpir_version() (casevh) + +Changes in gmpy 1.03 +-------------------- + +* Fixed the bug that caused crashes on gmpy.mpf(float('inf')) and + other such conversions, implicit and explicit +* Fixed a bug in get_zconst's prototype affecting 64-bit machines, + thanks to Gary Bunting +* Fixed a bug in hashing on 64-bit systems. hash(long) now equals + hash(mpz) for large values. (casevh) +* Changed int() to return a long value instead of OverFlowError. + Complies with PEP 237. (casevh) +* Added support in setup.py for darwinports/macports build of GMP + on MacOSX. (aleaxit) + +Changes in gmpy 1.02 +-------------------- + +* fix warning in comparison of mpq's +* added support of mpq('12.34') [[string w/o a slash, but with a dot]] +* fixes for 64-bit build (thanks to a patch by dmcooke) +* added experimental support for decimal.Decimal (and user-coded types) + via wider use of special conversion methods (if present) and their + sly insertion on-the-fly into the decimal.Decimal class (!) +* two bugfixes, thanks to Simon Burton +* Brought back into C89 compliance (thanks to Chip Turner), had + drifted to C99 (declarations in the middle of the code). +* Python 2.5 support (Py_ssize_t, __index__) thanks to Chip Turner +* Pushed coverage to 93.3% (missing only "sanity check" level error + tests [mostly for out-of-memory conditions], output to stderr + conditioned by global.debug, & a couple of very obscure cases) + +Changes in gmpy 1.01 +-------------------- + +* cleanups, ensure support for Python 2.4.1 on MacOSX 10.4/XCode 2.1 + as well as Python 2.2 and 2.3 (on MacOSX and Linux) +* fixed memory leak on divm (thanks to mensanator@aol.com) +* fixed bug on mpq('123') [[str2mpq on string w/o a slash]] +* added floordiv and truediv operators, and tests for them +* NOT tested on GMP 3 (have none left around...), ONLY on GMP 4.* + +Changes in gmpy 1.0 +------------------- + +* minor cleanups, ensure support for Python 2.3 +* fixed misdiagnosis of some argument counts in macro +* SELF_ONE_ARG_CONVERTED (tx to Paul Rubin!) + +Changes in gmpy 0.9 +------------------- + +* change ValueError to OverflowError for 'too-large' errors +* fix bug in mpq_pow (negative base, exp. with odd denominator) + (fix now corrected -- _even_ denominator is the error!) +* fixed gcc warnings reported by K. Briggs +* support GMP 4 (but added no GMP4-only functionality yet) +* updated tests to 0.9, better coverage + +Changes in gmpy 0.8 +------------------- + +(again, requests & suggestions by great Pearu!) + +* raise test coverage 72.5% -> 90.0% +* introduced callbacks (not documented/tested for now; + Pearu will test/support/document in PySymbolic) +* some errors went undiagnosed, caused crash: now fixed +* workaround for GMP bug(?s?) in mpz_fits\_... (?) +* added exposure of mpf\_ sqrt and pow_ui + +Changes in gmpy 0.7 +------------------- + +Good feedback from Keith Briggs, some advice from Tim Peters and Fred Lundh --- +thanks all! + +* fixed bug of '"%d" where "%ld" was meant' in many places + and other sundry minor warnings given by gcc +* fixed hash (delegating to Python) so mp[nqz](x) will + produce the same value as hash(x) for any Python number x +* workaround for GMP 3.1.1 bug, mpz_root wrongly returning + 'exact' for non-exact root if dest==source, which stopped + needed value-error for inexact mpq**mpq operations +* determined correct 'actual precision' of floats +* explicitly stored precision with binary-form mpf's +* extended explicit-bits request to all ->mpf operations + (good in itself, plus, preparing for future MPFR) +* removed the limitation of no binary-form for <0 mpz +* introduced macros to parse args, for conciseness + +Changes in gmpy 0.6 +------------------- + +(lots of good ideas from Pearu once more!-) + +* fixed silly bugs in kronecker and mpq_abs +* gmpy-level workaround for scan0/scan1 bugs (?) in gmp 3.1.1 +* added qdiv; anynum->mpq substituted for all such conversions + (also anynum->mpz and anynum->mpf by analogy, with care!) +* added global.fcoform for optional use of intermediate string in + float2mpf (used for any float->mpf conversion) +* added set_fcoform function for global.fcoform access +* general cleanup of sources; added alloca for msvc++; + - many sundry minor bugfixes & uniformization; + - a little useful refactoring (more would be good...) +* added caching of mpq objects +* power for mpq +* stern-brocot algorithm for mpf->mpq (also exposed as f2q) + - also used for float->mpq + - with stricter tracking of mpf's requested-precision + - added getrprec method to mpf, getrprec module-function +* exposed ceil, floor and trunc methods/functions for mpf's +* changed a couple exceptions from value to zerodivision +* added 'qual' and 'floa' options to gmpy.rand + +Changes in gmpy 0.5 +------------------- + +* added jacobi, legendre, kronecker +* added random-number generation, seed set/save, shuffling +* added mpq (at last!-) + +Changes in gmpy 0.4 +------------------- + +* split gmpy.c/gmpy.h introducing C-API interface (Pearu's suggestion) +* cleanup some casts using Pearu's new macros +* further cache-tweaks at Pearu's suggestion (macros introduced) +* added sign (Pearu's request), getbit, setbit +* added docstrings +* renamed copy functions to start with _ ('internal, private') +* added .comb as a synonym of .bincoef + +Changes in gmpy 0.3 +------------------- + +* performance tweaks via mpz-caching & fixed-constants +* added get/set functions for zcache, zco min/max +* added get-only function for versions (of gmp, and of gmpy) +* removed all 'traces' of mutability (to be re-done... much later!) +* cleaned up all of the mpz_cmp_ui(X,0) to mpz_sgn(X) +* cleaned up Py_BuildValue usage (N vs O, explicit-() for tuples) +* added numdigits, lowbits, root, next_prime, invert, popcount, +* hamdist, scan0, scan1 +* renamed bin to bincoef + +Changes in gmpy 0.2 +------------------- + +15 Nov 2000 + +* pre-alpha: bugfixes re formatting (tx, Peanu!) +* no tags on oct() and hex() of mpz's +* insert 'tagoff' in options (gmpy.mpz() vs mpz() in repr) (for Peanu!) +* speedups for _nonzero & _cmp (tx, Peanu!) +* slight speedup (7/8%?) for excess reallocs 4<->8 bytes (Peanu's help!) +* added copy/fcopy; bin; fib; remove + +Changes in gmpy 0.1 +------------------- + +6 Nov 2000 + +* pre-alpha --- first placed on sourceforge diff --git a/docs/install.rst b/docs/install.rst index 379bbe4b..086c97a5 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -10,6 +10,10 @@ or some specific version with:: pip install gmpy2==2.1.5 + +From Sources +------------ + If pre-compiled binary wheels aren't available for your platform, the pip will fallback to installation from sources. In this case you will need to have required libraries (GMP, MPFR and MPC) already installed on your system, along @@ -25,9 +29,6 @@ systed-wide with:: pacman -S gcc gmp-devel mpfr-devel mpc-devel python-setuptools python-pip -From Sources ------------- - If you are a developer or like to get the latest updates as they come, be sure to install from the git repository and include required extra dependencies, for example the optional "tests" list, which include packages required diff --git a/src/gmpy2.c b/src/gmpy2.c index aab8c22d..399f3815 100644 --- a/src/gmpy2.c +++ b/src/gmpy2.c @@ -54,433 +54,6 @@ * * Some hacks by Gustavo Niemeyer . * - * 0.1, pre-alpha; date: 2000-11-06 first placed on sourceforge - * - * 0.2, still pre-alpha: 2000-11-15: bugfixes re formatting (tx, Peanu!) - * no tags on oct() and hex() of mpz's - * insert 'tagoff' in options (gmpy.mpz() vs mpz() in repr) (for Peanu!) - * speedups for _nonzero & _cmp (tx, Peanu!) - * slight speedup (7/8%?) for excess reallocs 4<->8 bytes (Peanu's help!) - * added copy/fcopy; bin; fib; remove - * - * 0.3, still pre-alpha, but...: - * performance tweaks via mpz-caching & fixed-constants - * added get/set functions for zcache, zco min/max - * added get-only function for versions (of gmp, and of gmpy) - * removed all 'traces' of mutability (to be re-done... much later!) - * cleaned up all of the mpz_cmp_ui(X,0) to mpz_sgn(X) - * cleaned up Py_BuildValue usage (N vs O, explicit-() for tuples) - * added numdigits, lowbits, root, next_prime, invert, popcount, - * hamdist, scan0, scan1 - * renamed bin to bincoef - * - * 0.4: - * split gmpy.c/gmpy.h introducing C-API interface (Pearu's suggestion) - * cleanup some casts using Pearu's new macros - * further cache-tweaks at Pearu's suggestion (macros introduced) - * added sign (Pearu's request), getbit, setbit - * added docstrings - * renamed copy functions to start with _ ('internal, private') - * added .comb as a synonym of .bincoef - * - * 0.5: - * added jacobi, legendre, kronecker - * added random-number generation, seed set/save, shuffling - * added mpq (at last!-) - * - * 0.6: (lots of good ideas from Pearu once more!-): - * fixed silly bugs in kronecker and mpq_abs - * gmpy-level workaround for scan0/scan1 bugs (?) in GMP 3.1.1 - * added qdiv; anynum->mpq substituted for all such conversions - * (also anynum->mpz and anynum->mpf by analogy, with care!) - * added global.fcoform for optional use of intermediate string in - * float2mpf (used for any float->mpf conversion) - * added set_fcoform function for global.fcoform access - * general cleanup of sources; added alloca for MSVC++; - * many sundry minor bugfixes & uniformization; - * a little useful refactoring (more would be good...) - * added caching of mpq objects - * power for mpq - * Stern-Brocot algorithm for mpf->mpq (also exposed as f2q) - * also used for float->mpq - * with stricter tracking of mpf's requested-precision - * added getrprec method to mpf, getrprec module-function - * exposed ceil, floor and trunc methods/functions for mpf's - * changed a couple exceptions from Value to ZeroDivision - * added 'qual' and 'floa' options to gmpy.rand - * - * 0.7: (good feedback from Keith Briggs, some advice from Tim Peters - * and Fred Lundh -- thanks all!): - * fixed bug of '"%d" where "%ld" was meant' in many places - * and other sundry minor warnings given by gcc - * fixed hash (delegating to Python) so mp[nqz](x) will - * produce the same value as hash(x) for any Python number x - * workaround for GMP 3.1.1 bug, mpz_root wrongly returning - * 'exact' for non-exact root if dest==source, which stopped - * needed value-error for inexact mpq**mpq operations - * determined correct 'actual precision' of floats - * explicitly stored precision with binary-form mpf's - * extended explicit-bits request to all ->mpf operations - * (good in itself, plus, preparing for future MPFR) - * removed the limitation of no binary-form for <0 mpz - * introduced macros to parse args, for conciseness - * - * 0.8: (again, requests & suggestions by great Pearu!) - * raise test coverage 72.5% -> 90.0% - * introduced callbacks (not documented/tested for now; - * Pearu will test/support/document in PySymbolic) - * some errors went undiagnosed, caused crash: now fixed - * workaround for GMP bug(?s?) in mpz_fits_... (?) - * added exposure of mpf_ sqrt and pow_ui - * - * 0.9: (ditto) - * change ValueError to OverflowError for 'too-large' errors - * fix bug in mpq_pow (negative base, exp. with odd denominator) - * (fix now corrected -- _even_ denominator is the error!) - * fixed gcc warnings reported by K. Briggs - * - * 0.9b: - * support GMP 4 (but added no GMP4-only functionality yet) - * - * 0.9c: - * updated tests to 0.9, better coverage - * - * 1.0: - * minor cleanups, ensure support for Python 2.3 - * fixed misdiagnosis of some argument counts in macro - * SELF_ONE_ARG_CONVERTED (tx to Paul Rubin!) - * - * 1.01: - * cleanups, ensure support for Python 2.4.1 on MacOSX 10.4/XCode 2.1 - * as well as Python 2.2 and 2.3 (on MacOSX and Linux) - * fixed memory leak on divm (thanks to mensanator@aol.com) - * fixed bug on mpq('123') [[str2mpq on string w/o a slash]] - * added floordiv and truediv operators, and tests for them - * NOT tested on GMP 3 (have none left around...), ONLY on GMP 4.* - * - * 1.02: - * fix warning in comparison of mpq's - * added support of mpq('12.34') [[string w/o a slash, but with a dot]] - * fixes for 64-bit build (thanks to a patch by dmcooke) - * added experimental support for decimal.Decimal (and user-coded types) - * via wider use of special conversion methods (if present) and their - * sly insertion on-the-fly into the decimal.Decimal class (!) - * two bugfixes, thanks to Simon Burton - * Brought back into C89 compliance (thanks to Chip Turner), had - * drifted to C99 (declarations in the middle of the code). - * Python 2.5 support (Py_ssize_t, __index__) thanks to Chip Turner - * Pushed coverage to 93.3% (missing only "sanity check" level error - * tests [mostly for out-of-memory conditions], output to stderr - * conditioned by global.debug, & a couple of very obscure cases) - * - * 1.03: - * Fixed the bug that caused crashes on gmpy.mpf(float('inf')) and - * other such conversions, implicit and explicit - * Fixed a bug in get_zconst's prototype affecting 64-bit machines, - * thanks to Gary Bunting - * Fixed a bug in hashing on 64-bit systems. hash(long) now equals - * hash(mpz) for large values. (casevh) - * Changed int() to return a long value instead of OverFlowError. - * Complies with PEP 237. (casevh) - * Added support in setup.py for darwinports/macports build of GMP - * on MacOSX. (aleaxit) - * - * 1.04: - * Avoid GMP/mingw32 bug when converting very small floats to mpz. - * (casevh) - * Significant performance improvement for long->mpz and mpz->long. - * (casevh) - * Added "rich comparisons" to mpz, mpq and mpf types (aleaxit) - * Added additional tests (casevh, aleaxit) - * Fixed bug when converting very large mpz to str (casevh) - * Faster conversion from mpz->binary and binary->mpz (casevh) - * Added support for pickling (casevh) - * Added divexact (casevh) - * Fixed mpf comparisons by rounding mpf results when GMP returns - * a longer result. Added fround() (casevh) - * Added bit_length (Thanks Mario Pernici) - * Added helper functions for mpmath (casevh) - * Faster conversion from mpq->binary and binary->mpq (casevh) - * Recognize MPIR, mpir_version() (casevh) - * - * 1.10: - * Remove dependancy on pymemcompat.h (casevh) - * Remove callback (casevh) - * Added support for -DMPIR to include MPIR instead of GMP (casevh) - * Major code revisions to add support for Python 3.x (casevh) - * Fixed bug in binary() and qbinary() (casevh) - * Fixed bug in rich comparisons (casevh) - * Added % and divmod support to mpq and mpf (casevh) - * Changed memory allocation functions to use PyMem (casevh) - * Removed small number interning (casevh) - * Added tdivmod, cdivmod, and fdivmod (casevh) - * Added more helper functions for mpmath (casevh) - * Faster mpz<>PyLong conversion (casevh) - * Faster hash(mpz) (casevh) - * - * 1.11: - * Recognize True/False (bug in 1.10) (casevh) - * Optimize argument handling (casevh) - * Added caching for mpz (casevh) - * - ************************************************************************ - * - * 2.0.0 alpha and b1: - * Added caching for mpq (casevh) - * Added rootrem, fib2, lucas, lucas2 (casevh) - * Removed mpf.setprec(), use mpf.round() (casevh) - * Fix test compatibility with Python 3.1.2 and 3.2 (casevh) - * Support changed hash function in Python 3.2 (casevh) - * Added is_even, is_odd (casevh) - * Rename to gmpy2 to allow backwards incompatible changes (casevh) - * Remove old random number functions, to be replaced later (casevh) - * Add caching of the calculated hash value (casevh) - * Add xmpz (mutable mpz) type (casevh) - * Fix mpq formatting issue (casevh) - * Add read/write bit access using slices to xmpz (casevh) - * Add read-only bit access using slices to mpz (casevh) - * Add pack()/unpack() methods (casevh) - * Remove tagoff option (casevh) - * Add support for MPFR (casevh) - * Debug messages only available if compiled with -DDEBUG (casevh) - * Removed fcoform float conversion modifier (casevh) - * Add support for MPC (casevh) - * Renamed 'mpf' to 'mpfr' to reflect use of MPFR (casevh) - * Added context manager (casevh) - * Allow building with just GMP/MPIR if MPFR not available (casevh) - * Allow building with GMP/MPIR and MPFR if MPC not available (casevh) - * Removed most instance methods in favor of gmpy2.method (casevh) - * Added __ceil__, __floor__, and __trunc__ methods (casevh) - * Removed gmpy2.pow to avoid conflicts (casevh) - * Removed gmpy2._copy and added xmpz.copy (casevh) - * Added support for __format__ (casevh) - * Completed support for MPC (casevh) - * Added as_integer_ratio, as_mantissa_exp, as_simple_fraction (casevh) - * Update rich_compare (casevh) - * Require MPFR 3.1.0+ to get divby0 support (casevh) - * Added fsum(), degrees(), radians() (casevh) - * Renamed context() -> local_context(), new_context() -> context() (casevh) - * Added get_context() (casevh) - * Added random number generation support (casevh) - * Changed license to LGPL 3+ (casevh) - * Added lucasu, lucasu_mod, lucasv, and lucasv_mod (casevh) - * (Based on code contributed by David Cleaver.) - * Added probable-prime tests (casevh) - * (Based on code contributed by David Cleaver.) - * Added to_binary()/from_binary (casevh) - * Renamed numdigits() to num_digits() (casevh) - * Added keyword precision to constants (casevh) - * Added addmul() and submul() (casevh) - * Added __round__(), round2(), round_away() for mpfr (casevh) - * round() is no longer a module level function (casevh) - * pow() is no longer a module level function (casevh) - * Renamed module functions min()/max() to min2()/max2() (casevh) - * No longer conflicts with builtin min() and max() - * Removed set_debug() and related functionality (casevh) - * Released as 2.0.0b1 - * - * 2.0.0b2 - * Allow xmpz slice assignment to increase length of xmpz instance by - * specifying a value for stop (casevh) - * Fixed ref-count bug in several is_xxx_prp tests (casevh) - * Added iter_bits, iter_clear, iter_set methods to xmpz (casevh) - * Added powmod() for easy access to three argument pow() (casevh) - * Removed addmul() and submul() since they are slower than (casevh) - * just using Python code - * Bug fix in gcd_ext when both arguments are not mpz (casevh) - * Added ieee() to create contexts for 32, 64, or 128 bit floats (casevh) - * Bug fix in context() not setting emax/emin correctly if they (casevh) - * had been changed earlier - * Contexts can be directly used in with statement without (casevh) - * requiring set_context()/local_context() sequence - * local_context() now accepts an optional context (casevh) - * - * 2.0.0b3 - * mp_version(), mpc_version(), and mpfr_version() shouldn't (casevh) - * return Unicode on Python 2.x - * Fix warnings when shifting 32-bit integer by 32 bits (casevh) - * Faster conversion of Fraction to gmpy2 types (casevh) - * Fix conversion with Decimal, especially on Python 3.3 (casevh) - * Consistently return OverflowError when converting "inf" (casevh) - * Fix mpz.__format__() with # code (casevh) - * Add is_infinite(), deprecate is_inf() (casevh) - * Add is_finite(), deprecate is_number() (casevh) - * Fixed issues with mpc() and various is_XXX() functions (casevh) - * Fixed error handling with mpc(); mpc(1,"nan") is properly (casevh) - * handled - * Added caching for mpc objects; faster when real and (casevh) - * imaginary precisions are equal - * Add optimal path for mpfr/mpc + - * / when both operands (casevh) - * have the same type - * Fix mpfr + float segmentation fault (casevh) - * - * 2.0.0b4 - * Add __ceil__, __floor__, __trunc__, __round__ to mpz & mpq (casevh) - * Add __complex__ to mpc (casevh) - * round(mpfr) now correctly returns an mpz (casevh) - * Add mpz.denominator and mpz.numerator (casevh) - * mpz() returns mpz(0); also xmpz, mpq, mpfr, and mpc (casevh) - * Fix bug when comparing mpz to mpq (with mpz on left) (casevh) - * Add __sizeof__ (casevh) - * - * 2.0.0 - * Fix segfault in _mpmath_normalize if rnd not specified (casevh) - * Improved setup.py (casevh) - * Fix issues encountered when compiled without MPFR support (casevh) - * Conversion of too large an mpz to float now raises OverflowError (casevh) - * Renamed module functions min2()/max2() to minnum()/maxnum() (casevh) - * Added copy() method to contexts (casevh) - * get_context() no longer supports keyword arguments (casevh) - * - ************************************************************************ - * - * 2.1.0 - * Improvements to setup.py. - * Add thread-safe contexts. - * MPFR and MPC are now required. - * Invalid Operation exception now raised for addition, etc. - * inverse() now raises exception if inverse does not exist. - * Add context methods. - * Major code refactoring required to properly support thread-safe - * contexts. - * __str__ and __repr__ no longer append "L" on Python 2. - * mpq(mpfr) now returns the exact result. - * Fix repr(mpc) for precision >325 bits. - * Intermediate conversions of Integer to mpfr are now done with the - * full precision of the Integer. - * Remove support for interaction with Decimal type. - * No longer attempt to override the memory allocation functions. - * Register gmpy2 types into the numeric tower. - * mpz(x) call int(x) if mpz() does not know how to convert x - * directly. - * Convert `mpz` to a type using __new__ instead of a factory - * function. - * - * 2.1.0a1 - * Initial release. - * - * 2.1.0a2 - * Revised build process. - * Removal of unused code/macros. - * Cleanup of Cython interface. - * - * 2.1.0a3 - * Updates to setup.py. - * Initial support for MPFR4 - * - Add nrandom() - * - grandom() now calls nrandom twice; may return different values versus - * MPFR3 - * - Add rootn(); same as root() except different sign when taking even root - * of -0.0 - * - * 2.1.0a4 - * Fix issue 204; missing file for Cython. - * Additional support for MPFR 4 - * - Add fmma() and fmms() - * - * 2.1.0a5 - * Fix qdiv() not returning mpz() when it should. - * Added root_of_unity() - * - * 2.1.0b1 - * Added cmp() and cmp_abs(). - * Improved compatibility with _numbers_ protocol. - * Many bug fixes. - * - * 2.1.0b2 - * Many bug fixes. - * - * 2.1.0b3 - * Version bump only. - * - * 2.1.0b4 - * Fix comparisons with mpq and custom rational objects. - * Fixes for some uncommon integer conversions scenarios. - * - * 2.1.0b5 - * Avoid MPFR bug in mfr_fac_ui (gmpy2.factorial) on platforms where - * long is 32-bits and argument is >= 44787929. - * Fixed testing bugs with Python 2.7. - * Fixed mpz(0) to C long or long long. - * Fixed incorrect results in f2q(). - * Adjust test suite to reflect changes in output in MPFR 4.1.0. - * - * 2.1.0b6 - * Improve argument type processing by saving type information to - * decrease the number of type check calls. Especially helpful - * for mpfr and mpc types. (Not complete but common operations - * are done.) - * Resolve bug in mpfr to mpq conversion; issue #287. - * Added limited support for releasing the GIL; disabled by default; - * see context.allow_release_gil. - * Refactored handling of inplace operations for mpz and xmpz types; - * inplace operations on xmpz will only return an xmpz result. - * Refactored handling of conversion to C integer types. Some - * exception types changes to reflect Python types. - * gcd() and lcm() now support more than two arguments to align with - * the corresponding functions in the math module. - * - * 2.1.0rc1 - * Added support for embedded underscore characters in string - * literals. - * Allow GIL release for mpz/xmpz/mpq types only. - * - * 2.1.0rc2 - * Updates to builds. - * - * 2.1.0 - * Bug fix for <> ** <>. - * Compile with Python 3.11. - * - * 2.1.1 - * Code cleanup. - * Properly return NOTIMPLEMENTED for unsupported arguments in **. - * Issue 319. - * - * 2.1.2 - * Code cleanup. - * Support Apple Silicon binary wheels. - * is_prime(-2) now returns False. Issue 312. - * - * 2.1.3 - * Fix mpz(-3).is_prime(). - * Add powmod_sec(). - * Fix mpfr('inf') and mpfr('nan') if subnormalization is enabled. - * powmod() and powmod_sec() release the GIL. - * Fix error messages for iroot(x,n) for large n. - * Add powmod_base_list() and powmod_exp_list() (experimental). - * Fix gmpy2.mpq(mpq, int). - * Fix issues with INF, NAN, and mpfr("-0") when subnormalization - * is True - * - * 2.1.4 - * Version bump to fix wheel issues. No code changes. - * - * 2.1.5 - * Version bump to fix wheel issues. No code changes. - * - * - ************************************************************************ - * - * 2.2.0a1 - * Remove support for versions of Python < 3.7. () (skirpichev) - * Support more modern build tools. (skirpichev) - * Use contextvars to manage gmpy2 contexts. (casevh) - * _mpmath functions now use vectorcall protocol. (casevh) - * Many documentation updates. (skirpichev) - * Add mpz.as_integer_ratio()/to_bytes()/from_bytes(). (skirpichev) - * Add mpz_probab_prime_p() to directly expose the GMP behavior. - * (skirpichev) - * gcd()/lcm() now uses vectorcall protocol. (skirpichev) - * Expose context type. (skirpichev) - * Correct error in is_strong_bpsw_prp. (casevh) - * Added prev_prime if GMP version is >=6.3.0 (sethtroisi) - * - * 2.2.0a2 - * Change argument order of jn() and yn() to match MPFR. (casevh) - * Fix documentation and code for is_extra_strong_lucas_prp. (casevh) - * - * ************************************************************************ * * Discussion on sizes of C integer types. diff --git a/src/gmpy2_cache.c b/src/gmpy2_cache.c index 8df8349b..0f6c0cef 100644 --- a/src/gmpy2_cache.c +++ b/src/gmpy2_cache.c @@ -135,7 +135,7 @@ GMPy_MPZ_NewInit(PyTypeObject *type, PyObject *args, PyObject *keywds) if (!MPZ_Check(out)) { PyErr_Format(PyExc_TypeError, "object of type '%.200s' can not be interpreted as mpz", - out->ob_type->tp_name); + Py_TYPE(out)->tp_name); Py_DECREF(out); return NULL; } @@ -186,7 +186,7 @@ GMPy_MPZ_Dealloc(MPZ_Object *self) } else { mpz_clear(self->z); - PyObject_Del(self); + PyObject_Free(self); } } @@ -322,7 +322,7 @@ GMPy_XMPZ_Dealloc(XMPZ_Object *self) } else { mpz_clear(self->z); - PyObject_Del((PyObject*)self); + PyObject_Free((PyObject*)self); } } @@ -453,7 +453,7 @@ GMPy_MPQ_Dealloc(MPQ_Object *self) } else { mpq_clear(self->q); - PyObject_Del(self); + PyObject_Free(self); } } @@ -572,7 +572,7 @@ GMPy_MPFR_NewInit(PyTypeObject *type, PyObject *args, PyObject *keywds) if (!MPFR_Check(out)) { PyErr_Format(PyExc_TypeError, "object of type '%.200s' can not be interpreted as mpfr", - out->ob_type->tp_name); + Py_TYPE(out)->tp_name); Py_DECREF(out); return NULL; } @@ -614,7 +614,7 @@ GMPy_MPFR_Dealloc(MPFR_Object *self) } else { mpfr_clear(self->f); - PyObject_Del(self); + PyObject_Free(self); } } @@ -757,7 +757,7 @@ GMPy_MPC_NewInit(PyTypeObject *type, PyObject *args, PyObject *keywds) if (!MPC_Check(out)) { PyErr_Format(PyExc_TypeError, "object of type '%.200s' can not be interpreted as mpc", - out->ob_type->tp_name); + Py_TYPE(out)->tp_name); Py_DECREF(out); return NULL; } @@ -889,7 +889,7 @@ GMPy_MPC_Dealloc(MPC_Object *self) } else { mpc_clear(self->c); - PyObject_Del(self); + PyObject_Free(self); } } diff --git a/src/gmpy2_context.c b/src/gmpy2_context.c index f33b8069..c64e5dfd 100644 --- a/src/gmpy2_context.c +++ b/src/gmpy2_context.c @@ -50,6 +50,9 @@ * GMPy_current_context */ + +#include "pythoncapi_compat.h" + /* Create and delete Context objects. */ static PyObject * @@ -85,7 +88,7 @@ GMPy_CTXT_New(void) static void GMPy_CTXT_Dealloc(CTXT_Object *self) { - PyObject_Del(self); + PyObject_Free(self); }; /* Begin support for context vars. */ @@ -657,7 +660,7 @@ GMPy_CTXT_Set_##NAME(CTXT_Object *self, PyObject *value, void *closure) \ TYPE_ERROR(#NAME " must be True or False"); \ return -1; \ } \ - self->ctx.NAME = (value == Py_True) ? 1 : 0; \ + self->ctx.NAME = Py_IsTrue(value) ? 1 : 0; \ return 0; \ } @@ -678,7 +681,7 @@ GMPy_CTXT_Set_##NAME(CTXT_Object *self, PyObject *value, void *closure) \ TYPE_ERROR(#NAME " must be True or False"); \ return -1; \ } \ - if (value == Py_True) \ + if (Py_IsTrue(value)) \ self->ctx.traps |= TRAP; \ else \ self->ctx.traps &= ~(TRAP); \ diff --git a/src/gmpy2_convert.h b/src/gmpy2_convert.h index 40e59e05..004050a2 100644 --- a/src/gmpy2_convert.h +++ b/src/gmpy2_convert.h @@ -146,12 +146,10 @@ extern "C" { #if PY_VERSION_HEX >= 0x030C0000 # define GET_OB_DIGIT(obj) obj->long_value.ob_digit -# define _PyLong_IsNegative(obj) ((obj->long_value.lv_tag & 3) == 2) # define _PyLong_DigitCount(obj) (obj->long_value.lv_tag >> 3) #else # define GET_OB_DIGIT(obj) obj->ob_digit -# define _PyLong_IsNegative(obj) (Py_SIZE(obj) < 0) -# define _PyLong_DigitCount(obj) (_PyLong_IsNegative(obj)? -Py_SIZE(obj):Py_SIZE(obj)) +# define _PyLong_DigitCount(obj) (_PyLong_Sign(obj)<0 ? -Py_SIZE(obj):Py_SIZE(obj)) #endif /* Since the macros are used in gmpy2's codebase, these functions are skipped diff --git a/src/gmpy2_convert_gmp.c b/src/gmpy2_convert_gmp.c index 7321affd..8af191e6 100644 --- a/src/gmpy2_convert_gmp.c +++ b/src/gmpy2_convert_gmp.c @@ -38,42 +38,6 @@ * Conversion between native Python objects and MPZ. * * ======================================================================== */ -static MPZ_Object * -GMPy_MPZ_From_PyLong(PyObject *obj, CTXT_Object *context) -{ - MPZ_Object *result; - int negative; - Py_ssize_t len; - PyLongObject *templong = (PyLongObject*)obj; - - if(!(result = GMPy_MPZ_New(context))) { - /* LCOV_EXCL_START */ - return NULL; - /* LCOV_EXCL_STOP */ - } - - len = _PyLong_DigitCount(templong); - negative = _PyLong_IsNegative(templong); - - switch (len) { - case 1: - mpz_set_si(result->z, (sdigit)GET_OB_DIGIT(templong)[0]); - break; - case 0: - mpz_set_si(result->z, 0); - break; - default: - mpz_import(result->z, len, -1, sizeof(GET_OB_DIGIT(templong)[0]), 0, - sizeof(GET_OB_DIGIT(templong)[0])*8 - PyLong_SHIFT, - GET_OB_DIGIT(templong)); - } - - if (negative) { - mpz_neg(result->z, result->z); - } - return result; -} - /* To support creation of temporary mpz objects. */ static void mpz_set_PyLong(mpz_t z, PyObject *obj) @@ -83,7 +47,7 @@ mpz_set_PyLong(mpz_t z, PyObject *obj) PyLongObject *templong = (PyLongObject*)obj; len = _PyLong_DigitCount(templong); - negative = _PyLong_IsNegative(templong); + negative = _PyLong_Sign(obj) < 0; switch (len) { case 1: @@ -104,6 +68,22 @@ mpz_set_PyLong(mpz_t z, PyObject *obj) return; } +static MPZ_Object * +GMPy_MPZ_From_PyLong(PyObject *obj, CTXT_Object *context) +{ + MPZ_Object *result; + + if(!(result = GMPy_MPZ_New(context))) { + /* LCOV_EXCL_START */ + return NULL; + /* LCOV_EXCL_STOP */ + } + + mpz_set_PyLong(MPZ(result), obj); + + return result; +} + static MPZ_Object * GMPy_MPZ_From_PyStr(PyObject *s, int base, CTXT_Object *context) { @@ -393,25 +373,8 @@ GMPy_XMPZ_From_PyLong(PyObject *obj, CTXT_Object *context) /* LCOV_EXCL_STOP */ } - len = _PyLong_DigitCount(templong); - negative = _PyLong_IsNegative(templong); - - switch (len) { - case 1: - mpz_set_si(result->z, (sdigit)GET_OB_DIGIT(templong)[0]); - break; - case 0: - mpz_set_si(result->z, 0); - break; - default: - mpz_import(result->z, len, -1, sizeof(GET_OB_DIGIT(templong)[0]), 0, - sizeof(GET_OB_DIGIT(templong)[0])*8 - PyLong_SHIFT, - GET_OB_DIGIT(templong)); - } + mpz_set_PyLong(result->z, obj); - if (negative) { - mpz_neg(result->z, result->z); - } return result; } diff --git a/src/gmpy2_hash.c b/src/gmpy2_hash.c index d8d045cd..401579d2 100644 --- a/src/gmpy2_hash.c +++ b/src/gmpy2_hash.c @@ -24,6 +24,9 @@ * License along with GMPY2; if not, see * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "pythoncapi_compat.h" + static Py_hash_t GMPy_MPZ_Hash_Slot(MPZ_Object *self) { @@ -33,7 +36,7 @@ GMPy_MPZ_Hash_Slot(MPZ_Object *self) return self->hash_cache; } - hash = (Py_hash_t)mpn_mod_1(self->z->_mp_d, (mp_size_t)mpz_size(self->z), _PyHASH_MODULUS); + hash = (Py_hash_t)mpn_mod_1(self->z->_mp_d, (mp_size_t)mpz_size(self->z), PyHASH_MODULUS); if (mpz_sgn(self->z) < 0) { hash = -hash; } @@ -57,14 +60,14 @@ GMPy_MPQ_Hash_Slot(MPQ_Object *self) mpz_init(temp1); mpz_init(mask); mpz_set_si(mask, 1); - mpz_mul_2exp(mask, mask, _PyHASH_BITS); + mpz_mul_2exp(mask, mask, PyHASH_BITS); mpz_sub_ui(mask, mask, 1); if (!mpz_invert(temp, mpq_denref(self->q), mask)) { mpz_clear(temp); mpz_clear(temp1); mpz_clear(mask); - hash = _PyHASH_INF; + hash = PyHASH_INF; if (mpz_sgn(mpq_numref(self->q)) < 0) { hash = -hash; } @@ -77,7 +80,7 @@ GMPy_MPQ_Hash_Slot(MPQ_Object *self) mpz_tdiv_r(temp1, mpq_numref(self->q), mask); mpz_mul(temp, temp, temp1); - hash = (Py_hash_t)mpn_mod_1(temp->_mp_d, (mp_size_t)mpz_size(temp), _PyHASH_MODULUS); + hash = (Py_hash_t)mpn_mod_1(temp->_mp_d, (mp_size_t)mpz_size(temp), PyHASH_MODULUS); if (mpz_sgn(mpq_numref(self->q)) < 0) { hash = -hash; @@ -104,17 +107,15 @@ _mpfr_hash(mpfr_t f) if (!mpfr_number_p(f)) { if (mpfr_inf_p(f)) { if (mpfr_sgn(f) > 0) { - return _PyHASH_INF; + return PyHASH_INF; } else { - return -_PyHASH_INF; + return -PyHASH_INF; } } else { #if PY_VERSION_HEX >= 0x030A00A0 - /* The default object hash implementation in the CPython - * accepts void* pointer. */ - return PyBaseObject_Type.tp_hash((PyObject*)f); + return Py_HashPointer(f); #else return _PyHASH_NAN; #endif @@ -126,11 +127,11 @@ _mpfr_hash(mpfr_t f) /* Calculate the hash of the mantissa. */ if (mpfr_sgn(f) > 0) { - hash = mpn_mod_1(f->_mpfr_d, (mp_size_t)msize, _PyHASH_MODULUS); + hash = mpn_mod_1(f->_mpfr_d, (mp_size_t)msize, PyHASH_MODULUS); sign = 1; } else if (mpfr_sgn(f) < 0) { - hash = mpn_mod_1(f->_mpfr_d, (mp_size_t)msize, _PyHASH_MODULUS); + hash = mpn_mod_1(f->_mpfr_d, (mp_size_t)msize, PyHASH_MODULUS); sign = -1; } else { @@ -139,8 +140,8 @@ _mpfr_hash(mpfr_t f) /* Calculate the final hash. */ exp = f->_mpfr_exp - (msize * mp_bits_per_limb); - exp = exp >= 0 ? exp % _PyHASH_BITS : _PyHASH_BITS-1-((-1-exp) % _PyHASH_BITS); - hash = ((hash << exp) & _PyHASH_MODULUS) | hash >> (_PyHASH_BITS - exp); + exp = exp >= 0 ? exp % PyHASH_BITS : PyHASH_BITS-1-((-1-exp) % PyHASH_BITS); + hash = ((hash << exp) & PyHASH_MODULUS) | hash >> (PyHASH_BITS - exp); hash *= sign; if (hash == (Py_uhash_t)(-1)) { @@ -169,7 +170,7 @@ GMPy_MPC_Hash_Slot(MPC_Object *self) hashreal = (Py_uhash_t)_mpfr_hash(mpc_realref(self->c)); hashimag = (Py_uhash_t)_mpfr_hash(mpc_imagref(self->c)); - combined = hashreal + _PyHASH_IMAG * hashimag; + combined = hashreal + PyHASH_IMAG * hashimag; if (combined == (Py_uhash_t)(-1)) { combined = (Py_uhash_t)(-2); } diff --git a/src/gmpy2_pow.c b/src/gmpy2_pow.c index c191bdd6..24a63cf7 100644 --- a/src/gmpy2_pow.c +++ b/src/gmpy2_pow.c @@ -24,6 +24,9 @@ * License along with GMPY2; if not, see * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "pythoncapi_compat.h" + /* This file implements the ** operator, Python's pow() function, * gmpy2.powmod(), and context.pow(). */ @@ -50,7 +53,7 @@ GMPy_Integer_PowWithType(PyObject *b, int btype, PyObject *e, int etype, /* Try to parse the modulus value first. */ - if (m == Py_None) { + if (Py_IsNone(m)) { has_mod = 0; } else { @@ -410,7 +413,7 @@ GMPy_Rational_PowWithType(PyObject *base, int btype, PyObject *exp, int etype, int bsign; long tempexp; - if (mod != Py_None) { + if (!Py_IsNone(mod)) { TYPE_ERROR("pow() 3rd argument not allowed unless all arguments are integers"); return NULL; } @@ -486,7 +489,7 @@ GMPy_Real_PowWithType(PyObject *base, int btype, PyObject *exp, int etype, MPZ_Object *tempz = NULL; MPC_Object *mpc_result = NULL; - if (mod != Py_None) { + if (!Py_IsNone(mod)) { TYPE_ERROR("pow() 3rd argument not allowed unless all arguments are integers"); return NULL; } @@ -578,7 +581,7 @@ GMPy_Complex_PowWithType(PyObject *base, int btype, PyObject *exp, int etype, MPFR_Object *tempf = NULL; MPZ_Object *tempz = NULL; - if (mod != Py_None) { + if (!Py_IsNone(mod)) { TYPE_ERROR("pow() 3rd argument not allowed unless all arguments are integers"); return NULL; } diff --git a/src/gmpy2_random.c b/src/gmpy2_random.c index 2134a807..210d1aa9 100644 --- a/src/gmpy2_random.c +++ b/src/gmpy2_random.c @@ -39,7 +39,7 @@ static void GMPy_RandomState_Dealloc(RandomState_Object *self) { gmp_randclear(self->state); - PyObject_Del(self); + PyObject_Free(self); }; static PyObject * diff --git a/src/gmpy2_xmpz_misc.c b/src/gmpy2_xmpz_misc.c index f5eb6b32..5cf01706 100644 --- a/src/gmpy2_xmpz_misc.c +++ b/src/gmpy2_xmpz_misc.c @@ -24,6 +24,9 @@ * License along with GMPY2; if not, see * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "pythoncapi_compat.h" + PyDoc_STRVAR(GMPy_doc_xmpz_function_xbit_mask, "xbit_mask(n, /) -> xmpz\n\n" "Return an 'xmpz' exactly n bits in length with all bits set.\n"); @@ -234,7 +237,7 @@ GMPy_XMPZ_Method_AssignSubScript(XMPZ_Object* self, PyObject* item, PyObject* va Py_ssize_t cur, i, seq_len, start, stop, step, slicelength, temp; seq_len = mpz_sizeinbase(self->z, 2); - if (((PySliceObject*)item)->stop != Py_None) { + if (!Py_IsNone(((PySliceObject*)item)->stop)) { /* If a fixed endpoint is specified, and the endpoint is greater * than the length of the xmpz object, allow the underlying xmpz * object to be made larger. @@ -336,7 +339,7 @@ static void GMPy_Iter_Dealloc(GMPy_Iter_Object *self) { Py_XDECREF((PyObject*)self->bitmap); - PyObject_Del(self); + PyObject_Free(self); }; static PyObject * diff --git a/src/gmpy_mpz_prp.c b/src/gmpy_mpz_prp.c index c28452f6..13c9ddfb 100644 --- a/src/gmpy_mpz_prp.c +++ b/src/gmpy_mpz_prp.c @@ -29,6 +29,9 @@ * License along with GMPY2; if not, see * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "pythoncapi_compat.h" + /* ****************************************************************** * mpz_prp: (also called a Fermat probable prime) * A "probable prime" to the base a is a number n such that, @@ -1495,7 +1498,7 @@ GMPY_mpz_is_bpsw_prp(PyObject *self, PyObject *args) goto cleanup; result = GMPY_mpz_is_strong_prp(NULL, temp); Py_DECREF(temp); - if (result == Py_False) + if (Py_IsFalse(result)) goto return_result; /* Remember to ignore the preceding result */ Py_DECREF(result); @@ -1574,7 +1577,7 @@ GMPY_mpz_is_strongbpsw_prp(PyObject *self, PyObject *args) goto cleanup; result = GMPY_mpz_is_strong_prp(NULL, temp); Py_DECREF(temp); - if (result == Py_False) + if (Py_IsFalse(result)) goto return_result; /* Remember to ignore the preceding result */ Py_DECREF(result); diff --git a/src/mpz_pylong.c b/src/mpz_pylong.c index 26bdcb0b..e5192275 100644 --- a/src/mpz_pylong.c +++ b/src/mpz_pylong.c @@ -11,6 +11,9 @@ * */ + +#include "pythoncapi_compat.h" + /* This file created by merging mpn_pylong and mpz_pylong. Permission * was granted by the original author to make this code available under * the LGPLv2+ license. @@ -262,12 +265,12 @@ PyObject * mpz_get_PyLong(mpz_srcptr z) { size_t size = mpn_pylong_size(z->_mp_d, ABS(z->_mp_size)); - PyLongObject *lptr = PyObject_NEW_VAR(PyLongObject, &PyLong_Type, size); + PyLongObject *lptr = PyObject_NewVar(PyLongObject, &PyLong_Type, size); if (lptr != NULL) { mpn_get_pylong(lptr->ob_digit, size, z->_mp_d, ABS(z->_mp_size)); if (z->_mp_size < 0) - Py_SIZE(lptr) = -(Py_SIZE(lptr)); + Py_SET_SIZE(lptr, -(Py_SIZE(lptr))); } return (PyObject*)lptr; diff --git a/src/pythoncapi_compat.h b/src/pythoncapi_compat.h new file mode 100644 index 00000000..43ba0ddc --- /dev/null +++ b/src/pythoncapi_compat.h @@ -0,0 +1,1215 @@ +// Header file providing new C API functions to old Python versions. +// +// File distributed under the Zero Clause BSD (0BSD) license. +// Copyright Contributors to the pythoncapi_compat project. +// +// Homepage: +// https://github.com/python/pythoncapi_compat +// +// Latest version: +// https://raw.githubusercontent.com/python/pythoncapi_compat/master/pythoncapi_compat.h +// +// SPDX-License-Identifier: 0BSD + +#ifndef PYTHONCAPI_COMPAT +#define PYTHONCAPI_COMPAT + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +// Python 3.11.0b4 added PyFrame_Back() to Python.h +#if PY_VERSION_HEX < 0x030b00B4 && !defined(PYPY_VERSION) +# include "frameobject.h" // PyFrameObject, PyFrame_GetBack() +#endif + + +#ifndef _Py_CAST +# define _Py_CAST(type, expr) ((type)(expr)) +#endif + +// On C++11 and newer, _Py_NULL is defined as nullptr on C++11, +// otherwise it is defined as NULL. +#ifndef _Py_NULL +# if defined(__cplusplus) && __cplusplus >= 201103 +# define _Py_NULL nullptr +# else +# define _Py_NULL NULL +# endif +#endif + +// Cast argument to PyObject* type. +#ifndef _PyObject_CAST +# define _PyObject_CAST(op) _Py_CAST(PyObject*, op) +#endif + + +// bpo-42262 added Py_NewRef() to Python 3.10.0a3 +#if PY_VERSION_HEX < 0x030A00A3 && !defined(Py_NewRef) +static inline PyObject* _Py_NewRef(PyObject *obj) +{ + Py_INCREF(obj); + return obj; +} +#define Py_NewRef(obj) _Py_NewRef(_PyObject_CAST(obj)) +#endif + + +// bpo-42262 added Py_XNewRef() to Python 3.10.0a3 +#if PY_VERSION_HEX < 0x030A00A3 && !defined(Py_XNewRef) +static inline PyObject* _Py_XNewRef(PyObject *obj) +{ + Py_XINCREF(obj); + return obj; +} +#define Py_XNewRef(obj) _Py_XNewRef(_PyObject_CAST(obj)) +#endif + + +// bpo-39573 added Py_SET_REFCNT() to Python 3.9.0a4 +#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_REFCNT) +static inline void _Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) +{ + ob->ob_refcnt = refcnt; +} +#define Py_SET_REFCNT(ob, refcnt) _Py_SET_REFCNT(_PyObject_CAST(ob), refcnt) +#endif + + +// Py_SETREF() and Py_XSETREF() were added to Python 3.5.2. +// It is excluded from the limited C API. +#if (PY_VERSION_HEX < 0x03050200 && !defined(Py_SETREF)) && !defined(Py_LIMITED_API) +#define Py_SETREF(dst, src) \ + do { \ + PyObject **_tmp_dst_ptr = _Py_CAST(PyObject**, &(dst)); \ + PyObject *_tmp_dst = (*_tmp_dst_ptr); \ + *_tmp_dst_ptr = _PyObject_CAST(src); \ + Py_DECREF(_tmp_dst); \ + } while (0) + +#define Py_XSETREF(dst, src) \ + do { \ + PyObject **_tmp_dst_ptr = _Py_CAST(PyObject**, &(dst)); \ + PyObject *_tmp_dst = (*_tmp_dst_ptr); \ + *_tmp_dst_ptr = _PyObject_CAST(src); \ + Py_XDECREF(_tmp_dst); \ + } while (0) +#endif + + +// bpo-43753 added Py_Is(), Py_IsNone(), Py_IsTrue() and Py_IsFalse() +// to Python 3.10.0b1. +#if PY_VERSION_HEX < 0x030A00B1 && !defined(Py_Is) +# define Py_Is(x, y) ((x) == (y)) +#endif +#if PY_VERSION_HEX < 0x030A00B1 && !defined(Py_IsNone) +# define Py_IsNone(x) Py_Is(x, Py_None) +#endif +#if (PY_VERSION_HEX < 0x030A00B1 || defined(PYPY_VERSION)) && !defined(Py_IsTrue) +# define Py_IsTrue(x) Py_Is(x, Py_True) +#endif +#if (PY_VERSION_HEX < 0x030A00B1 || defined(PYPY_VERSION)) && !defined(Py_IsFalse) +# define Py_IsFalse(x) Py_Is(x, Py_False) +#endif + + +// bpo-39573 added Py_SET_TYPE() to Python 3.9.0a4 +#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_TYPE) +static inline void _Py_SET_TYPE(PyObject *ob, PyTypeObject *type) +{ + ob->ob_type = type; +} +#define Py_SET_TYPE(ob, type) _Py_SET_TYPE(_PyObject_CAST(ob), type) +#endif + + +// bpo-39573 added Py_SET_SIZE() to Python 3.9.0a4 +#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_SIZE) +static inline void _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) +{ + ob->ob_size = size; +} +#define Py_SET_SIZE(ob, size) _Py_SET_SIZE((PyVarObject*)(ob), size) +#endif + + +// bpo-40421 added PyFrame_GetCode() to Python 3.9.0b1 +#if PY_VERSION_HEX < 0x030900B1 || defined(PYPY_VERSION) +static inline PyCodeObject* PyFrame_GetCode(PyFrameObject *frame) +{ + assert(frame != _Py_NULL); + assert(frame->f_code != _Py_NULL); + return _Py_CAST(PyCodeObject*, Py_NewRef(frame->f_code)); +} +#endif + +static inline PyCodeObject* _PyFrame_GetCodeBorrow(PyFrameObject *frame) +{ + PyCodeObject *code = PyFrame_GetCode(frame); + Py_DECREF(code); + return code; +} + + +// bpo-40421 added PyFrame_GetBack() to Python 3.9.0b1 +#if PY_VERSION_HEX < 0x030900B1 && !defined(PYPY_VERSION) +static inline PyFrameObject* PyFrame_GetBack(PyFrameObject *frame) +{ + assert(frame != _Py_NULL); + return _Py_CAST(PyFrameObject*, Py_XNewRef(frame->f_back)); +} +#endif + +#if !defined(PYPY_VERSION) +static inline PyFrameObject* _PyFrame_GetBackBorrow(PyFrameObject *frame) +{ + PyFrameObject *back = PyFrame_GetBack(frame); + Py_XDECREF(back); + return back; +} +#endif + + +// bpo-40421 added PyFrame_GetLocals() to Python 3.11.0a7 +#if PY_VERSION_HEX < 0x030B00A7 && !defined(PYPY_VERSION) +static inline PyObject* PyFrame_GetLocals(PyFrameObject *frame) +{ +#if PY_VERSION_HEX >= 0x030400B1 + if (PyFrame_FastToLocalsWithError(frame) < 0) { + return NULL; + } +#else + PyFrame_FastToLocals(frame); +#endif + return Py_NewRef(frame->f_locals); +} +#endif + + +// bpo-40421 added PyFrame_GetGlobals() to Python 3.11.0a7 +#if PY_VERSION_HEX < 0x030B00A7 && !defined(PYPY_VERSION) +static inline PyObject* PyFrame_GetGlobals(PyFrameObject *frame) +{ + return Py_NewRef(frame->f_globals); +} +#endif + + +// bpo-40421 added PyFrame_GetBuiltins() to Python 3.11.0a7 +#if PY_VERSION_HEX < 0x030B00A7 && !defined(PYPY_VERSION) +static inline PyObject* PyFrame_GetBuiltins(PyFrameObject *frame) +{ + return Py_NewRef(frame->f_builtins); +} +#endif + + +// bpo-40421 added PyFrame_GetLasti() to Python 3.11.0b1 +#if PY_VERSION_HEX < 0x030B00B1 && !defined(PYPY_VERSION) +static inline int PyFrame_GetLasti(PyFrameObject *frame) +{ +#if PY_VERSION_HEX >= 0x030A00A7 + // bpo-27129: Since Python 3.10.0a7, f_lasti is an instruction offset, + // not a bytes offset anymore. Python uses 16-bit "wordcode" (2 bytes) + // instructions. + if (frame->f_lasti < 0) { + return -1; + } + return frame->f_lasti * 2; +#else + return frame->f_lasti; +#endif +} +#endif + + +// gh-91248 added PyFrame_GetVar() to Python 3.12.0a2 +#if PY_VERSION_HEX < 0x030C00A2 && !defined(PYPY_VERSION) +static inline PyObject* PyFrame_GetVar(PyFrameObject *frame, PyObject *name) +{ + PyObject *locals, *value; + + locals = PyFrame_GetLocals(frame); + if (locals == NULL) { + return NULL; + } +#if PY_VERSION_HEX >= 0x03000000 + value = PyDict_GetItemWithError(locals, name); +#else + value = _PyDict_GetItemWithError(locals, name); +#endif + Py_DECREF(locals); + + if (value == NULL) { + if (PyErr_Occurred()) { + return NULL; + } +#if PY_VERSION_HEX >= 0x03000000 + PyErr_Format(PyExc_NameError, "variable %R does not exist", name); +#else + PyErr_SetString(PyExc_NameError, "variable does not exist"); +#endif + return NULL; + } + return Py_NewRef(value); +} +#endif + + +// gh-91248 added PyFrame_GetVarString() to Python 3.12.0a2 +#if PY_VERSION_HEX < 0x030C00A2 && !defined(PYPY_VERSION) +static inline PyObject* +PyFrame_GetVarString(PyFrameObject *frame, const char *name) +{ + PyObject *name_obj, *value; +#if PY_VERSION_HEX >= 0x03000000 + name_obj = PyUnicode_FromString(name); +#else + name_obj = PyString_FromString(name); +#endif + if (name_obj == NULL) { + return NULL; + } + value = PyFrame_GetVar(frame, name_obj); + Py_DECREF(name_obj); + return value; +} +#endif + + +// bpo-39947 added PyThreadState_GetInterpreter() to Python 3.9.0a5 +#if PY_VERSION_HEX < 0x030900A5 || defined(PYPY_VERSION) +static inline PyInterpreterState * +PyThreadState_GetInterpreter(PyThreadState *tstate) +{ + assert(tstate != _Py_NULL); + return tstate->interp; +} +#endif + + +// bpo-40429 added PyThreadState_GetFrame() to Python 3.9.0b1 +#if PY_VERSION_HEX < 0x030900B1 && !defined(PYPY_VERSION) +static inline PyFrameObject* PyThreadState_GetFrame(PyThreadState *tstate) +{ + assert(tstate != _Py_NULL); + return _Py_CAST(PyFrameObject *, Py_XNewRef(tstate->frame)); +} +#endif + +#if !defined(PYPY_VERSION) +static inline PyFrameObject* +_PyThreadState_GetFrameBorrow(PyThreadState *tstate) +{ + PyFrameObject *frame = PyThreadState_GetFrame(tstate); + Py_XDECREF(frame); + return frame; +} +#endif + + +// bpo-39947 added PyInterpreterState_Get() to Python 3.9.0a5 +#if PY_VERSION_HEX < 0x030900A5 || defined(PYPY_VERSION) +static inline PyInterpreterState* PyInterpreterState_Get(void) +{ + PyThreadState *tstate; + PyInterpreterState *interp; + + tstate = PyThreadState_GET(); + if (tstate == _Py_NULL) { + Py_FatalError("GIL released (tstate is NULL)"); + } + interp = tstate->interp; + if (interp == _Py_NULL) { + Py_FatalError("no current interpreter"); + } + return interp; +} +#endif + + +// bpo-39947 added PyInterpreterState_Get() to Python 3.9.0a6 +#if 0x030700A1 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030900A6 && !defined(PYPY_VERSION) +static inline uint64_t PyThreadState_GetID(PyThreadState *tstate) +{ + assert(tstate != _Py_NULL); + return tstate->id; +} +#endif + +// bpo-43760 added PyThreadState_EnterTracing() to Python 3.11.0a2 +#if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION) +static inline void PyThreadState_EnterTracing(PyThreadState *tstate) +{ + tstate->tracing++; +#if PY_VERSION_HEX >= 0x030A00A1 + tstate->cframe->use_tracing = 0; +#else + tstate->use_tracing = 0; +#endif +} +#endif + +// bpo-43760 added PyThreadState_LeaveTracing() to Python 3.11.0a2 +#if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION) +static inline void PyThreadState_LeaveTracing(PyThreadState *tstate) +{ + int use_tracing = (tstate->c_tracefunc != _Py_NULL + || tstate->c_profilefunc != _Py_NULL); + tstate->tracing--; +#if PY_VERSION_HEX >= 0x030A00A1 + tstate->cframe->use_tracing = use_tracing; +#else + tstate->use_tracing = use_tracing; +#endif +} +#endif + + +// bpo-37194 added PyObject_CallNoArgs() to Python 3.9.0a1 +// PyObject_CallNoArgs() added to PyPy 3.9.16-v7.3.11 +#if !defined(PyObject_CallNoArgs) && PY_VERSION_HEX < 0x030900A1 +static inline PyObject* PyObject_CallNoArgs(PyObject *func) +{ + return PyObject_CallFunctionObjArgs(func, NULL); +} +#endif + + +// bpo-39245 made PyObject_CallOneArg() public (previously called +// _PyObject_CallOneArg) in Python 3.9.0a4 +// PyObject_CallOneArg() added to PyPy 3.9.16-v7.3.11 +#if !defined(PyObject_CallOneArg) && PY_VERSION_HEX < 0x030900A4 +static inline PyObject* PyObject_CallOneArg(PyObject *func, PyObject *arg) +{ + return PyObject_CallFunctionObjArgs(func, arg, NULL); +} +#endif + + +// bpo-1635741 added PyModule_AddObjectRef() to Python 3.10.0a3 +#if PY_VERSION_HEX < 0x030A00A3 +static inline int +PyModule_AddObjectRef(PyObject *module, const char *name, PyObject *value) +{ + int res; + + if (!value && !PyErr_Occurred()) { + // PyModule_AddObject() raises TypeError in this case + PyErr_SetString(PyExc_SystemError, + "PyModule_AddObjectRef() must be called " + "with an exception raised if value is NULL"); + return -1; + } + + Py_XINCREF(value); + res = PyModule_AddObject(module, name, value); + if (res < 0) { + Py_XDECREF(value); + } + return res; +} +#endif + + +// bpo-40024 added PyModule_AddType() to Python 3.9.0a5 +#if PY_VERSION_HEX < 0x030900A5 +static inline int PyModule_AddType(PyObject *module, PyTypeObject *type) +{ + const char *name, *dot; + + if (PyType_Ready(type) < 0) { + return -1; + } + + // inline _PyType_Name() + name = type->tp_name; + assert(name != _Py_NULL); + dot = strrchr(name, '.'); + if (dot != _Py_NULL) { + name = dot + 1; + } + + return PyModule_AddObjectRef(module, name, _PyObject_CAST(type)); +} +#endif + + +// bpo-40241 added PyObject_GC_IsTracked() to Python 3.9.0a6. +// bpo-4688 added _PyObject_GC_IS_TRACKED() to Python 2.7.0a2. +#if PY_VERSION_HEX < 0x030900A6 && !defined(PYPY_VERSION) +static inline int PyObject_GC_IsTracked(PyObject* obj) +{ + return (PyObject_IS_GC(obj) && _PyObject_GC_IS_TRACKED(obj)); +} +#endif + +// bpo-40241 added PyObject_GC_IsFinalized() to Python 3.9.0a6. +// bpo-18112 added _PyGCHead_FINALIZED() to Python 3.4.0 final. +#if PY_VERSION_HEX < 0x030900A6 && PY_VERSION_HEX >= 0x030400F0 && !defined(PYPY_VERSION) +static inline int PyObject_GC_IsFinalized(PyObject *obj) +{ + PyGC_Head *gc = _Py_CAST(PyGC_Head*, obj) - 1; + return (PyObject_IS_GC(obj) && _PyGCHead_FINALIZED(gc)); +} +#endif + + +// bpo-39573 added Py_IS_TYPE() to Python 3.9.0a4 +#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_IS_TYPE) +static inline int _Py_IS_TYPE(PyObject *ob, PyTypeObject *type) { + return Py_TYPE(ob) == type; +} +#define Py_IS_TYPE(ob, type) _Py_IS_TYPE(_PyObject_CAST(ob), type) +#endif + + +// bpo-46906 added PyFloat_Pack2() and PyFloat_Unpack2() to Python 3.11a7. +// bpo-11734 added _PyFloat_Pack2() and _PyFloat_Unpack2() to Python 3.6.0b1. +// Python 3.11a2 moved _PyFloat_Pack2() and _PyFloat_Unpack2() to the internal +// C API: Python 3.11a2-3.11a6 versions are not supported. +#if 0x030600B1 <= PY_VERSION_HEX && PY_VERSION_HEX <= 0x030B00A1 && !defined(PYPY_VERSION) +static inline int PyFloat_Pack2(double x, char *p, int le) +{ return _PyFloat_Pack2(x, (unsigned char*)p, le); } + +static inline double PyFloat_Unpack2(const char *p, int le) +{ return _PyFloat_Unpack2((const unsigned char *)p, le); } +#endif + + +// bpo-46906 added PyFloat_Pack4(), PyFloat_Pack8(), PyFloat_Unpack4() and +// PyFloat_Unpack8() to Python 3.11a7. +// Python 3.11a2 moved _PyFloat_Pack4(), _PyFloat_Pack8(), _PyFloat_Unpack4() +// and _PyFloat_Unpack8() to the internal C API: Python 3.11a2-3.11a6 versions +// are not supported. +#if PY_VERSION_HEX <= 0x030B00A1 && !defined(PYPY_VERSION) +static inline int PyFloat_Pack4(double x, char *p, int le) +{ return _PyFloat_Pack4(x, (unsigned char*)p, le); } + +static inline int PyFloat_Pack8(double x, char *p, int le) +{ return _PyFloat_Pack8(x, (unsigned char*)p, le); } + +static inline double PyFloat_Unpack4(const char *p, int le) +{ return _PyFloat_Unpack4((const unsigned char *)p, le); } + +static inline double PyFloat_Unpack8(const char *p, int le) +{ return _PyFloat_Unpack8((const unsigned char *)p, le); } +#endif + + +// gh-92154 added PyCode_GetCode() to Python 3.11.0b1 +#if PY_VERSION_HEX < 0x030B00B1 && !defined(PYPY_VERSION) +static inline PyObject* PyCode_GetCode(PyCodeObject *code) +{ + return Py_NewRef(code->co_code); +} +#endif + + +// gh-95008 added PyCode_GetVarnames() to Python 3.11.0rc1 +#if PY_VERSION_HEX < 0x030B00C1 && !defined(PYPY_VERSION) +static inline PyObject* PyCode_GetVarnames(PyCodeObject *code) +{ + return Py_NewRef(code->co_varnames); +} +#endif + +// gh-95008 added PyCode_GetFreevars() to Python 3.11.0rc1 +#if PY_VERSION_HEX < 0x030B00C1 && !defined(PYPY_VERSION) +static inline PyObject* PyCode_GetFreevars(PyCodeObject *code) +{ + return Py_NewRef(code->co_freevars); +} +#endif + +// gh-95008 added PyCode_GetCellvars() to Python 3.11.0rc1 +#if PY_VERSION_HEX < 0x030B00C1 && !defined(PYPY_VERSION) +static inline PyObject* PyCode_GetCellvars(PyCodeObject *code) +{ + return Py_NewRef(code->co_cellvars); +} +#endif + + +// Py_UNUSED() was added to Python 3.4.0b2. +#if PY_VERSION_HEX < 0x030400B2 && !defined(Py_UNUSED) +# if defined(__GNUC__) || defined(__clang__) +# define Py_UNUSED(name) _unused_ ## name __attribute__((unused)) +# else +# define Py_UNUSED(name) _unused_ ## name +# endif +#endif + + +// gh-105922 added PyImport_AddModuleRef() to Python 3.13.0a1 +#if PY_VERSION_HEX < 0x030D00A0 +static inline PyObject* PyImport_AddModuleRef(const char *name) +{ + return Py_XNewRef(PyImport_AddModule(name)); +} +#endif + + +// gh-105927 added PyWeakref_GetRef() to Python 3.13.0a1 +#if PY_VERSION_HEX < 0x030D0000 +static inline int PyWeakref_GetRef(PyObject *ref, PyObject **pobj) +{ + PyObject *obj; + if (ref != NULL && !PyWeakref_Check(ref)) { + *pobj = NULL; + PyErr_SetString(PyExc_TypeError, "expected a weakref"); + return -1; + } + obj = PyWeakref_GetObject(ref); + if (obj == NULL) { + // SystemError if ref is NULL + *pobj = NULL; + return -1; + } + if (obj == Py_None) { + *pobj = NULL; + return 0; + } + *pobj = Py_NewRef(obj); + return (*pobj != NULL); +} +#endif + + +// bpo-36974 added PY_VECTORCALL_ARGUMENTS_OFFSET to Python 3.8b1 +#ifndef PY_VECTORCALL_ARGUMENTS_OFFSET +# define PY_VECTORCALL_ARGUMENTS_OFFSET (_Py_CAST(size_t, 1) << (8 * sizeof(size_t) - 1)) +#endif + +// bpo-36974 added PyVectorcall_NARGS() to Python 3.8b1 +#if PY_VERSION_HEX < 0x030800B1 +static inline Py_ssize_t PyVectorcall_NARGS(size_t n) +{ + return n & ~PY_VECTORCALL_ARGUMENTS_OFFSET; +} +#endif + + +// gh-105922 added PyObject_Vectorcall() to Python 3.9.0a4 +#if PY_VERSION_HEX < 0x030900A4 +static inline PyObject* +PyObject_Vectorcall(PyObject *callable, PyObject *const *args, + size_t nargsf, PyObject *kwnames) +{ +#if PY_VERSION_HEX >= 0x030800B1 && !defined(PYPY_VERSION) + // bpo-36974 added _PyObject_Vectorcall() to Python 3.8.0b1 + return _PyObject_Vectorcall(callable, args, nargsf, kwnames); +#else + PyObject *posargs = NULL, *kwargs = NULL; + PyObject *res; + Py_ssize_t nposargs, nkwargs, i; + + if (nargsf != 0 && args == NULL) { + PyErr_BadInternalCall(); + goto error; + } + if (kwnames != NULL && !PyTuple_Check(kwnames)) { + PyErr_BadInternalCall(); + goto error; + } + + nposargs = (Py_ssize_t)PyVectorcall_NARGS(nargsf); + if (kwnames) { + nkwargs = PyTuple_GET_SIZE(kwnames); + } + else { + nkwargs = 0; + } + + posargs = PyTuple_New(nposargs); + if (posargs == NULL) { + goto error; + } + if (nposargs) { + for (i=0; i < nposargs; i++) { + PyTuple_SET_ITEM(posargs, i, Py_NewRef(*args)); + args++; + } + } + + if (nkwargs) { + kwargs = PyDict_New(); + if (kwargs == NULL) { + goto error; + } + + for (i = 0; i < nkwargs; i++) { + PyObject *key = PyTuple_GET_ITEM(kwnames, i); + PyObject *value = *args; + args++; + if (PyDict_SetItem(kwargs, key, value) < 0) { + goto error; + } + } + } + else { + kwargs = NULL; + } + + res = PyObject_Call(callable, posargs, kwargs); + Py_DECREF(posargs); + Py_XDECREF(kwargs); + return res; + +error: + Py_DECREF(posargs); + Py_XDECREF(kwargs); + return NULL; +#endif +} +#endif + + +// gh-106521 added PyObject_GetOptionalAttr() and +// PyObject_GetOptionalAttrString() to Python 3.13.0a1 +#if PY_VERSION_HEX < 0x030D00A1 +static inline int +PyObject_GetOptionalAttr(PyObject *obj, PyObject *attr_name, PyObject **result) +{ + // bpo-32571 added _PyObject_LookupAttr() to Python 3.7.0b1 +#if PY_VERSION_HEX >= 0x030700B1 && !defined(PYPY_VERSION) + return _PyObject_LookupAttr(obj, attr_name, result); +#else + *result = PyObject_GetAttr(obj, attr_name); + if (*result != NULL) { + return 1; + } + if (!PyErr_Occurred()) { + return 0; + } + if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + return 0; + } + return -1; +#endif +} + +static inline int +PyObject_GetOptionalAttrString(PyObject *obj, const char *attr_name, PyObject **result) +{ + PyObject *name_obj; + int rc; +#if PY_VERSION_HEX >= 0x03000000 + name_obj = PyUnicode_FromString(attr_name); +#else + name_obj = PyString_FromString(attr_name); +#endif + if (name_obj == NULL) { + *result = NULL; + return -1; + } + rc = PyObject_GetOptionalAttr(obj, name_obj, result); + Py_DECREF(name_obj); + return rc; +} +#endif + + +// gh-106307 added PyObject_GetOptionalAttr() and +// PyMapping_GetOptionalItemString() to Python 3.13.0a1 +#if PY_VERSION_HEX < 0x030D00A1 +static inline int +PyMapping_GetOptionalItem(PyObject *obj, PyObject *key, PyObject **result) +{ + *result = PyObject_GetItem(obj, key); + if (*result) { + return 1; + } + if (!PyErr_ExceptionMatches(PyExc_KeyError)) { + return -1; + } + PyErr_Clear(); + return 0; +} + +static inline int +PyMapping_GetOptionalItemString(PyObject *obj, const char *key, PyObject **result) +{ + PyObject *key_obj; + int rc; +#if PY_VERSION_HEX >= 0x03000000 + key_obj = PyUnicode_FromString(key); +#else + key_obj = PyString_FromString(key); +#endif + if (key_obj == NULL) { + *result = NULL; + return -1; + } + rc = PyMapping_GetOptionalItem(obj, key_obj, result); + Py_DECREF(key_obj); + return rc; +} +#endif + +// gh-108511 added PyMapping_HasKeyWithError() and +// PyMapping_HasKeyStringWithError() to Python 3.13.0a1 +#if PY_VERSION_HEX < 0x030D00A1 +static inline int +PyMapping_HasKeyWithError(PyObject *obj, PyObject *key) +{ + PyObject *res; + int rc = PyMapping_GetOptionalItem(obj, key, &res); + Py_XDECREF(res); + return rc; +} + +static inline int +PyMapping_HasKeyStringWithError(PyObject *obj, const char *key) +{ + PyObject *res; + int rc = PyMapping_GetOptionalItemString(obj, key, &res); + Py_XDECREF(res); + return rc; +} +#endif + + +// gh-108511 added PyObject_HasAttrWithError() and +// PyObject_HasAttrStringWithError() to Python 3.13.0a1 +#if PY_VERSION_HEX < 0x030D00A1 +static inline int +PyObject_HasAttrWithError(PyObject *obj, PyObject *attr) +{ + PyObject *res; + int rc = PyObject_GetOptionalAttr(obj, attr, &res); + Py_XDECREF(res); + return rc; +} + +static inline int +PyObject_HasAttrStringWithError(PyObject *obj, const char *attr) +{ + PyObject *res; + int rc = PyObject_GetOptionalAttrString(obj, attr, &res); + Py_XDECREF(res); + return rc; +} +#endif + + +// gh-106004 added PyDict_GetItemRef() and PyDict_GetItemStringRef() +// to Python 3.13.0a1 +#if PY_VERSION_HEX < 0x030D00A1 +static inline int +PyDict_GetItemRef(PyObject *mp, PyObject *key, PyObject **result) +{ +#if PY_VERSION_HEX >= 0x03000000 + PyObject *item = PyDict_GetItemWithError(mp, key); +#else + PyObject *item = _PyDict_GetItemWithError(mp, key); +#endif + if (item != NULL) { + *result = Py_NewRef(item); + return 1; // found + } + if (!PyErr_Occurred()) { + *result = NULL; + return 0; // not found + } + *result = NULL; + return -1; +} + +static inline int +PyDict_GetItemStringRef(PyObject *mp, const char *key, PyObject **result) +{ + int res; +#if PY_VERSION_HEX >= 0x03000000 + PyObject *key_obj = PyUnicode_FromString(key); +#else + PyObject *key_obj = PyString_FromString(key); +#endif + if (key_obj == NULL) { + *result = NULL; + return -1; + } + res = PyDict_GetItemRef(mp, key_obj, result); + Py_DECREF(key_obj); + return res; +} +#endif + + +// gh-106307 added PyModule_Add() to Python 3.13.0a1 +#if PY_VERSION_HEX < 0x030D00A1 +static inline int +PyModule_Add(PyObject *mod, const char *name, PyObject *value) +{ + int res = PyModule_AddObjectRef(mod, name, value); + Py_XDECREF(value); + return res; +} +#endif + + +// gh-108014 added Py_IsFinalizing() to Python 3.13.0a1 +// bpo-1856 added _Py_Finalizing to Python 3.2.1b1. +// _Py_IsFinalizing() was added to PyPy 7.3.0. +#if (0x030201B1 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030D00A1) \ + && (!defined(PYPY_VERSION_NUM) || PYPY_VERSION_NUM >= 0x7030000) +static inline int Py_IsFinalizing(void) +{ +#if PY_VERSION_HEX >= 0x030700A1 + // _Py_IsFinalizing() was added to Python 3.7.0a1. + return _Py_IsFinalizing(); +#else + return (_Py_Finalizing != NULL); +#endif +} +#endif + + +// gh-108323 added PyDict_ContainsString() to Python 3.13.0a1 +#if PY_VERSION_HEX < 0x030D00A1 +static inline int PyDict_ContainsString(PyObject *op, const char *key) +{ + PyObject *key_obj = PyUnicode_FromString(key); + if (key_obj == NULL) { + return -1; + } + int res = PyDict_Contains(op, key_obj); + Py_DECREF(key_obj); + return res; +} +#endif + + +// gh-108445 added PyLong_AsInt() to Python 3.13.0a1 +#if PY_VERSION_HEX < 0x030D00A1 +static inline int PyLong_AsInt(PyObject *obj) +{ +#ifdef PYPY_VERSION + long value = PyLong_AsLong(obj); + if (value == -1 && PyErr_Occurred()) { + return -1; + } + if (value < (long)INT_MIN || (long)INT_MAX < value) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C int"); + return -1; + } + return (int)value; +#else + return _PyLong_AsInt(obj); +#endif +} +#endif + + +// gh-107073 added PyObject_VisitManagedDict() to Python 3.13.0a1 +#if PY_VERSION_HEX < 0x030D00A1 +static inline int +PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg) +{ + PyObject **dict = _PyObject_GetDictPtr(obj); + if (*dict == NULL) { + return -1; + } + Py_VISIT(*dict); + return 0; +} + +static inline void +PyObject_ClearManagedDict(PyObject *obj) +{ + PyObject **dict = _PyObject_GetDictPtr(obj); + if (*dict == NULL) { + return; + } + Py_CLEAR(*dict); +} +#endif + +// gh-108867 added PyThreadState_GetUnchecked() to Python 3.13.0a1 +// Python 3.5.2 added _PyThreadState_UncheckedGet(). +#if PY_VERSION_HEX >= 0x03050200 && PY_VERSION_HEX < 0x030D00A1 +static inline PyThreadState* +PyThreadState_GetUnchecked(void) +{ + return _PyThreadState_UncheckedGet(); +} +#endif + +// gh-110289 added PyUnicode_EqualToUTF8() and PyUnicode_EqualToUTF8AndSize() +// to Python 3.13.0a1 +#if PY_VERSION_HEX < 0x030D00A1 +static inline int +PyUnicode_EqualToUTF8AndSize(PyObject *unicode, const char *str, Py_ssize_t str_len) +{ + Py_ssize_t len; + const void *utf8; + PyObject *exc_type, *exc_value, *exc_tb; + int res; + + // API cannot report errors so save/restore the exception + PyErr_Fetch(&exc_type, &exc_value, &exc_tb); + + // Python 3.3.0a1 added PyUnicode_AsUTF8AndSize() +#if PY_VERSION_HEX >= 0x030300A1 + if (PyUnicode_IS_ASCII(unicode)) { + utf8 = PyUnicode_DATA(unicode); + len = PyUnicode_GET_LENGTH(unicode); + } + else { + utf8 = PyUnicode_AsUTF8AndSize(unicode, &len); + if (utf8 == NULL) { + // Memory allocation failure. The API cannot report error, + // so ignore the exception and return 0. + res = 0; + goto done; + } + } + + if (len != str_len) { + res = 0; + goto done; + } + res = (memcmp(utf8, str, (size_t)len) == 0); +#else + PyObject *bytes = PyUnicode_AsUTF8String(unicode); + if (bytes == NULL) { + // Memory allocation failure. The API cannot report error, + // so ignore the exception and return 0. + res = 0; + goto done; + } + +#if PY_VERSION_HEX >= 0x03000000 + len = PyBytes_GET_SIZE(bytes); + utf8 = PyBytes_AS_STRING(bytes); +#else + len = PyString_GET_SIZE(bytes); + utf8 = PyString_AS_STRING(bytes); +#endif + if (len != str_len) { + Py_DECREF(bytes); + res = 0; + goto done; + } + + res = (memcmp(utf8, str, (size_t)len) == 0); + Py_DECREF(bytes); +#endif + +done: + PyErr_Restore(exc_type, exc_value, exc_tb); + return res; +} + +static inline int +PyUnicode_EqualToUTF8(PyObject *unicode, const char *str) +{ + return PyUnicode_EqualToUTF8AndSize(unicode, str, (Py_ssize_t)strlen(str)); +} +#endif + + +// gh-111138 added PyList_Extend() and PyList_Clear() to Python 3.13.0a2 +#if PY_VERSION_HEX < 0x030D00A2 +static inline int +PyList_Extend(PyObject *list, PyObject *iterable) +{ + return PyList_SetSlice(list, PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, iterable); +} + +static inline int +PyList_Clear(PyObject *list) +{ + return PyList_SetSlice(list, 0, PY_SSIZE_T_MAX, NULL); +} +#endif + +// gh-111262 added PyDict_Pop() and PyDict_PopString() to Python 3.13.0a2 +#if PY_VERSION_HEX < 0x030D00A2 +static inline int +PyDict_Pop(PyObject *dict, PyObject *key, PyObject **result) +{ + PyObject *value; + + if (!PyDict_Check(dict)) { + PyErr_BadInternalCall(); + if (result) { + *result = NULL; + } + return -1; + } + + // bpo-16991 added _PyDict_Pop() to Python 3.5.0b2. + // Python 3.6.0b3 changed _PyDict_Pop() first argument type to PyObject*. + // Python 3.13.0a1 removed _PyDict_Pop(). +#if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x030500b2 || PY_VERSION_HEX >= 0x030D0000 + value = PyObject_CallMethod(dict, "pop", "O", key); +#elif PY_VERSION_HEX < 0x030600b3 + value = _PyDict_Pop(_Py_CAST(PyDictObject*, dict), key, NULL); +#else + value = _PyDict_Pop(dict, key, NULL); +#endif + if (value == NULL) { + if (result) { + *result = NULL; + } + if (PyErr_Occurred() && !PyErr_ExceptionMatches(PyExc_KeyError)) { + return -1; + } + PyErr_Clear(); + return 0; + } + if (result) { + *result = value; + } + else { + Py_DECREF(value); + } + return 1; +} + +static inline int +PyDict_PopString(PyObject *dict, const char *key, PyObject **result) +{ + PyObject *key_obj = PyUnicode_FromString(key); + if (key_obj == NULL) { + if (result != NULL) { + *result = NULL; + } + return -1; + } + + int res = PyDict_Pop(dict, key_obj, result); + Py_DECREF(key_obj); + return res; +} +#endif + + +#if PY_VERSION_HEX < 0x030200A4 +// Python 3.2.0a4 added Py_hash_t type +typedef Py_ssize_t Py_hash_t; +#endif + + +// gh-111545 added Py_HashPointer() to Python 3.13.0a3 +#if PY_VERSION_HEX < 0x030D00A3 +static inline Py_hash_t Py_HashPointer(const void *ptr) +{ +#if PY_VERSION_HEX >= 0x030900A4 && !defined(PYPY_VERSION) + return _Py_HashPointer(ptr); +#else + return _Py_HashPointer(_Py_CAST(void*, ptr)); +#endif +} +#endif + + +// Python 3.13a4 added a PyTime API. +// Use the private API added to Python 3.5. +#if PY_VERSION_HEX < 0x030D00A4 && PY_VERSION_HEX >= 0x03050000 +typedef _PyTime_t PyTime_t; +#define PyTime_MIN _PyTime_MIN +#define PyTime_MAX _PyTime_MAX + +static inline double PyTime_AsSecondsDouble(PyTime_t t) +{ return _PyTime_AsSecondsDouble(t); } + +static inline int PyTime_Monotonic(PyTime_t *result) +{ return _PyTime_GetMonotonicClockWithInfo(result, NULL); } + +static inline int PyTime_Time(PyTime_t *result) +{ return _PyTime_GetSystemClockWithInfo(result, NULL); } + +static inline int PyTime_PerfCounter(PyTime_t *result) +{ +#if PY_VERSION_HEX >= 0x03070000 && !defined(PYPY_VERSION) + return _PyTime_GetPerfCounterWithInfo(result, NULL); +#elif PY_VERSION_HEX >= 0x03070000 + // Call time.perf_counter_ns() and convert Python int object to PyTime_t. + // Cache time.perf_counter_ns() function for best performance. + static PyObject *func = NULL; + if (func == NULL) { + PyObject *mod = PyImport_ImportModule("time"); + if (mod == NULL) { + return -1; + } + + func = PyObject_GetAttrString(mod, "perf_counter_ns"); + Py_DECREF(mod); + if (func == NULL) { + return -1; + } + } + + PyObject *res = PyObject_CallNoArgs(func); + if (res == NULL) { + return -1; + } + long long value = PyLong_AsLongLong(res); + Py_DECREF(res); + + if (value == -1 && PyErr_Occurred()) { + return -1; + } + + Py_BUILD_ASSERT(sizeof(value) >= sizeof(PyTime_t)); + *result = (PyTime_t)value; + return 0; +#else + // Call time.perf_counter() and convert C double to PyTime_t. + // Cache time.perf_counter() function for best performance. + static PyObject *func = NULL; + if (func == NULL) { + PyObject *mod = PyImport_ImportModule("time"); + if (mod == NULL) { + return -1; + } + + func = PyObject_GetAttrString(mod, "perf_counter"); + Py_DECREF(mod); + if (func == NULL) { + return -1; + } + } + + PyObject *res = PyObject_CallNoArgs(func); + if (res == NULL) { + return -1; + } + double d = PyFloat_AsDouble(res); + Py_DECREF(res); + + if (d == -1.0 && PyErr_Occurred()) { + return -1; + } + + // Avoid floor() to avoid having to link to libm + *result = (PyTime_t)(d * 1e9); + return 0; +#endif +} + +#endif + +// gh-111389 added hash constants to Python 3.13.0a5. These constants were +// added first as private macros to Python 3.4.0b1 and PyPy 7.3.9. +#if (!defined(PyHASH_BITS) \ + && ((!defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x030400B1) \ + || (defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x03070000 \ + && PYPY_VERSION_NUM >= 0x07090000))) +# define PyHASH_BITS _PyHASH_BITS +# define PyHASH_MODULUS _PyHASH_MODULUS +# define PyHASH_INF _PyHASH_INF +# define PyHASH_IMAG _PyHASH_IMAG +#endif + + +#ifdef __cplusplus +} +#endif +#endif // PYTHONCAPI_COMPAT